From 429dc18be8ec639cf517eeb1022218c6a347a8d9 Mon Sep 17 00:00:00 2001 From: simone Date: Mon, 10 Jun 2024 11:08:41 +0200 Subject: [PATCH 1/8] Feature n. 1 --- .../controller/WebSiteReconciler.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java index ae78af1..6daf9db 100644 --- a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java +++ b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java @@ -1,9 +1,11 @@ package intre.it.javaoperator.controller; import intre.it.javaoperator.model.WebSite; +import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.api.reconciler.Context; @ControllerConfiguration public class WebSiteReconciler implements Reconciler, Cleaner { @@ -15,6 +17,22 @@ public WebSiteReconciler() { @Override public UpdateControl reconcile(WebSite WebSite, Context context) throws Exception { + Pod pod = new PodBuilder() + .withKind("Pod") + .withApiVersion("v1") + .withMetadata( + new ObjectMetaBuilder() + .withName(WebSite.getSpec().getWebSiteName()) // Leggo le informazioni della Custom Resource Creata + .build()) + .withSpec(new PodSpecBuilder() + .withContainers(new ContainerBuilder() + .withName(WebSite.getSpec().getWebSiteName()) // OPZIONALE: Leggo le informazioni della Custom Resource Creata + .withImage("nginx:1.14.2") + .build()) + .build()) + .build(); + + client.pods().resource(pod).create(); return UpdateControl.patchStatus(WebSite); } From 75a8e9f79220ee8dadf80ef4327af07a1b7bc50a Mon Sep 17 00:00:00 2001 From: simone Date: Mon, 10 Jun 2024 11:12:04 +0200 Subject: [PATCH 2/8] Feature n. 2 --- .../java/intre/it/javaoperator/controller/WebSiteReconciler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java index 6daf9db..dc97a95 100644 --- a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java +++ b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java @@ -38,6 +38,7 @@ public UpdateControl reconcile(WebSite WebSite, Context contex @Override public DeleteControl cleanup(WebSite webSite, Context context) { + client.pods().withName(webSite.getSpec().getWebSiteName()).delete(); // cancello il pod return DeleteControl.defaultDelete(); } } From ed332e6e2e5ccc4c5492dce26767f07a4d54e166 Mon Sep 17 00:00:00 2001 From: simone Date: Mon, 10 Jun 2024 14:01:16 +0200 Subject: [PATCH 3/8] Feature n. 3 --- Readme.md | 6 ++- kubernetes-charts/operator-role.yaml | 12 +++++ kubernetes-charts/websites.intre.it-v1.yml | 40 +++++++++++++++++ .../controller/WebSiteReconciler.java | 45 ++++++++++++------- .../it/javaoperator/model/WebSiteSpec.java | 9 ++++ 5 files changed, 95 insertions(+), 17 deletions(-) create mode 100644 kubernetes-charts/websites.intre.it-v1.yml diff --git a/Readme.md b/Readme.md index 541dc63..ddec947 100644 --- a/Readme.md +++ b/Readme.md @@ -20,7 +20,7 @@ You should start from this schema and implement the following feature: - feat n.2: When a custom resource has been deleted, remove the linked resources (Pod) - feat n.3: When a new custom resource has been created or updated, the operator should deploy a deployment manifest and take the number of replicas from the new custom resource - feat n.4: When the pod starts, update the default nginx index.html and put inside a short description from the custom resource -- feat n.5: Show time: 🎉 Create a NodePort service for that deployment and retreive the public ip address. +- feat n.5: Show time: 🎉 Create a NodePort service for that deployment and retrieve the public ip address. ## How to generate manifests @@ -51,3 +51,7 @@ Apply it: (*) Reconciles: it stands for the act of the operator to edit (reconcile) the status of the kubernetes cluster as we want (looking at the custom resource) + + +https://docs.openshift.com/container-platform/4.11/operators/operator_sdk/java/osdk-java-tutorial.html +https://github.com/kubernetes-client/java/tree/b42fae2b5437836f8c0254d8f19f3a7ba9ebd503/kubernetes/docs diff --git a/kubernetes-charts/operator-role.yaml b/kubernetes-charts/operator-role.yaml index 5d1bc59..44b2711 100644 --- a/kubernetes-charts/operator-role.yaml +++ b/kubernetes-charts/operator-role.yaml @@ -14,6 +14,18 @@ rules: - create - update - delete +- apiGroups: + - "apps" + resources: + - deployments + verbs: + - get + - list + - create + - update + - delete + - watch + - patch - apiGroups: - coordination.k8s.io resources: diff --git a/kubernetes-charts/websites.intre.it-v1.yml b/kubernetes-charts/websites.intre.it-v1.yml new file mode 100644 index 0000000..f59528f --- /dev/null +++ b/kubernetes-charts/websites.intre.it-v1.yml @@ -0,0 +1,40 @@ +# Generated by Fabric8 CRDGenerator, manual edits might get overwritten! +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: websites.intre.it +spec: + group: intre.it + names: + kind: WebSite + plural: websites + singular: website + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + properties: + spec: + properties: + replicas: + type: integer + shortDescription: + type: string + url: + type: string + webSiteName: + type: string + type: object + status: + properties: + areWeGood: + type: boolean + observedGeneration: + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java index dc97a95..192b1a2 100644 --- a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java +++ b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java @@ -1,11 +1,11 @@ package intre.it.javaoperator.controller; import intre.it.javaoperator.model.WebSite; -import io.fabric8.kubernetes.api.model.*; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.api.reconciler.Context; @ControllerConfiguration public class WebSiteReconciler implements Reconciler, Cleaner { @@ -17,28 +17,41 @@ public WebSiteReconciler() { @Override public UpdateControl reconcile(WebSite WebSite, Context context) throws Exception { - Pod pod = new PodBuilder() - .withKind("Pod") - .withApiVersion("v1") - .withMetadata( - new ObjectMetaBuilder() - .withName(WebSite.getSpec().getWebSiteName()) // Leggo le informazioni della Custom Resource Creata - .build()) - .withSpec(new PodSpecBuilder() - .withContainers(new ContainerBuilder() - .withName(WebSite.getSpec().getWebSiteName()) // OPZIONALE: Leggo le informazioni della Custom Resource Creata + Deployment deployment = new DeploymentBuilder() + .withNewMetadata() + .withName(WebSite.getSpec().getWebSiteName()+"-deployment") + .addToLabels("app", WebSite.getSpec().getWebSiteName()) + .endMetadata() + .withNewSpec() + .withReplicas(WebSite.getSpec().getReplicas()) + .withNewSelector() + .addToMatchLabels("app", WebSite.getSpec().getWebSiteName()) + .endSelector() + .withNewTemplate() + .withNewMetadata() + .addToLabels("app", WebSite.getSpec().getWebSiteName()) + .endMetadata() + .withNewSpec() + .addNewContainer() + .withName("nginx") .withImage("nginx:1.14.2") - .build()) - .build()) + .addNewPort() + .withContainerPort(80) + .endPort() + .endContainer() + .endSpec() + .endTemplate() + .endSpec() .build(); - client.pods().resource(pod).create(); + + client.apps().deployments().resource(deployment).create(); return UpdateControl.patchStatus(WebSite); } @Override public DeleteControl cleanup(WebSite webSite, Context context) { - client.pods().withName(webSite.getSpec().getWebSiteName()).delete(); // cancello il pod + client.apps().deployments().withName(webSite.getSpec().getWebSiteName()+"-deployment").delete(); // cancello il deployment return DeleteControl.defaultDelete(); } } diff --git a/src/main/java/intre/it/javaoperator/model/WebSiteSpec.java b/src/main/java/intre/it/javaoperator/model/WebSiteSpec.java index 7aeccf8..a0fb575 100644 --- a/src/main/java/intre/it/javaoperator/model/WebSiteSpec.java +++ b/src/main/java/intre/it/javaoperator/model/WebSiteSpec.java @@ -5,6 +5,7 @@ public class WebSiteSpec { private String webSiteName; private String url; private String shortDescription; + private int replicas; public String getWebSiteName() { return webSiteName; @@ -29,4 +30,12 @@ public String getShortDescription() { public void setShortDescription(String shortDescription) { this.shortDescription = shortDescription; } + + public int getReplicas() { + return replicas; + } + + public void setReplicas(int replicas) { + this.replicas = replicas; + } } From 42523176425596b61829e1261dc08cd3d2346928 Mon Sep 17 00:00:00 2001 From: simone Date: Mon, 10 Jun 2024 14:50:19 +0200 Subject: [PATCH 4/8] FIX --- .../intre/it/javaoperator/controller/WebSiteReconciler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java index 192b1a2..f92fe4b 100644 --- a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java +++ b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java @@ -34,7 +34,7 @@ public UpdateControl reconcile(WebSite WebSite, Context contex .withNewSpec() .addNewContainer() .withName("nginx") - .withImage("nginx:1.14.2") + .withImage("nginx") .addNewPort() .withContainerPort(80) .endPort() From 40a048e3983ab6126c0a6443f064717ece424cd1 Mon Sep 17 00:00:00 2001 From: simone Date: Tue, 11 Jun 2024 09:06:32 +0200 Subject: [PATCH 5/8] Exercise Nr. 4 --- kubernetes-charts/operator-role.yaml | 1 + .../controller/WebSiteReconciler.java | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/kubernetes-charts/operator-role.yaml b/kubernetes-charts/operator-role.yaml index 44b2711..83e6c1f 100644 --- a/kubernetes-charts/operator-role.yaml +++ b/kubernetes-charts/operator-role.yaml @@ -8,6 +8,7 @@ rules: resources: - events - pods + - configmaps verbs: - get - list diff --git a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java index f92fe4b..a902150 100644 --- a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java +++ b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java @@ -1,11 +1,16 @@ package intre.it.javaoperator.controller; import intre.it.javaoperator.model.WebSite; +import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.api.reconciler.Context; + +import java.util.HashMap; +import java.util.Map; @ControllerConfiguration public class WebSiteReconciler implements Reconciler, Cleaner { @@ -17,6 +22,18 @@ public WebSiteReconciler() { @Override public UpdateControl reconcile(WebSite WebSite, Context context) throws Exception { + Map html = new HashMap<>(); + html.put("index.html", "" + WebSite.getSpec().getShortDescription() + ""); + + ConfigMap configMap = new ConfigMapBuilder() + .withNewMetadata() + .withName(WebSite.getSpec().getWebSiteName()+"-cm") + .addToLabels("app", WebSite.getSpec().getWebSiteName()) + .endMetadata() + .withData(html) + .build(); + client.configMaps().resource(configMap).create(); + Deployment deployment = new DeploymentBuilder() .withNewMetadata() .withName(WebSite.getSpec().getWebSiteName()+"-deployment") @@ -38,7 +55,22 @@ public UpdateControl reconcile(WebSite WebSite, Context contex .addNewPort() .withContainerPort(80) .endPort() + .addNewVolumeMount() + .withName("nginx-conf") + .withSubPath("index.html") + .withMountPath("/usr/share/nginx/html/index.html") + .endVolumeMount() .endContainer() + .addNewVolume() + .withName("nginx-conf") + .withNewConfigMap() + .withName(WebSite.getSpec().getWebSiteName()+"-cm") + .addNewItem() + .withKey("index.html") + .withPath("index.html") + .endItem() + .endConfigMap() + .endVolume() .endSpec() .endTemplate() .endSpec() @@ -52,6 +84,7 @@ public UpdateControl reconcile(WebSite WebSite, Context contex @Override public DeleteControl cleanup(WebSite webSite, Context context) { client.apps().deployments().withName(webSite.getSpec().getWebSiteName()+"-deployment").delete(); // cancello il deployment + client.configMaps().withName(webSite.getSpec().getWebSiteName()+"-cm").delete(); // cancello la configmap return DeleteControl.defaultDelete(); } } From 3e915101b46b1124960168eca41ad65da1cc0856 Mon Sep 17 00:00:00 2001 From: simone Date: Tue, 11 Jun 2024 09:11:23 +0200 Subject: [PATCH 6/8] Revert "Exercise Nr. 4" This reverts commit 40a048e3983ab6126c0a6443f064717ece424cd1. --- kubernetes-charts/operator-role.yaml | 1 - .../controller/WebSiteReconciler.java | 33 ------------------- 2 files changed, 34 deletions(-) diff --git a/kubernetes-charts/operator-role.yaml b/kubernetes-charts/operator-role.yaml index 83e6c1f..44b2711 100644 --- a/kubernetes-charts/operator-role.yaml +++ b/kubernetes-charts/operator-role.yaml @@ -8,7 +8,6 @@ rules: resources: - events - pods - - configmaps verbs: - get - list diff --git a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java index a902150..f92fe4b 100644 --- a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java +++ b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java @@ -1,16 +1,11 @@ package intre.it.javaoperator.controller; import intre.it.javaoperator.model.WebSite; -import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -import java.util.HashMap; -import java.util.Map; @ControllerConfiguration public class WebSiteReconciler implements Reconciler, Cleaner { @@ -22,18 +17,6 @@ public WebSiteReconciler() { @Override public UpdateControl reconcile(WebSite WebSite, Context context) throws Exception { - Map html = new HashMap<>(); - html.put("index.html", "" + WebSite.getSpec().getShortDescription() + ""); - - ConfigMap configMap = new ConfigMapBuilder() - .withNewMetadata() - .withName(WebSite.getSpec().getWebSiteName()+"-cm") - .addToLabels("app", WebSite.getSpec().getWebSiteName()) - .endMetadata() - .withData(html) - .build(); - client.configMaps().resource(configMap).create(); - Deployment deployment = new DeploymentBuilder() .withNewMetadata() .withName(WebSite.getSpec().getWebSiteName()+"-deployment") @@ -55,22 +38,7 @@ public UpdateControl reconcile(WebSite WebSite, Context contex .addNewPort() .withContainerPort(80) .endPort() - .addNewVolumeMount() - .withName("nginx-conf") - .withSubPath("index.html") - .withMountPath("/usr/share/nginx/html/index.html") - .endVolumeMount() .endContainer() - .addNewVolume() - .withName("nginx-conf") - .withNewConfigMap() - .withName(WebSite.getSpec().getWebSiteName()+"-cm") - .addNewItem() - .withKey("index.html") - .withPath("index.html") - .endItem() - .endConfigMap() - .endVolume() .endSpec() .endTemplate() .endSpec() @@ -84,7 +52,6 @@ public UpdateControl reconcile(WebSite WebSite, Context contex @Override public DeleteControl cleanup(WebSite webSite, Context context) { client.apps().deployments().withName(webSite.getSpec().getWebSiteName()+"-deployment").delete(); // cancello il deployment - client.configMaps().withName(webSite.getSpec().getWebSiteName()+"-cm").delete(); // cancello la configmap return DeleteControl.defaultDelete(); } } From 63d9940f8f404a623d6d6c04adf4713f46e39798 Mon Sep 17 00:00:00 2001 From: simone Date: Tue, 11 Jun 2024 09:16:26 +0200 Subject: [PATCH 7/8] Exercise Nr. 4 --- kubernetes-charts/operator-role.yaml | 1 + .../controller/WebSiteReconciler.java | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/kubernetes-charts/operator-role.yaml b/kubernetes-charts/operator-role.yaml index 44b2711..80c3c7e 100644 --- a/kubernetes-charts/operator-role.yaml +++ b/kubernetes-charts/operator-role.yaml @@ -8,6 +8,7 @@ rules: resources: - events - pods + - services verbs: - get - list diff --git a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java index f92fe4b..20c0469 100644 --- a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java +++ b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java @@ -1,11 +1,16 @@ package intre.it.javaoperator.controller; import intre.it.javaoperator.model.WebSite; +import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.api.reconciler.Context; + +import java.util.HashMap; +import java.util.Map; @ControllerConfiguration public class WebSiteReconciler implements Reconciler, Cleaner { @@ -44,6 +49,27 @@ public UpdateControl reconcile(WebSite WebSite, Context contex .endSpec() .build(); + //Configurazione service + Map selector = new HashMap<>(); + selector.put("app", WebSite.getSpec().getWebSiteName()); + + Service service = new ServiceBuilder() + .withNewMetadata() + .withName(WebSite.getSpec().getWebSiteName()+"-service") + .endMetadata() + .withNewSpec() + .withType("LoadBalancer") + .addToSelector(selector) + .addNewPort() + .withName("deploy-port") + .withPort(80) + .withNodePort(30007) + .withTargetPort(new IntOrString(80)) + .withProtocol("TCP") + .endPort() + .endSpec() + .build(); + client.services().resource(service).create();//Generiamo il service client.apps().deployments().resource(deployment).create(); return UpdateControl.patchStatus(WebSite); @@ -52,6 +78,7 @@ public UpdateControl reconcile(WebSite WebSite, Context contex @Override public DeleteControl cleanup(WebSite webSite, Context context) { client.apps().deployments().withName(webSite.getSpec().getWebSiteName()+"-deployment").delete(); // cancello il deployment + client.services().withName(webSite.getSpec().getWebSiteName()+"-service").delete(); //Cancello il service return DeleteControl.defaultDelete(); } } From 9ee6fb5a71b64c6799fa6a514fa2b10d4f14b8ae Mon Sep 17 00:00:00 2001 From: simone Date: Tue, 11 Jun 2024 09:19:59 +0200 Subject: [PATCH 8/8] Exercise Nr. 5 --- kubernetes-charts/operator-role.yaml | 1 + .../controller/WebSiteReconciler.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/kubernetes-charts/operator-role.yaml b/kubernetes-charts/operator-role.yaml index 80c3c7e..11eea73 100644 --- a/kubernetes-charts/operator-role.yaml +++ b/kubernetes-charts/operator-role.yaml @@ -8,6 +8,7 @@ rules: resources: - events - pods + - configmaps - services verbs: - get diff --git a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java index 20c0469..2d70ffa 100644 --- a/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java +++ b/src/main/java/intre/it/javaoperator/controller/WebSiteReconciler.java @@ -22,6 +22,18 @@ public WebSiteReconciler() { @Override public UpdateControl reconcile(WebSite WebSite, Context context) throws Exception { + Map html = new HashMap<>(); + html.put("index.html", "" + WebSite.getSpec().getShortDescription() + ""); + + ConfigMap configMap = new ConfigMapBuilder() + .withNewMetadata() + .withName(WebSite.getSpec().getWebSiteName()+"-cm") + .addToLabels("app", WebSite.getSpec().getWebSiteName()) + .endMetadata() + .withData(html) + .build(); + client.configMaps().resource(configMap).create(); + Deployment deployment = new DeploymentBuilder() .withNewMetadata() .withName(WebSite.getSpec().getWebSiteName()+"-deployment") @@ -43,7 +55,22 @@ public UpdateControl reconcile(WebSite WebSite, Context contex .addNewPort() .withContainerPort(80) .endPort() + .addNewVolumeMount() + .withName("nginx-conf") + .withSubPath("index.html") + .withMountPath("/usr/share/nginx/html/index.html") + .endVolumeMount() .endContainer() + .addNewVolume() + .withName("nginx-conf") + .withNewConfigMap() + .withName(WebSite.getSpec().getWebSiteName()+"-cm") + .addNewItem() + .withKey("index.html") + .withPath("index.html") + .endItem() + .endConfigMap() + .endVolume() .endSpec() .endTemplate() .endSpec() @@ -79,6 +106,7 @@ public UpdateControl reconcile(WebSite WebSite, Context contex public DeleteControl cleanup(WebSite webSite, Context context) { client.apps().deployments().withName(webSite.getSpec().getWebSiteName()+"-deployment").delete(); // cancello il deployment client.services().withName(webSite.getSpec().getWebSiteName()+"-service").delete(); //Cancello il service + client.configMaps().withName(webSite.getSpec().getWebSiteName()+"-cm").delete(); //Cancello la config map return DeleteControl.defaultDelete(); } }