From e7aaa5df202e1f98ee15bfe4330c5525add0de5b Mon Sep 17 00:00:00 2001 From: Alexander Demichev Date: Mon, 22 Mar 2021 17:57:22 +0100 Subject: [PATCH] Get instance tags from infrastructure object --- pkg/actuators/machine/instances.go | 33 ++++++++++++++++++++++++----- pkg/actuators/machine/reconciler.go | 12 ++++++++++- pkg/client/client.go | 6 +++--- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/pkg/actuators/machine/instances.go b/pkg/actuators/machine/instances.go index c5ecabf623..b070855968 100644 --- a/pkg/actuators/machine/instances.go +++ b/pkg/actuators/machine/instances.go @@ -10,6 +10,7 @@ import ( "time" "github.com/aws/aws-sdk-go/aws/awserr" + configv1 "github.com/openshift/api/config/v1" machinev1 "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1" mapierrors "github.com/openshift/machine-api-operator/pkg/controller/machine" "github.com/openshift/machine-api-operator/pkg/metrics" @@ -23,7 +24,7 @@ import ( awsclient "sigs.k8s.io/cluster-api-provider-aws/pkg/client" ) -// Scan machine tags, and return a deduped tags list +// Scan machine tags, and return a deduped tags list. The first found value gets precedence. func removeDuplicatedTags(tags []*ec2.Tag) []*ec2.Tag { m := make(map[string]bool) result := []*ec2.Tag{} @@ -272,7 +273,7 @@ func getBlockDeviceMappings(machine runtimeclient.ObjectKey, blockDeviceMappingS return blockDeviceMappings, nil } -func launchInstance(machine *machinev1.Machine, machineProviderConfig *awsproviderv1.AWSMachineProviderConfig, userData []byte, client awsclient.Client) (*ec2.Instance, error) { +func launchInstance(machine *machinev1.Machine, machineProviderConfig *awsproviderv1.AWSMachineProviderConfig, userData []byte, client awsclient.Client, infra *configv1.Infrastructure) (*ec2.Instance, error) { machineKey := runtimeclient.ObjectKey{ Name: machine.Name, Namespace: machine.Namespace, @@ -315,7 +316,7 @@ func launchInstance(machine *machinev1.Machine, machineProviderConfig *awsprovid return nil, mapierrors.InvalidMachineConfiguration("Unable to get cluster ID for machine: %q", machine.Name) } // Add tags to the created machine - tagList := buildTagList(machine.Name, clusterID, machineProviderConfig.Tags) + tagList := buildTagList(machine.Name, clusterID, machineProviderConfig.Tags, infra) tagInstance := &ec2.TagSpecification{ ResourceType: aws.String("instance"), @@ -410,9 +411,13 @@ func launchInstance(machine *machinev1.Machine, machineProviderConfig *awsprovid return runResult.Instances[0], nil } -func buildTagList(machineName string, clusterID string, machineTags []awsproviderv1.TagSpecification) []*ec2.Tag { +// buildTagList compile a list of ec2 tags from machine provider spec and infrastructure object platform spec +func buildTagList(machineName string, clusterID string, machineTags []awsproviderv1.TagSpecification, infra *configv1.Infrastructure) []*ec2.Tag { rawTagList := []*ec2.Tag{} - for _, tag := range machineTags { + + mergedTags := mergeInfrastructureAndMachineSpecTags(machineTags, infra) + + for _, tag := range mergedTags { // AWS tags are case sensitive, so we don't need to worry about other casing of "Name" if !strings.HasPrefix(tag.Name, "kubernetes.io/cluster/") && tag.Name != "Name" { rawTagList = append(rawTagList, &ec2.Tag{Key: aws.String(tag.Name), Value: aws.String(tag.Value)}) @@ -422,9 +427,27 @@ func buildTagList(machineName string, clusterID string, machineTags []awsprovide {Key: aws.String("kubernetes.io/cluster/" + clusterID), Value: aws.String("owned")}, {Key: aws.String("Name"), Value: aws.String(machineName)}, }...) + return removeDuplicatedTags(rawTagList) } +// mergeInfrastructureAndMachineSpecTags merge list of tags from machine provider spec and Infrastructure object platform spec. +// Machine tags have precedence over Infrastructure +func mergeInfrastructureAndMachineSpecTags(machineSpecTags []awsproviderv1.TagSpecification, infra *configv1.Infrastructure) []awsproviderv1.TagSpecification { + if infra == nil || infra.Status.PlatformStatus == nil || infra.Status.PlatformStatus.AWS == nil || infra.Status.PlatformStatus.AWS.ResourceTags == nil { + return machineSpecTags + } + + mergedList := []awsproviderv1.TagSpecification{} + mergedList = append(mergedList, machineSpecTags...) + + for _, tag := range infra.Status.PlatformStatus.AWS.ResourceTags { + mergedList = append(mergedList, awsproviderv1.TagSpecification{Name: tag.Key, Value: tag.Value}) + } + + return mergedList +} + type instanceList []*ec2.Instance func (il instanceList) Len() int { diff --git a/pkg/actuators/machine/reconciler.go b/pkg/actuators/machine/reconciler.go index 6ad60e5fcd..4322a14eb9 100644 --- a/pkg/actuators/machine/reconciler.go +++ b/pkg/actuators/machine/reconciler.go @@ -6,12 +6,15 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + configv1 "github.com/openshift/api/config/v1" machinecontroller "github.com/openshift/machine-api-operator/pkg/controller/machine" "github.com/openshift/machine-api-operator/pkg/metrics" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" errorutil "k8s.io/apimachinery/pkg/util/errors" "k8s.io/klog/v2" + awsclient "sigs.k8s.io/cluster-api-provider-aws/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client" awsproviderv1 "sigs.k8s.io/cluster-api-provider-aws/pkg/apis/awsprovider/v1beta1" ) @@ -64,7 +67,14 @@ func (r *Reconciler) create() error { return fmt.Errorf("failed to get user data: %w", err) } - instance, err := launchInstance(r.machine, r.providerSpec, userData, r.awsClient) + infra := &configv1.Infrastructure{} + infraName := client.ObjectKey{Name: awsclient.GlobalInfrastuctureName} + + if err := r.client.Get(r.Context, infraName, infra); err != nil { + return err + } + + instance, err := launchInstance(r.machine, r.providerSpec, userData, r.awsClient, infra) if err != nil { klog.Errorf("%s: error creating machine: %v", r.machine.Name, err) conditionFailed := conditionFailed() diff --git a/pkg/client/client.go b/pkg/client/client.go index a615745354..8ddc310aaf 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -53,8 +53,8 @@ const ( // AwsCredsSecretAccessKey is secret key containing AWS Secret Key AwsCredsSecretAccessKey = "aws_secret_access_key" - // globalInfrastuctureName default name for infrastructure object - globalInfrastuctureName = "cluster" + // GlobalInfrastuctureName default name for infrastructure object + GlobalInfrastuctureName = "cluster" // KubeCloudConfigNamespace is the namespace where the kube cloud config ConfigMap is located KubeCloudConfigNamespace = "openshift-config-managed" @@ -283,7 +283,7 @@ var addProviderVersionToUserAgent = request.NamedHandler{ func resolveEndpoints(awsConfig *aws.Config, ctrlRuntimeClient client.Client, region string) error { infra := &configv1.Infrastructure{} - infraName := client.ObjectKey{Name: globalInfrastuctureName} + infraName := client.ObjectKey{Name: GlobalInfrastuctureName} if err := ctrlRuntimeClient.Get(context.Background(), infraName, infra); err != nil { return err