From c5a6d3319de711da7612635602bd8c0525d7c88b Mon Sep 17 00:00:00 2001 From: hemalathagajendran Date: Wed, 16 Jul 2025 11:46:02 +0530 Subject: [PATCH 01/14] changes for primary fs removal Signed-off-by: hemalathagajendran --- driver/csiplugin/controllerserver.go | 75 +++-------------- driver/csiplugin/gpfs.go | 8 +- driver/csiplugin/gpfs_util.go | 6 +- driver/csiplugin/settings/scale_config.go | 18 ++--- operator/Makefile | 6 +- operator/controllers/config/constants.go | 2 - .../csiscaleoperator_controller.go | 81 +++++++------------ 7 files changed, 60 insertions(+), 136 deletions(-) diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index ab8c201ee..e23da855d 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -118,7 +118,7 @@ func (cs *ScaleControllerServer) createLWVol(ctx context.Context, scVol *scaleVo //VolID format for all newly created volumes (from 2.5.0 onwards): // ;;;;;; -func (cs *ScaleControllerServer) generateVolID(ctx context.Context, scVol *scaleVolume, uid string, isCGVolume, isShallowCopyVolume bool, targetPath string, filesetNameStatic string, ifPrimaryDisable bool) (string, error) { +func (cs *ScaleControllerServer) generateVolID(ctx context.Context, scVol *scaleVolume, uid string, isCGVolume, isShallowCopyVolume bool, targetPath string, filesetNameStatic string) (string, error) { loggerId := utils.GetLoggerId(ctx) klog.Infof("[%s] volume: [%v] - ControllerServer:generateVolId", loggerId, scVol.VolName) klog.V(4).Infof("[%s] scVol: [%+v] - ControllerServer:generateVolId targetPath:[%v]", loggerId, scVol, targetPath) @@ -131,7 +131,7 @@ func (cs *ScaleControllerServer) generateVolID(ctx context.Context, scVol *scale path := "" if !isShallowCopyVolume { - if isCGVolume || scVol.VolumeType == cacheVolume || scVol.IsStaticPVBased || ifPrimaryDisable { + if isCGVolume || scVol.VolumeType == cacheVolume || scVol.IsStaticPVBased { primaryConn, isprimaryConnPresent := cs.Driver.connmap["primary"] if !isprimaryConnPresent { klog.Errorf("[%s] unable to get connector for primary cluster", loggerId) @@ -830,37 +830,15 @@ func validateVACParams(ctx context.Context, mutableParams map[string]string) (ma return afmTuningParams, nil } -func (cs *ScaleControllerServer) getPrimaryClusterDetails(ctx context.Context, ifPrimaryDisable bool) (connectors.SpectrumScaleConnector, string, string, string, string, string, error) { +func (cs *ScaleControllerServer) getPrimaryClusterDetails(ctx context.Context) (connectors.SpectrumScaleConnector, string, error) { loggerId := utils.GetLoggerId(ctx) - klog.Infof("[%s] getPrimaryClusterDetails with ifPrimaryDisable: %t", loggerId, ifPrimaryDisable) klog.V(4).Infof("[%s] getPrimaryClusterDetails : cs.Driver.primary: [ %v ]", loggerId, cs.Driver.primary) primaryConn := cs.Driver.connmap["primary"] - var primaryFS, primaryFset, primaryFSMount, symlinkDirRelativePath, symlinkDirAbsolutePath string = "", "", "", "", "" var err error - if !ifPrimaryDisable { - primaryFS = cs.Driver.primary.GetPrimaryFs() - primaryFset = cs.Driver.primary.PrimaryFset - - // check if primary filesystem exists - fsMountInfo, err := primaryConn.GetFilesystemMountDetails(ctx, primaryFS) - if err != nil { - klog.Errorf("[%s] Failed to get details of primary filesystem %s", loggerId, primaryFS) - return nil, "", "", "", "", "", err - } - primaryFSMount = fsMountInfo.MountPoint - // If primary fset is not specified, then use default - if primaryFset == "" { - primaryFset = defaultPrimaryFileset - } - - symlinkDirRelativePath = primaryFset + "/" + symlinkDir - symlinkDirAbsolutePath = fsMountInfo.MountPoint + "/" + symlinkDirRelativePath - klog.V(4).Infof("[%s] symlinkDirPath [%s], symlinkDirRelPath [%s]", loggerId, symlinkDirAbsolutePath, symlinkDirRelativePath) - } - return primaryConn, symlinkDirRelativePath, primaryFS, primaryFSMount, symlinkDirAbsolutePath, cs.Driver.primary.PrimaryCid, err + return primaryConn, cs.Driver.primary.PrimaryCid, err } func (cs *ScaleControllerServer) getPrimaryFSMountPoint(ctx context.Context) (string, error) { @@ -926,13 +904,7 @@ func (cs *ScaleControllerServer) CreateVolume(newctx context.Context, req *csi.C return nil, status.Error(codes.InvalidArgument, "The Parameter(s) not supported in storageClass: "+invalidParams) } - ifPrimaryDisable := false - if strings.ToUpper(os.Getenv(settings.PrimaryFilesystemKey)) == settings.PrimaryFilesystemValue { - ifPrimaryDisable = true - } - klog.Infof("[%s] ifPrimaryDisable : %t", loggerId, ifPrimaryDisable) - - scaleVol, isCGVolume, primaryClusterID, err := cs.setScaleVolume(ctx, req, volName, volSize, ifPrimaryDisable) + scaleVol, isCGVolume, primaryClusterID, err := cs.setScaleVolume(ctx, req, volName, volSize) if err != nil { return nil, err } @@ -1015,16 +987,6 @@ func (cs *ScaleControllerServer) CreateVolume(newctx context.Context, req *csi.C } } - // skip primaryfset linking check when DISABLE_PRIMARY is set true as env - - if !ifPrimaryDisable { - if srcVolumeIDMembers.VolType != FILE_SHALLOWCOPY_VOLUME { - err = cs.checkFileSetLink(ctx, scaleVol.PrimaryConnector, scaleVol, scaleVol.PrimaryFS, cs.Driver.primary.PrimaryFset, "primary") - if err != nil { - return nil, err - } - } - } volFsInfo, err := checkVolumeFilesystemMountOnPrimary(ctx, scaleVol) if err != nil { return nil, err @@ -1088,7 +1050,7 @@ func (cs *ScaleControllerServer) CreateVolume(newctx context.Context, req *csi.C shallowCopyTargetPath = fmt.Sprintf("%s/%s/.snapshots/%s/%s", volFsInfo.Mount.MountPoint, snapIdMembers.FsetName, snapIdMembers.SnapName, snapIdMembers.Path) } - volID, volIDErr := cs.generateVolID(ctx, scaleVol, volFsInfo.UUID, isCGVolume, isShallowCopyVolume, shallowCopyTargetPath, scaleVol.VolName, ifPrimaryDisable) + volID, volIDErr := cs.generateVolID(ctx, scaleVol, volFsInfo.UUID, isCGVolume, isShallowCopyVolume, shallowCopyTargetPath, scaleVol.VolName) if volIDErr != nil { return nil, volIDErr } @@ -1188,18 +1150,7 @@ func (cs *ScaleControllerServer) CreateVolume(newctx context.Context, req *csi.C return nil, err } - // skip symbolic link creation when DISABLE_PRIMARY is set true as env - - if !ifPrimaryDisable { - if !isCGVolume && scaleVol.VolumeType != cacheVolume && !scaleVol.IsStaticPVBased { - // Create symbolic link if not present - err = cs.createSoftlink(ctx, scaleVol, targetPath) - if err != nil { - return nil, status.Error(codes.Internal, err.Error()) - } - } - } - volID, volIDErr := cs.generateVolID(ctx, scaleVol, volFsInfo.UUID, isCGVolume, isShallowCopyVolume, targetPath, filesetName, ifPrimaryDisable) + volID, volIDErr := cs.generateVolID(ctx, scaleVol, volFsInfo.UUID, isCGVolume, isShallowCopyVolume, targetPath, filesetName) if volIDErr != nil { return nil, volIDErr } @@ -1357,7 +1308,7 @@ func validateCacheSecret(secretData map[string]string) []string { return missingKeys } -func (cs *ScaleControllerServer) setScaleVolume(ctx context.Context, req *csi.CreateVolumeRequest, volName string, volSize int64, ifPrimaryDisable bool) (*scaleVolume, bool, string, error) { +func (cs *ScaleControllerServer) setScaleVolume(ctx context.Context, req *csi.CreateVolumeRequest, volName string, volSize int64) (*scaleVolume, bool, string, error) { scaleVol, err := getScaleVolumeOptions(ctx, req.GetParameters()) if err != nil { return nil, false, "", err @@ -1382,16 +1333,16 @@ func (cs *ScaleControllerServer) setScaleVolume(ctx context.Context, req *csi.Cr } /* Get details for Primary Cluster */ - primaryConn, symlinkDirRelativePath, primaryFS, primaryFSMount, symlinkDirAbsolutePath, primaryClusterID, err := cs.getPrimaryClusterDetails(ctx, ifPrimaryDisable) + primaryConn, primaryClusterID, err := cs.getPrimaryClusterDetails(ctx) if err != nil { return nil, isCGVolume, "", err } scaleVol.PrimaryConnector = primaryConn - scaleVol.PrimarySLnkRelPath = symlinkDirRelativePath - scaleVol.PrimaryFS = primaryFS - scaleVol.PrimaryFSMount = primaryFSMount - scaleVol.PrimarySLnkPath = symlinkDirAbsolutePath + //scaleVol.PrimarySLnkRelPath = symlinkDirRelativePath + //scaleVol.PrimaryFS = primaryFS + //scaleVol.PrimaryFSMount = primaryFSMount + //scaleVol.PrimarySLnkPath = symlinkDirAbsolutePath return scaleVol, isCGVolume, primaryClusterID, nil } diff --git a/driver/csiplugin/gpfs.go b/driver/csiplugin/gpfs.go index 464d2fc84..ce9357173 100644 --- a/driver/csiplugin/gpfs.go +++ b/driver/csiplugin/gpfs.go @@ -263,6 +263,7 @@ func (driver *ScaleDriver) PluginInitialize(ctx context.Context) (map[string]con scaleConnMap[cluster.ID] = sc + klog.Infof("[%s] cluster.Primary:[%+v], settings.Primary:[%+v]", loggerId, cluster.Primary, settings.Primary{}) if cluster.Primary != (settings.Primary{}) { // Check if GUI is reachable - only for primary cluster @@ -276,13 +277,14 @@ func (driver *ScaleDriver) PluginInitialize(ctx context.Context) (map[string]con scaleConfig.Clusters[i].Primary.PrimaryCid = clusterId //If primary fileset value is not specified then use the default one - if scaleConfig.Clusters[i].Primary.PrimaryFset == "" { - scaleConfig.Clusters[i].Primary.PrimaryFset = defaultPrimaryFileset - } + //if scaleConfig.Clusters[i].Primary.PrimaryFset == "" { + // scaleConfig.Clusters[i].Primary.PrimaryFset = defaultPrimaryFileset + //} primaryInfo = scaleConfig.Clusters[i].Primary } } + klog.Infof("[%s] scaleConfig:[%+v], primaryInfo:[%+v], scaleConnMap:[%+v]", utils.GetLoggerId(ctx), scaleConfig, primaryInfo, scaleConnMap) klog.Infof("[%s] IBM Storage Scale CSI driver initialized", utils.GetLoggerId(ctx)) return scaleConnMap, scaleConfig, primaryInfo, nil } diff --git a/driver/csiplugin/gpfs_util.go b/driver/csiplugin/gpfs_util.go index 405f1223a..c4e75c10c 100644 --- a/driver/csiplugin/gpfs_util.go +++ b/driver/csiplugin/gpfs_util.go @@ -82,9 +82,9 @@ type scaleVolume struct { InodeLimit string `json:"inodeLimit"` Connector connectors.SpectrumScaleConnector `json:"connector"` PrimaryConnector connectors.SpectrumScaleConnector `json:"primaryConnector"` - PrimarySLnkRelPath string `json:"primarySLnkRelPath"` - PrimarySLnkPath string `json:"primarySLnkPath"` - PrimaryFS string `json:"primaryFS"` + PrimarySLnkRelPath string `json:"primarySLnkRelPath"` //Deprecated from 3.0.0 + PrimarySLnkPath string `json:"primarySLnkPath"` //Deprecated from 3.0.0 + PrimaryFS string `json:"primaryFS"` //Deprecated from 3.0.0 PrimaryFSMount string `json:"primaryFSMount"` ParentFileset string `json:"parentFileset"` LocalFS string `json:"localFS"` diff --git a/driver/csiplugin/settings/scale_config.go b/driver/csiplugin/settings/scale_config.go index fbb24c77d..5d55b9152 100644 --- a/driver/csiplugin/settings/scale_config.go +++ b/driver/csiplugin/settings/scale_config.go @@ -52,16 +52,14 @@ const ( cacertFileSuffix = "-cacert" ) const ( - DirPath = "scalecsilogs" - LogFile = "ibm-spectrum-scale-csi.logs" - PersistentLog = "PERSISTENT_LOG" - NodePublishMethod = "NODEPUBLISH_METHOD" - VolumeStatsCapability = "VOLUME_STATS_CAPABILITY" - HostPath = "/host/var/adm/ras/" - RotateSize = 1024 - DiscoverCGFileset = "DISCOVER_CG_FILESET" - PrimaryFilesystemKey = "PRIMARY_FILESYSTEM" - PrimaryFilesystemValue = "DISABLED" + DirPath = "scalecsilogs" + LogFile = "ibm-spectrum-scale-csi.logs" + PersistentLog = "PERSISTENT_LOG" + NodePublishMethod = "NODEPUBLISH_METHOD" + VolumeStatsCapability = "VOLUME_STATS_CAPABILITY" + HostPath = "/host/var/adm/ras/" + RotateSize = 1024 + DiscoverCGFileset = "DISCOVER_CG_FILESET" ) /* diff --git a/operator/Makefile b/operator/Makefile index b8cf804d8..a26e8bb36 100644 --- a/operator/Makefile +++ b/operator/Makefile @@ -38,7 +38,7 @@ BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION) # Image URL to use all building/pushing image targets IMG ?= $(IMAGE_TAG_BASE):$(VERSION) # Produce CRDs that work back to Kubernetes 1.11 (no version conversion) -CRD_OPTIONS ?= "crd:trivialVersions=true,preserveUnknownFields=false" +CRD_OPTIONS ?= "crdVersions=v1" # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) @@ -75,7 +75,7 @@ help: ## Display this help. manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=ibm-spectrum-scale-csi-operator webhook paths="./..." output:crd:artifacts:config=config/crd/bases - + generate: controller-gen kustomize fmt ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. $(CONTROLLER_GEN) object:headerFile="hacks/boilerplate.go.txt" paths="./..." @@ -150,7 +150,7 @@ PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST)))) BIN_DIR := $(PROJECT_DIR)/bin CONTROLLER_GEN = $(BIN_DIR)/controller-gen controller-gen: ## Download controller-gen locally if necessary. - $(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.4.1) + $(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.5) KUSTOMIZE = $(BIN_DIR)/kustomize kustomize: ## Download kustomize locally if necessary. diff --git a/operator/controllers/config/constants.go b/operator/controllers/config/constants.go index e7db32770..acaa4f682 100644 --- a/operator/controllers/config/constants.go +++ b/operator/controllers/config/constants.go @@ -157,7 +157,6 @@ const ( EnvDiscoverCGFilesetKey = "DISCOVER_CG_FILESET" HostNetworkKey = "HOST_NETWORK" EnvVolNamePrefixKey = "VOLUME_NAME_PREFIX" - EnvPrimaryFilesystemKey = "PRIMARY_FILESYSTEM" // Optional ConfigMap keys with prefix EnvLogLevelKeyPrefixed = EnvVarPrefix + EnvLogLevelKey @@ -166,7 +165,6 @@ const ( EnvVolumeStatsCapabilityKeyPrefixed = EnvVarPrefix + EnvVolumeStatsCapabilityKey EnvDiscoverCGFilesetKeyPrefixed = EnvVarPrefix + EnvDiscoverCGFilesetKey EnvVolNamePrefixKeyPrefixed = EnvVarPrefix + EnvVolNamePrefixKey - EnvPrimaryFilesystemKeyPrefixed = EnvVarPrefix + EnvPrimaryFilesystemKey // Optional ConfigMap default values if not provided in the cm DriverCPULimitsDefaultValue = "600m" diff --git a/operator/controllers/csiscaleoperator_controller.go b/operator/controllers/csiscaleoperator_controller.go index e2ea0030b..8adb16bc5 100644 --- a/operator/controllers/csiscaleoperator_controller.go +++ b/operator/controllers/csiscaleoperator_controller.go @@ -403,24 +403,6 @@ func (r *CSIScaleOperatorReconciler) Reconcile(ctx context.Context, req ctrl.Req logger.Info("Final optional configmap values", "when the sent to syncer is ", cmData) - ifPrimaryDisable := false - if strings.ToUpper(cmData["PRIMARY_FILESYSTEM"]) == "DISABLED" { - ifPrimaryDisable = true - } - logger.Info("PRIMARY_FILESYSTEM is", " DISABLED ", ifPrimaryDisable) - - //For first pass handle primary FS and fileset - if !cmExists && !ifPrimaryDisable { - requeAfterDelay, err := r.handlePrimaryFSandFileset(instance) - if err != nil { - if requeAfterDelay == 0 { - return ctrl.Result{}, err - } else { - return ctrl.Result{RequeueAfter: requeAfterDelay}, nil - } - } - } - // Synchronizing node/driver daemonset CGPrefix := r.GetConsistencyGroupPrefix(instance) @@ -710,23 +692,23 @@ func (r *CSIScaleOperatorReconciler) updateChangedClusters(instance *csiscaleope //Check if the primary stanza from current configmap is changed //and return err if it is changed, as we don't want to change //the primary after first successful iteration. - if oldCMCluster.Primary != nil && !reflect.DeepEqual(oldCMCluster.Primary, crCluster.Primary) { - primaryString := fmt.Sprintf("{filesystem:%v, fileset:%v", - oldCMCluster.Primary.PrimaryFs, oldCMCluster.Primary.PrimaryFset) - if oldCMCluster.Primary.RemoteCluster != "" { - primaryString += fmt.Sprintf(", remote cluster: %v}", oldCMCluster.Primary.RemoteCluster) - } else { - primaryString += "}" - } - message := fmt.Sprintf("Primary stanza is modified for cluster with ID %s. Use the orignal primary %s and try again", - crCluster.Id, primaryString) - err := fmt.Errorf("%s", message) - logger.Error(err, "") - SetStatusAndRaiseEvent(instance, r.Recorder, corev1.EventTypeWarning, string(config.StatusConditionSuccess), - metav1.ConditionFalse, string(csiv1.PrimaryClusterStanzaModified), message, - ) - return err - } + //if oldCMCluster.Primary != nil && !reflect.DeepEqual(oldCMCluster.Primary, crCluster.Primary) { + //primaryString := fmt.Sprintf("{filesystem:%v, fileset:%v", + // oldCMCluster.Primary.PrimaryFs, oldCMCluster.Primary.PrimaryFset) + // if oldCMCluster.Primary.RemoteCluster != "" { + // primaryString += fmt.Sprintf(", remote cluster: %v}", oldCMCluster.Primary.RemoteCluster) + // } else { + // primaryString += "}" + // } + //message := fmt.Sprintf("Primary stanza is modified for cluster with ID %s. Use the orignal primary %s and try again", + // crCluster.Id, primaryString) + //err := fmt.Errorf("%s", message) + //logger.Error(err, "") + //SetStatusAndRaiseEvent(instance, r.Recorder, corev1.EventTypeWarning, string(config.StatusConditionSuccess), + // metav1.ConditionFalse, string(csiv1.PrimaryClusterStanzaModified), message, + //) + //return err + //} } } } @@ -1998,7 +1980,7 @@ func (r *CSIScaleOperatorReconciler) handleSpectrumScaleConnectors(instance *csi //1. Check if GUI is reachable for the 1st pass. // For pass no. 2+ if clusterstanza modified, check for only changed cluster if !cmExists || (clustersStanzaModified && isClusterChanged) { - if operatorRestarted && !isPrimaryCluster { + if operatorRestarted { //if operator is restarted and this is not a primary cluster, //no need to check if GUI is reachable or clusterID is valid. continue @@ -2347,12 +2329,12 @@ func ValidateCRParams(instance *csiscaleoperator.CSIScaleOperator) error { } primaryClusterFound = true - if cluster.Primary.PrimaryFs == "" { - issueFound = true - logger.Error(fmt.Errorf("mandatory parameter 'primaryFs' is not specified for primary cluster %v", cluster.Id), "") - } + //if cluster.Primary.PrimaryFs == "" { + // issueFound = true + // logger.Error(fmt.Errorf("mandatory parameter 'primaryFs' is not specified for primary cluster %v", cluster.Id), "") + //} - remoteClusterID = cluster.Primary.RemoteCluster + //remoteClusterID = cluster.Primary.RemoteCluster } else { //when its a not primary cluster nonPrimaryClusters[cluster.Id] = true @@ -2373,11 +2355,11 @@ func ValidateCRParams(instance *csiscaleoperator.CSIScaleOperator) error { issueFound = true logger.Error(fmt.Errorf("no primary clusters specified"), "") } - _, nonPrimaryClusterExists := nonPrimaryClusters[remoteClusterID] - if remoteClusterID != "" && !nonPrimaryClusterExists { - issueFound = true - logger.Error(fmt.Errorf("remote cluster specified for primary filesystem: %s, but no entry found for it in driver manifest", remoteClusterID), "") - } + //_, nonPrimaryClusterExists := nonPrimaryClusters[remoteClusterID] + //if remoteClusterID != "" && !nonPrimaryClusterExists { + // issueFound = true + // logger.Error(fmt.Errorf("remote cluster specified for primary filesystem: %s, but no entry found for it in driver manifest", remoteClusterID), "") + //} if issueFound { message := "one or more issues found while validating driver manifest, check operator logs for details" @@ -2434,8 +2416,6 @@ func (r *CSIScaleOperatorReconciler) parseConfigMap(instance *csiscaleoperator.C validateEnvVarValue(config.EnvVolumeStatsCapabilityValues[:], keyUpper, value, validEnvMap, invalidEnvValueMap) case config.EnvDiscoverCGFilesetKeyPrefixed: validateEnvVarValue(config.EnvDiscoverCGFilesetValues[:], keyUpper, value, validEnvMap, invalidEnvValueMap) - case config.EnvPrimaryFilesystemKeyPrefixed: - validateEnvVarValue(config.EnvPrimaryFilesystemValues[:], keyUpper, value, validEnvMap, invalidEnvValueMap) case config.EnvVolNamePrefixKeyPrefixed: validateVolNamePrefix(keyUpper, strings.ToLower(value), validEnvMap, invalidEnvValueMap) case config.DaemonSetUpgradeMaxUnavailableKey: @@ -2683,11 +2663,6 @@ func setDefaultDriverEnvValues(envMap map[string]string) { logger.Info("Sidecars Memory limits is empty or incorrect.", "Defaulting Memory limits to", config.SidecarMemoryLimitsDefaultValue) envMap[config.SidecarMemoryLimits] = config.SidecarMemoryLimitsDefaultValue } - // set default EnvPrimaryFilesystemKey when it is not present in envMap - if _, ok := envMap[config.EnvPrimaryFilesystemKey]; !ok { - logger.Info("PRIMARY_FILESYSTEM is empty or incorrect.", "Defaulting PRIMARY_FILESYSTEM to", config.EnvPrimaryFilesystemDefaultValue) - envMap[config.EnvPrimaryFilesystemKey] = config.EnvPrimaryFilesystemDefaultValue - } } // getDiscoverCGFilesetDefaultValue returns default value for CG fileset discovery From e710a12b3348b64697fce5de616377d374c4b1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chemalathagajendran=E2=80=9D?= <“hemalatha.gajendran@ibm.com”> Date: Wed, 16 Jul 2025 07:45:42 -0700 Subject: [PATCH 02/14] some more chnages for primary fs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: “hemalathagajendran” <“hemalatha.gajendran@ibm.com”> --- driver/csiplugin/controllerserver.go | 140 +++++------------- operator/controllers/config/constants.go | 4 +- .../csiscaleoperator_controller.go | 1 - 3 files changed, 42 insertions(+), 103 deletions(-) diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index e23da855d..f2a7c0f47 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -1163,7 +1163,7 @@ func (cs *ScaleControllerServer) CreateVolume(newctx context.Context, req *csi.C return nil, err } } else { - err = cs.copyVolumeContent(ctx, scaleVol, srcVolumeIDMembers, volFsInfo, targetPath, volID, ifPrimaryDisable) + err = cs.copyVolumeContent(ctx, scaleVol, srcVolumeIDMembers, volFsInfo, targetPath, volID) if err != nil { klog.Errorf("[%s] CreateVolume [%s]: [%v]", loggerId, volName, err) return nil, err @@ -1751,7 +1751,7 @@ func (cs *ScaleControllerServer) copyShallowVolumeContent(ctx context.Context, n } -func (cs *ScaleControllerServer) copyVolumeContent(ctx context.Context, newvolume *scaleVolume, sourcevolume scaleVolId, fsDetails connectors.FileSystem_v2, targetPath string, volID string, ifPrimaryDisable bool) error { +func (cs *ScaleControllerServer) copyVolumeContent(ctx context.Context, newvolume *scaleVolume, sourcevolume scaleVolId, fsDetails connectors.FileSystem_v2, targetPath string, volID string) error { loggerId := utils.GetLoggerId(ctx) klog.Infof("[%s] copyVolContent volume ID: [%v], scaleVolume: [%v], volume name: [%v]", loggerId, sourcevolume, newvolume, newvolume.VolName) conn, err := cs.getConnFromClusterID(ctx, sourcevolume.ClusterId) @@ -1801,19 +1801,18 @@ func (cs *ScaleControllerServer) copyVolumeContent(ctx context.Context, newvolum } else { var sLinkRelPath string - if ifPrimaryDisable { - klog.V(4).Infof("[%s] copyVolContent when PrimaryDisable, sourcevolume.Path=[%v], fsMntPt=[%v]", loggerId, sourcevolume.Path, fsMntPt) - sLinkRelPath = strings.Replace(sourcevolume.Path, fsMntPt, "", 1) - } else { - klog.V(4).Infof("[%s] copyVolContent when with Primary, sourcevolume.Path=[%v]", loggerId, sourcevolume.Path) - primaryFSMountPoint, err := cs.getPrimaryFSMountPoint(ctx) - if err != nil { - return err - } - klog.V(4).Infof("[%s] copyVolContent sourcevolume.Path=[%v], primaryFSMountPoint=[%v]", loggerId, sourcevolume.Path, primaryFSMountPoint) - sLinkRelPath = strings.Replace(sourcevolume.Path, primaryFSMountPoint, "", 1) - - } + klog.V(4).Infof("[%s] copyVolContent when PrimaryDisable, sourcevolume.Path=[%v], fsMntPt=[%v]", loggerId, sourcevolume.Path, fsMntPt) + sLinkRelPath = strings.Replace(sourcevolume.Path, fsMntPt, "", 1) + + //klog.V(4).Infof("[%s] copyVolContent when with Primary, sourcevolume.Path=[%v]", loggerId, sourcevolume.Path) + //primaryFSMountPoint, err := cs.getPrimaryFSMountPoint(ctx) + //if err != nil { + //return err + // } + // klog.V(4).Infof("[%s] copyVolContent sourcevolume.Path=[%v], primaryFSMountPoint=[%v]", loggerId, sourcevolume.Path, primaryFSMountPoint) + // sLinkRelPath = strings.Replace(sourcevolume.Path, primaryFSMountPoint, "", 1) + + // } klog.V(4).Infof("[%s] copyVolContent sourcevolume.Path=[%v], sourcevolume.FsName=[%v], sLinkRelPath=[%v], targetPath=[%v]", loggerId, sourcevolume.Path, sourcevolume.FsName, sLinkRelPath, targetPath) sLinkRelPath = strings.Trim(sLinkRelPath, "!/") @@ -1831,6 +1830,7 @@ func (cs *ScaleControllerServer) copyVolumeContent(ctx context.Context, newvolum klog.Errorf("[%s] failed while calling WaitForJobCompletionWithResp: %v.", loggerId, err) } } + isResponseStatusUnknown := false if len(response.Jobs) != 0 { if response.Jobs[0].Status == ResponseStatusUnknown { @@ -2503,12 +2503,6 @@ func (cs *ScaleControllerServer) DeleteVolume(newctx context.Context, req *csi.D reqToLog.Secrets = nil klog.Infof("[%s] DeleteVolume req: %v", loggerId, &reqToLog) - ifPrimaryDisable := false - if strings.ToUpper(os.Getenv(settings.PrimaryFilesystemKey)) == settings.PrimaryFilesystemValue { - ifPrimaryDisable = true - } - klog.Infof("[%s] ifPrimaryDisable : %t", loggerId, ifPrimaryDisable) - if err := cs.Driver.ValidateControllerServiceRequest(ctx, csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME); err != nil { klog.Errorf("[%s] Invalid delete volume req: %v", loggerId, req) return nil, status.Error(codes.InvalidArgument, @@ -2677,19 +2671,11 @@ func (cs *ScaleControllerServer) DeleteVolume(newctx context.Context, req *csi.D } // Delete fileset related symlink - if volumeIdMembers.StorageClassType == STORAGECLASS_CLASSIC && symlinkExists { - if ifPrimaryDisable && pfsName != "" { - err = primaryConn.DeleteSymLnk(ctx, pfsName, relPath) - if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("unable to delete symlnk [%v:%v] Error [%v]", pfsName, relPath, err)) - } - } else { - err = primaryConn.DeleteSymLnk(ctx, cs.Driver.primary.GetPrimaryFs(), relPath) - if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("unable to delete symlnk [%v:%v] Error [%v]", cs.Driver.primary.GetPrimaryFs(), relPath, err)) - } + if volumeIdMembers.StorageClassType == STORAGECLASS_CLASSIC { + err = primaryConn.DeleteSymLnk(ctx, pfsName, relPath) + if err != nil { + return nil, status.Error(codes.Internal, fmt.Sprintf("unable to delete symlnk [%v:%v] Error [%v]", pfsName, relPath, err)) } - } if volumeIdMembers.StorageClassType == STORAGECLASS_ADVANCED { @@ -2920,12 +2906,6 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re filesystemID := volumeIDMembers.FsUUID volumePath := volumeIDMembers.Path - ifPrimaryDisable := false - if strings.ToUpper(os.Getenv(settings.PrimaryFilesystemKey)) == settings.PrimaryFilesystemValue { - ifPrimaryDisable = true - } - klog.Infof("[%s] ifPrimaryDisable : %t", loggerId, ifPrimaryDisable) - // if SKIP_MOUNT_UNMOUNT == "yes" then mount/unmount will not be invoked skipMountUnmount := utils.GetEnv(SKIP_MOUNT_UNMOUNT, yes) klog.Infof("[%s] ControllerPublishVolume : SKIP_MOUNT_UNMOUNT is set to %s", loggerId, skipMountUnmount) @@ -2946,45 +2926,25 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re klog.V(4).Infof("[%s] ControllerPublishVolume : SHORTNAME_NODE_MAPPING is set to %s", loggerId, shortnameNodeMapping) } - if !ifPrimaryDisable { - //Check if primary filesystem is mounted. - primaryfsName = cs.Driver.primary.GetPrimaryFs() - pfsMount, err = cs.Driver.connmap["primary"].GetFilesystemMountDetails(ctx, primaryfsName) - if err != nil { - klog.Errorf("[%s] ControllerPublishVolume : Error in getting filesystem mount details for %s", loggerId, primaryfsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in getting filesystem mount details for %s. Error [%v]", primaryfsName, err)) - } - - // NodesMounted has admin node names - // This means node mapping must be to admin names. - // Unless shortnameNodeMapping=="yes", then we should check shortname portion matches. - if shortnameNodeMapping == yes { - ispFsMounted = shortnameInSlice(scalenodeID, pfsMount.NodesMounted) - } else { - ispFsMounted = utils.StringInSlice(scalenodeID, pfsMount.NodesMounted) - } - - klog.Infof("[%s] ControllerPublishVolume : Primary FS is mounted on %v", loggerId, pfsMount.NodesMounted) - klog.V(4).Infof("[%s] ControllerPublishVolume : Primary Fileystem is %s and Volume is from Filesystem %s", loggerId, primaryfsName, fsName) - // Skip if primary filesystem and volume filesystem is same - if volumeIDMembers.StorageClassType == STORAGECLASS_ADVANCED || primaryfsName != fsName { - //Check if filesystem is mounted - fsMount, err = cs.Driver.connmap["primary"].GetFilesystemMountDetails(ctx, fsName) - if err != nil { - klog.Errorf("[%s] ControllerPublishVolume : Error in getting filesystem mount details for %s", loggerId, fsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in getting filesystem mount details for %s. Error [%v]", fsName, err)) - } + // Skip if primary filesystem and volume filesystem is same + if volumeIDMembers.StorageClassType == STORAGECLASS_ADVANCED || primaryfsName != fsName { + //Check if filesystem is mounted + fsMount, err = cs.Driver.connmap["primary"].GetFilesystemMountDetails(ctx, fsName) + if err != nil { + klog.Errorf("[%s] ControllerPublishVolume : Error in getting filesystem mount details for %s", loggerId, fsName) + return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in getting filesystem mount details for %s. Error [%v]", fsName, err)) + } - if volumeIDMembers.StorageClassType == STORAGECLASS_ADVANCED && - !strings.HasPrefix(volumePath, fsMount.MountPoint) { - klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s", loggerId, volumePath, fsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s", volumePath, fsName)) - } else if !strings.HasPrefix(volumePath, fsMount.MountPoint) && - !strings.HasPrefix(volumePath, pfsMount.MountPoint) { - klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s or %s", loggerId, volumePath, primaryfsName, fsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s or %s", volumePath, primaryfsName, fsName)) - } + if volumeIDMembers.StorageClassType == STORAGECLASS_ADVANCED && + !strings.HasPrefix(volumePath, fsMount.MountPoint) { + klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s", loggerId, volumePath, fsName) + return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s", volumePath, fsName)) + } else if !strings.HasPrefix(volumePath, fsMount.MountPoint) && + !strings.HasPrefix(volumePath, pfsMount.MountPoint) { + klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s or %s", loggerId, volumePath, primaryfsName, fsName) + return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s or %s", volumePath, primaryfsName, fsName)) + } // NodesMounted has admin node names // This means node mapping must be to admin names. @@ -3094,7 +3054,7 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re isFsMountedOnGateway = isSubset(gatewayNodeNames, fsRemoteMountDetails.NodesMounted) //success when FS is mounted primary , volumeFS and on any of the gatewayNodes for "cache" volume - if !ifPrimaryDisable && isFsMounted && ispFsMounted && isFsMountedOnGateway { + if isFsMounted && isFsMountedOnGateway { klog.V(4).Infof("[%s] ControllerPublishVolume : filesystem %s is mounted on %s and on gatewayNodes %v so returning success", loggerId, fsName, scalenodeID, gatewayNodeNames) if fsName != primaryfsName { @@ -3148,7 +3108,7 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re } //mount the primary filesystem if not mounted - if !ifPrimaryDisable && !(ispFsMounted) { + if !(ispFsMounted) { klog.V(4).Infof("[%s] ControllerPublishVolume : mounting Filesystem %s on %s", loggerId, primaryfsName, scalenodeID) nodesNameList := []string{scalenodeID} err = cs.Driver.connmap["primary"].MountFilesystem(ctx, primaryfsName, nodesNameList) @@ -3159,7 +3119,7 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re } //mount the volume filesystem if mounted when fs is not primary - if !isFsMounted && (ifPrimaryDisable || (!ifPrimaryDisable && primaryfsName != fsName)) { + if !(isFsMounted) && primaryfsName != fsName { klog.V(4).Infof("[%s] ControllerPublishVolume : mounting %s on %s", loggerId, fsName, scalenodeID) nodesNameList := []string{scalenodeID} err = cs.Driver.connmap["primary"].MountFilesystem(ctx, fsName, nodesNameList) @@ -3284,30 +3244,12 @@ func (cs *ScaleControllerServer) CreateSnapshot(newctx context.Context, req *csi return nil, chkSnapshotErr } - ifPrimaryDisable := false - if strings.ToUpper(os.Getenv(settings.PrimaryFilesystemKey)) == settings.PrimaryFilesystemValue { - ifPrimaryDisable = true - } - - var primaryConn, scaleConn connectors.SpectrumScaleConnector - isprimaryConnPresent := false - if !ifPrimaryDisable { - primaryConn, isprimaryConnPresent = cs.Driver.connmap["primary"] - if !isprimaryConnPresent { - klog.Errorf("[%s] CreateSnapshot - unable to get connector for primary cluster", loggerId) - return nil, status.Error(codes.Internal, "CreateSnapshot - unable to find primary cluster details in custom resource") - } - scaleConn = primaryConn - } else { - scaleConn = conn - } - - filesystemName, err := scaleConn.GetFilesystemName(ctx, volumeIDMembers.FsUUID) + filesystemName, err := conn.GetFilesystemName(ctx, volumeIDMembers.FsUUID) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("CreateSnapshot - Unable to get filesystem Name for Filesystem Uid [%v] and clusterId [%v]. Error [%v]", volumeIDMembers.FsUUID, volumeIDMembers.ClusterId, err)) } - mountInfo, err := scaleConn.GetFilesystemMountDetails(ctx, filesystemName) + mountInfo, err := conn.GetFilesystemMountDetails(ctx, filesystemName) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("CreateSnapshot - unable to get mount info for FS [%v] in primary cluster", filesystemName)) } diff --git a/operator/controllers/config/constants.go b/operator/controllers/config/constants.go index acaa4f682..496d4c592 100644 --- a/operator/controllers/config/constants.go +++ b/operator/controllers/config/constants.go @@ -197,8 +197,7 @@ var CSIOptionalConfigMapKeys = []string{ DriverCPULimits, DriverMemoryLimits, SidecarCPULimits, - SidecarMemoryLimits, - EnvPrimaryFilesystemKeyPrefixed} + SidecarMemoryLimits} // allowed values of the optional cm variables var EnvLogLevelValues = []string{"TRACE", "DEBUG", "INFO", "WARNING", "ERROR", "FATAL"} @@ -207,7 +206,6 @@ var EnvPersistentLogValues = []string{"ENABLED", "DISABLED"} var EnvVolumeStatsCapabilityValues = []string{"ENABLED", "DISABLED"} var EnvDiscoverCGFilesetValues = []string{"ENABLED", "DISABLED"} var EnvHostNetworkValues = []string{"ENABLED", "DISABLED"} -var EnvPrimaryFilesystemValues = []string{"ENABLED", "DISABLED"} const ( StatusConditionReady = "Ready" diff --git a/operator/controllers/csiscaleoperator_controller.go b/operator/controllers/csiscaleoperator_controller.go index 8adb16bc5..70205fc69 100644 --- a/operator/controllers/csiscaleoperator_controller.go +++ b/operator/controllers/csiscaleoperator_controller.go @@ -2303,7 +2303,6 @@ func ValidateCRParams(instance *csiscaleoperator.CSIScaleOperator) error { } primaryClusterFound, issueFound := false, false - remoteClusterID := "" var nonPrimaryClusters = make(map[string]bool) for i := 0; i < len(instance.Spec.Clusters); i++ { From a768c1d4a3fa8fa515fb2094207d3e8a9910ed22 Mon Sep 17 00:00:00 2001 From: hemalathagajendran Date: Thu, 17 Jul 2025 10:22:36 +0530 Subject: [PATCH 03/14] changes to Controller publish Signed-off-by: hemalathagajendran --- driver/csiplugin/controllerserver.go | 169 +++++++++++---------------- 1 file changed, 69 insertions(+), 100 deletions(-) diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index f2a7c0f47..ae1728a41 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -1803,16 +1803,16 @@ func (cs *ScaleControllerServer) copyVolumeContent(ctx context.Context, newvolum var sLinkRelPath string klog.V(4).Infof("[%s] copyVolContent when PrimaryDisable, sourcevolume.Path=[%v], fsMntPt=[%v]", loggerId, sourcevolume.Path, fsMntPt) sLinkRelPath = strings.Replace(sourcevolume.Path, fsMntPt, "", 1) - + //klog.V(4).Infof("[%s] copyVolContent when with Primary, sourcevolume.Path=[%v]", loggerId, sourcevolume.Path) //primaryFSMountPoint, err := cs.getPrimaryFSMountPoint(ctx) //if err != nil { - //return err + //return err // } // klog.V(4).Infof("[%s] copyVolContent sourcevolume.Path=[%v], primaryFSMountPoint=[%v]", loggerId, sourcevolume.Path, primaryFSMountPoint) // sLinkRelPath = strings.Replace(sourcevolume.Path, primaryFSMountPoint, "", 1) - // } + // } klog.V(4).Infof("[%s] copyVolContent sourcevolume.Path=[%v], sourcevolume.FsName=[%v], sLinkRelPath=[%v], targetPath=[%v]", loggerId, sourcevolume.Path, sourcevolume.FsName, sLinkRelPath, targetPath) sLinkRelPath = strings.Trim(sLinkRelPath, "!/") @@ -1830,7 +1830,7 @@ func (cs *ScaleControllerServer) copyVolumeContent(ctx context.Context, newvolum klog.Errorf("[%s] failed while calling WaitForJobCompletionWithResp: %v.", loggerId, err) } } - + isResponseStatusUnknown := false if len(response.Jobs) != 0 { if response.Jobs[0].Status == ResponseStatusUnknown { @@ -2875,6 +2875,8 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume: ValidateControllerServiceRequest failed: %v", err)) } + //req &csi.ControllerPublishVolumeRequest{VolumeId:"2;2;15461220949750720109;69230B0A:67B82745;;pvc-0c5634b5-4391-4b9c-b879-94d6c2db9768;/ibm/fs1/pvc-0c5634b5-4391-4b9c-b879-94d6c2db9768", NodeId:"bnp-csi-main1-worker-1.fyre.ibm.com", VolumeCapability:(*csi.VolumeCapability)(0xc00011e680), Readonly:false, Secrets:map[string]string(nil), VolumeContext:map[string]string{"csi.storage.k8s.io/pv/name":"pvc-0c5634b5-4391-4b9c-b879-94d6c2db9768", "csi.storage.k8s.io/pvc/name":"cache-s3-pvc1", "csi.storage.k8s.io/pvc/namespace":"ibm-spectrum-scale-csi-driver", "storage.kubernetes.io/csiProvisionerIdentity":"1741361929928-7999-spectrumscale.csi.ibm.com", "volBackendFs":"fs1", "volumeType":"cache"}} + nodeID := req.GetNodeId() if nodeID == "" { @@ -2886,11 +2888,8 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re if volumeID == "" { return nil, status.Error(codes.InvalidArgument, "ControllerPublishVolume : VolumeID is not present") } - var primaryfsName, scalenodeID, fsNameRemote, shortnameNodeMapping string - var fsMount, pfsMount connectors.MountInfo - var ispFsMounted, isFsMounted, isFsMountedOnGateway bool - var gatewayNodeNames []string - var conn connectors.SpectrumScaleConnector + + var isFsMounted bool //Assumption : filesystem_uuid is always from local/primary cluster. @@ -2917,102 +2916,80 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in getting filesystem Name for filesystem ID of %s. Error [%v]", filesystemID, err)) } + //Check if primary filesystem is mounted. + primaryfsName := cs.Driver.primary.GetPrimaryFs() + pfsMount, err := cs.Driver.connmap["primary"].GetFilesystemMountDetails(ctx, primaryfsName) + if err != nil { + klog.Errorf("[%s] ControllerPublishVolume : Error in getting filesystem mount details for %s", loggerId, primaryfsName) + return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in getting filesystem mount details for %s. Error [%v]", primaryfsName, err)) + } + // Node mapping check - scalenodeID = getNodeMapping(nodeID) + scalenodeID := getNodeMapping(nodeID) klog.Infof("[%s] ControllerPublishVolume : scalenodeID:%s --known as-- k8snodeName: %s", loggerId, scalenodeID, nodeID) - shortnameNodeMapping = utils.GetEnv(SHORTNAME_NODE_MAPPING, no) + shortnameNodeMapping := utils.GetEnv(SHORTNAME_NODE_MAPPING, no) if shortnameNodeMapping == yes { klog.V(4).Infof("[%s] ControllerPublishVolume : SHORTNAME_NODE_MAPPING is set to %s", loggerId, shortnameNodeMapping) } + var ispFsMounted bool + // NodesMounted has admin node names + // This means node mapping must be to admin names. + // Unless shortnameNodeMapping=="yes", then we should check shortname portion matches. + if shortnameNodeMapping == yes { + ispFsMounted = shortnameInSlice(scalenodeID, pfsMount.NodesMounted) + } else { + ispFsMounted = utils.StringInSlice(scalenodeID, pfsMount.NodesMounted) + } + klog.Infof("[%s] ControllerPublishVolume : Primary FS is mounted on %v", loggerId, pfsMount.NodesMounted) + klog.V(4).Infof("[%s] ControllerPublishVolume : Primary Fileystem is %s and Volume is from Filesystem %s", loggerId, primaryfsName, fsName) + var fsMount connectors.MountInfo // Skip if primary filesystem and volume filesystem is same if volumeIDMembers.StorageClassType == STORAGECLASS_ADVANCED || primaryfsName != fsName { - //Check if filesystem is mounted - fsMount, err = cs.Driver.connmap["primary"].GetFilesystemMountDetails(ctx, fsName) - if err != nil { - klog.Errorf("[%s] ControllerPublishVolume : Error in getting filesystem mount details for %s", loggerId, fsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in getting filesystem mount details for %s. Error [%v]", fsName, err)) - } - - if volumeIDMembers.StorageClassType == STORAGECLASS_ADVANCED && - !strings.HasPrefix(volumePath, fsMount.MountPoint) { - klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s", loggerId, volumePath, fsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s", volumePath, fsName)) - } else if !strings.HasPrefix(volumePath, fsMount.MountPoint) && - !strings.HasPrefix(volumePath, pfsMount.MountPoint) { - klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s or %s", loggerId, volumePath, primaryfsName, fsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s or %s", volumePath, primaryfsName, fsName)) - } - - // NodesMounted has admin node names - // This means node mapping must be to admin names. - // Unless shortnameNodeMapping=="yes", then we should check shortname portion matches. - if shortnameNodeMapping == yes { - isFsMounted = shortnameInSlice(scalenodeID, pfsMount.NodesMounted) - } else { - isFsMounted = utils.StringInSlice(scalenodeID, pfsMount.NodesMounted) - } - - klog.Infof("[%s] ControllerPublishVolume : Volume Source FS is mounted on %v", loggerId, fsMount.NodesMounted) - } else { - if !strings.HasPrefix(volumePath, pfsMount.MountPoint) { - klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s", loggerId, volumePath, primaryfsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s", volumePath, primaryfsName)) - } - - isFsMounted = ispFsMounted - } - - klog.Infof("[%s] ControllerPublishVolume : Mount Status Primaryfs [ %t ], Sourcefs [ %t ]", loggerId, ispFsMounted, isFsMounted) - } else { - //Check if filesystem is mounted fsMount, err = cs.Driver.connmap["primary"].GetFilesystemMountDetails(ctx, fsName) if err != nil { klog.Errorf("[%s] ControllerPublishVolume : Error in getting filesystem mount details for %s", loggerId, fsName) return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in getting filesystem mount details for %s. Error [%v]", fsName, err)) } - // Check the volumePath is a symlink or not, and that path should be part of the filesystem mount point, comes when pvc is created with symlink and the primary filesystem was enabled. - volScalePathInContainer := hostDir + volumePath - f, err := os.Lstat(volScalePathInContainer) - if err != nil { - klog.Errorf("[%s] ControllerPublishVolume - lstat [%s] failed with error [%v]", loggerId, volScalePathInContainer, err) - return nil, fmt.Errorf("ControllerPublishVolume - Error in getting the stat of the volumePath [%s], might primaryFS is not available if volumePath is a symlink, failed with error [%v]", volumePath, err) - } - if f.Mode()&os.ModeSymlink != 0 { - symlinkTarget, readlinkErr := os.Readlink(volScalePathInContainer) - if readlinkErr != nil { - klog.Errorf("[%s] ControllerPublishVolume - readlink [%s] failed with error [%v]", loggerId, volScalePathInContainer, readlinkErr) - return nil, fmt.Errorf("ControllerPublishVolume - Error in getting the symlink details of the volumePath [%s], failed with error [%v]", volumePath, readlinkErr) - } - volScalePathInContainer = hostDir + symlinkTarget - volumePath = symlinkTarget - klog.V(4).Infof("[%s] ControllerPublishVolume - symlink targetPath in container is [%s]", loggerId, volScalePathInContainer) - klog.Infof("[%s] ControllerPublishVolume - symlink targetPath is [%s]", loggerId, volumePath) - } - if !strings.HasPrefix(volumePath, fsMount.MountPoint) { - klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s ", loggerId, volumePath, fsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s", volumePath, fsName)) + if volumeIDMembers.StorageClassType == STORAGECLASS_ADVANCED && + !strings.HasPrefix(volumePath, fsMount.MountPoint) { + klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s", loggerId, volumePath, fsName) + return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s", volumePath, fsName)) + } else if !strings.HasPrefix(volumePath, fsMount.MountPoint) && + !strings.HasPrefix(volumePath, pfsMount.MountPoint) { + klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s or %s", loggerId, volumePath, primaryfsName, fsName) + return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s or %s", volumePath, primaryfsName, fsName)) } // NodesMounted has admin node names // This means node mapping must be to admin names. // Unless shortnameNodeMapping=="yes", then we should check shortname portion matches. if shortnameNodeMapping == yes { - isFsMounted = shortnameInSlice(scalenodeID, fsMount.NodesMounted) + isFsMounted = shortnameInSlice(scalenodeID, pfsMount.NodesMounted) } else { - isFsMounted = utils.StringInSlice(scalenodeID, fsMount.NodesMounted) + isFsMounted = utils.StringInSlice(scalenodeID, pfsMount.NodesMounted) } - klog.V(4).Infof("[%s] ControllerPublishVolume : Volume Source FS is mounted on %v", loggerId, fsMount.NodesMounted) + klog.Infof("[%s] ControllerPublishVolume : Volume Source FS is mounted on %v", loggerId, fsMount.NodesMounted) + } else { + if !strings.HasPrefix(volumePath, pfsMount.MountPoint) { + klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s", loggerId, volumePath, primaryfsName) + return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s", volumePath, primaryfsName)) + } - klog.Infof("[%s] ControllerPublishVolume : Mount Status Sourcefs [ %t ]", loggerId, isFsMounted) + isFsMounted = ispFsMounted } - // Check if the filesystem is mounted on all the gateway nodes before pod attachment + klog.Infof("[%s] ControllerPublishVolume : Mount Status Primaryfs [ %t ], Sourcefs [ %t ]", loggerId, ispFsMounted, isFsMounted) + + var isFsMountedOnGateway bool + var gatewayNodeNames []string + var conn connectors.SpectrumScaleConnector + var fsNameRemote string if volumeIDMembers.StorageClassType == STORAGECLASS_CACHE { // To check all of the gateway nodes are having filesystem mounted conn, err = cs.getConnFromClusterID(ctx, volumeIDMembers.ClusterId) @@ -3028,14 +3005,11 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re // getting the remote FS name is case of remote filesystem. It will be same in case of local FS - if !ifPrimaryDisable && primaryfsName != fsName { + if primaryfsName != fsName { fsNameRemote = getRemoteFsName(fsMount.RemoteDeviceName) - } else if !ifPrimaryDisable { - fsNameRemote = getRemoteFsName(pfsMount.RemoteDeviceName) } else { - fsNameRemote = getRemoteFsName(fsMount.RemoteDeviceName) + fsNameRemote = getRemoteFsName(pfsMount.RemoteDeviceName) } - fsRemoteMountDetails, err := conn.GetFilesystemMountDetails(ctx, fsNameRemote) if err != nil { klog.Errorf("[%s] ControllerPublishVolume : Error in getting filesystem mount details for %s", loggerId, fsName) @@ -3050,38 +3024,30 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re klog.V(4).Infof("[%s] ControllerPublishVolume : filesystem:[%s] or fsNameRemote:[%s] is mounted on these nodes %v", loggerId, fsName, fsNameRemote, fsRemoteMountDetails.NodesMounted) - // check whether FS is mounted on any of the gateway nodes or not + // check whether FS is mounted on all the gateway nodes or not isFsMountedOnGateway = isSubset(gatewayNodeNames, fsRemoteMountDetails.NodesMounted) - //success when FS is mounted primary , volumeFS and on any of the gatewayNodes for "cache" volume - if isFsMounted && isFsMountedOnGateway { + //sucess when FS is mounted primary , volumeFS and on all the gatewayNodes for "cache" volume + if isFsMounted && ispFsMounted && isFsMountedOnGateway { klog.V(4).Infof("[%s] ControllerPublishVolume : filesystem %s is mounted on %s and on gatewayNodes %v so returning success", loggerId, fsName, scalenodeID, gatewayNodeNames) - if fsName != primaryfsName { klog.V(4).Infof("[%s] ControllerPublishVolume when not a primaryfs : filesystem %s is mounted on %s and on gatewayNodes %v so returning success", loggerId, primaryfsName, scalenodeID, gatewayNodeNames) } return &csi.ControllerPublishVolumeResponse{}, nil - } else if isFsMounted && isFsMountedOnGateway { - //success when FS is mounted primary , volumeFS and on any of the gatewayNodes for "cache" volume - klog.V(4).Infof("[%s] ControllerPublishVolume : filesystem %s is mounted on %s and on gatewayNodes %v so returning success", loggerId, fsName, scalenodeID, gatewayNodeNames) - return &csi.ControllerPublishVolumeResponse{}, nil } - } else if !ifPrimaryDisable && isFsMounted && ispFsMounted { + + } else if isFsMounted && ispFsMounted { klog.V(4).Infof("[%s] ControllerPublishVolume : filesystem %s is mounted on %s so returning success", loggerId, fsName, scalenodeID) if fsName != primaryfsName { klog.V(4).Infof("[%s] ControllerPublishVolume when not a primaryfs : filesystem %s is mounted on %s so returning success", loggerId, primaryfsName, scalenodeID) } - return &csi.ControllerPublishVolumeResponse{}, nil - } else if isFsMounted { - klog.V(4).Infof("[%s] ControllerPublishVolume : filesystem %s is mounted on %s so returning success", loggerId, fsName, scalenodeID) - return &csi.ControllerPublishVolumeResponse{}, nil } if skipMountUnmount == "yes" { - //error when FS is not mounted on any of the gatewayNodes for "cache" volume + //error when FS is not mounted on all the gatewayNodes for "cache" volume if volumeIDMembers.StorageClassType == STORAGECLASS_CACHE && !isFsMountedOnGateway { - message := fmt.Sprintf("[%s] ControllerPublishVolume : filesystem %s is not mounted on any of the gatewayNodes %v", loggerId, fsName, gatewayNodeNames) + message := fmt.Sprintf("[%s] ControllerPublishVolume : filesystem %s is not mounted on all the gatewayNodes %v", loggerId, fsName, gatewayNodeNames) klog.Errorf(message) return nil, status.Error(codes.Internal, message) } @@ -3090,12 +3056,14 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re klog.Errorf(message) return nil, status.Error(codes.Internal, message) } - if !ifPrimaryDisable && !ispFsMounted { - message := fmt.Sprintf("[%s] ControllerPublishVolume : primay filesystem %s is not mounted on node %s", loggerId, primaryfsName, scalenodeID) + if !ispFsMounted { + message := fmt.Sprintf("[%s] ControllerPublishVolume : filesystem %s is not mounted on node %s", loggerId, primaryfsName, scalenodeID) klog.Errorf(message) return nil, status.Error(codes.Internal, message) } - } else if skipMountUnmount == no { + } + + if skipMountUnmount == no { //mount the filesystem on the gateway node if not mounted for "cache" volume if volumeIDMembers.StorageClassType == STORAGECLASS_CACHE && !(isFsMountedOnGateway) { klog.V(4).Infof("[%s] ControllerPublishVolume : mounting remote Filesystem %s on the gatewayNode %v", loggerId, fsNameRemote, gatewayNodeNames) @@ -3118,7 +3086,7 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re } } - //mount the volume filesystem if mounted when fs is not primary + //mount the volume filesystem if mounted if !(isFsMounted) && primaryfsName != fsName { klog.V(4).Infof("[%s] ControllerPublishVolume : mounting %s on %s", loggerId, fsName, scalenodeID) nodesNameList := []string{scalenodeID} @@ -3130,6 +3098,7 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re } } return &csi.ControllerPublishVolumeResponse{}, nil + } func (cs *ScaleControllerServer) CheckNewSnapRequired(ctx context.Context, conn connectors.SpectrumScaleConnector, filesystemName string, filesetName string, snapWindow int) (string, error) { From e7da4a4cdeed1e0e90d64f18b441128659524e4a Mon Sep 17 00:00:00 2001 From: hemalathagajendran Date: Fri, 18 Jul 2025 04:22:20 +0530 Subject: [PATCH 04/14] changes for controller publish Signed-off-by: hemalathagajendran --- driver/csiplugin/controllerserver.go | 113 ++++++--------------------- 1 file changed, 24 insertions(+), 89 deletions(-) diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index ae1728a41..ac978cf2a 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -2876,23 +2876,16 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re } //req &csi.ControllerPublishVolumeRequest{VolumeId:"2;2;15461220949750720109;69230B0A:67B82745;;pvc-0c5634b5-4391-4b9c-b879-94d6c2db9768;/ibm/fs1/pvc-0c5634b5-4391-4b9c-b879-94d6c2db9768", NodeId:"bnp-csi-main1-worker-1.fyre.ibm.com", VolumeCapability:(*csi.VolumeCapability)(0xc00011e680), Readonly:false, Secrets:map[string]string(nil), VolumeContext:map[string]string{"csi.storage.k8s.io/pv/name":"pvc-0c5634b5-4391-4b9c-b879-94d6c2db9768", "csi.storage.k8s.io/pvc/name":"cache-s3-pvc1", "csi.storage.k8s.io/pvc/namespace":"ibm-spectrum-scale-csi-driver", "storage.kubernetes.io/csiProvisionerIdentity":"1741361929928-7999-spectrumscale.csi.ibm.com", "volBackendFs":"fs1", "volumeType":"cache"}} - nodeID := req.GetNodeId() - if nodeID == "" { return nil, status.Error(codes.InvalidArgument, "NodeID not present") } volumeID := req.GetVolumeId() - if volumeID == "" { return nil, status.Error(codes.InvalidArgument, "ControllerPublishVolume : VolumeID is not present") } - var isFsMounted bool - - //Assumption : filesystem_uuid is always from local/primary cluster. - if req.VolumeCapability == nil { return nil, status.Error(codes.InvalidArgument, "ControllerPublishVolume :volume capabilities are empty") } @@ -2902,8 +2895,10 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re return nil, status.Error(codes.InvalidArgument, "ControllerPublishVolume : VolumeID is not in proper format") } + //Assumption : filesystem_uuid is always from local/primary cluster. filesystemID := volumeIDMembers.FsUUID volumePath := volumeIDMembers.Path + klog.Infof("[%s] nodeID:%s, volumeID:%s, volumeIDMembers:[%+v], filesystemID:%s, volumePath:%s", loggerId, nodeID, volumeID, volumeIDMembers, filesystemID, volumePath) // if SKIP_MOUNT_UNMOUNT == "yes" then mount/unmount will not be invoked skipMountUnmount := utils.GetEnv(SKIP_MOUNT_UNMOUNT, yes) @@ -2916,12 +2911,11 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in getting filesystem Name for filesystem ID of %s. Error [%v]", filesystemID, err)) } - //Check if primary filesystem is mounted. - primaryfsName := cs.Driver.primary.GetPrimaryFs() - pfsMount, err := cs.Driver.connmap["primary"].GetFilesystemMountDetails(ctx, primaryfsName) + //Check if filesystem is mounted. + fsMount, err := cs.Driver.connmap["primary"].GetFilesystemMountDetails(ctx, fsName) if err != nil { - klog.Errorf("[%s] ControllerPublishVolume : Error in getting filesystem mount details for %s", loggerId, primaryfsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in getting filesystem mount details for %s. Error [%v]", primaryfsName, err)) + klog.Errorf("[%s] ControllerPublishVolume : Error in getting filesystem mount details for %s", loggerId, fsName) + return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in getting filesystem mount details for %s. Error [%v]", fsName, err)) } // Node mapping check @@ -2933,58 +2927,26 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re klog.V(4).Infof("[%s] ControllerPublishVolume : SHORTNAME_NODE_MAPPING is set to %s", loggerId, shortnameNodeMapping) } - var ispFsMounted bool + klog.Infof("[%s] fsName:%s, fsMount:%s, scalenodeID:%s", fsName, fsMount, scalenodeID) + klog.Infof("[%s] ControllerPublishVolume : FS is mounted on %v", loggerId, fsMount.NodesMounted) + klog.V(4).Infof("[%s] ControllerPublishVolume : Volume is from Filesystem %s", loggerId, fsName) + + if !strings.HasPrefix(volumePath, fsMount.MountPoint) { + klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s", loggerId, volumePath, fsName) + return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s", volumePath, fsName)) + } + + var isFsMounted bool // NodesMounted has admin node names // This means node mapping must be to admin names. // Unless shortnameNodeMapping=="yes", then we should check shortname portion matches. if shortnameNodeMapping == yes { - ispFsMounted = shortnameInSlice(scalenodeID, pfsMount.NodesMounted) - } else { - ispFsMounted = utils.StringInSlice(scalenodeID, pfsMount.NodesMounted) - } - - klog.Infof("[%s] ControllerPublishVolume : Primary FS is mounted on %v", loggerId, pfsMount.NodesMounted) - klog.V(4).Infof("[%s] ControllerPublishVolume : Primary Fileystem is %s and Volume is from Filesystem %s", loggerId, primaryfsName, fsName) - var fsMount connectors.MountInfo - // Skip if primary filesystem and volume filesystem is same - if volumeIDMembers.StorageClassType == STORAGECLASS_ADVANCED || primaryfsName != fsName { - //Check if filesystem is mounted - fsMount, err = cs.Driver.connmap["primary"].GetFilesystemMountDetails(ctx, fsName) - if err != nil { - klog.Errorf("[%s] ControllerPublishVolume : Error in getting filesystem mount details for %s", loggerId, fsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in getting filesystem mount details for %s. Error [%v]", fsName, err)) - } - - if volumeIDMembers.StorageClassType == STORAGECLASS_ADVANCED && - !strings.HasPrefix(volumePath, fsMount.MountPoint) { - klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s", loggerId, volumePath, fsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s", volumePath, fsName)) - } else if !strings.HasPrefix(volumePath, fsMount.MountPoint) && - !strings.HasPrefix(volumePath, pfsMount.MountPoint) { - klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s or %s", loggerId, volumePath, primaryfsName, fsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s or %s", volumePath, primaryfsName, fsName)) - } - - // NodesMounted has admin node names - // This means node mapping must be to admin names. - // Unless shortnameNodeMapping=="yes", then we should check shortname portion matches. - if shortnameNodeMapping == yes { - isFsMounted = shortnameInSlice(scalenodeID, pfsMount.NodesMounted) - } else { - isFsMounted = utils.StringInSlice(scalenodeID, pfsMount.NodesMounted) - } - - klog.Infof("[%s] ControllerPublishVolume : Volume Source FS is mounted on %v", loggerId, fsMount.NodesMounted) + isFsMounted = shortnameInSlice(scalenodeID, fsMount.NodesMounted) } else { - if !strings.HasPrefix(volumePath, pfsMount.MountPoint) { - klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s", loggerId, volumePath, primaryfsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s", volumePath, primaryfsName)) - } - - isFsMounted = ispFsMounted + isFsMounted = utils.StringInSlice(scalenodeID, fsMount.NodesMounted) } - - klog.Infof("[%s] ControllerPublishVolume : Mount Status Primaryfs [ %t ], Sourcefs [ %t ]", loggerId, ispFsMounted, isFsMounted) + klog.Infof("[%s] ControllerPublishVolume : Volume Source FS is mounted on %v", loggerId, fsMount.NodesMounted) + klog.Infof("[%s] ControllerPublishVolume : Mount Status of fs [ %t ]", loggerId, isFsMounted) var isFsMountedOnGateway bool var gatewayNodeNames []string @@ -3004,12 +2966,7 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re klog.Infof("[%s] ControllerPublishVolume : gatewayNodes present in the Storage Scale are : %v", loggerId, gatewayNodeNames) // getting the remote FS name is case of remote filesystem. It will be same in case of local FS - - if primaryfsName != fsName { - fsNameRemote = getRemoteFsName(fsMount.RemoteDeviceName) - } else { - fsNameRemote = getRemoteFsName(pfsMount.RemoteDeviceName) - } + fsNameRemote = getRemoteFsName(fsMount.RemoteDeviceName) fsRemoteMountDetails, err := conn.GetFilesystemMountDetails(ctx, fsNameRemote) if err != nil { klog.Errorf("[%s] ControllerPublishVolume : Error in getting filesystem mount details for %s", loggerId, fsName) @@ -3028,19 +2985,13 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re isFsMountedOnGateway = isSubset(gatewayNodeNames, fsRemoteMountDetails.NodesMounted) //sucess when FS is mounted primary , volumeFS and on all the gatewayNodes for "cache" volume - if isFsMounted && ispFsMounted && isFsMountedOnGateway { + if isFsMounted && isFsMountedOnGateway { klog.V(4).Infof("[%s] ControllerPublishVolume : filesystem %s is mounted on %s and on gatewayNodes %v so returning success", loggerId, fsName, scalenodeID, gatewayNodeNames) - if fsName != primaryfsName { - klog.V(4).Infof("[%s] ControllerPublishVolume when not a primaryfs : filesystem %s is mounted on %s and on gatewayNodes %v so returning success", loggerId, primaryfsName, scalenodeID, gatewayNodeNames) - } return &csi.ControllerPublishVolumeResponse{}, nil } - } else if isFsMounted && ispFsMounted { + } else if isFsMounted { klog.V(4).Infof("[%s] ControllerPublishVolume : filesystem %s is mounted on %s so returning success", loggerId, fsName, scalenodeID) - if fsName != primaryfsName { - klog.V(4).Infof("[%s] ControllerPublishVolume when not a primaryfs : filesystem %s is mounted on %s so returning success", loggerId, primaryfsName, scalenodeID) - } return &csi.ControllerPublishVolumeResponse{}, nil } @@ -3056,11 +3007,6 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re klog.Errorf(message) return nil, status.Error(codes.Internal, message) } - if !ispFsMounted { - message := fmt.Sprintf("[%s] ControllerPublishVolume : filesystem %s is not mounted on node %s", loggerId, primaryfsName, scalenodeID) - klog.Errorf(message) - return nil, status.Error(codes.Internal, message) - } } if skipMountUnmount == no { @@ -3075,19 +3021,8 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re } } - //mount the primary filesystem if not mounted - if !(ispFsMounted) { - klog.V(4).Infof("[%s] ControllerPublishVolume : mounting Filesystem %s on %s", loggerId, primaryfsName, scalenodeID) - nodesNameList := []string{scalenodeID} - err = cs.Driver.connmap["primary"].MountFilesystem(ctx, primaryfsName, nodesNameList) - if err != nil { - klog.Errorf("[%s] ControllerPublishVolume : Error in mounting filesystem %s on node %s", loggerId, primaryfsName, scalenodeID) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in mounting filesystem %s on node %s. Error [%v]", primaryfsName, scalenodeID, err)) - } - } - //mount the volume filesystem if mounted - if !(isFsMounted) && primaryfsName != fsName { + if !(isFsMounted) { klog.V(4).Infof("[%s] ControllerPublishVolume : mounting %s on %s", loggerId, fsName, scalenodeID) nodesNameList := []string{scalenodeID} err = cs.Driver.connmap["primary"].MountFilesystem(ctx, fsName, nodesNameList) From 6aa12749c3337b2ee46b9f1377d511a67ff1ccad Mon Sep 17 00:00:00 2001 From: hemalathagajendran Date: Fri, 18 Jul 2025 05:43:37 +0530 Subject: [PATCH 05/14] CreateSnaphot Signed-off-by: hemalathagajendran --- driver/cmd/ibm-spectrum-scale-csi/main.go | 2 +- driver/csiplugin/controllerserver.go | 37 +++++++---------------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/driver/cmd/ibm-spectrum-scale-csi/main.go b/driver/cmd/ibm-spectrum-scale-csi/main.go index e176dba73..d1a08c11e 100644 --- a/driver/cmd/ibm-spectrum-scale-csi/main.go +++ b/driver/cmd/ibm-spectrum-scale-csi/main.go @@ -48,7 +48,7 @@ var ( func main() { klog.InitFlags(nil) - for _, key := range []string{utils.LogLevel, settings.PersistentLog, settings.NodePublishMethod, settings.VolumeStatsCapability, driver.VolNamePrefixEnvKey, settings.DiscoverCGFileset, settings.PrimaryFilesystemKey} { + for _, key := range []string{utils.LogLevel, settings.PersistentLog, settings.NodePublishMethod, settings.VolumeStatsCapability, driver.VolNamePrefixEnvKey, settings.DiscoverCGFileset} { if val, ok := os.LookupEnv(key); ok { klog.Infof("[%s] found in the env : %s", key, val) } diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index ac978cf2a..6a466a47f 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -131,20 +131,16 @@ func (cs *ScaleControllerServer) generateVolID(ctx context.Context, scVol *scale path := "" if !isShallowCopyVolume { - if isCGVolume || scVol.VolumeType == cacheVolume || scVol.IsStaticPVBased { - primaryConn, isprimaryConnPresent := cs.Driver.connmap["primary"] - if !isprimaryConnPresent { - klog.Errorf("[%s] unable to get connector for primary cluster", loggerId) - return "", status.Error(codes.Internal, "unable to find primary cluster details in custom resource") - } - fsMountPoint, err := primaryConn.GetFilesystemMountDetails(ctx, scVol.LocalFS) - if err != nil { - return "", status.Error(codes.Internal, fmt.Sprintf("unable to get mount info for FS [%v] in cluster", scVol.LocalFS)) - } - path = fmt.Sprintf("%s/%s", fsMountPoint.MountPoint, targetPath) - } else { - path = fmt.Sprintf("%s/%s", scVol.PrimarySLnkPath, scVol.VolName) + primaryConn, isprimaryConnPresent := cs.Driver.connmap["primary"] + if !isprimaryConnPresent { + klog.Errorf("[%s] unable to get connector for primary cluster", loggerId) + return "", status.Error(codes.Internal, "unable to find primary cluster details in custom resource") } + fsMountPoint, err := primaryConn.GetFilesystemMountDetails(ctx, scVol.LocalFS) + if err != nil { + return "", status.Error(codes.Internal, fmt.Sprintf("unable to get mount info for FS [%v] in cluster", scVol.LocalFS)) + } + path = fmt.Sprintf("%s/%s", fsMountPoint.MountPoint, targetPath) } else { path = targetPath } @@ -3181,17 +3177,7 @@ func (cs *ScaleControllerServer) CreateSnapshot(newctx context.Context, req *csi filesetName := filesetResp.FilesetName relPath := "" - if volumeIDMembers.StorageClassType == STORAGECLASS_ADVANCED { - klog.V(4).Infof("[%s] CreateSnapshot - creating snapshot for advanced storageClass", loggerId) - relPath = strings.Replace(volumeIDMembers.Path, mountInfo.MountPoint, "", 1) - } else { - klog.V(4).Infof("[%s] CreateSnapshot - creating snapshot for classic storageClass", loggerId) - primaryFSMountPoint, err := cs.getPrimaryFSMountPoint(ctx) - if err != nil { - return nil, err - } - relPath = strings.Replace(volumeIDMembers.Path, primaryFSMountPoint, "", 1) - } + relPath = strings.Replace(volumeIDMembers.Path, mountInfo.MountPoint, "", 1) relPath = strings.Trim(relPath, "!/") var pvName string @@ -3258,8 +3244,7 @@ func (cs *ScaleControllerServer) CreateSnapshot(newctx context.Context, req *csi // storageclass_type;volumeType;clusterId;FSUUID;consistency_group;filesetName;snapshotName;metaSnapshotName snapID = fmt.Sprintf("%s;%s;%s;%s;%s;%s;%s;%s", volumeIDMembers.StorageClassType, volumeIDMembers.VolType, volumeIDMembers.ClusterId, volumeIDMembers.FsUUID, filesetName, filesetResp.FilesetName, snapName, req.GetName()) } else { - if strings.Contains(filesetResp.Config.Comment, connectors.FilesetComment) && - (cs.Driver.primary.PrimaryFset != filesetName || cs.Driver.primary.PrimaryFs != filesystemName) { + if strings.Contains(filesetResp.Config.Comment, connectors.FilesetComment) { // Dynamically created PVC, here path is the xxx-data directory within the fileset where all volume data resides // storageclass_type;volumeType;clusterId;FSUUID;consistency_group;filesetName;snapshotName;metaSnapshotName;path snapID = fmt.Sprintf("%s;%s;%s;%s;%s;%s;%s;%s;%s-data", volumeIDMembers.StorageClassType, volumeIDMembers.VolType, volumeIDMembers.ClusterId, volumeIDMembers.FsUUID, "", filesetName, snapName, "", filesetName) From 872da3275a1162f70cf7298f90afd15f9bdae366 Mon Sep 17 00:00:00 2001 From: hemalathagajendran Date: Sun, 20 Jul 2025 22:58:49 +0530 Subject: [PATCH 06/14] Fix for UT issues Signed-off-by: hemalathagajendran --- driver/csiplugin/controllerserver.go | 41 ++++++++++++---------------- driver/csiplugin/gpfs_util.go | 3 +- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index 6a466a47f..c94f1ea30 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -59,11 +59,11 @@ const ( fsetNotFoundErrCode = "EFSSG0072C" fsetNotFoundErrMsg = "400 Invalid value in 'filesetName'" - fsetLinkNotFoundErrCode = "EFSSG0449C" - fsetLinkNotFoundErrMsg = "is not linked" + //fsetLinkNotFoundErrCode = "EFSSG0449C" + //fsetLinkNotFoundErrMsg = "is not linked" - pvcNameKey = "csi.storage.k8s.io/pvc/name" - pvcNamespaceKey = "csi.storage.k8s.io/pvc/namespace" + //pvcNameKey = "csi.storage.k8s.io/pvc/name" + //pvcNamespaceKey = "csi.storage.k8s.io/pvc/namespace" ) type ScaleControllerServer struct { @@ -900,7 +900,7 @@ func (cs *ScaleControllerServer) CreateVolume(newctx context.Context, req *csi.C return nil, status.Error(codes.InvalidArgument, "The Parameter(s) not supported in storageClass: "+invalidParams) } - scaleVol, isCGVolume, primaryClusterID, err := cs.setScaleVolume(ctx, req, volName, volSize) + scaleVol, isCGVolume, err := cs.setScaleVolume(ctx, req, volName, volSize) if err != nil { return nil, err } @@ -987,7 +987,7 @@ func (cs *ScaleControllerServer) CreateVolume(newctx context.Context, req *csi.C if err != nil { return nil, err } - err = cs.setScaleVolumeWithRemoteCluster(ctx, scaleVol, volFsInfo, primaryClusterID) + err = cs.setScaleVolumeWithRemoteCluster(ctx, scaleVol, volFsInfo, scaleVol.PrimaryClusterId) if err != nil { return nil, err } @@ -1069,7 +1069,7 @@ func (cs *ScaleControllerServer) CreateVolume(newctx context.Context, req *csi.C } if scaleVol.IsFilesetBased && scaleVol.Tier != "" { - err = cs.checkVolTierAndSetFilesystemPolicy(ctx, scaleVol, volFsInfo, primaryClusterID) + err = cs.checkVolTierAndSetFilesystemPolicy(ctx, scaleVol, volFsInfo, scaleVol.PrimaryClusterId) if err != nil { return nil, err } @@ -1304,10 +1304,10 @@ func validateCacheSecret(secretData map[string]string) []string { return missingKeys } -func (cs *ScaleControllerServer) setScaleVolume(ctx context.Context, req *csi.CreateVolumeRequest, volName string, volSize int64) (*scaleVolume, bool, string, error) { +func (cs *ScaleControllerServer) setScaleVolume(ctx context.Context, req *csi.CreateVolumeRequest, volName string, volSize int64) (*scaleVolume, bool, error) { scaleVol, err := getScaleVolumeOptions(ctx, req.GetParameters()) if err != nil { - return nil, false, "", err + return nil, false, err } isCGVolume := false @@ -1318,7 +1318,7 @@ func (cs *ScaleControllerServer) setScaleVolume(ctx context.Context, req *csi.Cr // #nosec G115 -- false positive if uint64(volSize) > maximumPVSize { // larger than allowed pv size not allowed - return nil, false, "", fmt.Errorf("failed to create volume, request volume size: [%v] in Bytes is greater than the allowed PV max size: [%v]", uint64(volSize), maximumPVSizeForLog) + return nil, false, fmt.Errorf("failed to create volume, request volume size: [%v] in Bytes is greater than the allowed PV max size: [%v]", uint64(volSize), maximumPVSizeForLog) } // #nosec G115 -- false positive @@ -1331,7 +1331,7 @@ func (cs *ScaleControllerServer) setScaleVolume(ctx context.Context, req *csi.Cr /* Get details for Primary Cluster */ primaryConn, primaryClusterID, err := cs.getPrimaryClusterDetails(ctx) if err != nil { - return nil, isCGVolume, "", err + return nil, isCGVolume, err } scaleVol.PrimaryConnector = primaryConn @@ -1339,7 +1339,8 @@ func (cs *ScaleControllerServer) setScaleVolume(ctx context.Context, req *csi.Cr //scaleVol.PrimaryFS = primaryFS //scaleVol.PrimaryFSMount = primaryFSMount //scaleVol.PrimarySLnkPath = symlinkDirAbsolutePath - return scaleVol, isCGVolume, primaryClusterID, nil + scaleVol.PrimaryClusterId = primaryClusterID + return scaleVol, isCGVolume, nil } func (cs *ScaleControllerServer) getVolORSnapMembers(ctx context.Context, req *csi.CreateVolumeRequest, volName string) (bool, bool, *csi.VolumeContentSource, scaleSnapId, scaleVolId, error) { @@ -1797,7 +1798,7 @@ func (cs *ScaleControllerServer) copyVolumeContent(ctx context.Context, newvolum } else { var sLinkRelPath string - klog.V(4).Infof("[%s] copyVolContent when PrimaryDisable, sourcevolume.Path=[%v], fsMntPt=[%v]", loggerId, sourcevolume.Path, fsMntPt) + klog.V(4).Infof("[%s] copyVolContent with sourcevolume.Path=[%v], fsMntPt=[%v]", loggerId, sourcevolume.Path, fsMntPt) sLinkRelPath = strings.Replace(sourcevolume.Path, fsMntPt, "", 1) //klog.V(4).Infof("[%s] copyVolContent when with Primary, sourcevolume.Path=[%v]", loggerId, sourcevolume.Path) @@ -2526,22 +2527,16 @@ func (cs *ScaleControllerServer) DeleteVolume(newctx context.Context, req *csi.D if err != nil { return nil, err } - - primaryConn, isprimaryConnPresent := cs.Driver.connmap["primary"] - if !isprimaryConnPresent { - klog.Errorf("[%s] unable to get connector for primary cluster", loggerId) - return nil, status.Error(codes.Internal, "unable to find primary cluster details in custom resource") - } - + c /* FsUUID in volumeIdMembers will be of Primary cluster. So lets get Name of it from Primary cluster */ - FilesystemName, err := primaryConn.GetFilesystemName(ctx, volumeIdMembers.FsUUID) + FilesystemName, err := conn.GetFilesystemName(ctx, volumeIdMembers.FsUUID) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("unable to get filesystem Name for Id [%v] and clusterId [%v]. Error [%v]", volumeIdMembers.FsUUID, volumeIdMembers.ClusterId, err)) } - mountInfo, err := primaryConn.GetFilesystemMountDetails(ctx, FilesystemName) + mountInfo, err := conn.GetFilesystemMountDetails(ctx, FilesystemName) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("unable to get mount info for FS [%v] in primary cluster", FilesystemName)) @@ -3012,7 +3007,7 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re err = conn.MountFilesystem(ctx, fsNameRemote, gatewayNodeNames) if err != nil { - klog.Errorf("[%s] ControllerPublishVolume : Error in mounting remote filesystem %s on the gateway nodes %v", loggerId, primaryfsName, gatewayNodeNames) + klog.Errorf("[%s] ControllerPublishVolume : Error in mounting remote filesystem %s on the gateway nodes %v", loggerId, fsNameRemote, gatewayNodeNames) return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Error in mounting remote filesystem %s if any on the gateway nodes %v. Error [%v]", fsNameRemote, gatewayNodeNames, err)) } } diff --git a/driver/csiplugin/gpfs_util.go b/driver/csiplugin/gpfs_util.go index c4e75c10c..287bd1f5d 100644 --- a/driver/csiplugin/gpfs_util.go +++ b/driver/csiplugin/gpfs_util.go @@ -85,7 +85,8 @@ type scaleVolume struct { PrimarySLnkRelPath string `json:"primarySLnkRelPath"` //Deprecated from 3.0.0 PrimarySLnkPath string `json:"primarySLnkPath"` //Deprecated from 3.0.0 PrimaryFS string `json:"primaryFS"` //Deprecated from 3.0.0 - PrimaryFSMount string `json:"primaryFSMount"` + PrimaryFSMount string `json:"primaryFSMount"` //Deprecated from 3.0.0 + PrimaryClusterId string `json:"primaryClusterId"` ParentFileset string `json:"parentFileset"` LocalFS string `json:"localFS"` TargetPath string `json:"targetPath"` From a61b155da57e4179fb5c2c3f299eed74d8f78e79 Mon Sep 17 00:00:00 2001 From: hemalathagajendran Date: Wed, 23 Jul 2025 18:54:51 +0530 Subject: [PATCH 07/14] changes for delete volume Signed-off-by: hemalathagajendran --- driver/csiplugin/connectors/connectors.go | 1 + driver/csiplugin/connectors/rest_v2.go | 23 ++ driver/csiplugin/controllerserver.go | 97 ++++---- driver/csiplugin/gpfs.go | 5 - driver/csiplugin/settings/scale_config.go | 24 -- .../csiscaleoperator_controller.go | 213 ------------------ 6 files changed, 73 insertions(+), 290 deletions(-) diff --git a/driver/csiplugin/connectors/connectors.go b/driver/csiplugin/connectors/connectors.go index 857fecc13..c3ba3cae3 100644 --- a/driver/csiplugin/connectors/connectors.go +++ b/driver/csiplugin/connectors/connectors.go @@ -36,6 +36,7 @@ type SpectrumScaleConnector interface { GetFilesystemMountDetails(ctx context.Context, filesystemName string) (MountInfo, error) IsFilesystemMountedOnGUINode(ctx context.Context, filesystemName string) (bool, error) ListFilesystems(ctx context.Context) ([]string, error) + ListFilesystemsMountpoint(ctx context.Context) (map[string]string, error) GetFilesystemDetails(ctx context.Context, filesystemName string) (FileSystem_v2, error) GetFilesystemMountpoint(ctx context.Context, filesystemName string) (string, error) //Node operations diff --git a/driver/csiplugin/connectors/rest_v2.go b/driver/csiplugin/connectors/rest_v2.go index b946b8e33..77d0d1322 100644 --- a/driver/csiplugin/connectors/rest_v2.go +++ b/driver/csiplugin/connectors/rest_v2.go @@ -336,6 +336,29 @@ func (s *SpectrumRestV2) ListFilesystems(ctx context.Context) ([]string, error) return filesystems, nil } +func (s *SpectrumRestV2) ListFilesystemsMountpoint(ctx context.Context) (map[string]string, error) { + klog.V(4).Infof("[%s] rest_v2 ListFilesystems", utils.GetLoggerId(ctx)) + + listFilesystemsURL := "scalemgmt/v2/filesystems" + getFilesystemResponse := GetFilesystemResponse_v2{} + + err := s.doHTTP(ctx, listFilesystemsURL, "GET", &getFilesystemResponse, nil) + if err != nil { + klog.Errorf("[%s] Error in listing filesystems: %v", utils.GetLoggerId(ctx), err) + return nil, err + } + fsNumber := len(getFilesystemResponse.FileSystems) + filesystemsMountpoint := make(map[string]string, fsNumber) + if len(getFilesystemResponse.FileSystems) > 0 { + for i := 0; i < fsNumber; i++ { + filesystemsMountpoint[getFilesystemResponse.FileSystems[i].Name] = getFilesystemResponse.FileSystems[i].Mount.MountPoint + } + return filesystemsMountpoint, nil + } else { + return nil, fmt.Errorf("unable to fetch mount point as there is no filesystem listed") + } +} + func (s *SpectrumRestV2) GetFilesystemMountpoint(ctx context.Context, filesystemName string) (string, error) { klog.V(4).Infof("[%s] rest_v2 GetFilesystemMountpoint. filesystemName: %s", utils.GetLoggerId(ctx), filesystemName) diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index c94f1ea30..87a7f367d 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -837,21 +837,6 @@ func (cs *ScaleControllerServer) getPrimaryClusterDetails(ctx context.Context) ( return primaryConn, cs.Driver.primary.PrimaryCid, err } -func (cs *ScaleControllerServer) getPrimaryFSMountPoint(ctx context.Context) (string, error) { - loggerId := utils.GetLoggerId(ctx) - klog.Infof("[%s] getPrimaryFSMountPoint", loggerId) - - primaryConn := cs.Driver.connmap["primary"] - primaryFS := cs.Driver.primary.GetPrimaryFs() - fsMountInfo, err := primaryConn.GetFilesystemMountDetails(ctx, primaryFS) - if err != nil { - klog.Errorf("[%s] Failed to get details of primary filesystem %s:Error: %v", loggerId, primaryFS, err) - return "", status.Error(codes.NotFound, fmt.Sprintf("Failed to get details of primary filesystem %s. Error: %v", primaryFS, err)) - - } - return fsMountInfo.MountPoint, nil -} - // CreateVolume - Create Volume func (cs *ScaleControllerServer) CreateVolume(newctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) { //nolint:gocyclo,funlen loggerId := utils.GetLoggerId(newctx) @@ -1335,10 +1320,6 @@ func (cs *ScaleControllerServer) setScaleVolume(ctx context.Context, req *csi.Cr } scaleVol.PrimaryConnector = primaryConn - //scaleVol.PrimarySLnkRelPath = symlinkDirRelativePath - //scaleVol.PrimaryFS = primaryFS - //scaleVol.PrimaryFSMount = primaryFSMount - //scaleVol.PrimarySLnkPath = symlinkDirAbsolutePath scaleVol.PrimaryClusterId = primaryClusterID return scaleVol, isCGVolume, nil } @@ -1756,11 +1737,6 @@ func (cs *ScaleControllerServer) copyVolumeContent(ctx context.Context, newvolum return err } - // err = cs.validateRemoteFs(fsDetails, scVol) - // if err != nil { - // return err - // } - targetFsName, err := conn.GetFilesystemName(ctx, fsDetails.UUID) if err != nil { return err @@ -1798,18 +1774,13 @@ func (cs *ScaleControllerServer) copyVolumeContent(ctx context.Context, newvolum } else { var sLinkRelPath string - klog.V(4).Infof("[%s] copyVolContent with sourcevolume.Path=[%v], fsMntPt=[%v]", loggerId, sourcevolume.Path, fsMntPt) - sLinkRelPath = strings.Replace(sourcevolume.Path, fsMntPt, "", 1) - - //klog.V(4).Infof("[%s] copyVolContent when with Primary, sourcevolume.Path=[%v]", loggerId, sourcevolume.Path) - //primaryFSMountPoint, err := cs.getPrimaryFSMountPoint(ctx) - //if err != nil { - //return err - // } - // klog.V(4).Infof("[%s] copyVolContent sourcevolume.Path=[%v], primaryFSMountPoint=[%v]", loggerId, sourcevolume.Path, primaryFSMountPoint) - // sLinkRelPath = strings.Replace(sourcevolume.Path, primaryFSMountPoint, "", 1) - - // } + sourceFsDetails, err := conn.GetFilesystemDetails(ctx, sourcevolume.FsName) + if err != nil { + return err + } + sourceFsMntPt := sourceFsDetails.Mount.MountPoint + klog.V(4).Infof("[%s] copyVolContent with sourcevolume.Path=[%v], sourcefsMntPt=[%v]", loggerId, sourcevolume.Path, sourceFsMntPt) + sLinkRelPath = strings.Replace(sourcevolume.Path, sourceFsMntPt, "", 1) klog.V(4).Infof("[%s] copyVolContent sourcevolume.Path=[%v], sourcevolume.FsName=[%v], sLinkRelPath=[%v], targetPath=[%v]", loggerId, sourcevolume.Path, sourcevolume.FsName, sLinkRelPath, targetPath) sLinkRelPath = strings.Trim(sLinkRelPath, "!/") @@ -2527,7 +2498,7 @@ func (cs *ScaleControllerServer) DeleteVolume(newctx context.Context, req *csi.D if err != nil { return nil, err } - c + /* FsUUID in volumeIdMembers will be of Primary cluster. So lets get Name of it from Primary cluster */ FilesystemName, err := conn.GetFilesystemName(ctx, volumeIdMembers.FsUUID) @@ -2547,26 +2518,30 @@ func (cs *ScaleControllerServer) DeleteVolume(newctx context.Context, req *csi.D symlinkExists = true klog.Infof("[%s] DeleteVolume : symlink exists for volume path : [%t]", loggerId, symlinkExists) } + pfsName := "" // getting the primary filesystem name from the path when primary fs is not provided in the cr and pvc is older - /* if symlinkExists && ifPrimaryDisable { + if symlinkExists { parts := strings.Split(volumeIdMembers.Path, "/") for i, part := range parts { if part == ".volumes" && i >= 2 { pfsName = parts[i-2] - klog.Infof("[%s] DeleteVolume :primary fs from path is [%v]", loggerId, pfsName) + klog.Infof("[%s] DeleteVolume :primary fs from old pvc path is [%v]", loggerId, pfsName) } } - }*/ + } relPath := "" if volumeIdMembers.StorageClassType != STORAGECLASS_CLASSIC || volumeIdMembers.VolType == FILE_SHALLOWCOPY_VOLUME || !symlinkExists { relPath = strings.Replace(volumeIdMembers.Path, mountInfo.MountPoint, "", 1) } else { - primaryFSMountPoint, err := cs.getPrimaryFSMountPoint(ctx) + + pfsMountInfo, err := conn.GetFilesystemMountDetails(ctx, pfsName) if err != nil { - return nil, err + return nil, status.Error(codes.Internal, fmt.Sprintf("unable to get mount info for FS [%v] in primary cluster", FilesystemName)) } + primaryFSMountPoint := pfsMountInfo.MountPoint + relPath = strings.Replace(volumeIdMembers.Path, primaryFSMountPoint, "", 1) klog.V(4).Infof("[%s] DeleteVolume : relPath %v volumeIdMembers.Path [%v], primaryFSMountPoint [%v]", loggerId, relPath, volumeIdMembers.Path, primaryFSMountPoint) } @@ -2577,6 +2552,13 @@ func (cs *ScaleControllerServer) DeleteVolume(newctx context.Context, req *csi.D var shallowCopyRefPath string var snapshotName string var independentFileset string + + primaryConn, isprimaryConnPresent := cs.Driver.connmap["primary"] + if !isprimaryConnPresent { + klog.Errorf("[%s] unable to get connector for primary cluster", loggerId) + return nil, status.Error(codes.Internal, "unable to find primary cluster details in custom resource") + } + if volumeIdMembers.VolType == FILE_SHALLOWCOPY_VOLUME { if relPath != "" && strings.Contains(relPath, ".snapshots") { volPath := strings.Split(relPath, "/") @@ -2712,7 +2694,7 @@ func (cs *ScaleControllerServer) DeleteVolume(newctx context.Context, req *csi.D filesystemName = FilesystemName klog.V(4).Infof("[%s] DeleteVolume with PrimaryDisable: filesystemName %v", loggerId, filesystemName) } else { - filesystemName = cs.Driver.primary.GetPrimaryFs() + filesystemName = pfsName klog.V(4).Infof("[%s] DeleteVolume with Primary: filesystemName %v", loggerId, filesystemName) } klog.V(4).Infof("[%s] DeleteVolume : filesystemName [%v], relPath [%v]", loggerId, filesystemName, relPath) @@ -2724,10 +2706,10 @@ func (cs *ScaleControllerServer) DeleteVolume(newctx context.Context, req *csi.D } if volumeIdMembers.StorageClassType == STORAGECLASS_CLASSIC && !isPvcFromSnapshot && symlinkExists { - err = primaryConn.DeleteSymLnk(ctx, cs.Driver.primary.GetPrimaryFs(), relPath) + err = primaryConn.DeleteSymLnk(ctx, pfsName, relPath) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("unable to delete symlnk [%v:%v] Error [%v]", cs.Driver.primary.GetPrimaryFs(), relPath, err)) + return nil, status.Error(codes.Internal, fmt.Sprintf("unable to delete symlnk [%v:%v] Error [%v]", pfsName, relPath, err)) } } @@ -2918,13 +2900,32 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re klog.V(4).Infof("[%s] ControllerPublishVolume : SHORTNAME_NODE_MAPPING is set to %s", loggerId, shortnameNodeMapping) } - klog.Infof("[%s] fsName:%s, fsMount:%s, scalenodeID:%s", fsName, fsMount, scalenodeID) + klog.Infof("[%s] fsName:%s, fsMount:%s, scalenodeID:%s", loggerId, fsName, fsMount, scalenodeID) klog.Infof("[%s] ControllerPublishVolume : FS is mounted on %v", loggerId, fsMount.NodesMounted) klog.V(4).Infof("[%s] ControllerPublishVolume : Volume is from Filesystem %s", loggerId, fsName) if !strings.HasPrefix(volumePath, fsMount.MountPoint) { - klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the filesystem %s", loggerId, volumePath, fsName) - return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part of the filesystem %s", volumePath, fsName)) + klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the given filesystem %s", loggerId, volumePath, fsName) + fsMountpoints, err := cs.Driver.connmap["primary"].ListFilesystemsMountpoint(ctx) + mountPointFound := false + var volumePathfs string + if err != nil { + return nil, status.Error(codes.Internal, "ControllerPublishVolume : unable to fetch list of filesystems") + } else { + for fsValue, mountPoint := range fsMountpoints { + if strings.HasPrefix(volumePath, mountPoint) { + mountPointFound = true + volumePathfs = fsValue + break + } + } + if mountPointFound { + klog.Infof("[%s] ControllerPublishVolume: Volume path %s is part of the filesystem:%s", loggerId, volumePath, volumePathfs) + } + } + if !mountPointFound { + return nil, status.Error(codes.Internal, fmt.Sprintf("ControllerPublishVolume : Volume path %s is not part any of the filesystem", volumePath)) + } } var isFsMounted bool diff --git a/driver/csiplugin/gpfs.go b/driver/csiplugin/gpfs.go index ce9357173..02357069e 100644 --- a/driver/csiplugin/gpfs.go +++ b/driver/csiplugin/gpfs.go @@ -275,11 +275,6 @@ func (driver *ScaleDriver) PluginInitialize(ctx context.Context) (map[string]con scaleConnMap["primary"] = sc scaleConfig.Clusters[i].Primary.PrimaryCid = clusterId - - //If primary fileset value is not specified then use the default one - //if scaleConfig.Clusters[i].Primary.PrimaryFset == "" { - // scaleConfig.Clusters[i].Primary.PrimaryFset = defaultPrimaryFileset - //} primaryInfo = scaleConfig.Clusters[i].Primary } } diff --git a/driver/csiplugin/settings/scale_config.go b/driver/csiplugin/settings/scale_config.go index 5d55b9152..5130077cf 100644 --- a/driver/csiplugin/settings/scale_config.go +++ b/driver/csiplugin/settings/scale_config.go @@ -62,30 +62,6 @@ const ( DiscoverCGFileset = "DISCOVER_CG_FILESET" ) -/* -To support backwards compatibility if the PrimaryFs field is not defined then - - use the previous version of the field. -*/ -func (primary Primary) GetPrimaryFs() string { - if primary.PrimaryFs == "" { - return primary.PrimaryFSDep - } - return primary.PrimaryFs -} - -/* -To support backwards compatibility if the InodeLimit field is not defined then - - use the previous version of the field. -*/ -func (primary Primary) GetInodeLimit() string { - if primary.InodeLimits == "" { - return primary.InodeLimitDep - } - return primary.InodeLimits -} - type RestAPI struct { GuiHost string `json:"guiHost"` GuiPort int `json:"guiPort"` diff --git a/operator/controllers/csiscaleoperator_controller.go b/operator/controllers/csiscaleoperator_controller.go index 70205fc69..64aad66cc 100644 --- a/operator/controllers/csiscaleoperator_controller.go +++ b/operator/controllers/csiscaleoperator_controller.go @@ -23,7 +23,6 @@ import ( "encoding/json" "fmt" "net/http" - "path" "reflect" "strconv" "strings" @@ -2034,142 +2033,6 @@ func (r *CSIScaleOperatorReconciler) handleSpectrumScaleConnectors(instance *csi return requeAfterDelay, nil } -// handlePrimaryFSandFileset checks if primary FS exists, also checkes if primary fileset exists. -// If primary fileset does not exist, it is created and also if a directory -// to store symlinks is created if it does not exist. It returns the absolute path of symlink -// directory and error if there is any. -func (r *CSIScaleOperatorReconciler) handlePrimaryFSandFileset(instance *csiscaleoperator.CSIScaleOperator) (time.Duration, error) { - logger := csiLog.WithName("handlePrimaryFSandFileset") - requeAfterDelay := time.Duration(0) - primaryReference := r.getPrimaryCluster(instance) - if primaryReference == nil { - message := fmt.Sprintf("No primary cluster is defined in the IBM Storage Scale CSI configurations under Spec.Clusters section in the CSISCaleOperator instance %s/%s", instance.Kind, instance.Name) - err := fmt.Errorf("%s", message) - logger.Error(err, "") - SetStatusAndRaiseEvent(instance, r.Recorder, corev1.EventTypeWarning, string(config.StatusConditionSuccess), - metav1.ConditionFalse, string(csiv1.PrimaryClusterUndefined), message, - ) - return requeAfterDelay, err - } - - primary := *primaryReference - sc := scaleConnMap[config.Primary] - - // check if primary filesystem exists - fsMountInfo, err := sc.GetFilesystemMountDetails(context.TODO(), primary.PrimaryFs) - if err != nil { - requeAfterDelay = 2 * time.Minute - message := fmt.Sprintf("Failed to get the details of the primary filesystem: %s, retrying after 2 minutes", primary.PrimaryFs) - logger.Error(err, message) - SetStatusAndRaiseEvent(instance, r.Recorder, corev1.EventTypeWarning, string(config.StatusConditionSuccess), - metav1.ConditionFalse, string(csiv1.GetFileSystemFailed), message, - ) - return requeAfterDelay, err - } - - // In case primary fset value is not specified in configuation then use default - if primary.PrimaryFset == "" { - primary.PrimaryFset = config.DefaultPrimaryFileset - logger.Info("Primary fileset is not specified", "using default primary fileset %s", config.DefaultPrimaryFileset) - } - - primaryFSMount := fsMountInfo.MountPoint - - // Get FS name on owning cluster - // Examples of remoteDeviceName: - // 1. Local FS fs2 - - // "remoteDeviceName" : ":fs2" - // 2. Remote FS fs1 which can be mounted locally with a different name - // "remoteDeviceName" : ":fs1" - remoteDeviceName := strings.Split(fsMountInfo.RemoteDeviceName, ":") - fsNameOnOwningCluster := remoteDeviceName[len(remoteDeviceName)-1] - - // //check if multiple GUIs are passed - // if len(cluster.RestAPI) > 1 { - // err := driver.cs.checkGuiHASupport(sc) - // if err != nil { - // return "", err - // } - // } - - if primary.RemoteCluster != "" { - //if remote cluster is present, use connector of remote cluster - sc = scaleConnMap[primary.RemoteCluster] - if fsNameOnOwningCluster == "" { - message := "failed to get the name of the remote filesystem from the cluster" - logger.Error(err, message) - SetStatusAndRaiseEvent(instance, r.Recorder, corev1.EventTypeWarning, string(config.StatusConditionSuccess), - metav1.ConditionFalse, string(csiv1.GetRemoteFileSystemFailed), message, - ) - return requeAfterDelay, fmt.Errorf("%s", message) - } - } - - //check if primary filesystem exists on remote cluster and mounted on atleast one node - fsMountInfo, err = sc.GetFilesystemMountDetails(context.TODO(), fsNameOnOwningCluster) - if err != nil { - message := fmt.Sprintf("Failed to the get details of the filesystem: %s", fsNameOnOwningCluster) - logger.Error(err, message) - SetStatusAndRaiseEvent(instance, r.Recorder, corev1.EventTypeWarning, string(config.StatusConditionSuccess), - metav1.ConditionFalse, string(csiv1.GetFileSystemFailed), message, - ) - return requeAfterDelay, err - } - - fsMountPoint := fsMountInfo.MountPoint - - fsetLinkPath, err := r.createPrimaryFileset(instance, sc, fsNameOnOwningCluster, fsMountPoint, primary.PrimaryFset, primary.InodeLimit) - if err != nil { - message := fmt.Sprintf("Failed to create the primary fileset %s on the primary filesystem %s", primary.PrimaryFset, primary.PrimaryFs) - logger.Error(err, message) - return requeAfterDelay, err - } - - // In case primary FS is remotely mounted, run fileset refresh task on primary cluster - if primary.RemoteCluster != "" { - filesetInfo, err := scaleConnMap[config.Primary].ListFileset(context.TODO(), primary.PrimaryFs, primary.PrimaryFset) - if err != nil || reflect.ValueOf(filesetInfo).IsZero() { - logger.Info("Primary fileset is not visible on primary cluster. Running fileset refresh task", "fileset name", primary.PrimaryFset) - err = scaleConnMap[config.Primary].FilesetRefreshTask(context.TODO()) - if err != nil { - message := "error in fileset refresh task" - logger.Error(err, message) - SetStatusAndRaiseEvent(instance, r.Recorder, corev1.EventTypeWarning, string(config.StatusConditionSuccess), - metav1.ConditionFalse, string(csiv1.FilesetRefreshFailed), message, - ) - return requeAfterDelay, err - } - - // retry listing fileset again after some time after refresh - time.Sleep(8 * time.Second) - filesetInfo, err = scaleConnMap[config.Primary].ListFileset(context.TODO(), primary.PrimaryFs, primary.PrimaryFset) - if err != nil || reflect.ValueOf(filesetInfo).IsZero() { - message := fmt.Sprintf("Primary fileset %s is not visible on primary cluster even after running fileset refresh task", primary.PrimaryFset) - logger.Error(err, message) - SetStatusAndRaiseEvent(instance, r.Recorder, corev1.EventTypeWarning, string(config.StatusConditionSuccess), - metav1.ConditionFalse, string(csiv1.GetFilesetFailed), message, - ) - return requeAfterDelay, err - } - } - } - - //A directory can be created from accessing cluster, so get the path on accessing cluster - if fsMountPoint != primaryFSMount { - fsetLinkPath = strings.Replace(fsetLinkPath, fsMountPoint, primaryFSMount, 1) - } - - // Create directory where volume symlinks will reside - symlinkDirPath, _, err := r.createSymlinksDir(instance, scaleConnMap[config.Primary], primary.PrimaryFs, primaryFSMount, fsetLinkPath) - if err != nil { - message := fmt.Sprintf("Failed to create the directory %s on the primary filesystem %s", config.SymlinkDir, primary.PrimaryFs) - logger.Error(err, message) - return requeAfterDelay, err - } - logger.Info("The symlinks directory path is:", "symlinkDirPath", symlinkDirPath) - return requeAfterDelay, nil -} - // getPrimaryCluster returns primary cluster of the passed instance. func (r *CSIScaleOperatorReconciler) getPrimaryCluster(instance *csiscaleoperator.CSIScaleOperator) *csiv1.CSIFilesystem { var primary *csiv1.CSIFilesystem @@ -2181,82 +2044,6 @@ func (r *CSIScaleOperatorReconciler) getPrimaryCluster(instance *csiscaleoperato return primary } -// createPrimaryFileset creates a primary fileset and returns it's path -// where it is linked. If primary fileset exists and is already linked, -// the link path is returned. If primary fileset already exists and not linked, -// it is linked and link path is returned. -func (r *CSIScaleOperatorReconciler) createPrimaryFileset(instance *csiscaleoperator.CSIScaleOperator, sc connectors.SpectrumScaleConnector, fsNameOnOwningCluster string, - fsMountPoint string, filesetName string, inodeLimit string) (string, error) { - - logger := csiLog.WithName("createPrimaryFileset") - logger.Info("Creating primary fileset", " primaryFS", fsNameOnOwningCluster, - "mount point", fsMountPoint, "filesetName", filesetName) - - newLinkPath := path.Join(fsMountPoint, filesetName) //Link path to set if the fileset is not linked - - // create primary fileset if not already created - fsetResponse, err := sc.ListFileset(context.TODO(), fsNameOnOwningCluster, filesetName) - if err != nil { - message := fmt.Sprintf("Failed to list fileset in filesystem %s", fsNameOnOwningCluster) - logger.Error(err, message) - SetStatusAndRaiseEvent(instance, r.Recorder, corev1.EventTypeWarning, string(config.StatusConditionSuccess), - metav1.ConditionFalse, string(csiv1.GetFilesetFailed), message, - ) - return "", err - } else if reflect.ValueOf(fsetResponse).IsZero() { - logger.Info("Primary fileset not found, so creating it", "fileseName", filesetName) - opts := make(map[string]interface{}) - if inodeLimit != "" { - opts[connectors.UserSpecifiedInodeLimit] = inodeLimit - } - - err = sc.CreateFileset(context.TODO(), fsNameOnOwningCluster, filesetName, opts) - if err != nil { - message := fmt.Sprintf("Failed to create the primary fileset %s on the filesystem %s", filesetName, fsNameOnOwningCluster) - logger.Error(err, message) - SetStatusAndRaiseEvent(instance, r.Recorder, corev1.EventTypeWarning, string(config.StatusConditionSuccess), - metav1.ConditionFalse, string(csiv1.CreateFilesetFailed), message, - ) - return "", err - } - logger.Info("Primary fileset is created successfully", "filesetName", filesetName) - - fsetResponse, err = sc.ListFileset(context.TODO(), fsNameOnOwningCluster, filesetName) - if err != nil { - // fileset got created but listing failed, return without cleanup - message := fmt.Sprintf("unable to list newly created primary fileset [%v] in filesystem [%v]. Error: %v", filesetName, fsNameOnOwningCluster, err) - logger.Error(err, message) - return "", err - } - } else { - if !strings.Contains(fsetResponse.Config.Comment, connectors.FilesetComment) { - message := fmt.Sprintf("Primary fileset [%s] is not created by IBM Storage Scale CSI driver. Cannot use it.", filesetName) - err := fmt.Errorf("%s", message) - logger.Error(err, "") - return "", err - } - } - - linkPath := fsetResponse.Config.Path - if linkPath == "" || linkPath == "--" { - logger.Info("Primary fileset not linked. Linking it", "filesetName", filesetName) - err = sc.LinkFileset(context.TODO(), fsNameOnOwningCluster, filesetName, newLinkPath) - if err != nil { - message := fmt.Sprintf("Failed to link the primary fileset %s to the linkpath %s on the filesystem %s", filesetName, newLinkPath, fsNameOnOwningCluster) - logger.Error(err, message) - SetStatusAndRaiseEvent(instance, r.Recorder, corev1.EventTypeWarning, string(config.StatusConditionSuccess), - metav1.ConditionFalse, string(csiv1.LinkFilesetFailed), message, - ) - return "", err - } else { - logger.Info("Linked primary fileset", "filesetName", filesetName, "linkpath", newLinkPath) - } - } else { - logger.Info("Primary fileset exists and linked", "filesetName", filesetName, "linkpath", linkPath) - } - return newLinkPath, nil -} - // createSymlinksDir creates a .volumes directory on the fileset path fsetLinkPath, // and returns absolute, relative paths and error if there is any. func (r *CSIScaleOperatorReconciler) createSymlinksDir(instance *csiscaleoperator.CSIScaleOperator, sc connectors.SpectrumScaleConnector, fs string, fsMountPath string, From e9a0633757027a446344715b3011e90d366942c6 Mon Sep 17 00:00:00 2001 From: hemalathagajendran Date: Wed, 23 Jul 2025 22:23:46 +0530 Subject: [PATCH 08/14] Fix for symlink deletion Signed-off-by: hemalathagajendran --- driver/csiplugin/controllerserver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index 87a7f367d..ed317cd1b 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -2644,7 +2644,7 @@ func (cs *ScaleControllerServer) DeleteVolume(newctx context.Context, req *csi.D } // Delete fileset related symlink - if volumeIdMembers.StorageClassType == STORAGECLASS_CLASSIC { + if volumeIdMembers.StorageClassType == STORAGECLASS_CLASSIC && symlinkExists { err = primaryConn.DeleteSymLnk(ctx, pfsName, relPath) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("unable to delete symlnk [%v:%v] Error [%v]", pfsName, relPath, err)) From 7c98170d9bb9d185b0a30b104cddc4719844cdde Mon Sep 17 00:00:00 2001 From: hemalathagajendran Date: Thu, 24 Jul 2025 22:04:14 +0530 Subject: [PATCH 09/14] changes for delete volume Signed-off-by: hemalathagajendran --- driver/csiplugin/controllerserver.go | 18 ++++++++---------- .../controllers/csiscaleoperator_controller.go | 6 ------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index 63dd9bfee..63e5e6e89 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -2622,16 +2622,20 @@ func (cs *ScaleControllerServer) DeleteVolume(newctx context.Context, req *csi.D return nil, err } + primaryConn, isprimaryConnPresent := cs.Driver.connmap["primary"] + if !isprimaryConnPresent { + klog.Errorf("[%s] unable to get connector for primary cluster", loggerId) + return nil, status.Error(codes.Internal, "unable to find primary cluster details in custom resource") + } + /* FsUUID in volumeIdMembers will be of Primary cluster. So lets get Name of it from Primary cluster */ - FilesystemName, err := conn.GetFilesystemName(ctx, volumeIdMembers.FsUUID) - + FilesystemName, err := primaryConn.GetFilesystemName(ctx, volumeIdMembers.FsUUID) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("unable to get filesystem Name for Id [%v] and clusterId [%v]. Error [%v]", volumeIdMembers.FsUUID, volumeIdMembers.ClusterId, err)) } - mountInfo, err := conn.GetFilesystemMountDetails(ctx, FilesystemName) - + mountInfo, err := primaryConn.GetFilesystemMountDetails(ctx, FilesystemName) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("unable to get mount info for FS [%v] in primary cluster", FilesystemName)) } @@ -2676,12 +2680,6 @@ func (cs *ScaleControllerServer) DeleteVolume(newctx context.Context, req *csi.D var snapshotName string var independentFileset string - primaryConn, isprimaryConnPresent := cs.Driver.connmap["primary"] - if !isprimaryConnPresent { - klog.Errorf("[%s] unable to get connector for primary cluster", loggerId) - return nil, status.Error(codes.Internal, "unable to find primary cluster details in custom resource") - } - if volumeIdMembers.VolType == FILE_SHALLOWCOPY_VOLUME { if relPath != "" && strings.Contains(relPath, ".snapshots") { before, after, found := strings.Cut(relPath, ".snapshots") diff --git a/operator/controllers/csiscaleoperator_controller.go b/operator/controllers/csiscaleoperator_controller.go index 84c8f50e1..80acdf1a1 100644 --- a/operator/controllers/csiscaleoperator_controller.go +++ b/operator/controllers/csiscaleoperator_controller.go @@ -2144,12 +2144,6 @@ func ValidateCRParams(ctx context.Context, instance *csiscaleoperator.CSIScaleOp } primaryClusterFound = true - //if cluster.Primary.PrimaryFs == "" { - // issueFound = true - // logger.Error(fmt.Errorf("mandatory parameter 'primaryFs' is not specified for primary cluster %v", cluster.Id), "") - //} - - //remoteClusterID = cluster.Primary.RemoteCluster } else { //when its a not primary cluster nonPrimaryClusters[cluster.Id] = true From 3a10bc64f6b95b695d38fc8bee56c06fabbab9be Mon Sep 17 00:00:00 2001 From: hemalathagajendran Date: Thu, 24 Jul 2025 22:18:49 +0530 Subject: [PATCH 10/14] Missed changes Signed-off-by: hemalathagajendran --- operator/controllers/csiscaleoperator_controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator/controllers/csiscaleoperator_controller.go b/operator/controllers/csiscaleoperator_controller.go index 80acdf1a1..ec09cb701 100644 --- a/operator/controllers/csiscaleoperator_controller.go +++ b/operator/controllers/csiscaleoperator_controller.go @@ -23,6 +23,7 @@ import ( "encoding/json" "fmt" "net/http" + "os" "reflect" "strconv" "strings" @@ -2073,7 +2074,6 @@ func (r *CSIScaleOperatorReconciler) getPrimaryCluster(instance *csiscaleoperato return primary } - // createSymlinksDir creates a .volumes directory on the fileset path fsetLinkPath, // and returns absolute, relative paths and error if there is any. func (r *CSIScaleOperatorReconciler) createSymlinksDir(ctx context.Context, instance *csiscaleoperator.CSIScaleOperator, sc connectors.SpectrumScaleConnector, fs string, fsMountPath string, From 5e090c48d368965053f40ed89357c8944f4e92d7 Mon Sep 17 00:00:00 2001 From: hemalathagajendran Date: Fri, 25 Jul 2025 11:55:13 +0530 Subject: [PATCH 11/14] changes for UT fix Signed-off-by: hemalathagajendran --- driver/csiplugin/controllerserver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index 63e5e6e89..65523996b 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -3037,7 +3037,7 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re klog.V(4).Infof("[%s] ControllerPublishVolume : SHORTNAME_NODE_MAPPING is set to %s", loggerId, shortnameNodeMapping) } - klog.Infof("[%s] fsName:%s, fsMount:%s, scalenodeID:%s", loggerId, fsName, fsMount, scalenodeID) + klog.Infof("[%s] fsName:%s, fsMount:%+v, scalenodeID:%s", loggerId, fsName, fsMount, scalenodeID) klog.Infof("[%s] ControllerPublishVolume : FS is mounted on %v", loggerId, fsMount.NodesMounted) klog.V(4).Infof("[%s] ControllerPublishVolume : Volume is from Filesystem %s", loggerId, fsName) From 9deee502f723af2479636f953aa5a43367fd36b8 Mon Sep 17 00:00:00 2001 From: hemalathagajendran Date: Sun, 27 Jul 2025 22:29:44 +0530 Subject: [PATCH 12/14] Fix for create snapshot Signed-off-by: hemalathagajendran --- driver/csiplugin/controllerserver.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index 65523996b..439349032 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -3283,12 +3283,18 @@ func (cs *ScaleControllerServer) CreateSnapshot(newctx context.Context, req *csi return nil, chkSnapshotErr } - filesystemName, err := conn.GetFilesystemName(ctx, volumeIDMembers.FsUUID) + primaryConn, isprimaryConnPresent := cs.Driver.connmap["primary"] + if !isprimaryConnPresent { + klog.Errorf("[%s] CreateSnapshot - unable to get connector for primary cluster", loggerId) + return nil, status.Error(codes.Internal, "CreateSnapshot - unable to find primary cluster details in custom resource") + } + + filesystemName, err := primaryConn.GetFilesystemName(ctx, volumeIDMembers.FsUUID) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("CreateSnapshot - Unable to get filesystem Name for Filesystem Uid [%v] and clusterId [%v]. Error [%v]", volumeIDMembers.FsUUID, volumeIDMembers.ClusterId, err)) } - mountInfo, err := conn.GetFilesystemMountDetails(ctx, filesystemName) + mountInfo, err := primaryConn.GetFilesystemMountDetails(ctx, filesystemName) if err != nil { return nil, status.Error(codes.Internal, fmt.Sprintf("CreateSnapshot - unable to get mount info for FS [%v] in primary cluster", filesystemName)) } From 6553d4268c060fab1a755f24713b2eaad7b40532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chemalathagajendran=E2=80=9D?= <“hemalatha.gajendran@ibm.com”> Date: Fri, 1 Aug 2025 02:56:09 -0700 Subject: [PATCH 13/14] changes for adding localScaleCluster and review comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: “hemalathagajendran” <“hemalatha.gajendran@ibm.com”> --- driver/csiplugin/connectors/connectors.go | 3 +- driver/csiplugin/connectors/rest_v2.go | 37 +- driver/csiplugin/controllerserver.go | 5 +- driver/csiplugin/gpfs.go | 3 +- driver/csiplugin/settings/scale_config.go | 10 +- .../ibm-spectrum-scale-csi-operator-dev.yaml | 623 ++++++++-- .../ibm-spectrum-scale-csi-operator.yaml | 623 ++++++++-- operator/api/v1/csiscaleoperator_types.go | 5 + operator/api/v1/zz_generated.deepcopy.go | 1 - .../bases/csi.ibm.com_csiscaleoperators.yaml | 1083 ++++++++--------- operator/config/rbac/role.yaml | 2 - .../csiscaleoperators.csi.ibm.com_cr.yaml | 1 + operator/controllers/config/constants.go | 1 - .../csiscaleoperator_controller.go | 10 +- .../csiscaleoperator_package.go | 8 +- operator/controllers/syncer/csi_syncer.go | 7 +- 16 files changed, 1584 insertions(+), 838 deletions(-) diff --git a/driver/csiplugin/connectors/connectors.go b/driver/csiplugin/connectors/connectors.go index 901171a30..b932fc244 100644 --- a/driver/csiplugin/connectors/connectors.go +++ b/driver/csiplugin/connectors/connectors.go @@ -35,8 +35,7 @@ type SpectrumScaleConnector interface { //Filesystem operations GetFilesystemMountDetails(ctx context.Context, filesystemName string) (MountInfo, error) IsFilesystemMountedOnGUINode(ctx context.Context, filesystemName string) (bool, error) - ListFilesystems(ctx context.Context) ([]string, error) - ListFilesystemsMountpoint(ctx context.Context) (map[string]string, error) + ListFilesystems(ctx context.Context) (map[string]string, error) GetFilesystemDetails(ctx context.Context, filesystemName string) (FileSystem_v2, error) GetFilesystemMountpoint(ctx context.Context, filesystemName string) (string, error) //Node operations diff --git a/driver/csiplugin/connectors/rest_v2.go b/driver/csiplugin/connectors/rest_v2.go index 7655be422..0617d7388 100644 --- a/driver/csiplugin/connectors/rest_v2.go +++ b/driver/csiplugin/connectors/rest_v2.go @@ -322,26 +322,7 @@ func (s *SpectrumRestV2) IsFilesystemMountedOnGUINode(ctx context.Context, files } } -func (s *SpectrumRestV2) ListFilesystems(ctx context.Context) ([]string, error) { - klog.V(4).Infof("[%s] rest_v2 ListFilesystems", utils.GetLoggerId(ctx)) - - listFilesystemsURL := "scalemgmt/v2/filesystems" - getFilesystemResponse := GetFilesystemResponse_v2{} - - err := s.doHTTP(ctx, listFilesystemsURL, "GET", &getFilesystemResponse, nil) - if err != nil { - klog.Errorf("[%s] Error in listing filesystems: %v", utils.GetLoggerId(ctx), err) - return nil, err - } - fsNumber := len(getFilesystemResponse.FileSystems) - filesystems := make([]string, fsNumber) - for i := 0; i < fsNumber; i++ { - filesystems[i] = getFilesystemResponse.FileSystems[i].Name - } - return filesystems, nil -} - -func (s *SpectrumRestV2) ListFilesystemsMountpoint(ctx context.Context) (map[string]string, error) { +func (s *SpectrumRestV2) ListFilesystems(ctx context.Context) (map[string]string, error) { klog.V(4).Infof("[%s] rest_v2 ListFilesystems", utils.GetLoggerId(ctx)) listFilesystemsURL := "scalemgmt/v2/filesystems" @@ -354,14 +335,14 @@ func (s *SpectrumRestV2) ListFilesystemsMountpoint(ctx context.Context) (map[str } fsNumber := len(getFilesystemResponse.FileSystems) filesystemsMountpoint := make(map[string]string, fsNumber) - if len(getFilesystemResponse.FileSystems) > 0 { - for i := 0; i < fsNumber; i++ { - filesystemsMountpoint[getFilesystemResponse.FileSystems[i].Name] = getFilesystemResponse.FileSystems[i].Mount.MountPoint - } - return filesystemsMountpoint, nil - } else { - return nil, fmt.Errorf("unable to fetch mount point as there is no filesystem listed") - } + if len(getFilesystemResponse.FileSystems) > 0 { + for i := 0; i < fsNumber; i++ { + filesystemsMountpoint[getFilesystemResponse.FileSystems[i].Name] = getFilesystemResponse.FileSystems[i].Mount.MountPoint + } + return filesystemsMountpoint, nil + } else { + return nil, fmt.Errorf("unable to fetch mount point as there is no filesystem listed") + } } func (s *SpectrumRestV2) GetFilesystemMountpoint(ctx context.Context, filesystemName string) (string, error) { diff --git a/driver/csiplugin/controllerserver.go b/driver/csiplugin/controllerserver.go index 439349032..d1c6c8495 100644 --- a/driver/csiplugin/controllerserver.go +++ b/driver/csiplugin/controllerserver.go @@ -59,9 +59,6 @@ const ( fsetNotFoundErrCode = "EFSSG0072C" fsetNotFoundErrMsg = "400 Invalid value in 'filesetName'" - //fsetLinkNotFoundErrCode = "EFSSG0449C" - //fsetLinkNotFoundErrMsg = "is not linked" - //pvcNameKey = "csi.storage.k8s.io/pvc/name" //pvcNamespaceKey = "csi.storage.k8s.io/pvc/namespace" ) @@ -3043,7 +3040,7 @@ func (cs *ScaleControllerServer) ControllerPublishVolume(ctx context.Context, re if !strings.HasPrefix(volumePath, fsMount.MountPoint) { klog.Errorf("[%s] ControllerPublishVolume : Volume path %s is not part of the given filesystem %s", loggerId, volumePath, fsName) - fsMountpoints, err := cs.Driver.connmap["primary"].ListFilesystemsMountpoint(ctx) + fsMountpoints, err := cs.Driver.connmap["primary"].ListFilesystems(ctx) mountPointFound := false var volumePathfs string if err != nil { diff --git a/driver/csiplugin/gpfs.go b/driver/csiplugin/gpfs.go index 02357069e..b9f9557d0 100644 --- a/driver/csiplugin/gpfs.go +++ b/driver/csiplugin/gpfs.go @@ -263,8 +263,7 @@ func (driver *ScaleDriver) PluginInitialize(ctx context.Context) (map[string]con scaleConnMap[cluster.ID] = sc - klog.Infof("[%s] cluster.Primary:[%+v], settings.Primary:[%+v]", loggerId, cluster.Primary, settings.Primary{}) - if cluster.Primary != (settings.Primary{}) { + if (scaleConfig.LocalScaleCluster != "" && scaleConfig.LocalScaleCluster == cluster.ID) || cluster.Primary != (settings.Primary{}) { // Check if GUI is reachable - only for primary cluster clusterId, err := sc.GetClusterId(ctx) diff --git a/driver/csiplugin/settings/scale_config.go b/driver/csiplugin/settings/scale_config.go index 5130077cf..51d1aa706 100644 --- a/driver/csiplugin/settings/scale_config.go +++ b/driver/csiplugin/settings/scale_config.go @@ -29,17 +29,18 @@ import ( ) type ScaleSettingsConfigMap struct { + LocalScaleCluster string `json:"localScaleCluster"` Clusters []Clusters } type Primary struct { PrimaryFSDep string `json:"primaryFS"` // Deprecated - PrimaryFs string `json:"primaryFs"` - PrimaryFset string `json:"primaryFset"` + PrimaryFs string `json:"primaryFs"` //Deprecated + PrimaryFset string `json:"primaryFset"` //Deprecated PrimaryCid string `json:"primaryCid"` InodeLimitDep string `json:"inode-limit"` // Deprecated - InodeLimits string `json:"inodeLimit"` - RemoteCluster string `json:"remoteCluster"` + InodeLimits string `json:"inodeLimit"` //Deprecated + RemoteCluster string `json:"remoteCluster"` //Deprecated PrimaryFSMount string PrimaryFsetLink string @@ -74,6 +75,7 @@ type Clusters struct { Cacert string `json:"cacert"` Secrets string `json:"secrets"` RestAPI []RestAPI `json:"restApi"` + PrimaryCluster string `json:"primaryCluster"` MgmtUsername string MgmtPassword string diff --git a/generated/installer/ibm-spectrum-scale-csi-operator-dev.yaml b/generated/installer/ibm-spectrum-scale-csi-operator-dev.yaml index 58fcb964c..766b3020a 100644 --- a/generated/installer/ibm-spectrum-scale-csi-operator-dev.yaml +++ b/generated/installer/ibm-spectrum-scale-csi-operator-dev.yaml @@ -16,7 +16,6 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: ibm-spectrum-scale-csi-operator - creationTimestamp: null rules: - resources: - configmaps @@ -255,8 +254,7 @@ kind: CustomResourceDefinition metadata: name: csiscaleoperators.csi.ibm.com annotations: - controller-gen.kubebuilder.io/version: v0.4.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.16.5 spec: group: csi.ibm.com names: @@ -287,10 +285,19 @@ spec: properties: apiVersion: type: string - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources kind: type: string - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds metadata: type: object spec: @@ -299,7 +306,10 @@ spec: properties: imagePullSecrets: type: array - description: A passthrough option that distributes an imagePullSecrets array to the containers generated by the CSI scale operator. Please refer to official k8s documentation for your environment for more details. + description: |- + A passthrough option that distributes an imagePullSecrets array to the + containers generated by the CSI scale operator. Please refer to official + k8s documentation for your environment for more details. items: type: string affinity: @@ -312,10 +322,21 @@ spec: properties: preferredDuringSchedulingIgnoredDuringExecution: type: array - description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. items: type: object - description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). properties: preference: type: object @@ -326,43 +347,66 @@ spec: description: A list of node selector requirements by node's labels. items: type: object - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: type: string description: The label key that the selector applies to. operator: type: string - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. values: type: array - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchFields: type: array description: A list of node selector requirements by node's fields. items: type: object - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: type: string description: The label key that the selector applies to. operator: type: string - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. values: type: array - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic + x-kubernetes-map-type: atomic weight: type: integer description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. @@ -370,68 +414,111 @@ spec: required: - preference - weight + x-kubernetes-list-type: atomic requiredDuringSchedulingIgnoredDuringExecution: type: object - description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. properties: nodeSelectorTerms: type: array description: Required. A list of node selector terms. The terms are ORed. items: type: object - description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. properties: matchExpressions: type: array description: A list of node selector requirements by node's labels. items: type: object - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: type: string description: The label key that the selector applies to. operator: type: string - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. values: type: array - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchFields: type: array description: A list of node selector requirements by node's fields. items: type: object - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: type: string description: The label key that the selector applies to. operator: type: string - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. values: type: array - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic + x-kubernetes-map-type: atomic + x-kubernetes-list-type: atomic required: - nodeSelectorTerms + x-kubernetes-map-type: atomic podAffinity: type: object description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: type: array - description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. items: type: object description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) @@ -442,189 +529,341 @@ spec: properties: labelSelector: type: object - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic matchLabelKeys: type: array - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic mismatchLabelKeys: type: array - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic namespaceSelector: type: object - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic namespaces: type: array - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string + x-kubernetes-list-type: atomic topologyKey: type: string - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. required: - topologyKey weight: type: integer - description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. format: int32 required: - podAffinityTerm - weight + x-kubernetes-list-type: atomic requiredDuringSchedulingIgnoredDuringExecution: type: array - description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: type: object - description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: type: object - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic matchLabelKeys: type: array - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic mismatchLabelKeys: type: array - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic namespaceSelector: type: object - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic namespaces: type: array - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string + x-kubernetes-list-type: atomic topologyKey: type: string - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. required: - topologyKey + x-kubernetes-list-type: atomic podAntiAffinity: type: object description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: type: array - description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. items: type: object description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) @@ -635,204 +874,365 @@ spec: properties: labelSelector: type: object - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic matchLabelKeys: type: array - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic mismatchLabelKeys: type: array - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic namespaceSelector: type: object - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic namespaces: type: array - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string + x-kubernetes-list-type: atomic topologyKey: type: string - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. required: - topologyKey weight: type: integer - description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. format: int32 required: - podAffinityTerm - weight + x-kubernetes-list-type: atomic requiredDuringSchedulingIgnoredDuringExecution: type: array - description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: type: object - description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: type: object - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic matchLabelKeys: type: array - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic mismatchLabelKeys: type: array - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic namespaceSelector: type: object - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic namespaces: type: array - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string + x-kubernetes-list-type: atomic topologyKey: type: string - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. required: - topologyKey + x-kubernetes-list-type: atomic tolerations: type: array - description: Array of tolerations that will be distributed to CSI pods. Please refer to official k8s documentation for your environment for more details. + description: |- + Array of tolerations that will be distributed to CSI pods. Please refer to + official k8s documentation for your environment for more details. items: type: object - description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . properties: value: type: string - description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. effect: type: string - description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. key: type: string - description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. operator: type: string - description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. tolerationSeconds: type: integer - description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. format: int64 attacher: type: string @@ -918,7 +1318,9 @@ spec: - secureSslMode consistencyGroupPrefix: type: string - description: consistencyGroupPrefix is a prefix of consistency group of an application. This is expected to be an RFC4122 UUID value (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx in hexadecimal values) + description: |- + consistencyGroupPrefix is a prefix of consistency group of an application. + This is expected to be an RFC4122 UUID value (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx in hexadecimal values) csipspname: type: string description: PodSecurityPolicy name for CSI driver and sidecar pods. @@ -931,6 +1333,9 @@ spec: livenessprobe: type: string description: livenessprobe is the image for livenessProbe container (liveness probe is used to know when to restart a container). + localScaleCluster: + type: string + description: localScaleCluster is the cluster ID where kubernetes is installed nodeMapping: type: array description: nodeMapping specifies mapping of K8s node with IBM Storage Scale node. @@ -1046,11 +1451,11 @@ spec: description: conditions contains the details for one aspect of the current state of this custom resource. items: type: object - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" + description: Condition contains details for one aspect of the current state of this API Resource. properties: type: type: string - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: type of condition in CamelCase or in foo.example.com/CamelCase. maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ status: @@ -1062,20 +1467,32 @@ spec: - Unknown lastTransitionTime: type: string - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time message: type: string - description: message is a human readable message indicating details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 observedGeneration: type: integer - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 reason: type: string - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. maxLength: 1024 minLength: 1 pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ @@ -1101,9 +1518,3 @@ spec: storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/generated/installer/ibm-spectrum-scale-csi-operator.yaml b/generated/installer/ibm-spectrum-scale-csi-operator.yaml index 946e5a198..547783f08 100644 --- a/generated/installer/ibm-spectrum-scale-csi-operator.yaml +++ b/generated/installer/ibm-spectrum-scale-csi-operator.yaml @@ -16,7 +16,6 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: ibm-spectrum-scale-csi-operator - creationTimestamp: null rules: - resources: - configmaps @@ -255,8 +254,7 @@ kind: CustomResourceDefinition metadata: name: csiscaleoperators.csi.ibm.com annotations: - controller-gen.kubebuilder.io/version: v0.4.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.16.5 spec: group: csi.ibm.com names: @@ -287,10 +285,19 @@ spec: properties: apiVersion: type: string - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources kind: type: string - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds metadata: type: object spec: @@ -299,7 +306,10 @@ spec: properties: imagePullSecrets: type: array - description: A passthrough option that distributes an imagePullSecrets array to the containers generated by the CSI scale operator. Please refer to official k8s documentation for your environment for more details. + description: |- + A passthrough option that distributes an imagePullSecrets array to the + containers generated by the CSI scale operator. Please refer to official + k8s documentation for your environment for more details. items: type: string affinity: @@ -312,10 +322,21 @@ spec: properties: preferredDuringSchedulingIgnoredDuringExecution: type: array - description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. items: type: object - description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). properties: preference: type: object @@ -326,43 +347,66 @@ spec: description: A list of node selector requirements by node's labels. items: type: object - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: type: string description: The label key that the selector applies to. operator: type: string - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. values: type: array - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchFields: type: array description: A list of node selector requirements by node's fields. items: type: object - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: type: string description: The label key that the selector applies to. operator: type: string - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. values: type: array - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic + x-kubernetes-map-type: atomic weight: type: integer description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. @@ -370,68 +414,111 @@ spec: required: - preference - weight + x-kubernetes-list-type: atomic requiredDuringSchedulingIgnoredDuringExecution: type: object - description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. properties: nodeSelectorTerms: type: array description: Required. A list of node selector terms. The terms are ORed. items: type: object - description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. properties: matchExpressions: type: array description: A list of node selector requirements by node's labels. items: type: object - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: type: string description: The label key that the selector applies to. operator: type: string - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. values: type: array - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchFields: type: array description: A list of node selector requirements by node's fields. items: type: object - description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: type: string description: The label key that the selector applies to. operator: type: string - description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. values: type: array - description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic + x-kubernetes-map-type: atomic + x-kubernetes-list-type: atomic required: - nodeSelectorTerms + x-kubernetes-map-type: atomic podAffinity: type: object description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: type: array - description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. items: type: object description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) @@ -442,189 +529,341 @@ spec: properties: labelSelector: type: object - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic matchLabelKeys: type: array - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic mismatchLabelKeys: type: array - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic namespaceSelector: type: object - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic namespaces: type: array - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string + x-kubernetes-list-type: atomic topologyKey: type: string - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. required: - topologyKey weight: type: integer - description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. format: int32 required: - podAffinityTerm - weight + x-kubernetes-list-type: atomic requiredDuringSchedulingIgnoredDuringExecution: type: array - description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: type: object - description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: type: object - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic matchLabelKeys: type: array - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic mismatchLabelKeys: type: array - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic namespaceSelector: type: object - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic namespaces: type: array - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string + x-kubernetes-list-type: atomic topologyKey: type: string - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. required: - topologyKey + x-kubernetes-list-type: atomic podAntiAffinity: type: object description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: type: array - description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. items: type: object description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) @@ -635,204 +874,365 @@ spec: properties: labelSelector: type: object - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic matchLabelKeys: type: array - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic mismatchLabelKeys: type: array - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic namespaceSelector: type: object - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic namespaces: type: array - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string + x-kubernetes-list-type: atomic topologyKey: type: string - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. required: - topologyKey weight: type: integer - description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. format: int32 required: - podAffinityTerm - weight + x-kubernetes-list-type: atomic requiredDuringSchedulingIgnoredDuringExecution: type: array - description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: type: object - description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: type: object - description: A label query over a set of resources, in this case pods. If it's null, this PodAffinityTerm matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic matchLabelKeys: type: array - description: MatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. Also, MatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic mismatchLabelKeys: type: array - description: MismatchLabelKeys is a set of pod label keys to select which pods will be taken into consideration. The keys are used to lookup values from the incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` to select the group of existing pods which pods will be taken into consideration for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming pod labels will be ignored. The default value is empty. The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string x-kubernetes-list-type: atomic namespaceSelector: type: object - description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: type: array description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: type: object - description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: type: string description: key is the label key that the selector applies to. operator: type: string - description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. values: type: array - description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string + x-kubernetes-list-type: atomic required: - key - operator + x-kubernetes-list-type: atomic matchLabels: type: object additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + x-kubernetes-map-type: atomic namespaces: type: array - description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string + x-kubernetes-list-type: atomic topologyKey: type: string - description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. required: - topologyKey + x-kubernetes-list-type: atomic tolerations: type: array - description: Array of tolerations that will be distributed to CSI pods. Please refer to official k8s documentation for your environment for more details. + description: |- + Array of tolerations that will be distributed to CSI pods. Please refer to + official k8s documentation for your environment for more details. items: type: object - description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . properties: value: type: string - description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. effect: type: string - description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. key: type: string - description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. operator: type: string - description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. tolerationSeconds: type: integer - description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. format: int64 attacher: type: string @@ -918,7 +1318,9 @@ spec: - secureSslMode consistencyGroupPrefix: type: string - description: consistencyGroupPrefix is a prefix of consistency group of an application. This is expected to be an RFC4122 UUID value (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx in hexadecimal values) + description: |- + consistencyGroupPrefix is a prefix of consistency group of an application. + This is expected to be an RFC4122 UUID value (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx in hexadecimal values) csipspname: type: string description: PodSecurityPolicy name for CSI driver and sidecar pods. @@ -931,6 +1333,9 @@ spec: livenessprobe: type: string description: livenessprobe is the image for livenessProbe container (liveness probe is used to know when to restart a container). + localScaleCluster: + type: string + description: localScaleCluster is the cluster ID where kubernetes is installed nodeMapping: type: array description: nodeMapping specifies mapping of K8s node with IBM Storage Scale node. @@ -1046,11 +1451,11 @@ spec: description: conditions contains the details for one aspect of the current state of this custom resource. items: type: object - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n \ttype FooStatus struct{ \t // Represents the observations of a foo's current state. \t // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" \t // +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map \t // +listMapKey=type \t Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields \t}" + description: Condition contains details for one aspect of the current state of this API Resource. properties: type: type: string - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: type of condition in CamelCase or in foo.example.com/CamelCase. maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ status: @@ -1062,20 +1467,32 @@ spec: - Unknown lastTransitionTime: type: string - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time message: type: string - description: message is a human readable message indicating details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 observedGeneration: type: integer - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 reason: type: string - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. maxLength: 1024 minLength: 1 pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ @@ -1101,9 +1518,3 @@ spec: storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/operator/api/v1/csiscaleoperator_types.go b/operator/api/v1/csiscaleoperator_types.go index fb4a6e0f8..512baec8a 100644 --- a/operator/api/v1/csiscaleoperator_types.go +++ b/operator/api/v1/csiscaleoperator_types.go @@ -39,6 +39,11 @@ type CSIScaleOperatorSpec struct { //+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Attacher Node Selector",xDescriptors="urn:alm:descriptor:com.tectonic.ui:advanced" AttacherNodeSelector []CSINodeSelector `json:"attacherNodeSelector,omitempty"` + // localScaleCluster is the cluster ID where kubernetes is installed + // +kubebuilder:validation:Optional + //+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Local Scale Cluster",xDescriptors="urn:alm:descriptor:com.tectonic.ui:advanced" + LocalScaleCluster string `json:"localScaleCluster,omitempty"` + // clusters is a collection of IBM Storage Scale cluster properties for the CSI driver to mount. //+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Clusters" Clusters []CSICluster `json:"clusters"` diff --git a/operator/api/v1/zz_generated.deepcopy.go b/operator/api/v1/zz_generated.deepcopy.go index 787e2fbd1..d6ef014b9 100644 --- a/operator/api/v1/zz_generated.deepcopy.go +++ b/operator/api/v1/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright 2022. diff --git a/operator/config/crd/bases/csi.ibm.com_csiscaleoperators.yaml b/operator/config/crd/bases/csi.ibm.com_csiscaleoperators.yaml index ef5c44e57..ee04b1147 100644 --- a/operator/config/crd/bases/csi.ibm.com_csiscaleoperators.yaml +++ b/operator/config/crd/bases/csi.ibm.com_csiscaleoperators.yaml @@ -1,11 +1,9 @@ - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.4.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.16.5 name: csiscaleoperators.csi.ibm.com spec: group: csi.ibm.com @@ -35,14 +33,19 @@ spec: description: CSIScaleOperator is the Schema for the csiscaleoperators API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -57,22 +60,20 @@ spec: pod. properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to - nodes that satisfy the affinity expressions specified by - this field, but it may choose a node that violates one or - more of the expressions. The node that is most preferred - is the one with the greatest sum of weights, i.e. for each - node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, - etc.), compute a sum by iterating through the elements of - this field and adding "weight" to the sum if the node matches - the corresponding matchExpressions; the node(s) with the - highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. items: - description: An empty preferred scheduling term matches - all objects with implicit weight 0 (i.e. it's a no-op). - A null preferred scheduling term matches no objects (i.e. - is also a no-op). + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). properties: preference: description: A node selector term, associated with the @@ -82,75 +83,72 @@ spec: description: A list of node selector requirements by node's labels. items: - description: A node selector requirement is a - selector that contains values, a key, and an - operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators are - In, NotIn, Exists, DoesNotExist. Gt, and - Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. If - the operator is In or NotIn, the values - array must be non-empty. If the operator - is Exists or DoesNotExist, the values array - must be empty. If the operator is Gt or - Lt, the values array must have a single - element, which will be interpreted as an - integer. This array is replaced during a - strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchFields: description: A list of node selector requirements by node's fields. items: - description: A node selector requirement is a - selector that contains values, a key, and an - operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators are - In, NotIn, Exists, DoesNotExist. Gt, and - Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. If - the operator is In or NotIn, the values - array must be non-empty. If the operator - is Exists or DoesNotExist, the values array - must be empty. If the operator is Gt or - Lt, the values array must have a single - element, which will be interpreted as an - integer. This array is replaced during a - strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic type: object + x-kubernetes-map-type: atomic weight: description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. @@ -161,116 +159,115 @@ spec: - weight type: object type: array + x-kubernetes-list-type: atomic requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified by this - field are not met at scheduling time, the pod will not be - scheduled onto the node. If the affinity requirements specified - by this field cease to be met at some point during pod execution - (e.g. due to an update), the system may or may not try to - eventually evict the pod from its node. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. properties: nodeSelectorTerms: description: Required. A list of node selector terms. The terms are ORed. items: - description: A null or empty node selector term matches - no objects. The requirements of them are ANDed. The - TopologySelectorTerm type implements a subset of the - NodeSelectorTerm. + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. properties: matchExpressions: description: A list of node selector requirements by node's labels. items: - description: A node selector requirement is a - selector that contains values, a key, and an - operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators are - In, NotIn, Exists, DoesNotExist. Gt, and - Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. If - the operator is In or NotIn, the values - array must be non-empty. If the operator - is Exists or DoesNotExist, the values array - must be empty. If the operator is Gt or - Lt, the values array must have a single - element, which will be interpreted as an - integer. This array is replaced during a - strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchFields: description: A list of node selector requirements by node's fields. items: - description: A node selector requirement is a - selector that contains values, a key, and an - operator that relates the key and values. + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. properties: key: description: The label key that the selector applies to. type: string operator: - description: Represents a key's relationship - to a set of values. Valid operators are - In, NotIn, Exists, DoesNotExist. Gt, and - Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string values. If - the operator is In or NotIn, the values - array must be non-empty. If the operator - is Exists or DoesNotExist, the values array - must be empty. If the operator is Gt or - Lt, the values array must have a single - element, which will be interpreted as an - integer. This array is replaced during a - strategic merge patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic type: object + x-kubernetes-map-type: atomic type: array + x-kubernetes-list-type: atomic required: - nodeSelectorTerms type: object + x-kubernetes-map-type: atomic type: object podAffinity: description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to - nodes that satisfy the affinity expressions specified by - this field, but it may choose a node that violates one or - more of the expressions. The node that is most preferred - is the one with the greatest sum of weights, i.e. for each - node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, - etc.), compute a sum by iterating through the elements of - this field and adding "weight" to the sum if the node has - pods which matches the corresponding podAffinityTerm; the + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm @@ -281,176 +278,161 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. If it's null, this PodAffinityTerm - matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic matchLabelKeys: - description: MatchLabelKeys is a set of pod label - keys to select which pods will be taken into consideration. - The keys are used to lookup values from the incoming - pod labels, those key-value labels are merged - with `LabelSelector` as `key in (value)` to select - the group of existing pods which pods will be - taken into consideration for the incoming pod's - pod (anti) affinity. Keys that don't exist in - the incoming pod labels will be ignored. The default - value is empty. The same key is forbidden to exist - in both MatchLabelKeys and LabelSelector. Also, - MatchLabelKeys cannot be set when LabelSelector - isn't set. This is an alpha field and requires - enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array x-kubernetes-list-type: atomic mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label - keys to select which pods will be taken into consideration. - The keys are used to lookup values from the incoming - pod labels, those key-value labels are merged - with `LabelSelector` as `key notin (value)` to - select the group of existing pods which pods will - be taken into consideration for the incoming pod's - pod (anti) affinity. Keys that don't exist in - the incoming pod labels will be ignored. The default - value is empty. The same key is forbidden to exist - in both MismatchLabelKeys and LabelSelector. Also, - MismatchLabelKeys cannot be set when LabelSelector - isn't set. This is an alpha field and requires - enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array x-kubernetes-list-type: atomic namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by this - field and the ones listed in the namespaces field. - null selector and null or empty namespaces list - means "this pod's namespace". An empty selector - ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. The - term is applied to the union of the namespaces - listed in this field and the ones selected by - namespaceSelector. null or empty namespaces list - and null namespaceSelector means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array + x-kubernetes-list-type: atomic topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the pods - matching the labelSelector in the specified namespaces, - where co-located is defined as running on a node - whose value of the label with key topologyKey - matches that of any node on which any of the selected - pods is running. Empty topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey type: object weight: - description: weight associated with matching the corresponding - podAffinityTerm, in the range 1-100. + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. format: int32 type: integer required: @@ -458,184 +440,177 @@ spec: - weight type: object type: array + x-kubernetes-list-type: atomic requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified by this - field are not met at scheduling time, the pod will not be - scheduled onto the node. If the affinity requirements specified - by this field cease to be met at some point during pod execution - (e.g. due to a pod label update), the system may or may - not try to eventually evict the pod from its node. When - there are multiple elements, the lists of nodes corresponding - to each podAffinityTerm are intersected, i.e. all terms - must be satisfied. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: - description: Defines a set of pods (namely those matching - the labelSelector relative to the given namespace(s)) - that this pod should be co-located (affinity) or not co-located - (anti-affinity) with, where co-located is defined as running - on a node whose value of the label with key - matches that of any node on which a pod of the set of - pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. If it's null, this PodAffinityTerm - matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a - selector that contains values, a key, and an - operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. If the - operator is Exists or DoesNotExist, the - values array must be empty. This array is - replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is "In", - and the values array contains only "value". The - requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys - to select which pods will be taken into consideration. - The keys are used to lookup values from the incoming - pod labels, those key-value labels are merged with - `LabelSelector` as `key in (value)` to select the - group of existing pods which pods will be taken into - consideration for the incoming pod's pod (anti) affinity. - Keys that don't exist in the incoming pod labels will - be ignored. The default value is empty. The same key - is forbidden to exist in both MatchLabelKeys and LabelSelector. - Also, MatchLabelKeys cannot be set when LabelSelector - isn't set. This is an alpha field and requires enabling - MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array x-kubernetes-list-type: atomic mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label - keys to select which pods will be taken into consideration. - The keys are used to lookup values from the incoming - pod labels, those key-value labels are merged with - `LabelSelector` as `key notin (value)` to select the - group of existing pods which pods will be taken into - consideration for the incoming pod's pod (anti) affinity. - Keys that don't exist in the incoming pod labels will - be ignored. The default value is empty. The same key - is forbidden to exist in both MismatchLabelKeys and - LabelSelector. Also, MismatchLabelKeys cannot be set - when LabelSelector isn't set. This is an alpha field - and requires enabling MatchLabelKeysInPodAffinity - feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array x-kubernetes-list-type: atomic namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied to the - union of the namespaces selected by this field and - the ones listed in the namespaces field. null selector - and null or empty namespaces list means "this pod's - namespace". An empty selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a - selector that contains values, a key, and an - operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. If the - operator is Exists or DoesNotExist, the - values array must be empty. This array is - replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is "In", - and the values array contains only "value". The - requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static list of namespace - names that the term applies to. The term is applied - to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. null or - empty namespaces list and null namespaceSelector means - "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array + x-kubernetes-list-type: atomic topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where - co-located is defined as running on a node whose value - of the label with key topologyKey matches that of - any node on which any of the selected pods is running. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. Empty topologyKey is not allowed. type: string required: - topologyKey type: object type: array + x-kubernetes-list-type: atomic type: object podAntiAffinity: description: Describes pod anti-affinity scheduling rules (e.g. @@ -643,16 +618,15 @@ spec: other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods to - nodes that satisfy the anti-affinity expressions specified - by this field, but it may choose a node that violates one - or more of the expressions. The node that is most preferred - is the one with the greatest sum of weights, i.e. for each - node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, - etc.), compute a sum by iterating through the elements of - this field and adding "weight" to the sum if the node has - pods which matches the corresponding podAffinityTerm; the + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm @@ -663,176 +637,161 @@ spec: with the corresponding weight. properties: labelSelector: - description: A label query over a set of resources, - in this case pods. If it's null, this PodAffinityTerm - matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic matchLabelKeys: - description: MatchLabelKeys is a set of pod label - keys to select which pods will be taken into consideration. - The keys are used to lookup values from the incoming - pod labels, those key-value labels are merged - with `LabelSelector` as `key in (value)` to select - the group of existing pods which pods will be - taken into consideration for the incoming pod's - pod (anti) affinity. Keys that don't exist in - the incoming pod labels will be ignored. The default - value is empty. The same key is forbidden to exist - in both MatchLabelKeys and LabelSelector. Also, - MatchLabelKeys cannot be set when LabelSelector - isn't set. This is an alpha field and requires - enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array x-kubernetes-list-type: atomic mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label - keys to select which pods will be taken into consideration. - The keys are used to lookup values from the incoming - pod labels, those key-value labels are merged - with `LabelSelector` as `key notin (value)` to - select the group of existing pods which pods will - be taken into consideration for the incoming pod's - pod (anti) affinity. Keys that don't exist in - the incoming pod labels will be ignored. The default - value is empty. The same key is forbidden to exist - in both MismatchLabelKeys and LabelSelector. Also, - MismatchLabelKeys cannot be set when LabelSelector - isn't set. This is an alpha field and requires - enabling MatchLabelKeysInPodAffinity feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array x-kubernetes-list-type: atomic namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by this - field and the ones listed in the namespaces field. - null selector and null or empty namespaces list - means "this pod's namespace". An empty selector - ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. The - term is applied to the union of the namespaces - listed in this field and the ones selected by - namespaceSelector. null or empty namespaces list - and null namespaceSelector means "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array + x-kubernetes-list-type: atomic topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the pods - matching the labelSelector in the specified namespaces, - where co-located is defined as running on a node - whose value of the label with key topologyKey - matches that of any node on which any of the selected - pods is running. Empty topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey type: object weight: - description: weight associated with matching the corresponding - podAffinityTerm, in the range 1-100. + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. format: int32 type: integer required: @@ -840,184 +799,177 @@ spec: - weight type: object type: array + x-kubernetes-list-type: atomic requiredDuringSchedulingIgnoredDuringExecution: - description: If the anti-affinity requirements specified by - this field are not met at scheduling time, the pod will - not be scheduled onto the node. If the anti-affinity requirements - specified by this field cease to be met at some point during - pod execution (e.g. due to a pod label update), the system - may or may not try to eventually evict the pod from its - node. When there are multiple elements, the lists of nodes - corresponding to each podAffinityTerm are intersected, i.e. - all terms must be satisfied. + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: - description: Defines a set of pods (namely those matching - the labelSelector relative to the given namespace(s)) - that this pod should be co-located (affinity) or not co-located - (anti-affinity) with, where co-located is defined as running - on a node whose value of the label with key - matches that of any node on which a pod of the set of - pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: - description: A label query over a set of resources, - in this case pods. If it's null, this PodAffinityTerm - matches with no Pods. + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a - selector that contains values, a key, and an - operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. If the - operator is Exists or DoesNotExist, the - values array must be empty. This array is - replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is "In", - and the values array contains only "value". The - requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic matchLabelKeys: - description: MatchLabelKeys is a set of pod label keys - to select which pods will be taken into consideration. - The keys are used to lookup values from the incoming - pod labels, those key-value labels are merged with - `LabelSelector` as `key in (value)` to select the - group of existing pods which pods will be taken into - consideration for the incoming pod's pod (anti) affinity. - Keys that don't exist in the incoming pod labels will - be ignored. The default value is empty. The same key - is forbidden to exist in both MatchLabelKeys and LabelSelector. - Also, MatchLabelKeys cannot be set when LabelSelector - isn't set. This is an alpha field and requires enabling - MatchLabelKeysInPodAffinity feature gate. + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array x-kubernetes-list-type: atomic mismatchLabelKeys: - description: MismatchLabelKeys is a set of pod label - keys to select which pods will be taken into consideration. - The keys are used to lookup values from the incoming - pod labels, those key-value labels are merged with - `LabelSelector` as `key notin (value)` to select the - group of existing pods which pods will be taken into - consideration for the incoming pod's pod (anti) affinity. - Keys that don't exist in the incoming pod labels will - be ignored. The default value is empty. The same key - is forbidden to exist in both MismatchLabelKeys and - LabelSelector. Also, MismatchLabelKeys cannot be set - when LabelSelector isn't set. This is an alpha field - and requires enabling MatchLabelKeysInPodAffinity - feature gate. + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). items: type: string type: array x-kubernetes-list-type: atomic namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied to the - union of the namespaces selected by this field and - the ones listed in the namespaces field. null selector - and null or empty namespaces list means "this pod's - namespace". An empty selector ({}) matches all namespaces. + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a - selector that contains values, a key, and an - operator that relates the key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are - In, NotIn, Exists and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. If the - operator is Exists or DoesNotExist, the - values array must be empty. This array is - replaced during a strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is "In", - and the values array contains only "value". The - requirements are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object + x-kubernetes-map-type: atomic namespaces: - description: namespaces specifies a static list of namespace - names that the term applies to. The term is applied - to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. null or - empty namespaces list and null namespaceSelector means - "this pod's namespace". + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". items: type: string type: array + x-kubernetes-list-type: atomic topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where - co-located is defined as running on a node whose value - of the label with key topologyKey matches that of - any node on which any of the selected pods is running. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. Empty topologyKey is not allowed. type: string required: - topologyKey type: object type: array + x-kubernetes-list-type: atomic type: object type: object attacher: @@ -1113,9 +1065,9 @@ spec: type: object type: array consistencyGroupPrefix: - description: consistencyGroupPrefix is a prefix of consistency group - of an application. This is expected to be an RFC4122 UUID value - (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx in hexadecimal values) + description: |- + consistencyGroupPrefix is a prefix of consistency group of an application. + This is expected to be an RFC4122 UUID value (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx in hexadecimal values) type: string csipspname: description: PodSecurityPolicy name for CSI driver and sidecar pods. @@ -1125,10 +1077,10 @@ spec: IBM Storage Scale CSI plugin pods. type: string imagePullSecrets: - description: A passthrough option that distributes an imagePullSecrets - array to the containers generated by the CSI scale operator. Please - refer to official k8s documentation for your environment for more - details. + description: |- + A passthrough option that distributes an imagePullSecrets array to the + containers generated by the CSI scale operator. Please refer to official + k8s documentation for your environment for more details. items: type: string type: array @@ -1139,6 +1091,10 @@ spec: description: livenessprobe is the image for livenessProbe container (liveness probe is used to know when to restart a container). type: string + localScaleCluster: + description: localScaleCluster is the cluster ID where kubernetes + is installed + type: string nodeMapping: description: nodeMapping specifies mapping of K8s node with IBM Storage Scale node. @@ -1255,44 +1211,43 @@ spec: CSI node driver plugin container. type: string tolerations: - description: Array of tolerations that will be distributed to CSI - pods. Please refer to official k8s documentation for your environment - for more details. + description: |- + Array of tolerations that will be distributed to CSI pods. Please refer to + official k8s documentation for your environment for more details. items: - description: The pod this Toleration is attached to tolerates any - taint that matches the triple using the matching - operator . + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . properties: effect: - description: Effect indicates the taint effect to match. Empty - means match all taint effects. When specified, allowed values - are NoSchedule, PreferNoSchedule and NoExecute. + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: Key is the taint key that the toleration applies - to. Empty means match all taint keys. If the key is empty, - operator must be Exists; this combination means to match all - values and all keys. + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: Operator represents a key's relationship to the - value. Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod - can tolerate all taints of a particular category. + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. type: string tolerationSeconds: - description: TolerationSeconds represents the period of time - the toleration (which must be of effect NoExecute, otherwise - this field is ignored) tolerates the taint. By default, it - is not set, which means tolerate the taint forever (do not - evict). Zero and negative values will be treated as 0 (evict - immediately) by the system. + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: Value is the taint value the toleration matches - to. If the operator is Exists, the value should be empty, - otherwise just a regular string. + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array @@ -1306,45 +1261,35 @@ spec: description: conditions contains the details for one aspect of the current state of this custom resource. items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n \ttype FooStatus struct{ \t // Represents the observations - of a foo's current state. \t // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\" \t // - +patchMergeKey=type \t // +patchStrategy=merge \t // +listType=map - \t // +listMapKey=type \t Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n \t // other fields - \t}" + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -1359,10 +1304,6 @@ spec: type: string type: description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string @@ -1395,9 +1336,3 @@ spec: storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/operator/config/rbac/role.yaml b/operator/config/rbac/role.yaml index 1e4e834b4..d46fdfd42 100644 --- a/operator/config/rbac/role.yaml +++ b/operator/config/rbac/role.yaml @@ -1,9 +1,7 @@ - --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null name: ibm-spectrum-scale-csi-operator rules: - apiGroups: diff --git a/operator/config/samples/csiscaleoperators.csi.ibm.com_cr.yaml b/operator/config/samples/csiscaleoperators.csi.ibm.com_cr.yaml index 12bac4f69..de11bf7c2 100644 --- a/operator/config/samples/csiscaleoperators.csi.ibm.com_cr.yaml +++ b/operator/config/samples/csiscaleoperators.csi.ibm.com_cr.yaml @@ -23,6 +23,7 @@ spec: # Below specifies the details of a IBM Storage Scale cluster configuration used by the # plugin. It can have multiple values. # ================================================================================== + localScaleCluster: "" clusters: - id: "" secrets: "secret1" diff --git a/operator/controllers/config/constants.go b/operator/controllers/config/constants.go index b5a04a635..b6a0c141a 100644 --- a/operator/controllers/config/constants.go +++ b/operator/controllers/config/constants.go @@ -176,7 +176,6 @@ const ( EnvVolumeStatsCapabilityDefaultValue = "ENABLED" EnvHostNetworkDefaultValue = "ENABLED" EnvVolNamePrefixDefaultValue = "pvc" - EnvPrimaryFilesystemDefaultValue = "ENABLED" // Driver and Sidecar Containers Resources limits PodsCPULimitsLowerValue = "20m" diff --git a/operator/controllers/csiscaleoperator_controller.go b/operator/controllers/csiscaleoperator_controller.go index ec09cb701..c668ba522 100644 --- a/operator/controllers/csiscaleoperator_controller.go +++ b/operator/controllers/csiscaleoperator_controller.go @@ -1978,8 +1978,11 @@ func (r *CSIScaleOperatorReconciler) handleSpectrumScaleConnectors(ctx context.C //scaleGuiSecretChanged := false requeAfterDelay := time.Duration(0) operatorRestarted := (len(scaleConnMap) == 0) && cmExists + isPrimaryCluster := false for _, cluster := range instance.Spec.Clusters { - isPrimaryCluster := cluster.Primary != nil + if instance.Spec.LocalScaleCluster == cluster.Id || cluster.Primary != nil { + isPrimaryCluster = true + } if !cmExists || clustersStanzaModified || operatorRestarted { //These are the prerequisite checks and preprocessing done at //multiple passes of operator/driver: @@ -2137,12 +2140,13 @@ func ValidateCRParams(ctx context.Context, instance *csiscaleoperator.CSIScaleOp logger.Error(fmt.Errorf("mandatory parameter 'guiHost' is not specified for cluster %v", cluster.Id), "") } - if cluster.Primary != nil && *cluster.Primary != (csiv1.CSIFilesystem{}) { + if instance.Spec.LocalScaleCluster != "" && instance.Spec.LocalScaleCluster == cluster.Id { + primaryClusterFound = true + } else if cluster.Primary != nil && *cluster.Primary != (csiv1.CSIFilesystem{}) { if primaryClusterFound { issueFound = true logger.Error(fmt.Errorf("more than one primary clusters specified"), "") } - primaryClusterFound = true } else { //when its a not primary cluster diff --git a/operator/controllers/internal/csiscaleoperator/csiscaleoperator_package.go b/operator/controllers/internal/csiscaleoperator/csiscaleoperator_package.go index 35495e758..c68949a51 100644 --- a/operator/controllers/internal/csiscaleoperator/csiscaleoperator_package.go +++ b/operator/controllers/internal/csiscaleoperator/csiscaleoperator_package.go @@ -508,10 +508,10 @@ func (c *CSIScaleOperator) GenerateResizerClusterRole() *rbacv1.ClusterRole { Verbs: []string{verbGet, verbList, verbWatch}, }, { - APIGroups: []string{storageApiGroup}, - Resources: []string{volumeAttributeClassesResource}, - Verbs: []string{verbGet, verbList, verbWatch}, - }, + APIGroups: []string{storageApiGroup}, + Resources: []string{volumeAttributeClassesResource}, + Verbs: []string{verbGet, verbList, verbWatch}, + }, { APIGroups: []string{coordinationApiGroup}, Resources: []string{leaseResource}, diff --git a/operator/controllers/syncer/csi_syncer.go b/operator/controllers/syncer/csi_syncer.go index d46a07b41..53f70da8c 100644 --- a/operator/controllers/syncer/csi_syncer.go +++ b/operator/controllers/syncer/csi_syncer.go @@ -200,12 +200,17 @@ func (s *csiControllerSyncer) SyncConfigMapFn(ctx context.Context) error { out := s.obj.(*corev1.ConfigMap) out.ObjectMeta = metav1.ObjectMeta{Name: config.CSIConfigMap, Namespace: s.driver.Namespace, Labels: s.driver.GetLabels()} + localScaleClusterData, specErr := json.Marshal(&s.driver.Spec.LocalScaleCluster) + if specErr != nil { + return specErr + } + clustersData, err := json.Marshal(&s.driver.Spec.Clusters) if err != nil { return err } - clustersDataWithKey := "{ \"clusters\": " + string(clustersData) + " }" + clustersDataWithKey := "{ \"localScaleCluster\": " + string(localScaleClusterData) + " , \"clusters\": " + string(clustersData) + " }" out.Data = map[string]string{ config.CSIConfigMap + ".json": clustersDataWithKey, } From 9ac85fc4c2ba4b76ce244f4946f0f52f783a6076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Chemalathagajendran=E2=80=9D?= <“hemalatha.gajendran@ibm.com”> Date: Sun, 3 Aug 2025 23:48:29 -0700 Subject: [PATCH 14/14] changes added MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: “hemalathagajendran” <“hemalatha.gajendran@ibm.com”> --- operator/config/samples/csiscaleoperators.csi.ibm.com_cr.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/operator/config/samples/csiscaleoperators.csi.ibm.com_cr.yaml b/operator/config/samples/csiscaleoperators.csi.ibm.com_cr.yaml index de11bf7c2..a02c446f5 100644 --- a/operator/config/samples/csiscaleoperators.csi.ibm.com_cr.yaml +++ b/operator/config/samples/csiscaleoperators.csi.ibm.com_cr.yaml @@ -28,8 +28,8 @@ spec: - id: "" secrets: "secret1" secureSslMode: false - primary: - primaryFs: "< Primary Filesystem >" +# primary: +# primaryFs: "< Primary Filesystem >" # primaryFset: "< Fileset in Primary Filesystem >" # Optional - default:spectrum-scale-csi-volume-store # inodeLimit: "< inode limit for Primary Fileset >" # Optional # remoteCluster: "< Remote ClusterID >" # Optional - This is only required if primaryFs is remote cluster's filesystem and this ID should have separate entry in Clusters map too.