From d616cfe4648a10fa9ca775eee378b59f1f8bd5bb Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 5 Dec 2024 13:01:36 +0100 Subject: [PATCH 01/15] Implement basic reconciliation logic in controller and manager. --- api/v1alpha1/awsiamprovision_types.go | 28 +- api/v1alpha1/zz_generated.deepcopy.go | 84 +++++- cmd/main.go | 109 ++++--- .../iam.aws.edenlab.io_awsiamprovisions.yaml | 57 +++- .../samples/iam_v1alpha1_awsiamprovision.yaml | 215 +++++++++++++- go.mod | 56 ++-- go.sum | 130 ++++---- .../controller/awsiamprovision_controller.go | 46 ++- .../awsiamprovision_controller_test.go | 84 ------ internal/controller/reconciliation_manager.go | 278 ++++++++++++++++++ 10 files changed, 813 insertions(+), 274 deletions(-) delete mode 100644 internal/controller/awsiamprovision_controller_test.go create mode 100644 internal/controller/reconciliation_manager.go diff --git a/api/v1alpha1/awsiamprovision_types.go b/api/v1alpha1/awsiamprovision_types.go index 21fd775..951a241 100644 --- a/api/v1alpha1/awsiamprovision_types.go +++ b/api/v1alpha1/awsiamprovision_types.go @@ -23,23 +23,47 @@ import ( // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. +type AWSIAMProvisionPolicySpec struct { + PolicyDocument string `json:"policyDocument"` +} + +type AWSIAMProvisionPolicy struct { + Spec AWSIAMProvisionPolicySpec `json:"spec"` +} + +type AWSIAMProvisionRoleSpec struct { + AssumeRolePolicyDocument string `json:"assumeRolePolicyDocument"` + MaxSessionDuration int64 `json:"maxSessionDuration"` +} + +type AWSIAMProvisionRole struct { + Spec AWSIAMProvisionRoleSpec `json:"spec"` +} + // AWSIAMProvisionSpec defines the desired state of AWSIAMProvision. type AWSIAMProvisionSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file - // Foo is an example field of AWSIAMProvision. Edit awsiamprovision_types.go to remove/update - Foo string `json:"foo,omitempty"` + EksClusterName string `json:"eksClusterName"` + Role map[string]AWSIAMProvisionRole `json:"role"` + Policies map[string]AWSIAMProvisionPolicy `json:"policies"` } // AWSIAMProvisionStatus defines the observed state of AWSIAMProvision. type AWSIAMProvisionStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file + + Error string `json:"error,omitempty"` + LastUpdatedTime *metav1.Time `json:"lastUpdatedTime,omitempty"` + Phase string `json:"phase,omitempty"` } // +kubebuilder:object:root=true // +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="PHASE",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="LAST-UPDATED-TIME",type=string,JSONPath=".status.lastUpdatedTime" // AWSIAMProvision is the Schema for the awsiamprovisions API. type AWSIAMProvision struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index bb67fcc..1662483 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -29,8 +29,8 @@ func (in *AWSIAMProvision) DeepCopyInto(out *AWSIAMProvision) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSIAMProvision. @@ -83,9 +83,85 @@ func (in *AWSIAMProvisionList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSIAMProvisionPolicy) DeepCopyInto(out *AWSIAMProvisionPolicy) { + *out = *in + out.Spec = in.Spec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSIAMProvisionPolicy. +func (in *AWSIAMProvisionPolicy) DeepCopy() *AWSIAMProvisionPolicy { + if in == nil { + return nil + } + out := new(AWSIAMProvisionPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSIAMProvisionPolicySpec) DeepCopyInto(out *AWSIAMProvisionPolicySpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSIAMProvisionPolicySpec. +func (in *AWSIAMProvisionPolicySpec) DeepCopy() *AWSIAMProvisionPolicySpec { + if in == nil { + return nil + } + out := new(AWSIAMProvisionPolicySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSIAMProvisionRole) DeepCopyInto(out *AWSIAMProvisionRole) { + *out = *in + out.Spec = in.Spec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSIAMProvisionRole. +func (in *AWSIAMProvisionRole) DeepCopy() *AWSIAMProvisionRole { + if in == nil { + return nil + } + out := new(AWSIAMProvisionRole) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSIAMProvisionRoleSpec) DeepCopyInto(out *AWSIAMProvisionRoleSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSIAMProvisionRoleSpec. +func (in *AWSIAMProvisionRoleSpec) DeepCopy() *AWSIAMProvisionRoleSpec { + if in == nil { + return nil + } + out := new(AWSIAMProvisionRoleSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AWSIAMProvisionSpec) DeepCopyInto(out *AWSIAMProvisionSpec) { *out = *in + if in.Role != nil { + in, out := &in.Role, &out.Role + *out = make(map[string]AWSIAMProvisionRole, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Policies != nil { + in, out := &in.Policies, &out.Policies + *out = make(map[string]AWSIAMProvisionPolicy, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSIAMProvisionSpec. @@ -101,6 +177,10 @@ func (in *AWSIAMProvisionSpec) DeepCopy() *AWSIAMProvisionSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AWSIAMProvisionStatus) DeepCopyInto(out *AWSIAMProvisionStatus) { *out = *in + if in.LastUpdatedTime != nil { + in, out := &in.LastUpdatedTime, &out.LastUpdatedTime + *out = (*in).DeepCopy() + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSIAMProvisionStatus. diff --git a/cmd/main.go b/cmd/main.go index a2b74c3..8875ab4 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -17,26 +17,28 @@ limitations under the License. package main import ( - "crypto/tls" "flag" + "fmt" + "go.uber.org/zap/zapcore" "os" + "sigs.k8s.io/controller-runtime/pkg/cache" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "strings" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. _ "k8s.io/client-go/plugin/pkg/client/auth" + iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" + "aws-iam-provisioner.operators.infra/internal/controller" + iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" + cpv1beta2 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" - "sigs.k8s.io/controller-runtime/pkg/metrics/filters" - metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" - "sigs.k8s.io/controller-runtime/pkg/webhook" - - iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" - "aws-iam-provisioner.operators.infra/internal/controller" // +kubebuilder:scaffold:imports ) @@ -47,8 +49,9 @@ var ( func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - utilruntime.Must(iamv1alpha1.AddToScheme(scheme)) + utilruntime.Must(iamctrlv1alpha1.AddToScheme(scheme)) + utilruntime.Must(cpv1beta2.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } @@ -56,72 +59,29 @@ func main() { var metricsAddr string var enableLeaderElection bool var probeAddr string - var secureMetrics bool - var enableHTTP2 bool - var tlsOpts []func(*tls.Config) flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") flag.BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") - flag.BoolVar(&secureMetrics, "metrics-secure", true, - "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") - flag.BoolVar(&enableHTTP2, "enable-http2", false, - "If set, HTTP/2 will be enabled for the metrics and webhook servers") - opts := zap.Options{ - Development: true, - } + opts := zap.Options{Development: true, StacktraceLevel: zapcore.DPanicLevel} opts.BindFlags(flag.CommandLine) flag.Parse() ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) - // if the enable-http2 flag is false (the default), http/2 should be disabled - // due to its vulnerabilities. More specifically, disabling http/2 will - // prevent from being vulnerable to the HTTP/2 Stream Cancellation and - // Rapid Reset CVEs. For more information see: - // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 - // - https://github.com/advisories/GHSA-4374-p667-p6c8 - disableHTTP2 := func(c *tls.Config) { - setupLog.Info("disabling http/2") - c.NextProtos = []string{"http/1.1"} - } - - if !enableHTTP2 { - tlsOpts = append(tlsOpts, disableHTTP2) - } - - webhookServer := webhook.NewServer(webhook.Options{ - TLSOpts: tlsOpts, - }) - // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. // More info: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/server // - https://book.kubebuilder.io/reference/metrics.html metricsServerOptions := metricsserver.Options{ - BindAddress: metricsAddr, - SecureServing: secureMetrics, - TLSOpts: tlsOpts, - } - - if secureMetrics { - // FilterProvider is used to protect the metrics endpoint with authn/authz. - // These configurations ensure that only authorized users and service accounts - // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: - // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/filters#WithAuthenticationAndAuthorization - metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization - - // TODO(user): If CertDir, CertName, and KeyName are not specified, controller-runtime will automatically - // generate self-signed certificates for the metrics server. While convenient for development and testing, - // this setup is not recommended for production. + BindAddress: metricsAddr, } - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + options := ctrl.Options{ Scheme: scheme, Metrics: metricsServerOptions, - WebhookServer: webhookServer, HealthProbeBindAddress: probeAddr, LeaderElection: enableLeaderElection, LeaderElectionID: "223fc060.aws.edenlab.io", @@ -136,7 +96,31 @@ func main() { // if you are doing or is intended to do any operation such as perform cleanups // after the manager stops then its usage might be unsafe. // LeaderElectionReleaseOnCancel: true, - }) + } + + watchNamespaces, err := getWatchNamespaces() + if err != nil { + setupLog.Info("unable to get WATCH_NAMESPACES env, " + + "the manager will watch and manage resources in all namespaces") + } + + // Add support for watching multiple namespaces set in WATCH_NAMESPACES (e.g. ns1,ns2) + if len(watchNamespaces) > 0 { + setupLog.Info("manager set up with multiple namespaces", "namespaces", watchNamespaces) + + cacheConfigMap := map[string]cache.Config{} + + for _, namespace := range strings.Split(watchNamespaces, ",") { + cacheConfigMap[namespace] = cache.Config{} + } + + options.Cache = cache.Options{ + DefaultNamespaces: cacheConfigMap, + } + } + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), options) + if err != nil { setupLog.Error(err, "unable to start manager") os.Exit(1) @@ -166,3 +150,18 @@ func main() { os.Exit(1) } } + +// getWatchNamespaces returns the Namespace the operator should be watching for changes +func getWatchNamespaces() (string, error) { + // WatchNamespaceEnvVar is the constant for env variable WATCH_NAMESPACE + // which specifies the Namespace to watch. + // An empty value means the operator is running with cluster scope. + var watchNamespaceEnvVar = "WATCH_NAMESPACES" + + ns, found := os.LookupEnv(watchNamespaceEnvVar) + if !found { + return "", fmt.Errorf("%s env must be set", watchNamespaceEnvVar) + } + + return ns, nil +} diff --git a/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml b/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml index bf43ead..ee4cec4 100644 --- a/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml +++ b/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml @@ -14,7 +14,14 @@ spec: singular: awsiamprovision scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .status.phase + name: PHASE + type: string + - jsonPath: .status.lastUpdatedTime + name: LAST-UPDATED-TIME + type: string + name: v1alpha1 schema: openAPIV3Schema: description: AWSIAMProvision is the Schema for the awsiamprovisions API. @@ -39,13 +46,55 @@ spec: spec: description: AWSIAMProvisionSpec defines the desired state of AWSIAMProvision. properties: - foo: - description: Foo is an example field of AWSIAMProvision. Edit awsiamprovision_types.go - to remove/update + eksClusterName: type: string + policies: + additionalProperties: + properties: + spec: + properties: + policyDocument: + type: string + required: + - policyDocument + type: object + required: + - spec + type: object + type: object + role: + additionalProperties: + properties: + spec: + properties: + assumeRolePolicyDocument: + type: string + maxSessionDuration: + format: int64 + type: integer + required: + - assumeRolePolicyDocument + - maxSessionDuration + type: object + required: + - spec + type: object + type: object + required: + - eksClusterName + - policies + - role type: object status: description: AWSIAMProvisionStatus defines the observed state of AWSIAMProvision. + properties: + error: + type: string + lastUpdatedTime: + format: date-time + type: string + phase: + type: string type: object type: object served: true diff --git a/config/samples/iam_v1alpha1_awsiamprovision.yaml b/config/samples/iam_v1alpha1_awsiamprovision.yaml index 36e0f45..de87bd8 100644 --- a/config/samples/iam_v1alpha1_awsiamprovision.yaml +++ b/config/samples/iam_v1alpha1_awsiamprovision.yaml @@ -4,6 +4,217 @@ metadata: labels: app.kubernetes.io/name: aws-iam-provisioner app.kubernetes.io/managed-by: kustomize - name: awsiamprovision-sample + name: deps-ffs-1-ebs-csi-controller spec: - # TODO(user): Add fields here + eksClusterName: deps-ffs-1 + role: + deps-ffs-1-ebs-csi-controller: + spec: + assumeRolePolicyDocument: | + { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "", + "Effect": "Allow", + "Principal": { + "Federated": "{{ .OIDCProviderARN }}" + }, + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": { + "StringEquals": { + "{{ .OIDCProviderName }}:sub": "system:serviceaccount:kube-system:ebs-csi-controller" + } + } + } + ] + } + maxSessionDuration: 3600 + policies: + deps-ffs-1-ebs-csi-controller-core: + spec: + policyDocument: | + { + "Statement": [ + { + "Action": [ + "ec2:CreateSnapshot", + "ec2:AttachVolume", + "ec2:DetachVolume", + "ec2:ModifyVolume", + "ec2:DescribeAvailabilityZones", + "ec2:DescribeInstances", + "ec2:DescribeSnapshots", + "ec2:DescribeTags", + "ec2:DescribeVolumes", + "ec2:DescribeVolumesModifications" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:CreateTags" + ], + "Condition": { + "StringEquals": { + "ec2:CreateAction": [ + "CreateVolume", + "CreateSnapshot" + ] + } + }, + "Effect": "Allow", + "Resource": [ + "arn:aws:ec2:*:*:volume/*", + "arn:aws:ec2:*:*:snapshot/*" + ] + }, + { + "Action": [ + "ec2:DeleteTags" + ], + "Effect": "Allow", + "Resource": [ + "arn:aws:ec2:*:*:volume/*", + "arn:aws:ec2:*:*:snapshot/*" + ] + }, + { + "Action": [ + "ec2:CreateVolume" + ], + "Condition": { + "StringLike": { + "aws:RequestTag/ebs.csi.aws.com/cluster": "true" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:CreateVolume" + ], + "Condition": { + "StringLike": { + "aws:RequestTag/CSIVolumeName": "*" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:CreateVolume" + ], + "Condition": { + "StringLike": { + "aws:RequestTag/kubernetes.io/cluster/*": "owned" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:DeleteVolume" + ], + "Condition": { + "StringLike": { + "ec2:ResourceTag/ebs.csi.aws.com/cluster": "true" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:DeleteVolume" + ], + "Condition": { + "StringLike": { + "ec2:ResourceTag/CSIVolumeName": "*" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:DeleteVolume" + ], + "Condition": { + "StringLike": { + "ec2:ResourceTag/kubernetes.io/cluster/*": "owned" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:DeleteSnapshot" + ], + "Condition": { + "StringLike": { + "ec2:ResourceTag/CSIVolumeSnapshotName": "*" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "ec2:DeleteSnapshot" + ], + "Condition": { + "StringLike": { + "ec2:ResourceTag/ebs.csi.aws.com/cluster": "true" + } + }, + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + deps-ffs-1-ebs-csi-controller-kms: + spec: + policyDocument: | + { + "Statement": [ + { + "Action": [ + "kms:CreateGrant", + "kms:ListGrants", + "kms:RevokeGrant" + ], + "Condition": { + "Bool": { + "kms:GrantIsForAWSResource": "true" + } + }, + "Effect": "Allow", + "Resource": [ + "arn:aws:kms:*:*:alias/*", + "arn:aws:kms:*:*:key/*" + ] + }, + { + "Action": [ + "kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:DescribeKey" + ], + "Effect": "Allow", + "Resource": [ + "arn:aws:kms:*:*:alias/*", + "arn:aws:kms:*:*:key/*" + ] + } + ], + "Version": "2012-10-17" + } diff --git a/go.mod b/go.mod index b9a2c11..bac5bbd 100644 --- a/go.mod +++ b/go.mod @@ -3,28 +3,29 @@ module aws-iam-provisioner.operators.infra go 1.22.0 require ( - github.com/onsi/ginkgo/v2 v2.19.0 - github.com/onsi/gomega v1.33.1 + github.com/aws-controllers-k8s/iam-controller v1.3.13 + github.com/onsi/ginkgo/v2 v2.19.1 + github.com/onsi/gomega v1.34.0 + go.uber.org/zap v1.27.0 k8s.io/apimachinery v0.31.0 k8s.io/client-go v0.31.0 + sigs.k8s.io/cluster-api-provider-aws/v2 v2.7.1 sigs.k8s.io/controller-runtime v0.19.1 ) require ( - github.com/antlr4-go/antlr/v4 v4.13.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect + github.com/apparentlymart/go-cidr v1.1.0 // indirect + github.com/aws-controllers-k8s/runtime v0.39.0 // indirect + github.com/aws/aws-sdk-go v1.55.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect - github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect @@ -33,15 +34,13 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/cel-go v0.20.1 // indirect - github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect - github.com/imdario/mergo v0.3.6 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -53,45 +52,30 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/spf13/cobra v1.8.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace // indirect github.com/x448/float16 v0.8.4 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.26.0 // indirect - golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect - golang.org/x/net v0.26.0 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/term v0.21.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/grpc v1.65.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.31.0 // indirect k8s.io/apiextensions-apiserver v0.31.0 // indirect - k8s.io/apiserver v0.31.0 // indirect k8s.io/component-base v0.31.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect + sigs.k8s.io/cluster-api v1.8.4 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 0958667..4d6d869 100644 --- a/go.sum +++ b/go.sum @@ -1,38 +1,36 @@ -github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= -github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= +github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= +github.com/aws-controllers-k8s/iam-controller v1.3.13 h1:+8gBtaaz72UENArVq4T26kMNUi4Gs9N+UuGFY3gAtGA= +github.com/aws-controllers-k8s/iam-controller v1.3.13/go.mod h1:R/W8Z7TI1e+OXf7tePZUcAqA4z6UZ/7zR0t/Yg5Bt1U= +github.com/aws-controllers-k8s/runtime v0.39.0 h1:IgOXluSzvb4UcDr9eU7SPw5MJnL7kt5R6DuF5Qu9zVQ= +github.com/aws-controllers-k8s/runtime v0.39.0/go.mod h1:G07g26y1cxyZO6Ngp+LwXf03CqFyLNL7os4Py4IdyGY= +github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= +github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= -github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= +github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= +github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= @@ -44,16 +42,18 @@ github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogB github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= +github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= -github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU= +github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1:BkkQ4L1KS1xMt2aWSPStnn55ChGC0DPOn2FQYj+f25M= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -64,12 +64,12 @@ github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2 github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -92,10 +92,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0= +github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA= +github.com/onsi/gomega v1.34.0 h1:eSSPsPNp6ZpsG8X1OVmOTxig+CblTc4AxpPBykhe2Os= +github.com/onsi/gomega v1.34.0/go.mod h1:MIKI8c+f+QLWk+hxbePD4i0LMJSExPaZOVfkoex4cAo= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -111,18 +111,12 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace h1:9PNP1jnUjRhfmGMlkXHjYPishpcw4jpSt/V/xYY3FMA= +github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -132,61 +126,45 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= -golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -199,12 +177,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -214,11 +186,11 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSP gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= @@ -227,8 +199,6 @@ k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24 k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY= -k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk= k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs= @@ -239,8 +209,10 @@ k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7F k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/cluster-api v1.8.4 h1:jBKQH1H/HUdUFk8T6qDzIxZJfWw1F5ZP0ZpYQJDmTHs= +sigs.k8s.io/cluster-api v1.8.4/go.mod h1:pXv5LqLxuIbhGIXykyNKiJh+KrLweSBajVHHitPLyoY= +sigs.k8s.io/cluster-api-provider-aws/v2 v2.7.1 h1:NmsH/IZsMIiQV/kfJY7+mNriqvk5ImCGZrnmbxUMEM0= +sigs.k8s.io/cluster-api-provider-aws/v2 v2.7.1/go.mod h1:fQ/aPIQs1YKb1hDJtibBY7kspUqvXb9JSWIYkzWlX34= sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk= sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/internal/controller/awsiamprovision_controller.go b/internal/controller/awsiamprovision_controller.go index 1199b35..11327dd 100644 --- a/internal/controller/awsiamprovision_controller.go +++ b/internal/controller/awsiamprovision_controller.go @@ -18,19 +18,25 @@ package controller import ( "context" - "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "time" iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" + iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" +) + +const ( + frequency = time.Second * 10 ) // AWSIAMProvisionReconciler reconciles a AWSIAMProvision object type AWSIAMProvisionReconciler struct { client.Client Scheme *runtime.Scheme + rm *ReconciliationManager } // +kubebuilder:rbac:groups=iam.aws.edenlab.io,resources=awsiamprovisions,verbs=get;list;watch;create;update;patch;delete @@ -39,25 +45,45 @@ type AWSIAMProvisionReconciler struct { // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. -// TODO(user): Modify the Reconcile function to compare the state specified by -// the AWSIAMProvision object against the actual cluster state, and then -// perform operations to make the cluster state reflect the state specified by -// the user. // // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/reconcile func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - _ = log.FromContext(ctx) + rm := NewReconciliationManager(r, &ctx, &req) + + awsIAMProvision, eksControlPlane, err := rm.GetClusterResources() + if err != nil { + return ctrl.Result{}, err + } + + var policies []*iamctrlv1alpha1.Policy + for name, item := range awsIAMProvision.Spec.Policies { + k8sResource, err := rm.HandlePolicy(awsIAMProvision, name, &item) + if err != nil { + return ctrl.Result{}, err + } + + policies = append(policies, k8sResource) + } + + for name, item := range awsIAMProvision.Spec.Role { + _, err := rm.HandleRole(awsIAMProvision, eksControlPlane, policies, name, &item) + if err != nil { + return ctrl.Result{}, err + } + } - // TODO(user): your logic here + if err := rm.UpdateCRDStatus(awsIAMProvision, "Provisioned", ""); err != nil { + return ctrl.Result{}, err + } - return ctrl.Result{}, nil + return ctrl.Result{RequeueAfter: frequency}, nil } // SetupWithManager sets up the controller with the Manager. func (r *AWSIAMProvisionReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&iamv1alpha1.AWSIAMProvision{}). - Named("awsiamprovision"). + WithEventFilter(predicate.GenerationChangedPredicate{}). Complete(r) } diff --git a/internal/controller/awsiamprovision_controller_test.go b/internal/controller/awsiamprovision_controller_test.go deleted file mode 100644 index df4a1a4..0000000 --- a/internal/controller/awsiamprovision_controller_test.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 2024 anovikov-el. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controller - -import ( - "context" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" -) - -var _ = Describe("AWSIAMProvision Controller", func() { - Context("When reconciling a resource", func() { - const resourceName = "test-resource" - - ctx := context.Background() - - typeNamespacedName := types.NamespacedName{ - Name: resourceName, - Namespace: "default", // TODO(user):Modify as needed - } - awsiamprovision := &iamv1alpha1.AWSIAMProvision{} - - BeforeEach(func() { - By("creating the custom resource for the Kind AWSIAMProvision") - err := k8sClient.Get(ctx, typeNamespacedName, awsiamprovision) - if err != nil && errors.IsNotFound(err) { - resource := &iamv1alpha1.AWSIAMProvision{ - ObjectMeta: metav1.ObjectMeta{ - Name: resourceName, - Namespace: "default", - }, - // TODO(user): Specify other spec details if needed. - } - Expect(k8sClient.Create(ctx, resource)).To(Succeed()) - } - }) - - AfterEach(func() { - // TODO(user): Cleanup logic after each test, like removing the resource instance. - resource := &iamv1alpha1.AWSIAMProvision{} - err := k8sClient.Get(ctx, typeNamespacedName, resource) - Expect(err).NotTo(HaveOccurred()) - - By("Cleanup the specific resource instance AWSIAMProvision") - Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) - }) - It("should successfully reconcile the resource", func() { - By("Reconciling the created resource") - controllerReconciler := &AWSIAMProvisionReconciler{ - Client: k8sClient, - Scheme: k8sClient.Scheme(), - } - - _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ - NamespacedName: typeNamespacedName, - }) - Expect(err).NotTo(HaveOccurred()) - // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. - // Example: If you expect a certain status condition after reconciliation, verify it here. - }) - }) -}) diff --git a/internal/controller/reconciliation_manager.go b/internal/controller/reconciliation_manager.go new file mode 100644 index 0000000..3f398ca --- /dev/null +++ b/internal/controller/reconciliation_manager.go @@ -0,0 +1,278 @@ +package controller + +import ( + iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" + "bytes" + "context" + "errors" + "fmt" + iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" + ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" + "github.com/go-logr/logr" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/log" + "strings" + "text/template" + "time" +) + +var ( + policyMeta = metav1.TypeMeta{ + APIVersion: "iam.services.k8s.aws", + Kind: "Policy", + } + roleMeta = metav1.TypeMeta{ + APIVersion: "iam.services.k8s.aws", + Kind: "Role", + } +) + +type oidcProviderTemplateData struct { + OIDCProviderARN string + OIDCProviderName string +} + +type ReconciliationManager struct { + r *AWSIAMProvisionReconciler + ctx *context.Context + req *ctrl.Request + logger *logr.Logger +} + +func NewReconciliationManager(r *AWSIAMProvisionReconciler, ctx *context.Context, req *ctrl.Request) *ReconciliationManager { + logger := log.FromContext(*ctx) + + return &ReconciliationManager{ + r, + ctx, + req, + &logger, + } +} + +func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvision, *ekscontrolplanev1.AWSManagedControlPlane, error) { + awsIAMProvision := &iamv1alpha1.AWSIAMProvision{} + + if err := rm.r.Client.Get(*rm.ctx, rm.req.NamespacedName, awsIAMProvision); err != nil { + if k8serrors.IsNotFound(err) { + err = errors.New(fmt.Sprintf("Cannot find AWSIAMProvision: %s", rm.req.NamespacedName)) + } + + return nil, nil, err + } + + rm.logger.Info(fmt.Sprintf("Found AWSIAMProvision: %s", rm.req.NamespacedName)) + + eksControlPlane := &ekscontrolplanev1.AWSManagedControlPlane{} + eksControlPlaneNamespacedName := types.NamespacedName{Name: awsIAMProvision.Spec.EksClusterName, Namespace: rm.req.NamespacedName.Namespace} + + if err := rm.r.Client.Get(*rm.ctx, eksControlPlaneNamespacedName, eksControlPlane); err != nil { + if k8serrors.IsNotFound(err) { + err = errors.New(fmt.Sprintf("Cannot get AWSManagedControlPlane: %s", eksControlPlaneNamespacedName)) + } + + if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + return nil, nil, err + } + + return nil, nil, err + } + + rm.logger.Info(fmt.Sprintf("Found AWSManagedControlPlane: %s", eksControlPlaneNamespacedName)) + + if !eksControlPlane.Status.Ready { + err := errors.New(fmt.Sprintf("AWSManagedControlPlane not ready: %s", eksControlPlaneNamespacedName)) + + if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + return nil, nil, err + } + + return nil, nil, err + } + + return awsIAMProvision, eksControlPlane, nil +} + +func (rm *ReconciliationManager) HandlePolicy(awsIAMProvision *iamv1alpha1.AWSIAMProvision, name string, item *iamv1alpha1.AWSIAMProvisionPolicy) (*iamctrlv1alpha1.Policy, error) { + k8sResource := &iamctrlv1alpha1.Policy{} + k8sResourceNamespacedName := types.NamespacedName{Name: name, Namespace: rm.req.NamespacedName.Namespace} + + if err := rm.r.Client.Get(*rm.ctx, k8sResourceNamespacedName, k8sResource); err != nil { + if k8serrors.IsNotFound(err) { + // Create new policy + k8sResource.TypeMeta = policyMeta + k8sResource.ObjectMeta = metav1.ObjectMeta{ + Name: name, + Namespace: rm.req.NamespacedName.Namespace, + } + k8sResource.Spec.PolicyDocument = &item.Spec.PolicyDocument + k8sResource.Spec.Name = &name + + // Used to ensure that the created resource will be deleted when the custom resource object is removed + if err := ctrl.SetControllerReference(awsIAMProvision, k8sResource, rm.r.Scheme); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + return nil, err + } + + return nil, err + } + + if err = rm.r.Client.Create(*rm.ctx, k8sResource); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + return nil, err + } + + return nil, err + } + + rm.logger.Info(fmt.Sprintf("Created IAM Policy: %s", k8sResourceNamespacedName)) + } else { + return nil, err + } + } else { + rm.logger.Info(*k8sResource.Spec.PolicyDocument) + rm.logger.Info(item.Spec.PolicyDocument) + + if k8sResource.Spec.PolicyDocument != &item.Spec.PolicyDocument { + // Update policy with new values + k8sResource.Spec.PolicyDocument = &item.Spec.PolicyDocument + + if err := rm.r.Client.Update(*rm.ctx, k8sResource); err != nil { + return nil, err + } + + rm.logger.Info(fmt.Sprintf("Updated IAM Policy: %s", k8sResourceNamespacedName)) + } + } + + return k8sResource, nil +} + +func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, policies []*iamctrlv1alpha1.Policy, name string, item *iamv1alpha1.AWSIAMProvisionRole) (*iamctrlv1alpha1.Role, error) { + k8sResource := &iamctrlv1alpha1.Role{} + k8sResourceNamespacedName := types.NamespacedName{Name: name, Namespace: rm.req.NamespacedName.Namespace} + + oidcProviderArn := eksControlPlane.Status.OIDCProvider.ARN + _, oidcProviderName, oidcProviderArnFound := strings.Cut(oidcProviderArn, "/") + + if !oidcProviderArnFound { + err := errors.New(fmt.Sprintf("OIDC ARN malformed: %s", oidcProviderArn)) + + if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + return nil, err + } + + return nil, err + } + + if err := rm.r.Client.Get(*rm.ctx, k8sResourceNamespacedName, k8sResource); err != nil { + if k8serrors.IsNotFound(err) { + // Create new role + k8sResource.TypeMeta = roleMeta + k8sResource.ObjectMeta = metav1.ObjectMeta{ + Name: name, + Namespace: rm.req.NamespacedName.Namespace, + } + + assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(item.Spec.AssumeRolePolicyDocument, oidcProviderArn, oidcProviderName) + if err != nil { + return nil, err + } + + k8sResource.Spec.AssumeRolePolicyDocument = &assumeRolePolicyDocument + k8sResource.Spec.MaxSessionDuration = &item.Spec.MaxSessionDuration + k8sResource.Spec.Name = &name + k8sResource.Spec.PolicyRefs = rm.transformPoliciesToRefs(policies) + + // Used to ensure that the created resource will be deleted when the custom resource object is removed + if err := ctrl.SetControllerReference(awsIAMProvision, k8sResource, rm.r.Scheme); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + return nil, err + } + + return nil, err + } + + if err = rm.r.Client.Create(*rm.ctx, k8sResource); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + return nil, err + } + + return nil, err + } + + rm.logger.Info(fmt.Sprintf("Created IAM Role: %s", k8sResourceNamespacedName)) + } else { + return nil, err + } + } else { + // Update role with new values + assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(item.Spec.AssumeRolePolicyDocument, oidcProviderArn, oidcProviderName) + if err != nil { + return nil, err + } + + if k8sResource.Spec.AssumeRolePolicyDocument != &assumeRolePolicyDocument || + k8sResource.Spec.MaxSessionDuration != &item.Spec.MaxSessionDuration || + len(k8sResource.Spec.PolicyRefs) != len(policies) { // todo check policy refs differ + k8sResource.Spec.AssumeRolePolicyDocument = &assumeRolePolicyDocument + k8sResource.Spec.MaxSessionDuration = &item.Spec.MaxSessionDuration + k8sResource.Spec.PolicyRefs = rm.transformPoliciesToRefs(policies) + + if err := rm.r.Client.Update(*rm.ctx, k8sResource); err != nil { + return nil, err + } + + rm.logger.Info(fmt.Sprintf("Updated IAM Role: %s", k8sResourceNamespacedName)) + } + } + + return k8sResource, nil +} + +func (rm *ReconciliationManager) renderOIDCProviderTemplate(oidcProviderTemplate, oidcProviderArn, oidcProviderName string) (string, error) { + oidcProviderTemplateData := oidcProviderTemplateData{oidcProviderArn, oidcProviderName} + + tmpl, err := template.New("").Parse(oidcProviderTemplate) + if err != nil { + return "", err + } + + var tmplString bytes.Buffer + if err := tmpl.Execute(&tmplString, oidcProviderTemplateData); err != nil { + return "", err + } + + return tmplString.String(), nil +} + +func (rm *ReconciliationManager) transformPoliciesToRefs(policies []*iamctrlv1alpha1.Policy) []*ackv1alpha1.AWSResourceReferenceWrapper { + var policyRefs []*ackv1alpha1.AWSResourceReferenceWrapper + + for _, policy := range policies { + policyRefs = append(policyRefs, &ackv1alpha1.AWSResourceReferenceWrapper{ + From: &ackv1alpha1.AWSResourceReference{ + Name: &policy.Name, + Namespace: &policy.Namespace, + }, + }) + } + + return policyRefs +} + +func (rm *ReconciliationManager) UpdateCRDStatus(awsIAMProvision *iamv1alpha1.AWSIAMProvision, phase, errText string) error { + awsIAMProvision.Status.LastUpdatedTime = &metav1.Time{Time: time.Now()} + awsIAMProvision.Status.Phase = phase + awsIAMProvision.Status.Error = errText + + if err := rm.r.Status().Update(*rm.ctx, awsIAMProvision); err != nil { + return errors.New(fmt.Sprintf("Unable to update status for CRD: %s", awsIAMProvision.Name)) + } + + return nil +} From be613f6f3488ce6097742f4694a558db9a7f8ebc Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Wed, 11 Dec 2024 19:52:40 +0100 Subject: [PATCH 02/15] Embed iamctrlv1alpha1.RoleSpec into AWSIAMProvisionRole. Remove static IAM policy management (will be managed by aws-iam-controller and the config chart). --- api/v1alpha1/awsiamprovision_types.go | 21 +- api/v1alpha1/zz_generated.deepcopy.go | 57 +---- .../iam.aws.edenlab.io_awsiamprovisions.yaml | 171 +++++++++++++-- .../samples/iam_v1alpha1_awsiamprovision.yaml | 197 +----------------- .../controller/awsiamprovision_controller.go | 15 +- internal/controller/reconciliation_manager.go | 132 ++++++------ 6 files changed, 234 insertions(+), 359 deletions(-) diff --git a/api/v1alpha1/awsiamprovision_types.go b/api/v1alpha1/awsiamprovision_types.go index 951a241..96cff61 100644 --- a/api/v1alpha1/awsiamprovision_types.go +++ b/api/v1alpha1/awsiamprovision_types.go @@ -17,27 +17,15 @@ limitations under the License. package v1alpha1 import ( + iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. -type AWSIAMProvisionPolicySpec struct { - PolicyDocument string `json:"policyDocument"` -} - -type AWSIAMProvisionPolicy struct { - Spec AWSIAMProvisionPolicySpec `json:"spec"` -} - -type AWSIAMProvisionRoleSpec struct { - AssumeRolePolicyDocument string `json:"assumeRolePolicyDocument"` - MaxSessionDuration int64 `json:"maxSessionDuration"` -} - type AWSIAMProvisionRole struct { - Spec AWSIAMProvisionRoleSpec `json:"spec"` + Spec iamctrlv1alpha1.RoleSpec `json:"spec"` } // AWSIAMProvisionSpec defines the desired state of AWSIAMProvision. @@ -45,9 +33,8 @@ type AWSIAMProvisionSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file - EksClusterName string `json:"eksClusterName"` - Role map[string]AWSIAMProvisionRole `json:"role"` - Policies map[string]AWSIAMProvisionPolicy `json:"policies"` + EksClusterName string `json:"eksClusterName"` + Role map[string]AWSIAMProvisionRole `json:"role"` } // AWSIAMProvisionStatus defines the observed state of AWSIAMProvision. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 1662483..5a7be6b 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -83,41 +83,10 @@ func (in *AWSIAMProvisionList) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AWSIAMProvisionPolicy) DeepCopyInto(out *AWSIAMProvisionPolicy) { - *out = *in - out.Spec = in.Spec -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSIAMProvisionPolicy. -func (in *AWSIAMProvisionPolicy) DeepCopy() *AWSIAMProvisionPolicy { - if in == nil { - return nil - } - out := new(AWSIAMProvisionPolicy) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AWSIAMProvisionPolicySpec) DeepCopyInto(out *AWSIAMProvisionPolicySpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSIAMProvisionPolicySpec. -func (in *AWSIAMProvisionPolicySpec) DeepCopy() *AWSIAMProvisionPolicySpec { - if in == nil { - return nil - } - out := new(AWSIAMProvisionPolicySpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AWSIAMProvisionRole) DeepCopyInto(out *AWSIAMProvisionRole) { *out = *in - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSIAMProvisionRole. @@ -130,21 +99,6 @@ func (in *AWSIAMProvisionRole) DeepCopy() *AWSIAMProvisionRole { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AWSIAMProvisionRoleSpec) DeepCopyInto(out *AWSIAMProvisionRoleSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSIAMProvisionRoleSpec. -func (in *AWSIAMProvisionRoleSpec) DeepCopy() *AWSIAMProvisionRoleSpec { - if in == nil { - return nil - } - out := new(AWSIAMProvisionRoleSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AWSIAMProvisionSpec) DeepCopyInto(out *AWSIAMProvisionSpec) { *out = *in @@ -152,14 +106,7 @@ func (in *AWSIAMProvisionSpec) DeepCopyInto(out *AWSIAMProvisionSpec) { in, out := &in.Role, &out.Role *out = make(map[string]AWSIAMProvisionRole, len(*in)) for key, val := range *in { - (*out)[key] = val - } - } - if in.Policies != nil { - in, out := &in.Policies, &out.Policies - *out = make(map[string]AWSIAMProvisionPolicy, len(*in)) - for key, val := range *in { - (*out)[key] = val + (*out)[key] = *val.DeepCopy() } } } diff --git a/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml b/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml index ee4cec4..06091c9 100644 --- a/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml +++ b/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml @@ -48,33 +48,173 @@ spec: properties: eksClusterName: type: string - policies: - additionalProperties: - properties: - spec: - properties: - policyDocument: - type: string - required: - - policyDocument - type: object - required: - - spec - type: object - type: object role: additionalProperties: properties: spec: + description: |- + RoleSpec defines the desired state of Role. + + Contains information about an IAM role. This structure is returned as a response + element in several API operations that interact with roles. properties: assumeRolePolicyDocument: + description: |- + The trust relationship policy document that grants an entity permission to + assume the role. + + In IAM, you must provide a JSON policy that has been converted to a string. + However, for CloudFormation templates formatted in YAML, you can provide + the policy in JSON or YAML format. CloudFormation always converts a YAML + policy to JSON format before submitting it to IAM. + + The regex pattern (http://wikipedia.org/wiki/regex) used to validate this + parameter is a string of characters consisting of the following: + + - Any printable ASCII character ranging from the space character (\u0020) + through the end of the ASCII character range + + - The printable characters in the Basic Latin and Latin-1 Supplement character + set (through \u00FF) + + - The special characters tab (\u0009), line feed (\u000A), and carriage + return (\u000D) + + Upon success, the response includes the same trust policy in JSON format. + type: string + description: + description: A description of the role. type: string + inlinePolicies: + additionalProperties: + type: string + type: object maxSessionDuration: + description: |- + The maximum session duration (in seconds) that you want to set for the specified + role. If you do not specify a value for this setting, the default value of + one hour is applied. This setting can have a value from 1 hour to 12 hours. + + Anyone who assumes the role from the CLI or API can use the DurationSeconds + API parameter or the duration-seconds CLI parameter to request a longer session. + The MaxSessionDuration setting determines the maximum duration that can be + requested using the DurationSeconds parameter. If users don't specify a value + for the DurationSeconds parameter, their security credentials are valid for + one hour by default. This applies when you use the AssumeRole* API operations + or the assume-role* CLI operations but does not apply when you use those + operations to create a console URL. For more information, see Using IAM roles + (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html) in the + IAM User Guide. format: int64 type: integer + name: + description: |- + The name of the role to create. + + IAM user, group, role, and policy names must be unique within the account. + Names are not distinguished by case. For example, you cannot create resources + named both "MyResource" and "myresource". + + This parameter allows (through its regex pattern (http://wikipedia.org/wiki/regex)) + a string of characters consisting of upper and lowercase alphanumeric characters + with no spaces. You can also include any of the following characters: _+=,.@- + type: string + path: + description: |- + The path to the role. For more information about paths, see IAM Identifiers + (https://docs.aws.amazon.com/IAM/latest/UserGuide/Using_Identifiers.html) + in the IAM User Guide. + + This parameter is optional. If it is not included, it defaults to a slash + (/). + + This parameter allows (through its regex pattern (http://wikipedia.org/wiki/regex)) + a string of characters consisting of either a forward slash (/) by itself + or a string that must begin and end with forward slashes. In addition, it + can contain any ASCII character from the ! (\u0021) through the DEL character + (\u007F), including most punctuation characters, digits, and upper and lowercased + letters. + type: string + permissionsBoundary: + description: |- + The ARN of the managed policy that is used to set the permissions boundary + for the role. + + A permissions boundary policy defines the maximum permissions that identity-based + policies can grant to an entity, but does not grant permissions. Permissions + boundaries do not define the maximum permissions that a resource-based policy + can grant to an entity. To learn more, see Permissions boundaries for IAM + entities (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html) + in the IAM User Guide. + + For more information about policy types, see Policy types (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#access_policy-types) + in the IAM User Guide. + type: string + permissionsBoundaryRef: + description: "AWSResourceReferenceWrapper provides a wrapper + around *AWSResourceReference\ntype to provide more user + friendly syntax for references using 'from' field\nEx:\nAPIIDRef:\n\n\tfrom:\n\t + \ name: my-api" + properties: + from: + description: |- + AWSResourceReference provides all the values necessary to reference another + k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + namespace: + type: string + type: object + type: object + policies: + items: + type: string + type: array + policyRefs: + items: + description: "AWSResourceReferenceWrapper provides a wrapper + around *AWSResourceReference\ntype to provide more user + friendly syntax for references using 'from' field\nEx:\nAPIIDRef:\n\n\tfrom:\n\t + \ name: my-api" + properties: + from: + description: |- + AWSResourceReference provides all the values necessary to reference another + k8s resource for finding the identifier(Id/ARN/Name) + properties: + name: + type: string + namespace: + type: string + type: object + type: object + type: array + tags: + description: |- + A list of tags that you want to attach to the new role. Each tag consists + of a key name and an associated value. For more information about tagging, + see Tagging IAM resources (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_tags.html) + in the IAM User Guide. + + If any one of the tags is invalid or if you exceed the allowed maximum number + of tags, then the entire request fails and the resource is not created. + items: + description: |- + A structure that represents user-provided metadata that can be associated + with an IAM resource. For more information about tagging, see Tagging IAM + resources (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_tags.html) + in the IAM User Guide. + properties: + key: + type: string + value: + type: string + type: object + type: array required: - assumeRolePolicyDocument - - maxSessionDuration + - name type: object required: - spec @@ -82,7 +222,6 @@ spec: type: object required: - eksClusterName - - policies - role type: object status: diff --git a/config/samples/iam_v1alpha1_awsiamprovision.yaml b/config/samples/iam_v1alpha1_awsiamprovision.yaml index de87bd8..8dce1bb 100644 --- a/config/samples/iam_v1alpha1_awsiamprovision.yaml +++ b/config/samples/iam_v1alpha1_awsiamprovision.yaml @@ -30,191 +30,12 @@ spec: ] } maxSessionDuration: 3600 - policies: - deps-ffs-1-ebs-csi-controller-core: - spec: - policyDocument: | - { - "Statement": [ - { - "Action": [ - "ec2:CreateSnapshot", - "ec2:AttachVolume", - "ec2:DetachVolume", - "ec2:ModifyVolume", - "ec2:DescribeAvailabilityZones", - "ec2:DescribeInstances", - "ec2:DescribeSnapshots", - "ec2:DescribeTags", - "ec2:DescribeVolumes", - "ec2:DescribeVolumesModifications" - ], - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:CreateTags" - ], - "Condition": { - "StringEquals": { - "ec2:CreateAction": [ - "CreateVolume", - "CreateSnapshot" - ] - } - }, - "Effect": "Allow", - "Resource": [ - "arn:aws:ec2:*:*:volume/*", - "arn:aws:ec2:*:*:snapshot/*" - ] - }, - { - "Action": [ - "ec2:DeleteTags" - ], - "Effect": "Allow", - "Resource": [ - "arn:aws:ec2:*:*:volume/*", - "arn:aws:ec2:*:*:snapshot/*" - ] - }, - { - "Action": [ - "ec2:CreateVolume" - ], - "Condition": { - "StringLike": { - "aws:RequestTag/ebs.csi.aws.com/cluster": "true" - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:CreateVolume" - ], - "Condition": { - "StringLike": { - "aws:RequestTag/CSIVolumeName": "*" - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:CreateVolume" - ], - "Condition": { - "StringLike": { - "aws:RequestTag/kubernetes.io/cluster/*": "owned" - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DeleteVolume" - ], - "Condition": { - "StringLike": { - "ec2:ResourceTag/ebs.csi.aws.com/cluster": "true" - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DeleteVolume" - ], - "Condition": { - "StringLike": { - "ec2:ResourceTag/CSIVolumeName": "*" - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DeleteVolume" - ], - "Condition": { - "StringLike": { - "ec2:ResourceTag/kubernetes.io/cluster/*": "owned" - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DeleteSnapshot" - ], - "Condition": { - "StringLike": { - "ec2:ResourceTag/CSIVolumeSnapshotName": "*" - } - }, - "Effect": "Allow", - "Resource": "*" - }, - { - "Action": [ - "ec2:DeleteSnapshot" - ], - "Condition": { - "StringLike": { - "ec2:ResourceTag/ebs.csi.aws.com/cluster": "true" - } - }, - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - } - deps-ffs-1-ebs-csi-controller-kms: - spec: - policyDocument: | - { - "Statement": [ - { - "Action": [ - "kms:CreateGrant", - "kms:ListGrants", - "kms:RevokeGrant" - ], - "Condition": { - "Bool": { - "kms:GrantIsForAWSResource": "true" - } - }, - "Effect": "Allow", - "Resource": [ - "arn:aws:kms:*:*:alias/*", - "arn:aws:kms:*:*:key/*" - ] - }, - { - "Action": [ - "kms:Encrypt", - "kms:Decrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", - "kms:DescribeKey" - ], - "Effect": "Allow", - "Resource": [ - "arn:aws:kms:*:*:alias/*", - "arn:aws:kms:*:*:key/*" - ] - } - ], - "Version": "2012-10-17" - } + name: deps-ffs-1-ebs-csi-controller + path: / + policyRefs: + - from: + name: deps-ffs-1-ebs-csi-controller-core + namespace: capa-system + - from: + name: deps-ffs-1-ebs-csi-controller-kms + namespace: capa-system diff --git a/internal/controller/awsiamprovision_controller.go b/internal/controller/awsiamprovision_controller.go index 11327dd..69c6ba0 100644 --- a/internal/controller/awsiamprovision_controller.go +++ b/internal/controller/awsiamprovision_controller.go @@ -25,7 +25,6 @@ import ( "time" iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" - iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" ) const ( @@ -56,18 +55,8 @@ func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } - var policies []*iamctrlv1alpha1.Policy - for name, item := range awsIAMProvision.Spec.Policies { - k8sResource, err := rm.HandlePolicy(awsIAMProvision, name, &item) - if err != nil { - return ctrl.Result{}, err - } - - policies = append(policies, k8sResource) - } - for name, item := range awsIAMProvision.Spec.Role { - _, err := rm.HandleRole(awsIAMProvision, eksControlPlane, policies, name, &item) + _, err := rm.HandleRole(awsIAMProvision, eksControlPlane, name, &item) if err != nil { return ctrl.Result{}, err } @@ -77,6 +66,8 @@ func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } + // todo partial update statuses? + return ctrl.Result{RequeueAfter: frequency}, nil } diff --git a/internal/controller/reconciliation_manager.go b/internal/controller/reconciliation_manager.go index 3f398ca..a9f6356 100644 --- a/internal/controller/reconciliation_manager.go +++ b/internal/controller/reconciliation_manager.go @@ -9,6 +9,7 @@ import ( iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" "github.com/go-logr/logr" + "github.com/google/go-cmp/cmp" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -21,10 +22,6 @@ import ( ) var ( - policyMeta = metav1.TypeMeta{ - APIVersion: "iam.services.k8s.aws", - Kind: "Policy", - } roleMeta = metav1.TypeMeta{ APIVersion: "iam.services.k8s.aws", Kind: "Role", @@ -97,62 +94,7 @@ func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvi return awsIAMProvision, eksControlPlane, nil } -func (rm *ReconciliationManager) HandlePolicy(awsIAMProvision *iamv1alpha1.AWSIAMProvision, name string, item *iamv1alpha1.AWSIAMProvisionPolicy) (*iamctrlv1alpha1.Policy, error) { - k8sResource := &iamctrlv1alpha1.Policy{} - k8sResourceNamespacedName := types.NamespacedName{Name: name, Namespace: rm.req.NamespacedName.Namespace} - - if err := rm.r.Client.Get(*rm.ctx, k8sResourceNamespacedName, k8sResource); err != nil { - if k8serrors.IsNotFound(err) { - // Create new policy - k8sResource.TypeMeta = policyMeta - k8sResource.ObjectMeta = metav1.ObjectMeta{ - Name: name, - Namespace: rm.req.NamespacedName.Namespace, - } - k8sResource.Spec.PolicyDocument = &item.Spec.PolicyDocument - k8sResource.Spec.Name = &name - - // Used to ensure that the created resource will be deleted when the custom resource object is removed - if err := ctrl.SetControllerReference(awsIAMProvision, k8sResource, rm.r.Scheme); err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { - return nil, err - } - - return nil, err - } - - if err = rm.r.Client.Create(*rm.ctx, k8sResource); err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { - return nil, err - } - - return nil, err - } - - rm.logger.Info(fmt.Sprintf("Created IAM Policy: %s", k8sResourceNamespacedName)) - } else { - return nil, err - } - } else { - rm.logger.Info(*k8sResource.Spec.PolicyDocument) - rm.logger.Info(item.Spec.PolicyDocument) - - if k8sResource.Spec.PolicyDocument != &item.Spec.PolicyDocument { - // Update policy with new values - k8sResource.Spec.PolicyDocument = &item.Spec.PolicyDocument - - if err := rm.r.Client.Update(*rm.ctx, k8sResource); err != nil { - return nil, err - } - - rm.logger.Info(fmt.Sprintf("Updated IAM Policy: %s", k8sResourceNamespacedName)) - } - } - - return k8sResource, nil -} - -func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, policies []*iamctrlv1alpha1.Policy, name string, item *iamv1alpha1.AWSIAMProvisionRole) (*iamctrlv1alpha1.Role, error) { +func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, name string, item *iamv1alpha1.AWSIAMProvisionRole) (*iamctrlv1alpha1.Role, error) { k8sResource := &iamctrlv1alpha1.Role{} k8sResourceNamespacedName := types.NamespacedName{Name: name, Namespace: rm.req.NamespacedName.Namespace} @@ -177,16 +119,22 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP Name: name, Namespace: rm.req.NamespacedName.Namespace, } + k8sResource.Spec = item.Spec - assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(item.Spec.AssumeRolePolicyDocument, oidcProviderArn, oidcProviderName) + assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(*item.Spec.AssumeRolePolicyDocument, oidcProviderArn, oidcProviderName) if err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + return nil, err + } + return nil, err } k8sResource.Spec.AssumeRolePolicyDocument = &assumeRolePolicyDocument - k8sResource.Spec.MaxSessionDuration = &item.Spec.MaxSessionDuration - k8sResource.Spec.Name = &name - k8sResource.Spec.PolicyRefs = rm.transformPoliciesToRefs(policies) + + if err := rm.handleRolePolicyRefs(awsIAMProvision, item, k8sResource); err != nil { + return nil, err + } // Used to ensure that the created resource will be deleted when the custom resource object is removed if err := ctrl.SetControllerReference(awsIAMProvision, k8sResource, rm.r.Scheme); err != nil { @@ -211,18 +159,24 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP } } else { // Update role with new values - assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(item.Spec.AssumeRolePolicyDocument, oidcProviderArn, oidcProviderName) + k8sResource.Spec = item.Spec + + assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(*item.Spec.AssumeRolePolicyDocument, oidcProviderArn, oidcProviderName) if err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + return nil, err + } + return nil, err } - if k8sResource.Spec.AssumeRolePolicyDocument != &assumeRolePolicyDocument || - k8sResource.Spec.MaxSessionDuration != &item.Spec.MaxSessionDuration || - len(k8sResource.Spec.PolicyRefs) != len(policies) { // todo check policy refs differ - k8sResource.Spec.AssumeRolePolicyDocument = &assumeRolePolicyDocument - k8sResource.Spec.MaxSessionDuration = &item.Spec.MaxSessionDuration - k8sResource.Spec.PolicyRefs = rm.transformPoliciesToRefs(policies) + k8sResource.Spec.AssumeRolePolicyDocument = &assumeRolePolicyDocument + + if err := rm.handleRolePolicyRefs(awsIAMProvision, item, k8sResource); err != nil { + return nil, err + } + if !cmp.Equal(item.Spec, k8sResource.Spec) { if err := rm.r.Client.Update(*rm.ctx, k8sResource); err != nil { return nil, err } @@ -234,6 +188,42 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP return k8sResource, nil } +func (rm *ReconciliationManager) handleRolePolicyRefs(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole, k8sResource *iamctrlv1alpha1.Role) error { + for _, policyRef := range item.Spec.PolicyRefs { + // Check IAM policy exists + _, err := rm.getPolicy(awsIAMProvision, policyRef) + + if err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + return err + } + + return err + } + } + + return nil +} + +func (rm *ReconciliationManager) getPolicy(awsIAMProvision *iamv1alpha1.AWSIAMProvision, policyRef *ackv1alpha1.AWSResourceReferenceWrapper) (*iamctrlv1alpha1.Policy, error) { + k8sResource := &iamctrlv1alpha1.Policy{} + k8sResourceNamespacedName := types.NamespacedName{Name: *policyRef.From.Name, Namespace: *policyRef.From.Namespace} + + if err := rm.r.Client.Get(*rm.ctx, k8sResourceNamespacedName, k8sResource); err != nil { + if k8serrors.IsNotFound(err) { + err = errors.New(fmt.Sprintf("Cannot get IAM Policy: %s", k8sResourceNamespacedName)) + } + + if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + return nil, err + } + + return nil, err + } + + return k8sResource, nil +} + func (rm *ReconciliationManager) renderOIDCProviderTemplate(oidcProviderTemplate, oidcProviderArn, oidcProviderName string) (string, error) { oidcProviderTemplateData := oidcProviderTemplateData{oidcProviderArn, oidcProviderName} From b152602356872b6513c7d42b483399fb0ccfe447 Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 11:37:18 +0100 Subject: [PATCH 03/15] Change errors and phases to PartiallyProvisioned for non-critical cases. --- .../controller/awsiamprovision_controller.go | 6 +- internal/controller/reconciliation_manager.go | 61 +++++++++++-------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/internal/controller/awsiamprovision_controller.go b/internal/controller/awsiamprovision_controller.go index 69c6ba0..1e1e7eb 100644 --- a/internal/controller/awsiamprovision_controller.go +++ b/internal/controller/awsiamprovision_controller.go @@ -55,6 +55,10 @@ func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } + if awsIAMProvision == nil || eksControlPlane == nil { + return ctrl.Result{RequeueAfter: frequency}, nil + } + for name, item := range awsIAMProvision.Spec.Role { _, err := rm.HandleRole(awsIAMProvision, eksControlPlane, name, &item) if err != nil { @@ -66,8 +70,6 @@ func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } - // todo partial update statuses? - return ctrl.Result{RequeueAfter: frequency}, nil } diff --git a/internal/controller/reconciliation_manager.go b/internal/controller/reconciliation_manager.go index a9f6356..40b4e01 100644 --- a/internal/controller/reconciliation_manager.go +++ b/internal/controller/reconciliation_manager.go @@ -56,7 +56,9 @@ func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvi if err := rm.r.Client.Get(*rm.ctx, rm.req.NamespacedName, awsIAMProvision); err != nil { if k8serrors.IsNotFound(err) { - err = errors.New(fmt.Sprintf("Cannot find AWSIAMProvision: %s", rm.req.NamespacedName)) + rm.logger.Info(fmt.Sprintf("Cannot find AWSIAMProvision: %s", rm.req.NamespacedName)) + + return nil, nil, nil } return nil, nil, err @@ -69,26 +71,33 @@ func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvi if err := rm.r.Client.Get(*rm.ctx, eksControlPlaneNamespacedName, eksControlPlane); err != nil { if k8serrors.IsNotFound(err) { - err = errors.New(fmt.Sprintf("Cannot get AWSManagedControlPlane: %s", eksControlPlaneNamespacedName)) + msg := fmt.Sprintf("Cannot get AWSManagedControlPlane: %s", eksControlPlaneNamespacedName) + rm.logger.Info(msg) + + if err := rm.UpdateCRDStatus(awsIAMProvision, "PartiallyProvisioned", msg); err != nil { + return awsIAMProvision, nil, err + } + + return awsIAMProvision, nil, nil } - if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { - return nil, nil, err + if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { + return awsIAMProvision, nil, err } - return nil, nil, err + return awsIAMProvision, nil, err } rm.logger.Info(fmt.Sprintf("Found AWSManagedControlPlane: %s", eksControlPlaneNamespacedName)) if !eksControlPlane.Status.Ready { - err := errors.New(fmt.Sprintf("AWSManagedControlPlane not ready: %s", eksControlPlaneNamespacedName)) + msg := fmt.Sprintf("AWSManagedControlPlane not ready: %s", eksControlPlaneNamespacedName) - if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { - return nil, nil, err + if err := rm.UpdateCRDStatus(awsIAMProvision, "PartiallyProvisioned", msg); err != nil { + return awsIAMProvision, nil, err } - return nil, nil, err + return awsIAMProvision, nil, nil } return awsIAMProvision, eksControlPlane, nil @@ -104,7 +113,7 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP if !oidcProviderArnFound { err := errors.New(fmt.Sprintf("OIDC ARN malformed: %s", oidcProviderArn)) - if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err } @@ -123,7 +132,7 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(*item.Spec.AssumeRolePolicyDocument, oidcProviderArn, oidcProviderName) if err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err } @@ -138,7 +147,7 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP // Used to ensure that the created resource will be deleted when the custom resource object is removed if err := ctrl.SetControllerReference(awsIAMProvision, k8sResource, rm.r.Scheme); err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err } @@ -146,7 +155,7 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP } if err = rm.r.Client.Create(*rm.ctx, k8sResource); err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err } @@ -158,25 +167,25 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP return nil, err } } else { - // Update role with new values - k8sResource.Spec = item.Spec - - assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(*item.Spec.AssumeRolePolicyDocument, oidcProviderArn, oidcProviderName) - if err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + if assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(*item.Spec.AssumeRolePolicyDocument, oidcProviderArn, oidcProviderName); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err } return nil, err + } else { + // set rendered AssumeRolePolicyDocument for future comparison + item.Spec.AssumeRolePolicyDocument = &assumeRolePolicyDocument } - k8sResource.Spec.AssumeRolePolicyDocument = &assumeRolePolicyDocument + if !cmp.Equal(item.Spec, k8sResource.Spec) { + // Update role with new values + k8sResource.Spec = item.Spec - if err := rm.handleRolePolicyRefs(awsIAMProvision, item, k8sResource); err != nil { - return nil, err - } + if err := rm.handleRolePolicyRefs(awsIAMProvision, item, k8sResource); err != nil { + return nil, err + } - if !cmp.Equal(item.Spec, k8sResource.Spec) { if err := rm.r.Client.Update(*rm.ctx, k8sResource); err != nil { return nil, err } @@ -194,7 +203,7 @@ func (rm *ReconciliationManager) handleRolePolicyRefs(awsIAMProvision *iamv1alph _, err := rm.getPolicy(awsIAMProvision, policyRef) if err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return err } @@ -214,7 +223,7 @@ func (rm *ReconciliationManager) getPolicy(awsIAMProvision *iamv1alpha1.AWSIAMPr err = errors.New(fmt.Sprintf("Cannot get IAM Policy: %s", k8sResourceNamespacedName)) } - if err := rm.UpdateCRDStatus(awsIAMProvision, "Error", err.Error()); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err } From c0414099e3ba8fcd4b192f835dbe763a5e7f1a10 Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 12:56:41 +0100 Subject: [PATCH 04/15] Remove unneeded status updates when no diff detected. --- .../controller/awsiamprovision_controller.go | 17 +- internal/controller/reconciliation_manager.go | 160 +++++++++--------- 2 files changed, 97 insertions(+), 80 deletions(-) diff --git a/internal/controller/awsiamprovision_controller.go b/internal/controller/awsiamprovision_controller.go index 1e1e7eb..e1ea598 100644 --- a/internal/controller/awsiamprovision_controller.go +++ b/internal/controller/awsiamprovision_controller.go @@ -56,18 +56,29 @@ func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Requ } if awsIAMProvision == nil || eksControlPlane == nil { + // Resources not ready, re-queuing return ctrl.Result{RequeueAfter: frequency}, nil } + provisioned := false for name, item := range awsIAMProvision.Spec.Role { - _, err := rm.HandleRole(awsIAMProvision, eksControlPlane, name, &item) + k8sResource, err := rm.HandleRole(awsIAMProvision, eksControlPlane, name, &item) + if err != nil { return ctrl.Result{}, err } + + if k8sResource != nil { + // If a resource has been returned, there was a change to it + provisioned = true + } } - if err := rm.UpdateCRDStatus(awsIAMProvision, "Provisioned", ""); err != nil { - return ctrl.Result{}, err + if provisioned { + // Resources have been provisioned, updating status + if err := rm.UpdateCRDStatus(awsIAMProvision, "Provisioned", ""); err != nil { + return ctrl.Result{}, err + } } return ctrl.Result{RequeueAfter: frequency}, nil diff --git a/internal/controller/reconciliation_manager.go b/internal/controller/reconciliation_manager.go index 40b4e01..4abe2e0 100644 --- a/internal/controller/reconciliation_manager.go +++ b/internal/controller/reconciliation_manager.go @@ -64,7 +64,7 @@ func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvi return nil, nil, err } - rm.logger.Info(fmt.Sprintf("Found AWSIAMProvision: %s", rm.req.NamespacedName)) + rm.logger.Info(fmt.Sprintf("Got AWSIAMProvision: %s", rm.req.NamespacedName)) eksControlPlane := &ekscontrolplanev1.AWSManagedControlPlane{} eksControlPlaneNamespacedName := types.NamespacedName{Name: awsIAMProvision.Spec.EksClusterName, Namespace: rm.req.NamespacedName.Namespace} @@ -74,30 +74,31 @@ func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvi msg := fmt.Sprintf("Cannot get AWSManagedControlPlane: %s", eksControlPlaneNamespacedName) rm.logger.Info(msg) - if err := rm.UpdateCRDStatus(awsIAMProvision, "PartiallyProvisioned", msg); err != nil { - return awsIAMProvision, nil, err + if err := rm.UpdateCRDStatus(awsIAMProvision, "Provisioning", msg); err != nil { + return nil, nil, err } - return awsIAMProvision, nil, nil + return nil, nil, nil } if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { - return awsIAMProvision, nil, err + return nil, nil, err } - return awsIAMProvision, nil, err + return nil, nil, err } - rm.logger.Info(fmt.Sprintf("Found AWSManagedControlPlane: %s", eksControlPlaneNamespacedName)) + rm.logger.Info(fmt.Sprintf("Got AWSManagedControlPlane: %s", eksControlPlaneNamespacedName)) if !eksControlPlane.Status.Ready { msg := fmt.Sprintf("AWSManagedControlPlane not ready: %s", eksControlPlaneNamespacedName) + rm.logger.Info(msg) - if err := rm.UpdateCRDStatus(awsIAMProvision, "PartiallyProvisioned", msg); err != nil { - return awsIAMProvision, nil, err + if err := rm.UpdateCRDStatus(awsIAMProvision, "Provisioning", msg); err != nil { + return nil, nil, err } - return awsIAMProvision, nil, nil + return nil, nil, nil } return awsIAMProvision, eksControlPlane, nil @@ -107,45 +108,25 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP k8sResource := &iamctrlv1alpha1.Role{} k8sResourceNamespacedName := types.NamespacedName{Name: name, Namespace: rm.req.NamespacedName.Namespace} - oidcProviderArn := eksControlPlane.Status.OIDCProvider.ARN - _, oidcProviderName, oidcProviderArnFound := strings.Cut(oidcProviderArn, "/") - - if !oidcProviderArnFound { - err := errors.New(fmt.Sprintf("OIDC ARN malformed: %s", oidcProviderArn)) - - if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { - return nil, err - } - - return nil, err - } - if err := rm.r.Client.Get(*rm.ctx, k8sResourceNamespacedName, k8sResource); err != nil { if k8serrors.IsNotFound(err) { // Create new role - k8sResource.TypeMeta = roleMeta - k8sResource.ObjectMeta = metav1.ObjectMeta{ - Name: name, - Namespace: rm.req.NamespacedName.Namespace, + if err := rm.setAssumeRolePolicyDocument(awsIAMProvision, eksControlPlane, item); err != nil { + return nil, err } - k8sResource.Spec = item.Spec - - assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(*item.Spec.AssumeRolePolicyDocument, oidcProviderArn, oidcProviderName) - if err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { - return nil, err - } + if err := rm.validateRolePolicyRefs(awsIAMProvision, item); err != nil { return nil, err } - k8sResource.Spec.AssumeRolePolicyDocument = &assumeRolePolicyDocument - - if err := rm.handleRolePolicyRefs(awsIAMProvision, item, k8sResource); err != nil { - return nil, err + k8sResource.TypeMeta = roleMeta + k8sResource.ObjectMeta = metav1.ObjectMeta{ + Name: name, + Namespace: rm.req.NamespacedName.Namespace, } + k8sResource.Spec = item.Spec - // Used to ensure that the created resource will be deleted when the custom resource object is removed + // Set ownerReferences to ensure that the created resource will be deleted when the custom resource object is removed if err := ctrl.SetControllerReference(awsIAMProvision, k8sResource, rm.r.Scheme); err != nil { if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err @@ -163,41 +144,51 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP } rm.logger.Info(fmt.Sprintf("Created IAM Role: %s", k8sResourceNamespacedName)) - } else { - return nil, err - } - } else { - if assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(*item.Spec.AssumeRolePolicyDocument, oidcProviderArn, oidcProviderName); err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { - return nil, err - } - return nil, err - } else { - // set rendered AssumeRolePolicyDocument for future comparison - item.Spec.AssumeRolePolicyDocument = &assumeRolePolicyDocument + return k8sResource, nil } - if !cmp.Equal(item.Spec, k8sResource.Spec) { - // Update role with new values - k8sResource.Spec = item.Spec + return nil, err + } - if err := rm.handleRolePolicyRefs(awsIAMProvision, item, k8sResource); err != nil { - return nil, err - } + if err := rm.setAssumeRolePolicyDocument(awsIAMProvision, eksControlPlane, item); err != nil { + return nil, err + } - if err := rm.r.Client.Update(*rm.ctx, k8sResource); err != nil { - return nil, err - } + if cmp.Equal(item.Spec, k8sResource.Spec) { + // No diff with existing resource, exiting without error + return nil, nil + } - rm.logger.Info(fmt.Sprintf("Updated IAM Role: %s", k8sResourceNamespacedName)) - } + if err := rm.validateRolePolicyRefs(awsIAMProvision, item); err != nil { + return nil, err } + // Update role with new values + k8sResource.Spec = item.Spec + + if err := rm.r.Client.Update(*rm.ctx, k8sResource); err != nil { + return nil, err + } + + rm.logger.Info(fmt.Sprintf("Updated IAM Role: %s", k8sResourceNamespacedName)) + return k8sResource, nil } -func (rm *ReconciliationManager) handleRolePolicyRefs(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole, k8sResource *iamctrlv1alpha1.Role) error { +func (rm *ReconciliationManager) UpdateCRDStatus(awsIAMProvision *iamv1alpha1.AWSIAMProvision, phase, errText string) error { + awsIAMProvision.Status.LastUpdatedTime = &metav1.Time{Time: time.Now()} + awsIAMProvision.Status.Phase = phase + awsIAMProvision.Status.Error = errText + + if err := rm.r.Status().Update(*rm.ctx, awsIAMProvision); err != nil { + return errors.New(fmt.Sprintf("Unable to update status for CRD: %s", awsIAMProvision.Name)) + } + + return nil +} + +func (rm *ReconciliationManager) validateRolePolicyRefs(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole) error { for _, policyRef := range item.Spec.PolicyRefs { // Check IAM policy exists _, err := rm.getPolicy(awsIAMProvision, policyRef) @@ -233,8 +224,35 @@ func (rm *ReconciliationManager) getPolicy(awsIAMProvision *iamv1alpha1.AWSIAMPr return k8sResource, nil } -func (rm *ReconciliationManager) renderOIDCProviderTemplate(oidcProviderTemplate, oidcProviderArn, oidcProviderName string) (string, error) { - oidcProviderTemplateData := oidcProviderTemplateData{oidcProviderArn, oidcProviderName} +func (rm *ReconciliationManager) setAssumeRolePolicyDocument(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, item *iamv1alpha1.AWSIAMProvisionRole) error { + oidcProviderARN := eksControlPlane.Status.OIDCProvider.ARN + _, oidcProviderName, oidcProviderARNFound := strings.Cut(oidcProviderARN, "/") + + if !oidcProviderARNFound { + err := errors.New(fmt.Sprintf("OIDC ARN malformed: %s", oidcProviderARN)) + + if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { + return err + } + + return err + } + + if assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(*item.Spec.AssumeRolePolicyDocument, oidcProviderARN, oidcProviderName); err != nil { + if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { + return err + } + + return err + } else { + item.Spec.AssumeRolePolicyDocument = &assumeRolePolicyDocument + + return nil + } +} + +func (rm *ReconciliationManager) renderOIDCProviderTemplate(oidcProviderTemplate, oidcProviderARN, oidcProviderName string) (string, error) { + oidcProviderTemplateData := oidcProviderTemplateData{oidcProviderARN, oidcProviderName} tmpl, err := template.New("").Parse(oidcProviderTemplate) if err != nil { @@ -263,15 +281,3 @@ func (rm *ReconciliationManager) transformPoliciesToRefs(policies []*iamctrlv1al return policyRefs } - -func (rm *ReconciliationManager) UpdateCRDStatus(awsIAMProvision *iamv1alpha1.AWSIAMProvision, phase, errText string) error { - awsIAMProvision.Status.LastUpdatedTime = &metav1.Time{Time: time.Now()} - awsIAMProvision.Status.Phase = phase - awsIAMProvision.Status.Error = errText - - if err := rm.r.Status().Update(*rm.ctx, awsIAMProvision); err != nil { - return errors.New(fmt.Sprintf("Unable to update status for CRD: %s", awsIAMProvision.Name)) - } - - return nil -} From 337c021c658b6f964b4824850c011ad055cea4d4 Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 13:36:55 +0100 Subject: [PATCH 05/15] Improve logging. --- api/v1alpha1/awsiamprovision_types.go | 2 +- .../iam.aws.edenlab.io_awsiamprovisions.yaml | 4 +- internal/controller/reconciliation_manager.go | 39 ++++++++++--------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/api/v1alpha1/awsiamprovision_types.go b/api/v1alpha1/awsiamprovision_types.go index 96cff61..c4c18d5 100644 --- a/api/v1alpha1/awsiamprovision_types.go +++ b/api/v1alpha1/awsiamprovision_types.go @@ -42,7 +42,7 @@ type AWSIAMProvisionStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file - Error string `json:"error,omitempty"` + Message string `json:"message,omitempty"` LastUpdatedTime *metav1.Time `json:"lastUpdatedTime,omitempty"` Phase string `json:"phase,omitempty"` } diff --git a/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml b/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml index 06091c9..b1fc3b6 100644 --- a/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml +++ b/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml @@ -227,11 +227,11 @@ spec: status: description: AWSIAMProvisionStatus defines the observed state of AWSIAMProvision. properties: - error: - type: string lastUpdatedTime: format: date-time type: string + message: + type: string phase: type: string type: object diff --git a/internal/controller/reconciliation_manager.go b/internal/controller/reconciliation_manager.go index 4abe2e0..b43cc89 100644 --- a/internal/controller/reconciliation_manager.go +++ b/internal/controller/reconciliation_manager.go @@ -56,7 +56,7 @@ func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvi if err := rm.r.Client.Get(*rm.ctx, rm.req.NamespacedName, awsIAMProvision); err != nil { if k8serrors.IsNotFound(err) { - rm.logger.Info(fmt.Sprintf("Cannot find AWSIAMProvision: %s", rm.req.NamespacedName)) + rm.logger.Info(fmt.Sprintf("AWSIAMProvision not found: %s", rm.req.NamespacedName)) return nil, nil, nil } @@ -64,14 +64,14 @@ func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvi return nil, nil, err } - rm.logger.Info(fmt.Sprintf("Got AWSIAMProvision: %s", rm.req.NamespacedName)) + rm.logger.Info(fmt.Sprintf("AWSIAMProvision found: %s", rm.req.NamespacedName)) eksControlPlane := &ekscontrolplanev1.AWSManagedControlPlane{} - eksControlPlaneNamespacedName := types.NamespacedName{Name: awsIAMProvision.Spec.EksClusterName, Namespace: rm.req.NamespacedName.Namespace} + namespacedName := types.NamespacedName{Name: awsIAMProvision.Spec.EksClusterName, Namespace: rm.req.NamespacedName.Namespace} - if err := rm.r.Client.Get(*rm.ctx, eksControlPlaneNamespacedName, eksControlPlane); err != nil { + if err := rm.r.Client.Get(*rm.ctx, namespacedName, eksControlPlane); err != nil { if k8serrors.IsNotFound(err) { - msg := fmt.Sprintf("Cannot get AWSManagedControlPlane: %s", eksControlPlaneNamespacedName) + msg := fmt.Sprintf("AWSManagedControlPlane of %s AWSIAMProvision not found: %s", rm.req.NamespacedName, namespacedName) rm.logger.Info(msg) if err := rm.UpdateCRDStatus(awsIAMProvision, "Provisioning", msg); err != nil { @@ -88,10 +88,10 @@ func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvi return nil, nil, err } - rm.logger.Info(fmt.Sprintf("Got AWSManagedControlPlane: %s", eksControlPlaneNamespacedName)) + rm.logger.Info(fmt.Sprintf("AWSManagedControlPlane of %s AWSIAMProvision found: %s", rm.req.NamespacedName, namespacedName)) if !eksControlPlane.Status.Ready { - msg := fmt.Sprintf("AWSManagedControlPlane not ready: %s", eksControlPlaneNamespacedName) + msg := fmt.Sprintf("AWSManagedControlPlane of %s AWSIAMProvision not ready: %s", rm.req.NamespacedName, namespacedName) rm.logger.Info(msg) if err := rm.UpdateCRDStatus(awsIAMProvision, "Provisioning", msg); err != nil { @@ -106,9 +106,9 @@ func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvi func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, name string, item *iamv1alpha1.AWSIAMProvisionRole) (*iamctrlv1alpha1.Role, error) { k8sResource := &iamctrlv1alpha1.Role{} - k8sResourceNamespacedName := types.NamespacedName{Name: name, Namespace: rm.req.NamespacedName.Namespace} + namespacedName := types.NamespacedName{Name: name, Namespace: rm.req.NamespacedName.Namespace} - if err := rm.r.Client.Get(*rm.ctx, k8sResourceNamespacedName, k8sResource); err != nil { + if err := rm.r.Client.Get(*rm.ctx, namespacedName, k8sResource); err != nil { if k8serrors.IsNotFound(err) { // Create new role if err := rm.setAssumeRolePolicyDocument(awsIAMProvision, eksControlPlane, item); err != nil { @@ -143,7 +143,7 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP return nil, err } - rm.logger.Info(fmt.Sprintf("Created IAM Role: %s", k8sResourceNamespacedName)) + rm.logger.Info(fmt.Sprintf("IAM Role of %s AWSIAMProvision created: %s", rm.req.NamespacedName, namespacedName)) return k8sResource, nil } @@ -171,15 +171,15 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP return nil, err } - rm.logger.Info(fmt.Sprintf("Updated IAM Role: %s", k8sResourceNamespacedName)) + rm.logger.Info(fmt.Sprintf("IAM Role of %s AWSIAMProvision updated: %s", rm.req.NamespacedName, namespacedName)) return k8sResource, nil } -func (rm *ReconciliationManager) UpdateCRDStatus(awsIAMProvision *iamv1alpha1.AWSIAMProvision, phase, errText string) error { +func (rm *ReconciliationManager) UpdateCRDStatus(awsIAMProvision *iamv1alpha1.AWSIAMProvision, phase, message string) error { awsIAMProvision.Status.LastUpdatedTime = &metav1.Time{Time: time.Now()} awsIAMProvision.Status.Phase = phase - awsIAMProvision.Status.Error = errText + awsIAMProvision.Status.Message = message if err := rm.r.Status().Update(*rm.ctx, awsIAMProvision); err != nil { return errors.New(fmt.Sprintf("Unable to update status for CRD: %s", awsIAMProvision.Name)) @@ -191,7 +191,7 @@ func (rm *ReconciliationManager) UpdateCRDStatus(awsIAMProvision *iamv1alpha1.AW func (rm *ReconciliationManager) validateRolePolicyRefs(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole) error { for _, policyRef := range item.Spec.PolicyRefs { // Check IAM policy exists - _, err := rm.getPolicy(awsIAMProvision, policyRef) + _, err := rm.getPolicy(awsIAMProvision, item, policyRef) if err != nil { if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { @@ -205,13 +205,13 @@ func (rm *ReconciliationManager) validateRolePolicyRefs(awsIAMProvision *iamv1al return nil } -func (rm *ReconciliationManager) getPolicy(awsIAMProvision *iamv1alpha1.AWSIAMProvision, policyRef *ackv1alpha1.AWSResourceReferenceWrapper) (*iamctrlv1alpha1.Policy, error) { +func (rm *ReconciliationManager) getPolicy(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole, policyRef *ackv1alpha1.AWSResourceReferenceWrapper) (*iamctrlv1alpha1.Policy, error) { k8sResource := &iamctrlv1alpha1.Policy{} - k8sResourceNamespacedName := types.NamespacedName{Name: *policyRef.From.Name, Namespace: *policyRef.From.Namespace} + namespacedName := types.NamespacedName{Name: *policyRef.From.Name, Namespace: *policyRef.From.Namespace} - if err := rm.r.Client.Get(*rm.ctx, k8sResourceNamespacedName, k8sResource); err != nil { + if err := rm.r.Client.Get(*rm.ctx, namespacedName, k8sResource); err != nil { if k8serrors.IsNotFound(err) { - err = errors.New(fmt.Sprintf("Cannot get IAM Policy: %s", k8sResourceNamespacedName)) + err = errors.New(fmt.Sprintf("IAM Policy of %s IAM Role of %s AWSIAMProvision not found: %s", *item.Spec.Name, rm.req.NamespacedName, namespacedName)) } if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { @@ -229,7 +229,8 @@ func (rm *ReconciliationManager) setAssumeRolePolicyDocument(awsIAMProvision *ia _, oidcProviderName, oidcProviderARNFound := strings.Cut(oidcProviderARN, "/") if !oidcProviderARNFound { - err := errors.New(fmt.Sprintf("OIDC ARN malformed: %s", oidcProviderARN)) + namespacedName := types.NamespacedName{Name: awsIAMProvision.Spec.EksClusterName, Namespace: rm.req.NamespacedName.Namespace} + err := errors.New(fmt.Sprintf("OIDC ARN of %s AWSManagedControlPlane of %s AWSIAMProvision malformed: %s", namespacedName, rm.req.NamespacedName, oidcProviderARN)) if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return err From 4c474fc412417b7ec4b9c103fe5b36aa427406d9 Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 14:01:56 +0100 Subject: [PATCH 06/15] Set Provisioned status in case the previous status was different. Renames Role to Roles in AWSIAMProvisionSpec. --- api/v1alpha1/awsiamprovision_types.go | 2 +- api/v1alpha1/zz_generated.deepcopy.go | 4 ++-- .../crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml | 4 ++-- config/samples/iam_v1alpha1_awsiamprovision.yaml | 4 ++-- internal/controller/awsiamprovision_controller.go | 9 ++++++--- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/api/v1alpha1/awsiamprovision_types.go b/api/v1alpha1/awsiamprovision_types.go index c4c18d5..ab4d953 100644 --- a/api/v1alpha1/awsiamprovision_types.go +++ b/api/v1alpha1/awsiamprovision_types.go @@ -34,7 +34,7 @@ type AWSIAMProvisionSpec struct { // Important: Run "make" to regenerate code after modifying this file EksClusterName string `json:"eksClusterName"` - Role map[string]AWSIAMProvisionRole `json:"role"` + Roles map[string]AWSIAMProvisionRole `json:"roles"` } // AWSIAMProvisionStatus defines the observed state of AWSIAMProvision. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 5a7be6b..4e37b50 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -102,8 +102,8 @@ func (in *AWSIAMProvisionRole) DeepCopy() *AWSIAMProvisionRole { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AWSIAMProvisionSpec) DeepCopyInto(out *AWSIAMProvisionSpec) { *out = *in - if in.Role != nil { - in, out := &in.Role, &out.Role + if in.Roles != nil { + in, out := &in.Roles, &out.Roles *out = make(map[string]AWSIAMProvisionRole, len(*in)) for key, val := range *in { (*out)[key] = *val.DeepCopy() diff --git a/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml b/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml index b1fc3b6..4fad224 100644 --- a/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml +++ b/config/crd/bases/iam.aws.edenlab.io_awsiamprovisions.yaml @@ -48,7 +48,7 @@ spec: properties: eksClusterName: type: string - role: + roles: additionalProperties: properties: spec: @@ -222,7 +222,7 @@ spec: type: object required: - eksClusterName - - role + - roles type: object status: description: AWSIAMProvisionStatus defines the observed state of AWSIAMProvision. diff --git a/config/samples/iam_v1alpha1_awsiamprovision.yaml b/config/samples/iam_v1alpha1_awsiamprovision.yaml index 8dce1bb..97a5a84 100644 --- a/config/samples/iam_v1alpha1_awsiamprovision.yaml +++ b/config/samples/iam_v1alpha1_awsiamprovision.yaml @@ -4,10 +4,10 @@ metadata: labels: app.kubernetes.io/name: aws-iam-provisioner app.kubernetes.io/managed-by: kustomize - name: deps-ffs-1-ebs-csi-controller + name: deps-ffs-1 spec: eksClusterName: deps-ffs-1 - role: + roles: deps-ffs-1-ebs-csi-controller: spec: assumeRolePolicyDocument: | diff --git a/internal/controller/awsiamprovision_controller.go b/internal/controller/awsiamprovision_controller.go index e1ea598..4f8f635 100644 --- a/internal/controller/awsiamprovision_controller.go +++ b/internal/controller/awsiamprovision_controller.go @@ -18,6 +18,7 @@ package controller import ( "context" + "fmt" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -61,7 +62,7 @@ func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Requ } provisioned := false - for name, item := range awsIAMProvision.Spec.Role { + for name, item := range awsIAMProvision.Spec.Roles { k8sResource, err := rm.HandleRole(awsIAMProvision, eksControlPlane, name, &item) if err != nil { @@ -74,8 +75,10 @@ func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Requ } } - if provisioned { - // Resources have been provisioned, updating status + if awsIAMProvision.Status.Phase != "Provisioned" || provisioned { + // Resources have been provisioned successfully + rm.logger.Info(fmt.Sprintf("AWSIAMProvision provisioned: %s", rm.req.NamespacedName)) + if err := rm.UpdateCRDStatus(awsIAMProvision, "Provisioned", ""); err != nil { return ctrl.Result{}, err } From 5998ff31f9bd3206640af092f83f8f1f0cabaab3 Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 14:22:29 +0100 Subject: [PATCH 07/15] Remove unneeded kubebuilder's comments. --- api/v1alpha1/awsiamprovision_types.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/api/v1alpha1/awsiamprovision_types.go b/api/v1alpha1/awsiamprovision_types.go index ab4d953..fe0e7b2 100644 --- a/api/v1alpha1/awsiamprovision_types.go +++ b/api/v1alpha1/awsiamprovision_types.go @@ -21,7 +21,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. type AWSIAMProvisionRole struct { @@ -30,7 +29,6 @@ type AWSIAMProvisionRole struct { // AWSIAMProvisionSpec defines the desired state of AWSIAMProvision. type AWSIAMProvisionSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file EksClusterName string `json:"eksClusterName"` @@ -39,7 +37,6 @@ type AWSIAMProvisionSpec struct { // AWSIAMProvisionStatus defines the observed state of AWSIAMProvision. type AWSIAMProvisionStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file Message string `json:"message,omitempty"` From 30c84c4e4e9d9cfde97cd3cd4c52c231c135f32f Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 14:27:26 +0100 Subject: [PATCH 08/15] Sort and re-group packages. --- internal/controller/awsiamprovision_controller.go | 6 +++--- internal/controller/reconciliation_manager.go | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/internal/controller/awsiamprovision_controller.go b/internal/controller/awsiamprovision_controller.go index 4f8f635..7a9cbac 100644 --- a/internal/controller/awsiamprovision_controller.go +++ b/internal/controller/awsiamprovision_controller.go @@ -19,13 +19,13 @@ package controller import ( "context" "fmt" + "time" + + iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/predicate" - "time" - - iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" ) const ( diff --git a/internal/controller/reconciliation_manager.go b/internal/controller/reconciliation_manager.go index b43cc89..d92e2b8 100644 --- a/internal/controller/reconciliation_manager.go +++ b/internal/controller/reconciliation_manager.go @@ -1,11 +1,15 @@ package controller import ( - iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" "bytes" "context" "errors" "fmt" + "strings" + "text/template" + "time" + + iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" "github.com/go-logr/logr" @@ -16,9 +20,6 @@ import ( ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/log" - "strings" - "text/template" - "time" ) var ( From 2bf2030932081252afff2b7e942d33b8502caba4 Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 14:31:35 +0100 Subject: [PATCH 09/15] Sort and re-group packages. --- internal/controller/awsiamprovision_controller.go | 3 ++- internal/controller/reconciliation_manager.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/controller/awsiamprovision_controller.go b/internal/controller/awsiamprovision_controller.go index 7a9cbac..a6d8c88 100644 --- a/internal/controller/awsiamprovision_controller.go +++ b/internal/controller/awsiamprovision_controller.go @@ -21,11 +21,12 @@ import ( "fmt" "time" - iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/predicate" + + iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" ) const ( diff --git a/internal/controller/reconciliation_manager.go b/internal/controller/reconciliation_manager.go index d92e2b8..ee2f2fc 100644 --- a/internal/controller/reconciliation_manager.go +++ b/internal/controller/reconciliation_manager.go @@ -9,7 +9,6 @@ import ( "text/template" "time" - iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" "github.com/go-logr/logr" @@ -20,6 +19,8 @@ import ( ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/log" + + iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" ) var ( From 077ab8e73e15bf45f13be7d2427a30166487830d Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 14:33:21 +0100 Subject: [PATCH 10/15] Sort and re-group packages. --- cmd/main.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 8875ab4..3007506 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -25,20 +25,20 @@ import ( metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" "strings" - // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) - // to ensure that exec-entrypoint and run can make use of them. - _ "k8s.io/client-go/plugin/pkg/client/auth" - - iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" - "aws-iam-provisioner.operators.infra/internal/controller" iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" cpv1beta2 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" + + iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" + "aws-iam-provisioner.operators.infra/internal/controller" // +kubebuilder:scaffold:imports ) From b7acff877e473f9ac6da071e9278d31b69f3d161 Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 14:35:00 +0100 Subject: [PATCH 11/15] Sort and re-group packages. --- cmd/main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 3007506..b719134 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -19,16 +19,16 @@ package main import ( "flag" "fmt" - "go.uber.org/zap/zapcore" "os" - "sigs.k8s.io/controller-runtime/pkg/cache" - metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" "strings" iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" + "go.uber.org/zap/zapcore" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/cache" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. _ "k8s.io/client-go/plugin/pkg/client/auth" From 2b1a38d3ac2dc23be187e8871c9dd0246c214e92 Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 15:04:05 +0100 Subject: [PATCH 12/15] Embed reconciliationManager structure into AWSIAMProvisionReconciler. --- .../samples/iam_v1alpha1_awsiamprovision.yaml | 4 +- .../controller/awsiamprovision_controller.go | 17 ++- internal/controller/reconciliation_manager.go | 105 ++++++++---------- 3 files changed, 59 insertions(+), 67 deletions(-) diff --git a/config/samples/iam_v1alpha1_awsiamprovision.yaml b/config/samples/iam_v1alpha1_awsiamprovision.yaml index 97a5a84..e2769e6 100644 --- a/config/samples/iam_v1alpha1_awsiamprovision.yaml +++ b/config/samples/iam_v1alpha1_awsiamprovision.yaml @@ -18,12 +18,12 @@ spec: "Sid": "", "Effect": "Allow", "Principal": { - "Federated": "{{ .OIDCProviderARN }}" + "Federated": "{{ .oidcProviderARN }}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { - "{{ .OIDCProviderName }}:sub": "system:serviceaccount:kube-system:ebs-csi-controller" + "{{ .oidcProviderName }}:sub": "system:serviceaccount:kube-system:ebs-csi-controller" } } } diff --git a/internal/controller/awsiamprovision_controller.go b/internal/controller/awsiamprovision_controller.go index a6d8c88..dc37e8b 100644 --- a/internal/controller/awsiamprovision_controller.go +++ b/internal/controller/awsiamprovision_controller.go @@ -19,6 +19,7 @@ package controller import ( "context" "fmt" + "sigs.k8s.io/controller-runtime/pkg/log" "time" "k8s.io/apimachinery/pkg/runtime" @@ -36,8 +37,8 @@ const ( // AWSIAMProvisionReconciler reconciles a AWSIAMProvision object type AWSIAMProvisionReconciler struct { client.Client + *reconciliationManager Scheme *runtime.Scheme - rm *ReconciliationManager } // +kubebuilder:rbac:groups=iam.aws.edenlab.io,resources=awsiamprovisions,verbs=get;list;watch;create;update;patch;delete @@ -50,9 +51,13 @@ type AWSIAMProvisionReconciler struct { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/reconcile func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - rm := NewReconciliationManager(r, &ctx, &req) + logger := log.FromContext(ctx) - awsIAMProvision, eksControlPlane, err := rm.GetClusterResources() + r.context = &ctx + r.logger = &logger + r.request = &req + + awsIAMProvision, eksControlPlane, err := r.getClusterResources() if err != nil { return ctrl.Result{}, err } @@ -64,7 +69,7 @@ func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Requ provisioned := false for name, item := range awsIAMProvision.Spec.Roles { - k8sResource, err := rm.HandleRole(awsIAMProvision, eksControlPlane, name, &item) + k8sResource, err := r.handleRole(awsIAMProvision, eksControlPlane, name, &item) if err != nil { return ctrl.Result{}, err @@ -78,9 +83,9 @@ func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Requ if awsIAMProvision.Status.Phase != "Provisioned" || provisioned { // Resources have been provisioned successfully - rm.logger.Info(fmt.Sprintf("AWSIAMProvision provisioned: %s", rm.req.NamespacedName)) + r.logger.Info(fmt.Sprintf("AWSIAMProvision provisioned: %s", r.request.NamespacedName)) - if err := rm.UpdateCRDStatus(awsIAMProvision, "Provisioned", ""); err != nil { + if err := r.updateCRDStatus(awsIAMProvision, "Provisioned", ""); err != nil { return ctrl.Result{}, err } } diff --git a/internal/controller/reconciliation_manager.go b/internal/controller/reconciliation_manager.go index ee2f2fc..8ccbca4 100644 --- a/internal/controller/reconciliation_manager.go +++ b/internal/controller/reconciliation_manager.go @@ -9,6 +9,7 @@ import ( "text/template" "time" + iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" "github.com/go-logr/logr" @@ -18,9 +19,6 @@ import ( "k8s.io/apimachinery/pkg/types" ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2" ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/log" - - iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" ) var ( @@ -31,34 +29,23 @@ var ( ) type oidcProviderTemplateData struct { - OIDCProviderARN string - OIDCProviderName string + oidcProviderARN string + oidcProviderName string } -type ReconciliationManager struct { - r *AWSIAMProvisionReconciler - ctx *context.Context - req *ctrl.Request - logger *logr.Logger -} - -func NewReconciliationManager(r *AWSIAMProvisionReconciler, ctx *context.Context, req *ctrl.Request) *ReconciliationManager { - logger := log.FromContext(*ctx) - - return &ReconciliationManager{ - r, - ctx, - req, - &logger, - } +type reconciliationManager struct { + context *context.Context + logger *logr.Logger + reconciler *AWSIAMProvisionReconciler + request *ctrl.Request } -func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvision, *ekscontrolplanev1.AWSManagedControlPlane, error) { +func (rm *reconciliationManager) getClusterResources() (*iamv1alpha1.AWSIAMProvision, *ekscontrolplanev1.AWSManagedControlPlane, error) { awsIAMProvision := &iamv1alpha1.AWSIAMProvision{} - if err := rm.r.Client.Get(*rm.ctx, rm.req.NamespacedName, awsIAMProvision); err != nil { + if err := rm.reconciler.Client.Get(*rm.context, rm.request.NamespacedName, awsIAMProvision); err != nil { if k8serrors.IsNotFound(err) { - rm.logger.Info(fmt.Sprintf("AWSIAMProvision not found: %s", rm.req.NamespacedName)) + rm.logger.Info(fmt.Sprintf("AWSIAMProvision not found: %s", rm.request.NamespacedName)) return nil, nil, nil } @@ -66,37 +53,37 @@ func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvi return nil, nil, err } - rm.logger.Info(fmt.Sprintf("AWSIAMProvision found: %s", rm.req.NamespacedName)) + rm.logger.Info(fmt.Sprintf("AWSIAMProvision found: %s", rm.request.NamespacedName)) eksControlPlane := &ekscontrolplanev1.AWSManagedControlPlane{} - namespacedName := types.NamespacedName{Name: awsIAMProvision.Spec.EksClusterName, Namespace: rm.req.NamespacedName.Namespace} + namespacedName := types.NamespacedName{Name: awsIAMProvision.Spec.EksClusterName, Namespace: rm.request.NamespacedName.Namespace} - if err := rm.r.Client.Get(*rm.ctx, namespacedName, eksControlPlane); err != nil { + if err := rm.reconciler.Client.Get(*rm.context, namespacedName, eksControlPlane); err != nil { if k8serrors.IsNotFound(err) { - msg := fmt.Sprintf("AWSManagedControlPlane of %s AWSIAMProvision not found: %s", rm.req.NamespacedName, namespacedName) + msg := fmt.Sprintf("AWSManagedControlPlane of %s AWSIAMProvision not found: %s", rm.request.NamespacedName, namespacedName) rm.logger.Info(msg) - if err := rm.UpdateCRDStatus(awsIAMProvision, "Provisioning", msg); err != nil { + if err := rm.updateCRDStatus(awsIAMProvision, "Provisioning", msg); err != nil { return nil, nil, err } return nil, nil, nil } - if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { + if err := rm.updateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, nil, err } return nil, nil, err } - rm.logger.Info(fmt.Sprintf("AWSManagedControlPlane of %s AWSIAMProvision found: %s", rm.req.NamespacedName, namespacedName)) + rm.logger.Info(fmt.Sprintf("AWSManagedControlPlane of %s AWSIAMProvision found: %s", rm.request.NamespacedName, namespacedName)) if !eksControlPlane.Status.Ready { - msg := fmt.Sprintf("AWSManagedControlPlane of %s AWSIAMProvision not ready: %s", rm.req.NamespacedName, namespacedName) + msg := fmt.Sprintf("AWSManagedControlPlane of %s AWSIAMProvision not ready: %s", rm.request.NamespacedName, namespacedName) rm.logger.Info(msg) - if err := rm.UpdateCRDStatus(awsIAMProvision, "Provisioning", msg); err != nil { + if err := rm.updateCRDStatus(awsIAMProvision, "Provisioning", msg); err != nil { return nil, nil, err } @@ -106,11 +93,11 @@ func (rm *ReconciliationManager) GetClusterResources() (*iamv1alpha1.AWSIAMProvi return awsIAMProvision, eksControlPlane, nil } -func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, name string, item *iamv1alpha1.AWSIAMProvisionRole) (*iamctrlv1alpha1.Role, error) { +func (rm *reconciliationManager) handleRole(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, name string, item *iamv1alpha1.AWSIAMProvisionRole) (*iamctrlv1alpha1.Role, error) { k8sResource := &iamctrlv1alpha1.Role{} - namespacedName := types.NamespacedName{Name: name, Namespace: rm.req.NamespacedName.Namespace} + namespacedName := types.NamespacedName{Name: name, Namespace: rm.request.NamespacedName.Namespace} - if err := rm.r.Client.Get(*rm.ctx, namespacedName, k8sResource); err != nil { + if err := rm.reconciler.Client.Get(*rm.context, namespacedName, k8sResource); err != nil { if k8serrors.IsNotFound(err) { // Create new role if err := rm.setAssumeRolePolicyDocument(awsIAMProvision, eksControlPlane, item); err != nil { @@ -124,28 +111,28 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP k8sResource.TypeMeta = roleMeta k8sResource.ObjectMeta = metav1.ObjectMeta{ Name: name, - Namespace: rm.req.NamespacedName.Namespace, + Namespace: rm.request.NamespacedName.Namespace, } k8sResource.Spec = item.Spec // Set ownerReferences to ensure that the created resource will be deleted when the custom resource object is removed - if err := ctrl.SetControllerReference(awsIAMProvision, k8sResource, rm.r.Scheme); err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { + if err := ctrl.SetControllerReference(awsIAMProvision, k8sResource, rm.reconciler.Scheme); err != nil { + if err := rm.updateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err } return nil, err } - if err = rm.r.Client.Create(*rm.ctx, k8sResource); err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { + if err = rm.reconciler.Client.Create(*rm.context, k8sResource); err != nil { + if err := rm.updateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err } return nil, err } - rm.logger.Info(fmt.Sprintf("IAM Role of %s AWSIAMProvision created: %s", rm.req.NamespacedName, namespacedName)) + rm.logger.Info(fmt.Sprintf("IAM Role of %s AWSIAMProvision created: %s", rm.request.NamespacedName, namespacedName)) return k8sResource, nil } @@ -169,34 +156,34 @@ func (rm *ReconciliationManager) HandleRole(awsIAMProvision *iamv1alpha1.AWSIAMP // Update role with new values k8sResource.Spec = item.Spec - if err := rm.r.Client.Update(*rm.ctx, k8sResource); err != nil { + if err := rm.reconciler.Client.Update(*rm.context, k8sResource); err != nil { return nil, err } - rm.logger.Info(fmt.Sprintf("IAM Role of %s AWSIAMProvision updated: %s", rm.req.NamespacedName, namespacedName)) + rm.logger.Info(fmt.Sprintf("IAM Role of %s AWSIAMProvision updated: %s", rm.request.NamespacedName, namespacedName)) return k8sResource, nil } -func (rm *ReconciliationManager) UpdateCRDStatus(awsIAMProvision *iamv1alpha1.AWSIAMProvision, phase, message string) error { +func (rm *reconciliationManager) updateCRDStatus(awsIAMProvision *iamv1alpha1.AWSIAMProvision, phase, message string) error { awsIAMProvision.Status.LastUpdatedTime = &metav1.Time{Time: time.Now()} awsIAMProvision.Status.Phase = phase awsIAMProvision.Status.Message = message - if err := rm.r.Status().Update(*rm.ctx, awsIAMProvision); err != nil { + if err := rm.reconciler.Status().Update(*rm.context, awsIAMProvision); err != nil { return errors.New(fmt.Sprintf("Unable to update status for CRD: %s", awsIAMProvision.Name)) } return nil } -func (rm *ReconciliationManager) validateRolePolicyRefs(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole) error { +func (rm *reconciliationManager) validateRolePolicyRefs(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole) error { for _, policyRef := range item.Spec.PolicyRefs { // Check IAM policy exists _, err := rm.getPolicy(awsIAMProvision, item, policyRef) if err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { + if err := rm.updateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return err } @@ -207,16 +194,16 @@ func (rm *ReconciliationManager) validateRolePolicyRefs(awsIAMProvision *iamv1al return nil } -func (rm *ReconciliationManager) getPolicy(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole, policyRef *ackv1alpha1.AWSResourceReferenceWrapper) (*iamctrlv1alpha1.Policy, error) { +func (rm *reconciliationManager) getPolicy(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole, policyRef *ackv1alpha1.AWSResourceReferenceWrapper) (*iamctrlv1alpha1.Policy, error) { k8sResource := &iamctrlv1alpha1.Policy{} namespacedName := types.NamespacedName{Name: *policyRef.From.Name, Namespace: *policyRef.From.Namespace} - if err := rm.r.Client.Get(*rm.ctx, namespacedName, k8sResource); err != nil { + if err := rm.reconciler.Client.Get(*rm.context, namespacedName, k8sResource); err != nil { if k8serrors.IsNotFound(err) { - err = errors.New(fmt.Sprintf("IAM Policy of %s IAM Role of %s AWSIAMProvision not found: %s", *item.Spec.Name, rm.req.NamespacedName, namespacedName)) + err = errors.New(fmt.Sprintf("IAM Policy of %s IAM Role of %s AWSIAMProvision not found: %s", *item.Spec.Name, rm.request.NamespacedName, namespacedName)) } - if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { + if err := rm.updateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err } @@ -226,15 +213,15 @@ func (rm *ReconciliationManager) getPolicy(awsIAMProvision *iamv1alpha1.AWSIAMPr return k8sResource, nil } -func (rm *ReconciliationManager) setAssumeRolePolicyDocument(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, item *iamv1alpha1.AWSIAMProvisionRole) error { +func (rm *reconciliationManager) setAssumeRolePolicyDocument(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, item *iamv1alpha1.AWSIAMProvisionRole) error { oidcProviderARN := eksControlPlane.Status.OIDCProvider.ARN _, oidcProviderName, oidcProviderARNFound := strings.Cut(oidcProviderARN, "/") if !oidcProviderARNFound { - namespacedName := types.NamespacedName{Name: awsIAMProvision.Spec.EksClusterName, Namespace: rm.req.NamespacedName.Namespace} - err := errors.New(fmt.Sprintf("OIDC ARN of %s AWSManagedControlPlane of %s AWSIAMProvision malformed: %s", namespacedName, rm.req.NamespacedName, oidcProviderARN)) + namespacedName := types.NamespacedName{Name: awsIAMProvision.Spec.EksClusterName, Namespace: rm.request.NamespacedName.Namespace} + err := errors.New(fmt.Sprintf("OIDC ARN of %s AWSManagedControlPlane of %s AWSIAMProvision malformed: %s", namespacedName, rm.request.NamespacedName, oidcProviderARN)) - if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { + if err := rm.updateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return err } @@ -242,7 +229,7 @@ func (rm *ReconciliationManager) setAssumeRolePolicyDocument(awsIAMProvision *ia } if assumeRolePolicyDocument, err := rm.renderOIDCProviderTemplate(*item.Spec.AssumeRolePolicyDocument, oidcProviderARN, oidcProviderName); err != nil { - if err := rm.UpdateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { + if err := rm.updateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return err } @@ -254,7 +241,7 @@ func (rm *ReconciliationManager) setAssumeRolePolicyDocument(awsIAMProvision *ia } } -func (rm *ReconciliationManager) renderOIDCProviderTemplate(oidcProviderTemplate, oidcProviderARN, oidcProviderName string) (string, error) { +func (rm *reconciliationManager) renderOIDCProviderTemplate(oidcProviderTemplate, oidcProviderARN, oidcProviderName string) (string, error) { oidcProviderTemplateData := oidcProviderTemplateData{oidcProviderARN, oidcProviderName} tmpl, err := template.New("").Parse(oidcProviderTemplate) @@ -270,7 +257,7 @@ func (rm *ReconciliationManager) renderOIDCProviderTemplate(oidcProviderTemplate return tmplString.String(), nil } -func (rm *ReconciliationManager) transformPoliciesToRefs(policies []*iamctrlv1alpha1.Policy) []*ackv1alpha1.AWSResourceReferenceWrapper { +func (rm *reconciliationManager) transformPoliciesToRefs(policies []*iamctrlv1alpha1.Policy) []*ackv1alpha1.AWSResourceReferenceWrapper { var policyRefs []*ackv1alpha1.AWSResourceReferenceWrapper for _, policy := range policies { From 53081c3b4579ef41e44e8a90637eb0f18c0bdecd Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 15:46:07 +0100 Subject: [PATCH 13/15] Embed reconciliationManager structure into AWSIAMProvisionReconciler. --- cmd/main.go | 5 +- .../controller/awsiamprovision_controller.go | 5 +- internal/controller/reconciliation_manager.go | 49 ++++++++++--------- internal/controller/suite_test.go | 1 - 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index b719134..6a8977e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -127,8 +127,9 @@ func main() { } if err = (&controller.AWSIAMProvisionReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + ReconciliationManager: &controller.ReconciliationManager{}, + Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AWSIAMProvision") os.Exit(1) diff --git a/internal/controller/awsiamprovision_controller.go b/internal/controller/awsiamprovision_controller.go index dc37e8b..62b02bd 100644 --- a/internal/controller/awsiamprovision_controller.go +++ b/internal/controller/awsiamprovision_controller.go @@ -37,7 +37,7 @@ const ( // AWSIAMProvisionReconciler reconciles a AWSIAMProvision object type AWSIAMProvisionReconciler struct { client.Client - *reconciliationManager + *ReconciliationManager Scheme *runtime.Scheme } @@ -54,8 +54,11 @@ func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Requ logger := log.FromContext(ctx) r.context = &ctx + r.client = r.Client r.logger = &logger r.request = &req + r.scheme = r.Scheme + r.status = r.Status() awsIAMProvision, eksControlPlane, err := r.getClusterResources() if err != nil { diff --git a/internal/controller/reconciliation_manager.go b/internal/controller/reconciliation_manager.go index 8ccbca4..de371db 100644 --- a/internal/controller/reconciliation_manager.go +++ b/internal/controller/reconciliation_manager.go @@ -5,11 +5,11 @@ import ( "context" "errors" "fmt" + "k8s.io/apimachinery/pkg/runtime" "strings" "text/template" "time" - iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" iamctrlv1alpha1 "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1" ackv1alpha1 "github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1" "github.com/go-logr/logr" @@ -19,6 +19,9 @@ import ( "k8s.io/apimachinery/pkg/types" ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + iamv1alpha1 "aws-iam-provisioner.operators.infra/api/v1alpha1" ) var ( @@ -33,17 +36,19 @@ type oidcProviderTemplateData struct { oidcProviderName string } -type reconciliationManager struct { - context *context.Context - logger *logr.Logger - reconciler *AWSIAMProvisionReconciler - request *ctrl.Request +type ReconciliationManager struct { + context *context.Context + client client.Client + logger *logr.Logger + request *ctrl.Request + scheme *runtime.Scheme + status client.SubResourceWriter } -func (rm *reconciliationManager) getClusterResources() (*iamv1alpha1.AWSIAMProvision, *ekscontrolplanev1.AWSManagedControlPlane, error) { +func (rm *ReconciliationManager) getClusterResources() (*iamv1alpha1.AWSIAMProvision, *ekscontrolplanev1.AWSManagedControlPlane, error) { awsIAMProvision := &iamv1alpha1.AWSIAMProvision{} - if err := rm.reconciler.Client.Get(*rm.context, rm.request.NamespacedName, awsIAMProvision); err != nil { + if err := rm.client.Get(*rm.context, rm.request.NamespacedName, awsIAMProvision); err != nil { if k8serrors.IsNotFound(err) { rm.logger.Info(fmt.Sprintf("AWSIAMProvision not found: %s", rm.request.NamespacedName)) @@ -58,7 +63,7 @@ func (rm *reconciliationManager) getClusterResources() (*iamv1alpha1.AWSIAMProvi eksControlPlane := &ekscontrolplanev1.AWSManagedControlPlane{} namespacedName := types.NamespacedName{Name: awsIAMProvision.Spec.EksClusterName, Namespace: rm.request.NamespacedName.Namespace} - if err := rm.reconciler.Client.Get(*rm.context, namespacedName, eksControlPlane); err != nil { + if err := rm.client.Get(*rm.context, namespacedName, eksControlPlane); err != nil { if k8serrors.IsNotFound(err) { msg := fmt.Sprintf("AWSManagedControlPlane of %s AWSIAMProvision not found: %s", rm.request.NamespacedName, namespacedName) rm.logger.Info(msg) @@ -93,11 +98,11 @@ func (rm *reconciliationManager) getClusterResources() (*iamv1alpha1.AWSIAMProvi return awsIAMProvision, eksControlPlane, nil } -func (rm *reconciliationManager) handleRole(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, name string, item *iamv1alpha1.AWSIAMProvisionRole) (*iamctrlv1alpha1.Role, error) { +func (rm *ReconciliationManager) handleRole(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, name string, item *iamv1alpha1.AWSIAMProvisionRole) (*iamctrlv1alpha1.Role, error) { k8sResource := &iamctrlv1alpha1.Role{} namespacedName := types.NamespacedName{Name: name, Namespace: rm.request.NamespacedName.Namespace} - if err := rm.reconciler.Client.Get(*rm.context, namespacedName, k8sResource); err != nil { + if err := rm.client.Get(*rm.context, namespacedName, k8sResource); err != nil { if k8serrors.IsNotFound(err) { // Create new role if err := rm.setAssumeRolePolicyDocument(awsIAMProvision, eksControlPlane, item); err != nil { @@ -116,7 +121,7 @@ func (rm *reconciliationManager) handleRole(awsIAMProvision *iamv1alpha1.AWSIAMP k8sResource.Spec = item.Spec // Set ownerReferences to ensure that the created resource will be deleted when the custom resource object is removed - if err := ctrl.SetControllerReference(awsIAMProvision, k8sResource, rm.reconciler.Scheme); err != nil { + if err := ctrl.SetControllerReference(awsIAMProvision, k8sResource, rm.scheme); err != nil { if err := rm.updateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err } @@ -124,7 +129,7 @@ func (rm *reconciliationManager) handleRole(awsIAMProvision *iamv1alpha1.AWSIAMP return nil, err } - if err = rm.reconciler.Client.Create(*rm.context, k8sResource); err != nil { + if err = rm.client.Create(*rm.context, k8sResource); err != nil { if err := rm.updateCRDStatus(awsIAMProvision, "Failed", err.Error()); err != nil { return nil, err } @@ -156,7 +161,7 @@ func (rm *reconciliationManager) handleRole(awsIAMProvision *iamv1alpha1.AWSIAMP // Update role with new values k8sResource.Spec = item.Spec - if err := rm.reconciler.Client.Update(*rm.context, k8sResource); err != nil { + if err := rm.client.Update(*rm.context, k8sResource); err != nil { return nil, err } @@ -165,19 +170,19 @@ func (rm *reconciliationManager) handleRole(awsIAMProvision *iamv1alpha1.AWSIAMP return k8sResource, nil } -func (rm *reconciliationManager) updateCRDStatus(awsIAMProvision *iamv1alpha1.AWSIAMProvision, phase, message string) error { +func (rm *ReconciliationManager) updateCRDStatus(awsIAMProvision *iamv1alpha1.AWSIAMProvision, phase, message string) error { awsIAMProvision.Status.LastUpdatedTime = &metav1.Time{Time: time.Now()} awsIAMProvision.Status.Phase = phase awsIAMProvision.Status.Message = message - if err := rm.reconciler.Status().Update(*rm.context, awsIAMProvision); err != nil { + if err := rm.status.Update(*rm.context, awsIAMProvision); err != nil { return errors.New(fmt.Sprintf("Unable to update status for CRD: %s", awsIAMProvision.Name)) } return nil } -func (rm *reconciliationManager) validateRolePolicyRefs(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole) error { +func (rm *ReconciliationManager) validateRolePolicyRefs(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole) error { for _, policyRef := range item.Spec.PolicyRefs { // Check IAM policy exists _, err := rm.getPolicy(awsIAMProvision, item, policyRef) @@ -194,11 +199,11 @@ func (rm *reconciliationManager) validateRolePolicyRefs(awsIAMProvision *iamv1al return nil } -func (rm *reconciliationManager) getPolicy(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole, policyRef *ackv1alpha1.AWSResourceReferenceWrapper) (*iamctrlv1alpha1.Policy, error) { +func (rm *ReconciliationManager) getPolicy(awsIAMProvision *iamv1alpha1.AWSIAMProvision, item *iamv1alpha1.AWSIAMProvisionRole, policyRef *ackv1alpha1.AWSResourceReferenceWrapper) (*iamctrlv1alpha1.Policy, error) { k8sResource := &iamctrlv1alpha1.Policy{} namespacedName := types.NamespacedName{Name: *policyRef.From.Name, Namespace: *policyRef.From.Namespace} - if err := rm.reconciler.Client.Get(*rm.context, namespacedName, k8sResource); err != nil { + if err := rm.client.Get(*rm.context, namespacedName, k8sResource); err != nil { if k8serrors.IsNotFound(err) { err = errors.New(fmt.Sprintf("IAM Policy of %s IAM Role of %s AWSIAMProvision not found: %s", *item.Spec.Name, rm.request.NamespacedName, namespacedName)) } @@ -213,7 +218,7 @@ func (rm *reconciliationManager) getPolicy(awsIAMProvision *iamv1alpha1.AWSIAMPr return k8sResource, nil } -func (rm *reconciliationManager) setAssumeRolePolicyDocument(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, item *iamv1alpha1.AWSIAMProvisionRole) error { +func (rm *ReconciliationManager) setAssumeRolePolicyDocument(awsIAMProvision *iamv1alpha1.AWSIAMProvision, eksControlPlane *ekscontrolplanev1.AWSManagedControlPlane, item *iamv1alpha1.AWSIAMProvisionRole) error { oidcProviderARN := eksControlPlane.Status.OIDCProvider.ARN _, oidcProviderName, oidcProviderARNFound := strings.Cut(oidcProviderARN, "/") @@ -241,7 +246,7 @@ func (rm *reconciliationManager) setAssumeRolePolicyDocument(awsIAMProvision *ia } } -func (rm *reconciliationManager) renderOIDCProviderTemplate(oidcProviderTemplate, oidcProviderARN, oidcProviderName string) (string, error) { +func (rm *ReconciliationManager) renderOIDCProviderTemplate(oidcProviderTemplate, oidcProviderARN, oidcProviderName string) (string, error) { oidcProviderTemplateData := oidcProviderTemplateData{oidcProviderARN, oidcProviderName} tmpl, err := template.New("").Parse(oidcProviderTemplate) @@ -257,7 +262,7 @@ func (rm *reconciliationManager) renderOIDCProviderTemplate(oidcProviderTemplate return tmplString.String(), nil } -func (rm *reconciliationManager) transformPoliciesToRefs(policies []*iamctrlv1alpha1.Policy) []*ackv1alpha1.AWSResourceReferenceWrapper { +func (rm *ReconciliationManager) transformPoliciesToRefs(policies []*iamctrlv1alpha1.Policy) []*ackv1alpha1.AWSResourceReferenceWrapper { var policyRefs []*ackv1alpha1.AWSResourceReferenceWrapper for _, policy := range policies { diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index 68f988c..8ac3dfc 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -25,7 +25,6 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" From 948537733b7b6ef46548de01379fa2546fb387c8 Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 15:54:59 +0100 Subject: [PATCH 14/15] Fix template OIDCProviderARN and OIDCProviderName. --- config/samples/iam_v1alpha1_awsiamprovision.yaml | 4 ++-- internal/controller/reconciliation_manager.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/samples/iam_v1alpha1_awsiamprovision.yaml b/config/samples/iam_v1alpha1_awsiamprovision.yaml index e2769e6..97a5a84 100644 --- a/config/samples/iam_v1alpha1_awsiamprovision.yaml +++ b/config/samples/iam_v1alpha1_awsiamprovision.yaml @@ -18,12 +18,12 @@ spec: "Sid": "", "Effect": "Allow", "Principal": { - "Federated": "{{ .oidcProviderARN }}" + "Federated": "{{ .OIDCProviderARN }}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { - "{{ .oidcProviderName }}:sub": "system:serviceaccount:kube-system:ebs-csi-controller" + "{{ .OIDCProviderName }}:sub": "system:serviceaccount:kube-system:ebs-csi-controller" } } } diff --git a/internal/controller/reconciliation_manager.go b/internal/controller/reconciliation_manager.go index de371db..4454de5 100644 --- a/internal/controller/reconciliation_manager.go +++ b/internal/controller/reconciliation_manager.go @@ -32,8 +32,8 @@ var ( ) type oidcProviderTemplateData struct { - oidcProviderARN string - oidcProviderName string + OIDCProviderARN string + OIDCProviderName string } type ReconciliationManager struct { From 64bb61fd643d6d0c2f5861023b741f1b9bf440a8 Mon Sep 17 00:00:00 2001 From: Anton Novikov Date: Thu, 12 Dec 2024 15:59:46 +0100 Subject: [PATCH 15/15] Fix template OIDCProviderARN and OIDCProviderName. --- internal/controller/awsiamprovision_controller.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/internal/controller/awsiamprovision_controller.go b/internal/controller/awsiamprovision_controller.go index 62b02bd..c1051f0 100644 --- a/internal/controller/awsiamprovision_controller.go +++ b/internal/controller/awsiamprovision_controller.go @@ -53,12 +53,7 @@ type AWSIAMProvisionReconciler struct { func (r *AWSIAMProvisionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { logger := log.FromContext(ctx) - r.context = &ctx - r.client = r.Client - r.logger = &logger - r.request = &req - r.scheme = r.Scheme - r.status = r.Status() + r.ReconciliationManager = &ReconciliationManager{&ctx, r.Client, &logger, &req, r.Scheme, r.Status()} awsIAMProvision, eksControlPlane, err := r.getClusterResources() if err != nil {