diff --git a/.gitignore b/.gitignore index d8cac19..32ab919 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ testbin/* bundle/ bundle.Dockerfile charts/ +testbin/ diff --git a/api/v1alpha1/globaldnszone_types.go b/api/v1alpha1/globaldnszone_types.go index f463f72..a4423f1 100644 --- a/api/v1alpha1/globaldnszone_types.go +++ b/api/v1alpha1/globaldnszone_types.go @@ -58,10 +58,11 @@ type Route53ProviderConfig struct { // +kubebuilder:validation:Required ZoneID string `json:"zoneID"` - //CredentialsSecretRef is a reference to a secret containing the credentials to access the AWS API //TODO (content and needed permissions) - // expected secret keys are "aws_access_key_id" and "aws_secret_access_key" - // +kubebuilder:validation:Required - CredentialsSecretRef NamespacedName `json:"credentialsSecretRef"` + //CredentialsSecretRef is a reference to a secret containing the credentials to access the AWS API. The expected secret keys are "aws_access_key_id" and "aws_secret_access_key". + // This is needed when you want to use route53 as your global load balancer but the operator does not run in an AWS cluster. + // If the operator runs in an AWS cluster, credentials are automatically requested via a CredendialRequest object. + // +kubebuilder:validation:Optional + CredentialsSecretRef NamespacedName `json:"credentialsSecretRef,omitempty"` } // GlobalDNSZoneStatus defines the observed state of GlobalDNSZone diff --git a/config/crd/bases/redhatcop.redhat.io_globaldnszones.yaml b/config/crd/bases/redhatcop.redhat.io_globaldnszones.yaml index 13f078c..2798c19 100644 --- a/config/crd/bases/redhatcop.redhat.io_globaldnszones.yaml +++ b/config/crd/bases/redhatcop.redhat.io_globaldnszones.yaml @@ -60,9 +60,12 @@ spec: properties: credentialsSecretRef: description: CredentialsSecretRef is a reference to a secret - containing the credentials to access the AWS API //TODO - (content and needed permissions) expected secret keys are - "aws_access_key_id" and "aws_secret_access_key" + containing the credentials to access the AWS API. The expected + secret keys are "aws_access_key_id" and "aws_secret_access_key". + This is needed when you want to use route53 as your global + load balancer but the operator does not run in an AWS cluster. + If the operator runs in an AWS cluster, credentials are + automatically requested via a CredendialRequest object. properties: name: type: string @@ -76,7 +79,6 @@ spec: description: ZoneID is the AWS route53 zone ID. type: string required: - - credentialsSecretRef - zoneID type: object type: object diff --git a/config/crd/external-dns/dnsendpoint-crd.yaml b/config/crd/external-dns/dnsendpoint-crd.yaml new file mode 100644 index 0000000..725d025 --- /dev/null +++ b/config/crd/external-dns/dnsendpoint-crd.yaml @@ -0,0 +1,86 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.5.0 + api-approved.kubernetes.io: "https://github.com/kubernetes-sigs/external-dns/pull/2007" + creationTimestamp: null + name: dnsendpoints.externaldns.k8s.io +spec: + group: externaldns.k8s.io + names: + kind: DNSEndpoint + listKind: DNSEndpointList + plural: dnsendpoints + singular: dnsendpoint + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + 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' + 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' + type: string + metadata: + type: object + spec: + description: DNSEndpointSpec defines the desired state of DNSEndpoint + properties: + endpoints: + items: + description: Endpoint is a high-level way of a connection between a service and an IP + properties: + dnsName: + description: The hostname of the DNS record + type: string + labels: + additionalProperties: + type: string + description: Labels stores labels defined for the Endpoint + type: object + providerSpecific: + description: ProviderSpecific stores provider specific config + items: + description: ProviderSpecificProperty holds the name and value of a configuration which is specific to individual DNS providers + properties: + name: + type: string + value: + type: string + type: object + type: array + recordTTL: + description: TTL for the record + format: int64 + type: integer + recordType: + description: RecordType type of record, e.g. CNAME, A, SRV, TXT etc + type: string + setIdentifier: + description: Identifier to distinguish multiple records with the same name and type (e.g. Route53 records with routing policies other than 'simple') + type: string + targets: + description: The targets the DNS record points to + items: + type: string + type: array + type: object + type: array + type: object + status: + description: DNSEndpointStatus defines the observed state of DNSEndpoint + properties: + observedGeneration: + description: The generation observed by the external-dns controller. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 658a6e2..f4a219c 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -5,6 +5,7 @@ resources: - bases/redhatcop.redhat.io_globaldnsrecords.yaml - bases/redhatcop.redhat.io_globalroutediscoveries.yaml - bases/redhatcop.redhat.io_globaldnszones.yaml +- external-dns/dnsendpoint-crd.yaml # +kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: diff --git a/config/helmchart/templates/manager.yaml b/config/helmchart/templates/manager.yaml index 875dc3a..b8bdfad 100644 --- a/config/helmchart/templates/manager.yaml +++ b/config/helmchart/templates/manager.yaml @@ -28,6 +28,11 @@ spec: - /manager args: - --leader-elect + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} name: {{ .Chart.Name }} diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 6ef428a..08ed4c1 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -28,6 +28,11 @@ spec: - /manager args: - --leader-elect + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace image: controller:latest name: manager securityContext: diff --git a/config/manifests/bases/global-load-balancer-operator.clusterserviceversion.yaml b/config/manifests/bases/global-load-balancer-operator.clusterserviceversion.yaml index 8cb9d71..d7bf29c 100644 --- a/config/manifests/bases/global-load-balancer-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/global-load-balancer-operator.clusterserviceversion.yaml @@ -7,9 +7,9 @@ metadata: categories: Networking, Cloud Provider certified: "false" containerImage: quay.io/redhat-cop/global-load-balancer-operator - operatorframework.io/suggested-namespace: global-load-balancer-operator createdAt: 07/30/2020 description: This operator creates automation around a DNS to operate as a global load balancer for a set of OpenShift clusters. + operatorframework.io/suggested-namespace: global-load-balancer-operator repository: https://github.com/redhat-cop/global-load-balancer-operator support: Best Effort name: global-load-balancer-operator.v0.0.0 diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index fb096fc..067f27a 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -24,6 +24,16 @@ rules: - get - list - watch +- apiGroups: + - cloudcredential.openshift.io + resources: + - credentialsrequests + verbs: + - create + - get + - list + - update + - watch - apiGroups: - externaldns.k8s.io resources: diff --git a/controllers/common/route53/route53.go b/controllers/common/route53/route53.go index a247d16..c5a8a68 100644 --- a/controllers/common/route53/route53.go +++ b/controllers/common/route53/route53.go @@ -3,21 +3,48 @@ package route53 import ( "context" "errors" + "os" + "reflect" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/route53" + cloudcredentialv1 "github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1" redhatcopv1alpha1 "github.com/redhat-cop/global-load-balancer-operator/api/v1alpha1" "github.com/redhat-cop/operator-utils/pkg/util" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" logf "sigs.k8s.io/controller-runtime/pkg/log" ) +const credentialsName = "global-load-balancer-operator-infra-credentials" +const credentialsNamespace = "openshift-cloud-credential-operator" +const credentialsSecretName = "global-load-balancer-operator-infra-credentials" + var log = logf.Log.WithName("common") +var operatorNamespace string + +func init() { + on, found := os.LookupEnv("NAMESPACE") + if !found { + log.Error(errors.New("the \"NAMESPACE\" environment variable must be defined. It must point to the namespace in which the operator runs"), "") + operatorNamespace = "global-load-balancer-operator" + return + } + operatorNamespace = on +} func GetRoute53Client(context context.Context, instance *redhatcopv1alpha1.GlobalDNSZone, r *util.ReconcilerBase) (*route53.Route53, error) { + err := ensureCredentialsRequestExists(context, r) + if err != nil { + log.Error(err, "unable to create CredentialRequest for route53") + return nil, err + } id, key, err := getAWSCredentials(context, instance, r) if err != nil { log.Error(err, "unable to get aws credentials") @@ -57,16 +84,114 @@ func getAWSCredentials(context context.Context, instance *redhatcopv1alpha1.Glob func getAWSCredentialSecret(context context.Context, instance *redhatcopv1alpha1.GlobalDNSZone, r *util.ReconcilerBase) (*corev1.Secret, error) { credentialSecret := &corev1.Secret{} + var secret_name, secret_namespace string + if instance.Spec.Provider.Route53.CredentialsSecretRef.Name != "" { + secret_name = instance.Spec.Provider.Route53.CredentialsSecretRef.Name + secret_namespace = instance.Spec.Provider.Route53.CredentialsSecretRef.Namespace + } else { + secret_name = credentialsSecretName + secret_namespace = operatorNamespace + } err := r.GetClient().Get(context, types.NamespacedName{ - Name: instance.Spec.Provider.Route53.CredentialsSecretRef.Name, - Namespace: instance.Spec.Provider.Route53.CredentialsSecretRef.Namespace, + Name: secret_name, + Namespace: secret_namespace, }, credentialSecret) if err != nil { log.Error(err, "unable to retrive aws credential ", "secret", types.NamespacedName{ - Name: instance.Spec.Provider.Route53.CredentialsSecretRef.Name, - Namespace: instance.Spec.Provider.Route53.CredentialsSecretRef.Namespace, + Name: secret_name, + Namespace: secret_namespace, }) return &corev1.Secret{}, err } return credentialSecret, nil } + +func ensureCredentialsRequestExists(context context.Context, r *util.ReconcilerBase) error { + + credentialRequest := &cloudcredentialv1.CredentialsRequest{} + err := r.GetClient().Get(context, types.NamespacedName{ + Name: credentialsName, + Namespace: credentialsNamespace, + }, credentialRequest) + + if err != nil { + if apierrors.IsNotFound(err) { + credentialRequest = getAWSCredentialRequest() + err := r.GetClient().Create(context, credentialRequest, &client.CreateOptions{}) + if err != nil { + log.Error(err, "unable to create", "credentials request", credentialRequest) + return err + } + } else { + log.Error(err, "unable to lookup", "credential request", types.NamespacedName{ + Name: credentialsName, + Namespace: credentialsNamespace, + }) + return err + } + + } + desiredCredentialRequest := getAWSCredentialRequest() + if !reflect.DeepEqual(credentialRequest.Spec, desiredCredentialRequest.Spec) { + credentialRequest.Spec = desiredCredentialRequest.Spec + err := r.GetClient().Update(context, credentialRequest, &client.UpdateOptions{}) + if err != nil { + log.Error(err, "unable to update ", "credentials request", credentialRequest) + return err + } + } + return nil +} + +func getAWSCredentialRequest() *cloudcredentialv1.CredentialsRequest { + awsSpec := cloudcredentialv1.AWSProviderSpec{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "cloudcredential.openshift.io/v1", + Kind: "AWSProviderSpec", + }, + StatementEntries: []cloudcredentialv1.StatementEntry{ + { + Action: []string{ + "route53:GetHostedZone", + "route53:CreateTrafficPolicy", + "route53:DeleteTrafficPolicy", + "route53:GetTrafficPolicy", + "route53:ListTrafficPolicies", + "route53:CreateTrafficPolicyInstance", + "route53:DeleteTrafficPolicyInstance", + "route53:GetTrafficPolicyInstance", + "route53:ListTrafficPolicyInstancesByHostedZone", + "route53:ListTrafficPolicyInstancesByPolicy", + "route53:ListHealthChecks", + "route53:GetHealthCheck", + "route53:UpdateHealthCheck", + "route53:DeleteHealthCheck", + "route53:CreateHealthCheck", + "route53:ChangeTagsForResource", + }, + Effect: "Allow", + Resource: "*", + }, + }, + } + request := cloudcredentialv1.CredentialsRequest{ + ObjectMeta: metav1.ObjectMeta{ + Name: credentialsName, + Namespace: credentialsNamespace, + }, + TypeMeta: metav1.TypeMeta{ + APIVersion: "cloudcredential.openshift.io/v1", + Kind: "CredentialsRequest", + }, + Spec: cloudcredentialv1.CredentialsRequestSpec{ + SecretRef: corev1.ObjectReference{ + Name: credentialsSecretName, + Namespace: operatorNamespace, + }, + ProviderSpec: &runtime.RawExtension{ + Object: &awsSpec, + }, + }, + } + return &request +} diff --git a/controllers/globaldnsrecord/endpointstatus_aws.go b/controllers/globaldnsrecord/endpointstatus_aws.go deleted file mode 100644 index bc3d6e5..0000000 --- a/controllers/globaldnsrecord/endpointstatus_aws.go +++ /dev/null @@ -1,210 +0,0 @@ -package globaldnsrecord - -import ( - "context" - errs "errors" - "reflect" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ec2" - cloudcredentialv1 "github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const operatorNamespace = "global-load-balancer-operator" -const credentialsName = "global-load-balancer-operator-infra-credentials" -const credentialsNamespace = "openshift-cloud-credential-operator" -const credentialsSecretName = "global-load-balancer-operator-infra-credentials" - -func (ep *EndpointStatus) loadELBConfig(context context.Context) error { - //verify/create global-dns-namespace exists - err := ep.ensureOperatorNamespaceExists(context) - if err != nil { - ep.log.Error(err, "unable to ensure existance of", "namespace", operatorNamespace, "for endpoint", ep.endpoint) - return err - } - - //verify/create credential request - err = ep.ensureCredentialsRequestExists(context) - if err != nil { - ep.log.Error(err, "unable to ensure existance of", "credentials request", types.NamespacedName{ - Name: credentialsSecretName, - Namespace: credentialsNamespace, - }, "for endpoint", ep.endpoint) - return err - } - - //verify secret exists - - credentialSecret, err := ep.getAWSCredentialSecret(context) - if err != nil { - ep.log.Error(err, "unable to lookup", "credential secret", types.NamespacedName{ - Name: credentialsSecretName, - Namespace: credentialsNamespace, - }, "for endpoint", ep.endpoint) - return err - } - - id, key, err := ep.getAWSCredentials(&credentialSecret) - - if err != nil { - ep.log.Error(err, "unable to find credentials in", "credential secret", credentialSecret, "for endpoint", ep.endpoint) - return err - } - - //create aws client - - mySession := session.Must(session.NewSession()) - _ = ec2.New(mySession, aws.NewConfig().WithCredentials(credentials.NewStaticCredentials(id, key, "")).WithRegion(ep.infrastructure.Status.PlatformStatus.AWS.Region)) - - //load ELB information - - return nil -} - -func (ep *EndpointStatus) getAWSCredentialSecret(context context.Context) (corev1.Secret, error) { - credentialSecret := &corev1.Secret{} - err := ep.client.Get(context, types.NamespacedName{ - Name: credentialsSecretName, - Namespace: credentialsNamespace, - }, credentialSecret) - - if err != nil { - ep.log.Error(err, "unable to lookup", "credential secret", types.NamespacedName{ - Name: credentialsSecretName, - Namespace: credentialsNamespace, - }, "for endpoint", ep.endpoint) - return corev1.Secret{}, err - } - return *credentialSecret, nil -} - -func (ep *EndpointStatus) ensureCredentialsRequestExists(context context.Context) error { - - credentialRequest := &cloudcredentialv1.CredentialsRequest{} - err := ep.client.Get(context, types.NamespacedName{ - Name: credentialsName, - Namespace: credentialsNamespace, - }, credentialRequest) - - if err != nil { - if errors.IsNotFound(err) { - credentialRequest = getAWSCredentialRequest() - err := ep.client.Create(context, credentialRequest, &client.CreateOptions{}) - if err != nil { - ep.log.Error(err, "unable to create", "credentials request", credentialRequest, "for endpoint", ep.endpoint) - return err - } - } else { - ep.log.Error(err, "unable to lookup", "credential request", types.NamespacedName{ - Name: credentialsName, - Namespace: credentialsNamespace, - }, "for endpoint", ep.endpoint) - return err - } - - } - desiredCredentialRequest := getAWSCredentialRequest() - if !reflect.DeepEqual(credentialRequest.Spec, desiredCredentialRequest.Spec) { - credentialRequest.Spec = desiredCredentialRequest.Spec - err := ep.client.Update(context, credentialRequest, &client.UpdateOptions{}) - if err != nil { - ep.log.Error(err, "unable to update ", "credentials request", credentialRequest, "for endpoint", ep.endpoint) - return err - } - } - return nil -} - -func (ep *EndpointStatus) ensureOperatorNamespaceExists(context context.Context) error { - namespace := &corev1.Namespace{} - err := ep.client.Get(context, types.NamespacedName{ - Name: operatorNamespace, - }, namespace) - if err != nil { - if errors.IsNotFound(err) { - //create the namespace - namespace.Name = operatorNamespace - err := ep.client.Create(context, namespace, &client.CreateOptions{}) - if err != nil { - ep.log.Error(err, "unable to create namespace ", "namespace", operatorNamespace, "for endpoint", ep.endpoint) - return err - } - } else { - ep.log.Error(err, "unable to lookup", "namespace", namespace, "for endpoint", ep.endpoint) - return err - } - } - return nil -} - -func (ep *EndpointStatus) getAWSCredentials(credentialSecret *corev1.Secret) (id string, key string, err error) { - - // aws_access_key_id: QUtJQVRKVjUyWVhTV1dTRFhQTEI= - // aws_secret_access_key: ZzlTQzR1VEd5YUV5ejhRZXVCYnMzOTgzZDlEQ216K1NESjJFVFNTYQ== - - awsAccessKeyID, ok := credentialSecret.Data["aws_access_key_id"] - if !ok { - err := errs.New("unable to find key aws_access_key_id in secret " + credentialSecret.String()) - ep.log.Error(err, "") - return "", "", err - } - - awsSecretAccessKey, ok := credentialSecret.Data["aws_secret_access_key"] - if !ok { - err := errs.New("unable to find key aws_secret_access_key in secret " + credentialSecret.String()) - ep.log.Error(err, "") - return "", "", err - } - - return string(awsAccessKeyID), string(awsSecretAccessKey), nil -} - -func getAWSCredentialRequest() *cloudcredentialv1.CredentialsRequest { - awsSpec := cloudcredentialv1.AWSProviderSpec{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "cloudcredential.openshift.io/v1", - Kind: "AWSProviderSpec", - }, - StatementEntries: []cloudcredentialv1.StatementEntry{ - { - Action: []string{ - // "ec2:DescribeInstances", - // "ec2:UnassignPrivateIpAddresses", - // "ec2:AssignPrivateIpAddresses", - // "ec2:DescribeSubnets", - // "ec2:DescribeNetworkInterfaces", - }, - Effect: "Allow", - Resource: "*", - }, - }, - } - request := cloudcredentialv1.CredentialsRequest{ - ObjectMeta: metav1.ObjectMeta{ - Name: credentialsName, - Namespace: credentialsNamespace, - }, - TypeMeta: metav1.TypeMeta{ - APIVersion: "cloudcredential.openshift.io/v1", - Kind: "CredentialsRequest", - }, - Spec: cloudcredentialv1.CredentialsRequestSpec{ - SecretRef: corev1.ObjectReference{ - Name: operatorNamespace, - Namespace: operatorNamespace, - }, - ProviderSpec: &runtime.RawExtension{ - Object: &awsSpec, - }, - }, - } - return &request -} diff --git a/controllers/globaldnsrecord/route53provider.go b/controllers/globaldnsrecord/route53provider.go index 6571ba1..24966ce 100644 --- a/controllers/globaldnsrecord/route53provider.go +++ b/controllers/globaldnsrecord/route53provider.go @@ -5,11 +5,10 @@ import ( "encoding/json" "errors" "reflect" + "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" "github.com/aws/aws-sdk-go/service/route53" ocpconfigv1 "github.com/openshift/api/config/v1" redhatcopv1alpha1 "github.com/redhat-cop/global-load-balancer-operator/api/v1alpha1" @@ -125,17 +124,22 @@ func (r *GlobalDNSRecordReconciler) createHealthCheck(probe *corev1.Probe, route return "", err } //add tagging of health check - tagClient := resourcegroupstaggingapi.New(session.Must(session.NewSession()), &route53Client.Config) - _, err = tagClient.TagResources(&resourcegroupstaggingapi.TagResourcesInput{ - ResourceARNList: []*string{aws.String("arn:aws:route53:::healthcheck/" + *result.Location)}, - Tags: map[string]*string{ - "Name": aws.String(probe.HTTPGet.Host + "@" + ip), + healthCheckID := strings.Split(*result.Location, "/")[len(strings.Split(*result.Location, "/"))-1] + _, err = route53Client.ChangeTagsForResource(&route53.ChangeTagsForResourceInput{ + AddTags: []*route53.Tag{ + { + Key: aws.String("Name"), + Value: aws.String(probe.HTTPGet.Host + "@" + ip), + }, }, + ResourceId: aws.String(healthCheckID), + ResourceType: aws.String("healthcheck"), }) if err != nil { - r.Log.Error(err, "unable to tag", "health check", *result.Location) + r.Log.Error(err, "unable to tag", "health check", healthCheckID) + return "", err } - return *result.Location, nil + return healthCheckID, nil } func (r *GlobalDNSRecordReconciler) getAWSHealthCheckConfig(probe *corev1.Probe, ip string) (*route53.HealthCheckConfig, error) { @@ -286,9 +290,11 @@ func (r *GlobalDNSRecordReconciler) deleteTrafficPolicy(trafficPolicy *route53.T for _, endpointRuleReference := range endpointRuleRefereces { if endpointRuleReference.HealthCheck != "" { + healthcheckId := strings.Split(endpointRuleReference.HealthCheck, "/")[len(strings.Split(endpointRuleReference.HealthCheck, "/"))-1] deleteHealthCheckInput := route53.DeleteHealthCheckInput{ - HealthCheckId: aws.String(endpointRuleReference.HealthCheck), + HealthCheckId: aws.String(healthcheckId), } + r.Log.Info("about to delete", "HealthCheck", healthcheckId) _, err := route53Client.DeleteHealthCheck(&deleteHealthCheckInput) if err != nil { if aerr, ok := err.(awserr.Error); ok { @@ -299,7 +305,7 @@ func (r *GlobalDNSRecordReconciler) deleteTrafficPolicy(trafficPolicy *route53.T } default: { - r.Log.Error(err, "unable to delete", "healthcheck", endpointRuleReference.HealthCheck) + r.Log.Error(err, "unable to delete", "healthcheck", healthcheckId) return err } } @@ -583,6 +589,7 @@ func (r *GlobalDNSRecordReconciler) getAWSTrafficPolicyDocument(instance *redhat return "", err } route53EndpointRuleReference.HealthCheck = healthCheckID + route53EndpointRuleReference.EvaluateTargetHealth = true instance.Status.ProviderStatus.Route53.HealthCheckIDs[instance.Spec.Name+"@"+IP] = healthCheckID } route53EndpointRuleReferences = append(route53EndpointRuleReferences, route53EndpointRuleReference) @@ -614,6 +621,7 @@ func (r *GlobalDNSRecordReconciler) getAWSTrafficPolicyDocument(instance *redhat return "", err } route53EndpointRuleReference.HealthCheck = healthCheckID + route53EndpointRuleReference.EvaluateTargetHealth = true instance.Status.ProviderStatus.Route53.HealthCheckIDs[instance.Spec.Name+"@"+IP] = healthCheckID } route53EndpointRuleReferences = append(route53EndpointRuleReferences, route53EndpointRuleReference) @@ -644,6 +652,7 @@ func (r *GlobalDNSRecordReconciler) getAWSTrafficPolicyDocument(instance *redhat return "", err } route53EndpointRuleReference.HealthCheck = healthCheckID + route53EndpointRuleReference.EvaluateTargetHealth = true instance.Status.ProviderStatus.Route53.HealthCheckIDs[instance.Spec.Name+"@"+IP] = healthCheckID } route53EndpointRuleReferences = append(route53EndpointRuleReferences, route53EndpointRuleReference) diff --git a/controllers/globaldnszone/globaldnszone_controller.go b/controllers/globaldnszone/globaldnszone_controller.go index b6ac3ec..6a537e0 100644 --- a/controllers/globaldnszone/globaldnszone_controller.go +++ b/controllers/globaldnszone/globaldnszone_controller.go @@ -42,6 +42,7 @@ type GlobalDNSZoneReconciler struct { // +kubebuilder:rbac:groups=redhatcop.redhat.io,resources=globaldnszones,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=redhatcop.redhat.io,resources=globaldnszones/status,verbs=get;update;patch // +kubebuilder:rbac:groups=redhatcop.redhat.io,resources=globaldnszones/finalizers,verbs=update +// +kubebuilder:rbac:groups="cloudcredential.openshift.io",resources=credentialsrequests,verbs=get;list;watch;create;update // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. diff --git a/main.go b/main.go index 08209f3..3ac11c3 100644 --- a/main.go +++ b/main.go @@ -26,6 +26,7 @@ import ( operatorv1 "github.com/openshift/api/operator/v1" routev1 "github.com/openshift/api/route/v1" + cloudcredentialv1 "github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1" redhatcopv1alpha1 "github.com/redhat-cop/global-load-balancer-operator/api/v1alpha1" "github.com/redhat-cop/global-load-balancer-operator/controllers/globaldnsrecord" "github.com/redhat-cop/global-load-balancer-operator/controllers/globaldnszone" @@ -52,6 +53,7 @@ func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(redhatcopv1alpha1.AddToScheme(scheme)) + utilruntime.Must(cloudcredentialv1.AddToScheme(scheme)) utilruntime.Must(routev1.AddToScheme(scheme)) utilruntime.Must(operatorv1.AddToScheme(scheme)) utilruntime.Must(addEnpointToScheme(scheme)) diff --git a/readme.md b/readme.md index a5eeb4c..f3069fa 100644 --- a/readme.md +++ b/readme.md @@ -262,10 +262,11 @@ helm upgrade global-load-balancer-operator global-load-balancer-operator/global- ```shell make install oc new-project global-load-balancer-operator-local +oc create serviceaccount global-load-balancer-controller-manager kustomize build ./config/local-development | oc apply -f - -n global-load-balancer-operator-local -export token=$(oc serviceaccounts get-token 'global-load-balancer-operator-controller-manager' -n global-load-balancer-operator-local) +export token=$(oc serviceaccounts get-token 'global-load-balancer-controller-manager' -n global-load-balancer-operator-local) oc login --token ${token} -make run ENABLE_WEBHOOKS=false +make run ENABLE_WEBHOOKS=false NAMESPACE=global-load-balancer-operator-local ``` ### Test helm chart locally