Merge pull request #172 from aleksandra-malinowska/add-taints-to-node-templates

add taints to GCE node template
This commit is contained in:
MaciekPytel 2017-07-13 10:35:02 +02:00 committed by GitHub
commit f17c67ef81
3 changed files with 84 additions and 9 deletions

View File

@ -26,7 +26,7 @@ import (
"sync" "sync"
"time" "time"
"gopkg.in/gcfg.v1" gcfg "gopkg.in/gcfg.v1"
"github.com/golang/glog" "github.com/golang/glog"
"golang.org/x/oauth2" "golang.org/x/oauth2"
@ -327,7 +327,7 @@ func (m *GceManager) buildNodeFromTemplate(mig *Mig, template *gce.InstanceTempl
// TODO: use proper allocatable!! // TODO: use proper allocatable!!
node.Status.Allocatable = node.Status.Capacity node.Status.Allocatable = node.Status.Capacity
// KubeEnvLabels // KubeEnv labels & taints
if template.Properties.Metadata == nil { if template.Properties.Metadata == nil {
return nil, fmt.Errorf("instance template %s has no metadata", template.Name) return nil, fmt.Errorf("instance template %s has no metadata", template.Name)
} }
@ -336,11 +336,18 @@ func (m *GceManager) buildNodeFromTemplate(mig *Mig, template *gce.InstanceTempl
if item.Value == nil { if item.Value == nil {
return nil, fmt.Errorf("no kube-env content in metadata") return nil, fmt.Errorf("no kube-env content in metadata")
} }
// Extract labels
kubeEnvLabels, err := extractLabelsFromKubeEnv(*item.Value) kubeEnvLabels, err := extractLabelsFromKubeEnv(*item.Value)
if err != nil { if err != nil {
return nil, err return nil, err
} }
node.Labels = cloudprovider.JoinStringMaps(node.Labels, kubeEnvLabels) node.Labels = cloudprovider.JoinStringMaps(node.Labels, kubeEnvLabels)
// Extract taints
kubeEnvTaints, err := extractTaintsFromKubeEnv(*item.Value)
if err != nil {
return nil, err
}
node.Spec.Taints = append(node.Spec.Taints, kubeEnvTaints...)
} }
} }
// GenericLabels // GenericLabels
@ -390,6 +397,18 @@ func parseCustomMachineType(machineType string) (cpu, mem int64, err error) {
} }
func extractLabelsFromKubeEnv(kubeEnv string) (map[string]string, error) { func extractLabelsFromKubeEnv(kubeEnv string) (map[string]string, error) {
return extractFromKubeEnv(kubeEnv, "NODE_LABELS")
}
func extractTaintsFromKubeEnv(kubeEnv string) ([]apiv1.Taint, error) {
taintMap, err := extractFromKubeEnv(kubeEnv, "NODE_TAINTS")
if err != nil {
return nil, err
}
return buildTaints(taintMap)
}
func extractFromKubeEnv(kubeEnv, resource string) (map[string]string, error) {
result := make(map[string]string) result := make(map[string]string)
for line, env := range strings.Split(kubeEnv, "\n") { for line, env := range strings.Split(kubeEnv, "\n") {
@ -403,15 +422,31 @@ func extractLabelsFromKubeEnv(kubeEnv string) (map[string]string, error) {
} }
key := strings.Trim(items[0], " ") key := strings.Trim(items[0], " ")
value := strings.Trim(items[1], " \"'") value := strings.Trim(items[1], " \"'")
if key == "NODE_LABELS" { if key == resource {
for _, label := range strings.Split(value, ",") { for _, val := range strings.Split(value, ",") {
labelItems := strings.SplitN(label, "=", 2) valItems := strings.SplitN(val, "=", 2)
if len(labelItems) != 2 { if len(valItems) != 2 {
return nil, fmt.Errorf("error while parsing label: %s", label) return nil, fmt.Errorf("error while parsing kube env value: %s", val)
} }
result[labelItems[0]] = labelItems[1] result[valItems[0]] = valItems[1]
} }
} }
} }
return result, nil return result, nil
} }
func buildTaints(kubeEnvTaints map[string]string) ([]apiv1.Taint, error) {
taints := make([]apiv1.Taint, 0)
for key, value := range kubeEnvTaints {
values := strings.SplitN(value, ":", 2)
if len(values) != 2 {
return nil, fmt.Errorf("error while parsing node taint value and effect: %s", value)
}
taints = append(taints, apiv1.Taint{
Key: key,
Value: values[0],
Effect: apiv1.TaintEffect(values[1]),
})
}
return taints, nil
}

View File

@ -20,6 +20,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
apiv1 "k8s.io/api/core/v1"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider" "k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
) )
@ -53,6 +54,45 @@ func TestExtractLabelsFromKubeEnv(t *testing.T) {
assert.Equal(t, "true", labels["cloud.google.com/gke-preemptible"]) assert.Equal(t, "true", labels["cloud.google.com/gke-preemptible"])
} }
func TestExtractTaintsFromKubeEnv(t *testing.T) {
kubeenv := "ENABLE_NODE_PROBLEM_DETECTOR: 'daemonset'\n" +
"NODE_LABELS: a=b,c=d,cloud.google.com/gke-nodepool=pool-3,cloud.google.com/gke-preemptible=true\n" +
"DNS_SERVER_IP: '10.0.0.10'\n" +
"NODE_TAINTS: 'dedicated=ml:NoSchedule,test=dev:PreferNoSchedule,a=b:c'\n"
expectedTaints := []apiv1.Taint{
{
Key: "dedicated",
Value: "ml",
Effect: apiv1.TaintEffectNoSchedule,
},
{
Key: "test",
Value: "dev",
Effect: apiv1.TaintEffectPreferNoSchedule,
},
{
Key: "a",
Value: "b",
Effect: apiv1.TaintEffect("c"),
},
}
taints, err := extractTaintsFromKubeEnv(kubeenv)
assert.Nil(t, err)
assert.Equal(t, 3, len(taints))
assert.Equal(t, makeTaintSet(expectedTaints), makeTaintSet(taints))
}
func makeTaintSet(taints []apiv1.Taint) map[apiv1.Taint]bool {
set := make(map[apiv1.Taint]bool)
for _, taint := range taints {
set[taint] = true
}
return set
}
func TestParseCustomMachineType(t *testing.T) { func TestParseCustomMachineType(t *testing.T) {
cpu, mem, err := parseCustomMachineType("custom-2-2816") cpu, mem, err := parseCustomMachineType("custom-2-2816")
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -293,7 +293,7 @@ func sanitizeTemplateNode(node *apiv1.Node, nodeGroup string) (*apiv1.Node, erro
return newNode, nil return newNode, nil
} }
// Removes unregisterd nodes if needed. Returns true if anything was removed and error if such occurred. // Removes unregistered nodes if needed. Returns true if anything was removed and error if such occurred.
func removeOldUnregisteredNodes(unregisteredNodes []clusterstate.UnregisteredNode, context *AutoscalingContext, func removeOldUnregisteredNodes(unregisteredNodes []clusterstate.UnregisteredNode, context *AutoscalingContext,
currentTime time.Time) (bool, error) { currentTime time.Time) (bool, error) {
removedAny := false removedAny := false