From a3d160c47cb53701b5422c5f66ca34843d185e00 Mon Sep 17 00:00:00 2001 From: kkb0318 Date: Wed, 15 May 2024 21:58:49 +0900 Subject: [PATCH] add IRSA api --- PROJECT | 9 ++ README.md | 18 ++- api/v1alpha1/irsa_types.go | 81 +++++++++++ api/v1alpha1/zz_generated.deepcopy.go | 131 ++++++++++++++++++ cmd/main.go | 7 + .../bases/irsa.kkb0318.github.io_irsas.yaml | 83 +++++++++++ config/crd/kustomization.yaml | 3 + config/rbac/irsa_editor_role.yaml | 31 +++++ config/rbac/irsa_viewer_role.yaml | 27 ++++ config/rbac/role.yaml | 26 ++++ config/samples/irsa_v1alpha1_irsa.yaml | 12 ++ config/samples/kustomization.yaml | 1 + docs/api.md | 75 +++++++++- docs/config.yaml | 2 +- internal/controller/irsa_controller.go | 62 +++++++++ internal/controller/irsa_controller_test.go | 84 +++++++++++ 16 files changed, 647 insertions(+), 5 deletions(-) create mode 100644 api/v1alpha1/irsa_types.go create mode 100644 config/crd/bases/irsa.kkb0318.github.io_irsas.yaml create mode 100644 config/rbac/irsa_editor_role.yaml create mode 100644 config/rbac/irsa_viewer_role.yaml create mode 100644 config/samples/irsa_v1alpha1_irsa.yaml create mode 100644 internal/controller/irsa_controller.go create mode 100644 internal/controller/irsa_controller_test.go diff --git a/PROJECT b/PROJECT index 52256c0..7915145 100644 --- a/PROJECT +++ b/PROJECT @@ -20,4 +20,13 @@ resources: kind: IRSASetup path: github.com/kkb0318/irsa-manager/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: kkb0318.github.io + group: irsa + kind: IRSA + path: github.com/kkb0318/irsa-manager/api/v1alpha1 + version: v1alpha1 version: "3" diff --git a/README.md b/README.md index 3b2b64a..356c2c5 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,20 @@ TODO - [x] delete secret -- [x] delete cloud resource -- [ ] only once secret creation (status check) +- [x] delete s3 +- [x] only once secret creation (status check) - [x] no update secret -- [ ] no update bucket object +- [x] no update bucket object +- [x] delete idp +- [x] issue: when irsasetup was deleted, resource remained with some error occured +- [x] certificate +- [ ] check keys.json keyid has to be empty or not +- [ ] IRSA api +- [ ] use with cert-manager + - [ ] validation webhook (invalid to change) + +``` +kubectl get secret -n kube-system irsa-manager-key -o jsonpath="{.data.ssh-privatekey}" | base64 --decode | sudo tee /etc/kubernetes/pki/irsa-manager.key > /dev/null +kubectl get secret -n kube-system irsa-manager-key -o jsonpath="{.data.ssh-publickey}" | base64 --decode | sudo tee /etc/kubernetes/pki/irsa-manager.pub > /dev/null +``` diff --git a/api/v1alpha1/irsa_types.go b/api/v1alpha1/irsa_types.go new file mode 100644 index 0000000..00fa184 --- /dev/null +++ b/api/v1alpha1/irsa_types.go @@ -0,0 +1,81 @@ +/* +Copyright 2024. + +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 v1alpha1 + +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. + +// IRSASpec defines the desired state of IRSA +type IRSASpec struct { + // ServiceAccount represents the Kubernetes service account associated with the IRSA + ServiceAccount IRSAServiceAccount `json:"serviceAccount,omitempty"` + // IamRole represents the IAM role details associated with the IRSA + IamRole IamRole `json:"iamRole,omitempty"` + // IamPolicies represents the list of IAM policies to be attached to the IAM role + IamPolicies []string `json:"iamPolicies,omitempty"` +} + +// IRSAServiceAccount represents the details of the Kubernetes service account +type IRSAServiceAccount struct { + // Name represents the name of the Kubernetes service account + Name string `json:"name,omitempty"` + // Namespaces represents the list of namespaces where the service account is used + Namespaces []string `json:"namespaces,omitempty"` +} + +// IamRole represents the IAM role configuration +type IamRole struct { + // Create specifies whether to create the IAM role or not + Create bool `json:"create,omitempty"` + // Name represents the name of the IAM role + Name string `json:"name,omitempty"` +} + +// IRSAStatus defines the observed state of IRSA +type IRSAStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// IRSA is the Schema for the irsas API +type IRSA struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec IRSASpec `json:"spec,omitempty"` + Status IRSAStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// IRSAList contains a list of IRSA +type IRSAList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IRSA `json:"items"` +} + +func init() { + SchemeBuilder.Register(&IRSA{}, &IRSAList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 184cfcb..d81dc27 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -57,6 +57,85 @@ func (in *Discovery) DeepCopy() *Discovery { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IRSA) DeepCopyInto(out *IRSA) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IRSA. +func (in *IRSA) DeepCopy() *IRSA { + if in == nil { + return nil + } + out := new(IRSA) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IRSA) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IRSAList) DeepCopyInto(out *IRSAList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IRSA, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IRSAList. +func (in *IRSAList) DeepCopy() *IRSAList { + if in == nil { + return nil + } + out := new(IRSAList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IRSAList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IRSAServiceAccount) DeepCopyInto(out *IRSAServiceAccount) { + *out = *in + if in.Namespaces != nil { + in, out := &in.Namespaces, &out.Namespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IRSAServiceAccount. +func (in *IRSAServiceAccount) DeepCopy() *IRSAServiceAccount { + if in == nil { + return nil + } + out := new(IRSAServiceAccount) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IRSASetup) DeepCopyInto(out *IRSASetup) { *out = *in @@ -155,6 +234,58 @@ func (in *IRSASetupStatus) DeepCopy() *IRSASetupStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IRSASpec) DeepCopyInto(out *IRSASpec) { + *out = *in + in.ServiceAccount.DeepCopyInto(&out.ServiceAccount) + out.IamRole = in.IamRole + if in.IamPolicies != nil { + in, out := &in.IamPolicies, &out.IamPolicies + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IRSASpec. +func (in *IRSASpec) DeepCopy() *IRSASpec { + if in == nil { + return nil + } + out := new(IRSASpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IRSAStatus) DeepCopyInto(out *IRSAStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IRSAStatus. +func (in *IRSAStatus) DeepCopy() *IRSAStatus { + if in == nil { + return nil + } + out := new(IRSAStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IamRole) DeepCopyInto(out *IamRole) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IamRole. +func (in *IamRole) DeepCopy() *IamRole { + if in == nil { + return nil + } + out := new(IamRole) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *S3Discovery) DeepCopyInto(out *S3Discovery) { *out = *in diff --git a/cmd/main.go b/cmd/main.go index eb5f464..7147a54 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -129,6 +129,13 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "IRSASetup") os.Exit(1) } + if err = (&controller.IRSAReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "IRSA") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/config/crd/bases/irsa.kkb0318.github.io_irsas.yaml b/config/crd/bases/irsa.kkb0318.github.io_irsas.yaml new file mode 100644 index 0000000..98ad280 --- /dev/null +++ b/config/crd/bases/irsa.kkb0318.github.io_irsas.yaml @@ -0,0 +1,83 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: irsas.irsa.kkb0318.github.io +spec: + group: irsa.kkb0318.github.io + names: + kind: IRSA + listKind: IRSAList + plural: irsas + singular: irsa + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: IRSA is the Schema for the irsas API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: IRSASpec defines the desired state of IRSA + properties: + iamPolicies: + description: IamPolicies represents the list of IAM policies to be + attached to the IAM role + items: + type: string + type: array + iamRole: + description: IamRole represents the IAM role details associated with + the IRSA + properties: + create: + description: Create specifies whether to create the IAM role or + not + type: boolean + name: + description: Name represents the name of the IAM role + type: string + type: object + serviceAccount: + description: ServiceAccount represents the Kubernetes service account + associated with the IRSA + properties: + name: + description: Name represents the name of the Kubernetes service + account + type: string + namespaces: + description: Namespaces represents the list of namespaces where + the service account is used + items: + type: string + type: array + type: object + type: object + status: + description: IRSAStatus defines the observed state of IRSA + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 33ea773..22cdfd4 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -3,17 +3,20 @@ # It should be run by config/default resources: - bases/irsa.kkb0318.github.io_irsasetups.yaml +- bases/irsa.kkb0318.github.io_irsas.yaml #+kubebuilder:scaffold:crdkustomizeresource patches: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. # patches here are for enabling the conversion webhook for each CRD #- path: patches/webhook_in_irsasetups.yaml +#- path: patches/webhook_in_irsas.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. # patches here are for enabling the CA injection for each CRD #- path: patches/cainjection_in_irsasetups.yaml +#- path: patches/cainjection_in_irsas.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # [WEBHOOK] To enable webhook, uncomment the following section diff --git a/config/rbac/irsa_editor_role.yaml b/config/rbac/irsa_editor_role.yaml new file mode 100644 index 0000000..6f64fb0 --- /dev/null +++ b/config/rbac/irsa_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit irsas. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: irsa-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: irsa-manager + app.kubernetes.io/part-of: irsa-manager + app.kubernetes.io/managed-by: kustomize + name: irsa-editor-role +rules: +- apiGroups: + - irsa.kkb0318.github.io + resources: + - irsas + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - irsa.kkb0318.github.io + resources: + - irsas/status + verbs: + - get diff --git a/config/rbac/irsa_viewer_role.yaml b/config/rbac/irsa_viewer_role.yaml new file mode 100644 index 0000000..245cdeb --- /dev/null +++ b/config/rbac/irsa_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view irsas. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: irsa-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: irsa-manager + app.kubernetes.io/part-of: irsa-manager + app.kubernetes.io/managed-by: kustomize + name: irsa-viewer-role +rules: +- apiGroups: + - irsa.kkb0318.github.io + resources: + - irsas + verbs: + - get + - list + - watch +- apiGroups: + - irsa.kkb0318.github.io + resources: + - irsas/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index d825cd7..812fc01 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -76,6 +76,32 @@ rules: - patch - update - watch +- apiGroups: + - irsa.kkb0318.github.io + resources: + - irsas + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - irsa.kkb0318.github.io + resources: + - irsas/finalizers + verbs: + - update +- apiGroups: + - irsa.kkb0318.github.io + resources: + - irsas/status + verbs: + - get + - patch + - update - apiGroups: - irsa.kkb0318.github.io resources: diff --git a/config/samples/irsa_v1alpha1_irsa.yaml b/config/samples/irsa_v1alpha1_irsa.yaml new file mode 100644 index 0000000..d94e1a1 --- /dev/null +++ b/config/samples/irsa_v1alpha1_irsa.yaml @@ -0,0 +1,12 @@ +apiVersion: irsa.kkb0318.github.io/v1alpha1 +kind: IRSA +metadata: + labels: + app.kubernetes.io/name: irsa + app.kubernetes.io/instance: irsa-sample + app.kubernetes.io/part-of: irsa-manager + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: irsa-manager + name: irsa-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index f28b49f..8df12c2 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -1,4 +1,5 @@ ## Append samples of your project ## resources: - irsa_v1alpha1_irsasetup.yaml +- irsa_v1alpha1_irsa.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/docs/api.md b/docs/api.md index 1743b0f..e91038a 100644 --- a/docs/api.md +++ b/docs/api.md @@ -9,6 +9,7 @@ Package v1alpha1 contains API Schema definitions for the irsa v1alpha1 API group ### Resource Types +- [IRSA](#irsa) - [IRSASetup](#irsasetup) @@ -46,6 +47,41 @@ _Appears in:_ | `s3` _[S3Discovery](#s3discovery)_ | S3 specifies the AWS S3 bucket details where the OIDC provider's discovery information is hosted. | | | +#### IRSA + + + +IRSA is the Schema for the irsas API + + + + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `irsa.kkb0318.github.io/v1alpha1` | | | +| `kind` _string_ | `IRSA` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `spec` _[IRSASpec](#irsaspec)_ | | | | + + +#### IRSAServiceAccount + + + +IRSAServiceAccount represents the details of the Kubernetes service account + + + +_Appears in:_ +- [IRSASpec](#irsaspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | Name represents the name of the Kubernetes service account | | | +| `namespaces` _string array_ | Namespaces represents the list of namespaces where the service account is used | | | + + #### IRSASetup @@ -60,7 +96,7 @@ IRSASetup represents a configuration for setting up IAM Roles for Service Accoun | --- | --- | --- | --- | | `apiVersion` _string_ | `irsa.kkb0318.github.io/v1alpha1` | | | | `kind` _string_ | `IRSASetup` | | | -| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | | `spec` _[IRSASetupSpec](#irsasetupspec)_ | | | | @@ -85,6 +121,43 @@ _Appears in:_ +#### IRSASpec + + + +IRSASpec defines the desired state of IRSA + + + +_Appears in:_ +- [IRSA](#irsa) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `serviceAccount` _[IRSAServiceAccount](#irsaserviceaccount)_ | ServiceAccount represents the Kubernetes service account associated with the IRSA | | | +| `iamRole` _[IamRole](#iamrole)_ | IamRole represents the IAM role details associated with the IRSA | | | +| `iamPolicies` _string array_ | IamPolicies represents the list of IAM policies to be attached to the IAM role | | | + + + + +#### IamRole + + + +IamRole represents the IAM role configuration + + + +_Appears in:_ +- [IRSASpec](#irsaspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `create` _boolean_ | Create specifies whether to create the IAM role or not | | | +| `name` _string_ | Name represents the name of the IAM role | | | + + #### S3Discovery diff --git a/docs/config.yaml b/docs/config.yaml index 0755c12..0af6b99 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -7,4 +7,4 @@ processor: - "TypeMeta$" render: - kubernetesVersion: 1.28 + kubernetesVersion: 1.29 diff --git a/internal/controller/irsa_controller.go b/internal/controller/irsa_controller.go new file mode 100644 index 0000000..ffc71de --- /dev/null +++ b/internal/controller/irsa_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2024. + +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" + + "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" + + irsav1alpha1 "github.com/kkb0318/irsa-manager/api/v1alpha1" +) + +// IRSAReconciler reconciles a IRSA object +type IRSAReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=irsa.kkb0318.github.io,resources=irsas,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=irsa.kkb0318.github.io,resources=irsas/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=irsa.kkb0318.github.io,resources=irsas/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the IRSA 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.16.3/pkg/reconcile +func (r *IRSAReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *IRSAReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&irsav1alpha1.IRSA{}). + Complete(r) +} diff --git a/internal/controller/irsa_controller_test.go b/internal/controller/irsa_controller_test.go new file mode 100644 index 0000000..ec2c5cb --- /dev/null +++ b/internal/controller/irsa_controller_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2024. + +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" + + irsav1alpha1 "github.com/kkb0318/irsa-manager/api/v1alpha1" +) + +var _ = Describe("IRSA 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 + } + irsa := &irsav1alpha1.IRSA{} + + BeforeEach(func() { + By("creating the custom resource for the Kind IRSA") + err := k8sClient.Get(ctx, typeNamespacedName, irsa) + if err != nil && errors.IsNotFound(err) { + resource := &irsav1alpha1.IRSA{ + 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 := &irsav1alpha1.IRSA{} + err := k8sClient.Get(ctx, typeNamespacedName, resource) + Expect(err).NotTo(HaveOccurred()) + + By("Cleanup the specific resource instance IRSA") + Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) + }) + It("should successfully reconcile the resource", func() { + By("Reconciling the created resource") + controllerReconciler := &IRSAReconciler{ + 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. + }) + }) +})