From 832bfc2470e3197f294d45a3786999a30288cc8b Mon Sep 17 00:00:00 2001 From: Enxebre Date: Wed, 28 Nov 2018 12:57:14 +0100 Subject: [PATCH] Add support getting machineClasses from machine.Spec.ProviderConfig.ValueFrom --- pkg/cloud/aws/actuators/machine/actuator.go | 8 +- pkg/cloud/aws/actuators/machine/utils.go | 38 +++++- pkg/cloud/aws/actuators/machine/utils_test.go | 124 ++++++++++++++++++ 3 files changed, 160 insertions(+), 10 deletions(-) create mode 100644 pkg/cloud/aws/actuators/machine/utils_test.go diff --git a/pkg/cloud/aws/actuators/machine/actuator.go b/pkg/cloud/aws/actuators/machine/actuator.go index 46f3a3f1e5..d23c61deb4 100644 --- a/pkg/cloud/aws/actuators/machine/actuator.go +++ b/pkg/cloud/aws/actuators/machine/actuator.go @@ -160,7 +160,7 @@ func (a *Actuator) updateMachineProviderConditions(machine *clusterv1.Machine, c // CreateMachine starts a new AWS instance as described by the cluster and machine resources func (a *Actuator) CreateMachine(cluster *clusterv1.Cluster, machine *clusterv1.Machine) (*ec2.Instance, error) { - machineProviderConfig, err := ProviderConfigFromMachine(machine) + machineProviderConfig, err := ProviderConfigFromMachine(a.client, machine) if err != nil { glog.Errorf("error decoding MachineProviderConfig: %v", err) return nil, err @@ -224,7 +224,7 @@ func (a *Actuator) Delete(context context.Context, cluster *clusterv1.Cluster, m // DeleteMachine deletes an AWS instance func (a *Actuator) DeleteMachine(cluster *clusterv1.Cluster, machine *clusterv1.Machine) error { - machineProviderConfig, err := ProviderConfigFromMachine(machine) + machineProviderConfig, err := ProviderConfigFromMachine(a.client, machine) if err != nil { glog.Errorf("error decoding MachineProviderConfig: %v", err) return err @@ -260,7 +260,7 @@ func (a *Actuator) DeleteMachine(cluster *clusterv1.Cluster, machine *clusterv1. func (a *Actuator) Update(context context.Context, cluster *clusterv1.Cluster, machine *clusterv1.Machine) error { glog.Info("updating machine") - machineProviderConfig, err := ProviderConfigFromMachine(machine) + machineProviderConfig, err := ProviderConfigFromMachine(a.client, machine) if err != nil { glog.Errorf("error decoding MachineProviderConfig: %v", err) return err @@ -360,7 +360,7 @@ func (a *Actuator) Describe(cluster *clusterv1.Cluster, machine *clusterv1.Machi } func (a *Actuator) getMachineInstances(cluster *clusterv1.Cluster, machine *clusterv1.Machine) ([]*ec2.Instance, error) { - machineProviderConfig, err := ProviderConfigFromMachine(machine) + machineProviderConfig, err := ProviderConfigFromMachine(a.client, machine) if err != nil { glog.Errorf("error decoding MachineProviderConfig: %v", err) return nil, err diff --git a/pkg/cloud/aws/actuators/machine/utils.go b/pkg/cloud/aws/actuators/machine/utils.go index 9e26dcbca0..4bd7b4bc9c 100644 --- a/pkg/cloud/aws/actuators/machine/utils.go +++ b/pkg/cloud/aws/actuators/machine/utils.go @@ -26,13 +26,15 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - providerconfigv1 "sigs.k8s.io/cluster-api-provider-aws/pkg/apis/awsproviderconfig/v1alpha1" - awsclient "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/aws/client" - clusterv1 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "github.com/ghodss/yaml" + "golang.org/x/net/context" + "k8s.io/apimachinery/pkg/types" + providerconfigv1 "sigs.k8s.io/cluster-api-provider-aws/pkg/apis/awsproviderconfig/v1alpha1" + awsclient "sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/aws/client" + clusterv1 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client" ) // getRunningInstance returns the AWS instance for a given machine. If multiple instances match our machine, @@ -138,9 +140,33 @@ func terminateInstances(client awsclient.Client, instances []*ec2.Instance) erro // ProviderConfigFromMachine gets the machine provider config MachineSetSpec from the // specified cluster-api MachineSpec. -func ProviderConfigFromMachine(machine *clusterv1.Machine) (*providerconfigv1.AWSMachineProviderConfig, error) { +func ProviderConfigFromMachine(client client.Client, machine *clusterv1.Machine) (*providerconfigv1.AWSMachineProviderConfig, error) { + var providerConfig runtime.RawExtension + + if machine.Spec.ProviderConfig.Value == nil && machine.Spec.ProviderConfig.ValueFrom == nil { + return nil, fmt.Errorf("unable to find machine provider config: neither Spec.ProviderConfig.Value nor Spec.ProviderConfig.ValueFrom set") + } + + // If no machine.Spec.ProviderConfig.Value then we lookup for machineClass + if machine.Spec.ProviderConfig.Value != nil { + providerConfig = *machine.Spec.ProviderConfig.Value + } else { + if machine.Spec.ProviderConfig.ValueFrom.MachineClass == nil { + return nil, fmt.Errorf("unable to find MachineClass on Spec.ProviderConfig.ValueFrom") + } + machineClass := &clusterv1.MachineClass{} + key := types.NamespacedName{ + Namespace: machine.Spec.ProviderConfig.ValueFrom.MachineClass.Namespace, + Name: machine.Spec.ProviderConfig.ValueFrom.MachineClass.Name, + } + if err := client.Get(context.Background(), key, machineClass); err != nil { + return nil, err + } + providerConfig = machineClass.ProviderConfig + } + var config providerconfigv1.AWSMachineProviderConfig - if err := yaml.Unmarshal(machine.Spec.ProviderConfig.Value.Raw, &config); err != nil { + if err := yaml.Unmarshal(providerConfig.Raw, &config); err != nil { return nil, err } return &config, nil diff --git a/pkg/cloud/aws/actuators/machine/utils_test.go b/pkg/cloud/aws/actuators/machine/utils_test.go new file mode 100644 index 0000000000..a64a17f748 --- /dev/null +++ b/pkg/cloud/aws/actuators/machine/utils_test.go @@ -0,0 +1,124 @@ +package machine + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/scheme" + "reflect" + providerconfigv1 "sigs.k8s.io/cluster-api-provider-aws/pkg/apis/awsproviderconfig/v1alpha1" + clusterv1 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "testing" +) + +func init() { + // Add types to scheme + clusterv1.AddToScheme(scheme.Scheme) +} + +func TestProviderConfigFromMachine(t *testing.T) { + + providerConfig := &providerconfigv1.AWSMachineProviderConfig{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "awsproviderconfig.k8s.io/v1alpha1", + Kind: "AWSMachineProviderConfig", + }, + InstanceType: "testInstance", + AMI: providerconfigv1.AWSResourceReference{ID: nil}, + Tags: []providerconfigv1.TagSpecification{ + {Name: "", Value: ""}, + }, + IAMInstanceProfile: &providerconfigv1.AWSResourceReference{ID: nil}, + UserDataSecret: &corev1.LocalObjectReference{Name: ""}, + Subnet: providerconfigv1.AWSResourceReference{ + Filters: []providerconfigv1.Filter{{ + Name: "tag:Name", + Values: []string{""}, + }}, + }, + Placement: providerconfigv1.Placement{Region: "", AvailabilityZone: ""}, + SecurityGroups: []providerconfigv1.AWSResourceReference{{ + Filters: []providerconfigv1.Filter{{ + Name: "tag:Name", + Values: []string{""}, + }}, + }}, + } + + codec, err := providerconfigv1.NewCodec() + if err != nil { + t.Error(err) + } + encodedProviderConfig, err := codec.EncodeProviderConfig(providerConfig) + if err != nil { + t.Error(err) + } + + machineClass := &clusterv1.MachineClass{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "openshift-cluster-api", + Name: "testClass", + }, + ProviderConfig: *encodedProviderConfig.Value, + } + + testCases := []struct { + machine *clusterv1.Machine + }{ + { + machine: &clusterv1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "configFromSpecProviderConfigValue", + Namespace: "", + Labels: map[string]string{ + "foo": "a", + }, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "Machine", + }, + Spec: clusterv1.MachineSpec{ + ProviderConfig: *encodedProviderConfig, + }, + }, + }, + { + machine: &clusterv1.Machine{ + ObjectMeta: metav1.ObjectMeta{ + Name: "configFromClass", + Namespace: "", + Labels: map[string]string{ + "foo": "a", + }, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "Machine", + }, + Spec: clusterv1.MachineSpec{ + ProviderConfig: clusterv1.ProviderConfig{ + ValueFrom: &clusterv1.ProviderConfigSource{ + MachineClass: &clusterv1.MachineClassRef{ + ObjectReference: &corev1.ObjectReference{ + Kind: "MachineClass", + Name: "testClass", + Namespace: "openshift-cluster-api", + }, + }, + }, + }, + }, + }, + }, + } + + client := fake.NewFakeClient(machineClass) + for _, tc := range testCases { + decodedProviderConfig, err := ProviderConfigFromMachine(client, tc.machine) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(decodedProviderConfig, providerConfig) { + t.Errorf("Test case %s. Expected: %v, got: %v", tc.machine.Name, providerConfig, decodedProviderConfig) + } + } +}