Skip to content

Commit

Permalink
Add ENV variables to specify default node selectors (#372)
Browse files Browse the repository at this point in the history
Signed-off-by: kmova <[email protected]>
  • Loading branch information
kmova authored and Amit Kumar Das committed Jun 16, 2018
1 parent 146b521 commit 437fc37
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 0 deletions.
59 changes: 59 additions & 0 deletions orchprovider/k8s/v1/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,38 @@ func (k *k8sOrchestrator) addNodeTolerationsToDeploy(nodeTaintTolerations []stri
return nil
}

// addNodeSelectorsToDeploy
func (k *k8sOrchestrator) addNodeSelectorsToDeploy(nodeSelectors []string, deploy *k8sApisExtnsBeta1.Deployment) error {

//Add nodeSelectors only if they are present.
if len(nodeSelectors) < 1 {
return nil
}

nsSpec := map[string]string{}

// nodeSelector is expected to be in key=value
for _, nodeSelector := range nodeSelectors {
kveArr := strings.Split(nodeSelector, "=")
if len(kveArr) != 2 {
glog.Warningf("Invalid args '%s' provided for node selector", nodeSelector)
continue
}

k := strings.TrimSpace(kveArr[0])
v := strings.TrimSpace(kveArr[1])

nsSpec[k] = v
}

//Add nodeSelectors only if they are present.
if len(nsSpec) > 0 {
deploy.Spec.Template.Spec.NodeSelector = nsSpec
}

return nil
}

// createControllerDeployment creates a persistent volume controller deployment in
// kubernetes
func (k *k8sOrchestrator) createControllerDeployment(volProProfile volProfile.VolumeProvisionerProfile, clusterIP string) (*k8sApisExtnsBeta1.Deployment, error) {
Expand Down Expand Up @@ -904,6 +936,20 @@ func (k *k8sOrchestrator) createControllerDeployment(volProProfile volProfile.Vo
return nil, err
}
}

// check if node level selectors are required for controller?
nodeSelectors, nsReqd, nsErr := volProProfile.IsControllerNodeSelectors()
if nsErr != nil {
return nil, nsErr
}

if nsReqd {
nsErr = k.addNodeSelectorsToDeploy(nodeSelectors, deploy)
if nsErr != nil {
return nil, nsErr
}
}

// is volume monitoring enabled ?
isMonitoring := !util.CheckFalsy(vol.Monitor)
if isMonitoring {
Expand Down Expand Up @@ -1140,6 +1186,19 @@ func (k *k8sOrchestrator) createReplicaDeployment(volProProfile volProfile.Volum
}
}

// check if node level selectors are required for replica?
nodeSelectors, nsReqd, nsErr := volProProfile.IsReplicaNodeSelectors()
if nsErr != nil {
return nil, nsErr
}

if nsReqd {
nsErr = k.addNodeSelectorsToDeploy(nodeSelectors, deploy)
if nsErr != nil {
return nil, nsErr
}
}

// We would set Annotations for the stated policies
// Why annotations ? Perhaps as these are mostly referential
// values. Labels may be considered for setting values.
Expand Down
20 changes: 20 additions & 0 deletions orchprovider/k8s/v1/k8s_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,16 @@ func (e *okVsmNameVolumeProfile) IsReplicaNodeTaintTolerations() ([]string, bool
return []string{"k=v:NoSchedule"}, true, nil
}

// IsControllerNodeSelectors specifies a single key value
func (e *okVsmNameVolumeProfile) IsControllerNodeSelectors() ([]string, bool, error) {
return []string{"k=v"}, true, nil
}

// IsReplicaNodeSelectors specifies a single key value
func (e *okVsmNameVolumeProfile) IsReplicaNodeSelectors() ([]string, bool, error) {
return []string{"k=v"}, true, nil
}

// okCtrlImgVolumeProfile focusses on not returning any error during invocation
// of ControllerImage() method
type okCtrlImgVolumeProfile struct {
Expand All @@ -447,6 +457,16 @@ func (e *okCtrlImgVolumeProfile) IsReplicaNodeTaintTolerations() ([]string, bool
return []string{"k=v:NoSchedule"}, true, nil
}

// IsControllerNodeSelectors specifies a single key value
func (e *okCtrlImgVolumeProfile) IsControllerNodeSelectors() ([]string, bool, error) {
return []string{"k=v"}, true, nil
}

// IsReplicaNodeSelectors specifies a single key value
func (e *okCtrlImgVolumeProfile) IsReplicaNodeSelectors() ([]string, bool, error) {
return []string{"k=v"}, true, nil
}

// errVsmNameVolumeProfile focusses on returning error during invocation of
// VSMName() method
type errVsmNameVolumeProfile struct {
Expand Down
20 changes: 20 additions & 0 deletions types/v1/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,20 @@ const (
// <CTX>__REPLICA_NODE_TAINT_TOLERATION = <some value>
PVPReplicaNodeTaintTolerationEnvVarKey EnvironmentVariableKey = "_REPLICA_NODE_TAINT_TOLERATION"

// PVPControllerNodeSelectorEnvVarKey is the environment variable key for
// persistent volume provisioner's node selector for controllers
//
// Usage:
// <CTX>__CONTROLLER_NODE_SELECTOR = <some value>
PVPControllerNodeSelectorEnvVarKey EnvironmentVariableKey = "_CONTROLLER_NODE_SELECTOR"

// PVPReplicaNodeSelectorEnvVarKey is the environment variable key for
// persistent volume provisioner's node selector for replicas
//
// Usage:
// <CTX>__REPLICA_NODE_SELECTOR = <some value>
PVPReplicaNodeSelectorEnvVarKey EnvironmentVariableKey = "_REPLICA_NODE_SELECTOR"

// OrchestratorNameEnvVarKey is the environment variable key for
// orchestration provider's name
//
Expand Down Expand Up @@ -253,6 +267,12 @@ const (
// Label / Tag for a persistent volume provisioner's replica node taint toleration
PVPReplicaNodeTaintTolerationLbl VolumeProvisionerProfileLabel = "volumeprovisioner.mapi.openebs.io/replica-node-taint-toleration"

// Label / Tag for a persistent volume provisioner's controller node selector
PVPControllerNodeSelectorLbl VolumeProvisionerProfileLabel = "volumeprovisioner.mapi.openebs.io/controller-node-selector"

// Label / Tag for a persistent volume provisioner's replica node selector
PVPReplicaNodeSelectorLbl VolumeProvisionerProfileLabel = "volumeprovisioner.mapi.openebs.io/replica-node-selector"

// PVPReplicaTopologyKeyLbl is the label for a persistent volume provisioner's
// VSM replica topology key
PVPReplicaTopologyKeyLbl VolumeProvisionerProfileLabel = "volumeprovisioner.mapi.openebs.io/replica-topology-key"
Expand Down
76 changes: 76 additions & 0 deletions types/v1/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,82 @@ func DefaultReplicaNodeTaintTolerations() (string, error) {
return "", nil
}

// GetControllerNodeSelectors gets the node selectors for controller if
// available
func GetControllerNodeSelectors(profileMap map[string]string) (string, error) {
val, err := ControllerNodeSelectors(profileMap)
if err != nil {
return "", err
}

if val == "" {
val, err = DefaultControllerNodeSelectors()
}

return val, err
}

// ControllerNodeSelectors extracts the node selectors for controller
func ControllerNodeSelectors(profileMap map[string]string) (string, error) {
val := ""
if profileMap != nil {
val = strings.TrimSpace(profileMap[string(PVPControllerNodeSelectorLbl)])
}

if val != "" {
return val, nil
}

// else get from environment variable
return OSGetEnv(string(PVPControllerNodeSelectorEnvVarKey), profileMap), nil
}

// DefaultControllerNodeSelectors will fetch the default value for node
// selectors for controller
func DefaultControllerNodeSelectors() (string, error) {
// Controller node selector property is optional. Hence returns blank
// (i.e. not required) as default.
return "", nil
}

// GetReplicaNodeSelectors gets the node selectors for replica if
// available
func GetReplicaNodeSelectors(profileMap map[string]string) (string, error) {
val, err := ReplicaNodeSelectors(profileMap)
if err != nil {
return "", err
}

if val == "" {
val, err = DefaultReplicaNodeSelectors()
}

return val, err
}

// ReplicaNodeSelectors extracts the node selectors for replica
func ReplicaNodeSelectors(profileMap map[string]string) (string, error) {
val := ""
if profileMap != nil {
val = strings.TrimSpace(profileMap[string(PVPReplicaNodeSelectorLbl)])
}

if val != "" {
return val, nil
}

// else get from environment variable
return OSGetEnv(string(PVPReplicaNodeSelectorEnvVarKey), profileMap), nil
}

// DefaultReplicaNodeSelectors will fetch the default value for node
// selectors for replicas
func DefaultReplicaNodeSelectors() (string, error) {
// Replica node selector property is optional. Hence returns blank
// (i.e. not required) as default.
return "", nil
}

// GetOrchestratorNetworkType gets the not nil orchestration provider's network
// type
func GetOrchestratorNetworkType(profileMap map[string]string) string {
Expand Down
48 changes: 48 additions & 0 deletions volume/profiles/profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ type VolumeProvisionerProfile interface {

// Verify if node level taint tolerations are required for replica?
IsReplicaNodeTaintTolerations() ([]string, bool, error)

// Verify if node selectors are required for controller?
IsControllerNodeSelectors() ([]string, bool, error)

// Verify if node selectors are required for replica?
IsReplicaNodeSelectors() ([]string, bool, error)
}

// GetVolProProfile will return a specific persistent volume provisioner
Expand Down Expand Up @@ -312,6 +318,48 @@ func (pp *defVolProProfile) IsReplicaNodeTaintTolerations() ([]string, bool, err
return strings.Split(nTTs, ","), true, nil
}

// IsControllerNodeSelectors provides the node selectors for controller
// Since node selectors for controller is an optional feature, it
// can return false.
func (pp *defVolProProfile) IsControllerNodeSelectors() ([]string, bool, error) {
// Extract the node selectors for Controller
nodeSelectors, err := v1.GetControllerNodeSelectors(nil)
if err != nil {
return nil, false, err
}

if strings.TrimSpace(nodeSelectors) == "" {
return nil, false, nil
}

// nodeSelectors is expected of below form
// key1=value1, key2=value2
// __or__
// key=value
return strings.Split(nodeSelectors, ","), true, nil
}

// IsReplicaNodeSelectors provides the node selectors for replica
// Since node selectors for replica is an optional feature, it
// can return false.
func (pp *defVolProProfile) IsReplicaNodeSelectors() ([]string, bool, error) {
// Extract the node selectors for replica
nodeSelectors, err := v1.GetReplicaNodeSelectors(nil)
if err != nil {
return nil, false, err
}

if strings.TrimSpace(nodeSelectors) == "" {
return nil, false, nil
}

// nodeSelectors is expected of below form
// key1=value1, key2=value2
// __or__
// key=value
return strings.Split(nodeSelectors, ","), true, nil
}

// StorageSize gets the storage size for each persistent volume replica(s)
func (pp *defVolProProfile) StorageSize() (string, error) {
// Extract the storage size
Expand Down

0 comments on commit 437fc37

Please sign in to comment.