Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature max vol limits #214

Merged
merged 1 commit into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions service/envvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,15 @@ const (
// EnvManagedArrays is an env variable with a list of space separated arrays.
EnvManagedArrays = "X_CSI_MANAGED_ARRAYS"

// EnvKubeConfigPath indicates kubernetes configuration that has to be used by CSI Driver
EnvKubeConfigPath = "KUBECONFIG"

// EnvConfigFilePath is an env variable which contains the full path for the config file
EnvConfigFilePath = "X_CSI_POWERMAX_CONFIG_PATH"

// EnvMaxVolumesPerNode specifies maximum number of volumes that controller can publish to the node.
EnvMaxVolumesPerNode = "X_CSI_MAX_VOLUMES_PER_NODE"

// EnvHealthMonitorEnabled is an env variable which indicated if volume health monitor is enabled
EnvHealthMonitorEnabled = "X_CSI_HEALTH_MONITOR_ENABLED"

Expand Down
41 changes: 41 additions & 0 deletions service/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -1050,11 +1050,52 @@ func (s *service) NodeGetInfo(
return nil, status.Error(codes.FailedPrecondition, "no topology keys could be generate")
}

var maxPowerMaxVolumesPerNode int64
labels, err := s.GetNodeLabels()
if err != nil {
log.Error("failed to get Node Labels with error", err.Error())
return nil, err
}
if val, ok := labels["max-powermax-volumes-per-node"]; ok {
maxPowerMaxVolumesPerNode, err = strconv.ParseInt(val, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid value '%s' specified for 'max-powermax-volumes-per-node' node label", val)
}
if s.opts.IsVsphereEnabled {
if maxPowerMaxVolumesPerNode <= 0 || maxPowerMaxVolumesPerNode > 60 {
log.Errorf("Node label max-powermax-volumes-per-node should not be greater than 60 or set to any negative value for RDM volumes, Setting to default value 60")
}
maxPowerMaxVolumesPerNode = 60
} else {
if maxPowerMaxVolumesPerNode < 0 {
log.Errorf("Node label max-powermax-volumes-per-node should not be set to negative value, Using default value 0")
maxPowerMaxVolumesPerNode = 0
}
}
log.Infof("node label 'max-powermax-volumes-per-node' is available and is set to value '%v'", maxPowerMaxVolumesPerNode)
} else {
// As per the csi spec the plugin MUST NOT set negative values to
// 'MaxVolumesPerNode' in the NodeGetInfoResponse response
log.Infof("Node label 'max-powermax-volumes-per-node' is not available. Retrieving the value from yaml file")
if s.opts.IsVsphereEnabled {
if s.opts.MaxVolumesPerNode <= 0 || s.opts.MaxVolumesPerNode > 60 {
log.Errorf("maxPowerMaxVolumesPerNode MUST NOT be greater than 60 or set to any negative value for RDM volumes. Setting to default value 60")
}
s.opts.MaxVolumesPerNode = 60
} else {
if s.opts.MaxVolumesPerNode < 0 {
log.Errorf("maxPowerMaxVolumesPerNode MUST NOT be set to negative value, setting to default value 0")
s.opts.MaxVolumesPerNode = 0
}
}
maxPowerMaxVolumesPerNode = s.opts.MaxVolumesPerNode
}
return &csi.NodeGetInfoResponse{
NodeId: s.opts.NodeName,
AccessibleTopology: &csi.Topology{
Segments: topology,
},
MaxVolumesPerNode: maxPowerMaxVolumesPerNode,
}, nil
}

Expand Down
36 changes: 36 additions & 0 deletions service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"time"

"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/dell/csi-powermax/v2/k8sutils"
"github.com/dell/gocsi"
csictx "github.com/dell/gocsi/context"
"github.com/dell/goiscsi"
Expand All @@ -46,6 +47,7 @@ import (
migrext "github.com/dell/dell-csi-extensions/migration"
csiext "github.com/dell/dell-csi-extensions/replication"
pmax "github.com/dell/gopowermax/v2"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// Constants for the service
Expand Down Expand Up @@ -95,6 +97,7 @@ type Opts struct {
Password string
SystemName string
NodeName string
NodeFullName string
TransportProtocol string
DriverName string
CHAPUserName string
Expand Down Expand Up @@ -125,6 +128,8 @@ type Opts struct {
VCenterHostURL string // vCenter host url
VCenterHostUserName string // vCenter host username
VCenterHostPassword string // vCenter password
MaxVolumesPerNode int64 // to specify volume limits
KubeConfigPath string // to specify k8s configuration to be used CSI driver
}

// NodeConfig defines rules for given node
Expand Down Expand Up @@ -362,6 +367,7 @@ func (s *service) BeforeServe(
if name, ok := csictx.LookupEnv(ctx, EnvNodeName); ok {
shortHostName := strings.Split(name, ".")[0]
opts.NodeName = shortHostName
opts.NodeFullName = name
}
if portgroups, ok := csictx.LookupEnv(ctx, EnvPortGroups); ok {
tempList, err := s.parseCommaSeperatedList(portgroups)
Expand All @@ -378,13 +384,27 @@ func (s *service) BeforeServe(
os.Exit(1)
}

if kubeConfigPath, ok := csictx.LookupEnv(ctx, EnvKubeConfigPath); ok {
opts.KubeConfigPath = kubeConfigPath
}

if replicationContextPrefix, ok := csictx.LookupEnv(ctx, EnvReplicationContextPrefix); ok {
opts.ReplicationContextPrefix = replicationContextPrefix
}
if replicationPrefix, ok := csictx.LookupEnv(ctx, EnvReplicationPrefix); ok {
opts.ReplicationPrefix = replicationPrefix
}

if MaxVolumesPerNode, ok := csictx.LookupEnv(ctx, EnvMaxVolumesPerNode); ok {
val, err := strconv.ParseInt(MaxVolumesPerNode, 10, 64)
if err != nil {
log.Warningf("error while parsing env variable '%s', %s, defaulting to 0", EnvMaxVolumesPerNode, err)
opts.MaxVolumesPerNode = 0
} else {
opts.MaxVolumesPerNode = val
}
}

opts.TransportProtocol = s.getTransportProtocolFromEnv()
opts.ProxyServiceHost, opts.ProxyServicePort, opts.UseProxy = s.getProxySettingsFromEnv()
if !opts.UseProxy && !inducedMockReverseProxy {
Expand Down Expand Up @@ -792,3 +812,19 @@ func getLogFields(ctx context.Context) log.Fields {
fields["RequestID"] = csiReqID
return fields
}

func (s *service) GetNodeLabels() (map[string]string, error) {
k8sclientset, err := k8sutils.CreateKubeClientSet(s.opts.KubeConfigPath)
if err != nil {
log.Errorf("init client failed: '%s'", err.Error())
return nil, err
}
// access the API to fetch node object
node, err := k8sclientset.CoreV1().Nodes().Get(context.TODO(), s.opts.NodeFullName, v1.GetOptions{})
if err != nil {
return nil, err
}
log.Debugf("Node %s details\n", node)

return node.Labels, nil
}
Loading