Skip to content

Commit

Permalink
Support for volume limits in CSI Powerstore
Browse files Browse the repository at this point in the history
  • Loading branch information
alankar-verma authored Jul 26, 2023
2 parents 18ac7d8 + a849ce3 commit 428ffe6
Show file tree
Hide file tree
Showing 10 changed files with 508 additions and 12 deletions.
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ require (
golang.org/x/net v0.10.0
google.golang.org/grpc v1.55.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.26.1
k8s.io/client-go v0.26.1
)

require (
Expand All @@ -57,6 +59,7 @@ require (
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/magiconair/properties v1.8.6 // indirect
Expand Down Expand Up @@ -103,8 +106,6 @@ require (
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/api v0.26.1 // indirect
k8s.io/apimachinery v0.26.1 // indirect
k8s.io/client-go v0.26.1 // indirect
k8s.io/component-base v0.24.1 // indirect
k8s.io/klog/v2 v2.80.1 // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jarcoal/httpmock v1.2.0 h1:gSvTxxFR/MEMfsGrvRbdfpRUMBStovlSRLw0Ep1bwwc=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
Expand Down
2 changes: 2 additions & 0 deletions helm/csi-powerstore/templates/node.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ spec:
value: {{ .Values.node.nodeNamePrefix }}
- name: X_CSI_POWERSTORE_NODE_ID_PATH
value: /node-id
- name: X_CSI_POWERSTORE_MAX_VOLUMES_PER_NODE
value: "{{ .Values.maxPowerstoreVolumesPerNode }}"
- name: X_CSI_POWERSTORE_NODE_CHROOT_PATH
value: /noderoot
- name: X_CSI_POWERSTORE_TMP_DIR
Expand Down
7 changes: 7 additions & 0 deletions helm/csi-powerstore/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ externalAccess:
# Default value: None
imagePullPolicy: IfNotPresent

# maxPowerstoreVolumesPerNode: Specify default value for maximum number of volumes that controller can publish to the node.
# If value is zero CO SHALL decide how many volumes of this type can be published by the controller to the node.
# This limit is applicable to all the nodes in the cluster for which node label 'max-powerstore-volumes-per-node' is not set.
# Allowed values: n, where n >= 0
# Default value: 0
maxPowerstoreVolumesPerNode: 0

# nfsAcls: enables setting permissions on NFS mount directory
# This value acts as default value for NFS ACL (nfsAcls), if not specified for an array config in secret
# Permissions can be specified in two formats:
Expand Down
152 changes: 152 additions & 0 deletions mocks/NodeLabelsRetriever.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions pkg/common/envvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,16 @@ const (
// node name
EnvKubeNodeName = "X_CSI_POWERSTORE_KUBE_NODE_NAME"

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

// EnvNodeNamePrefix is the name of the environment variable which stores prefix which will be
// used when registering node on PowerStore array
EnvNodeNamePrefix = "X_CSI_POWERSTORE_NODE_NAME_PREFIX"

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

// EnvNodeChrootPath is the name of the environment variable which store path to chroot where
// to execute iSCSI commands
EnvNodeChrootPath = "X_CSI_POWERSTORE_NODE_CHROOT_PATH"
Expand Down
110 changes: 110 additions & 0 deletions pkg/common/k8sutils/k8sutils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
Copyright (c) 2023 Dell Inc, or its subsidiaries.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package k8sutils

import (
"context"

v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)

// NodeLabelsRetrieverInterface defines the methods for retrieving Kubernetes Node Labels
type NodeLabelsRetrieverInterface interface {
BuildConfigFromFlags(masterURL, kubeconfig string) (*rest.Config, error)
InClusterConfig() (*rest.Config, error)
NewForConfig(config *rest.Config) (*kubernetes.Clientset, error)
GetNodeLabels(ctx context.Context, k8sclientset *kubernetes.Clientset, kubeNodeName string) (map[string]string, error)
}

// NodeLabelsRetrieverImpl provided the implementation for NodeLabelsRetrieverInterface
type NodeLabelsRetrieverImpl struct{}

// NodeLabelsRetriever is the actual instance of NodeLabelsRetrieverInterface which is used to retrieve the node labels
var NodeLabelsRetriever NodeLabelsRetrieverInterface

func init() {
NodeLabelsRetriever = new(NodeLabelsRetrieverImpl)
}

// BuildConfigFromFlags is a method for building kubernetes client config
func (svc *NodeLabelsRetrieverImpl) BuildConfigFromFlags(masterURL, kubeconfig string) (*rest.Config, error) {
return clientcmd.BuildConfigFromFlags(masterURL, kubeconfig)
}

// InClusterConfig returns a config object which uses the service account kubernetes gives to pods
func (svc *NodeLabelsRetrieverImpl) InClusterConfig() (*rest.Config, error) {
return rest.InClusterConfig()
}

// NewForConfig creates a new Clientset for the given config
func (svc *NodeLabelsRetrieverImpl) NewForConfig(config *rest.Config) (*kubernetes.Clientset, error) {
return kubernetes.NewForConfig(config)
}

// GetNodeLabels retrieves the kubernetes node object and returns its labels
func (svc *NodeLabelsRetrieverImpl) GetNodeLabels(ctx context.Context, k8sclientset *kubernetes.Clientset, kubeNodeName string) (map[string]string, error) {
if k8sclientset != nil {
node, err := k8sclientset.CoreV1().Nodes().Get(ctx, kubeNodeName, v1.GetOptions{})
if err != nil {
return nil, err
}

return node.Labels, nil
}

return nil, nil
}

// CreateKubeClientSet creates and returns kubeclient set
func CreateKubeClientSet(kubeconfig string) (*kubernetes.Clientset, error) {
var clientset *kubernetes.Clientset
if kubeconfig != "" {
config, err := NodeLabelsRetriever.BuildConfigFromFlags("", kubeconfig)
if err != nil {
return nil, err
}
// create the clientset
clientset, err = NodeLabelsRetriever.NewForConfig(config)
if err != nil {
return nil, err
}
} else {
config, err := NodeLabelsRetriever.InClusterConfig()
if err != nil {
return nil, err
}
// creates the clientset
clientset, err = NodeLabelsRetriever.NewForConfig(config)
if err != nil {
return nil, err
}
}
return clientset, nil
}

// GetNodeLabels returns labels present in the k8s node
func GetNodeLabels(ctx context.Context, kubeConfigPath string, kubeNodeName string) (map[string]string, error) {
k8sclientset, err := CreateKubeClientSet(kubeConfigPath)
if err != nil {
return nil, err
}

return NodeLabelsRetriever.GetNodeLabels(ctx, k8sclientset, kubeNodeName)
}
14 changes: 14 additions & 0 deletions pkg/node/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ func getNodeOptions() Opts {
opts.NodeIDFilePath = path
}

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

if prefix, ok := csictx.LookupEnv(ctx, common.EnvNodeNamePrefix); ok {
opts.NodeNamePrefix = prefix
}
Expand All @@ -107,6 +111,16 @@ func getNodeOptions() Opts {
opts.NodeChrootPath = defaultNodeChrootPath
}

if maxVolumesPerNodeStr, ok := csictx.LookupEnv(ctx, common.EnvMaxVolumesPerNode); ok {
maxVolumesPerNode, err := strconv.ParseInt(maxVolumesPerNodeStr, 10, 64)
if err != nil {
log.Warn("error while parsing the value of maxPowerstoreVolumesPerNode, using default value 0")
opts.MaxVolumesPerNode = 0
} else {
opts.MaxVolumesPerNode = maxVolumesPerNode
}
}

if tmpDir, ok := csictx.LookupEnv(ctx, common.EnvTmpDir); ok {
opts.TmpDir = tmpDir
}
Expand Down
Loading

0 comments on commit 428ffe6

Please sign in to comment.