1
0
mirror of https://github.com/openshift/openshift-docs.git synced 2026-02-05 12:46:18 +01:00

OSDOCS-2933 Java OSDK

peer review feedback

SME/QE review

final review feedback
This commit is contained in:
Andrew Taylor
2022-06-30 09:58:23 -04:00
committed by openshift-cherrypick-robot
parent fff17c4419
commit c61d8f0384
19 changed files with 850 additions and 37 deletions

View File

@@ -1,6 +1,7 @@
// Module included in the following assemblies:
//
// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc
// * operators/operator_sdk/java/osdk-java-tutorial.adoc
// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc
// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc
// * operators/operator_sdk/osdk-working-bundle-images.adoc
@@ -40,7 +41,7 @@ $ make docker-build IMG=<registry>/<user>/<operator_image_name>:<tag>
+
[NOTE]
====
The Dockerfile generated by the SDK for the Operator explicitly references `GOARCH=amd64` for `go build`. This can be amended to `GOARCH=$TARGETARCH` for non-AMD64 architectures. Docker will automatically set the environment variable to the value specified by `platform`. With Buildah, the `build-arg` will need to be used for the purpose. For more information, see link:https://sdk.operatorframework.io/docs/advanced-topics/multi-arch/#supporting-multiple-architectures[Multiple Architectures].
The Dockerfile generated by the SDK for the Operator explicitly references `GOARCH=amd64` for `go build`. This can be amended to `GOARCH=$TARGETARCH` for non-AMD64 architectures. Docker will automatically set the environment variable to the value specified by `platform`. With Buildah, the `build-arg` will need to be used for the purpose. For more information, see link:https://sdk.operatorframework.io/docs/advanced-topics/multi-arch/#supporting-multiple-architectures[Multiple Architectures].
====
.. Push the image to a repository:

View File

@@ -19,6 +19,11 @@ ifeval::["{context}" == "osdk-helm-tutorial"]
:type: Helm
:app: nginx
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:java:
:type: Java
:app: memcached
endif::[]
:_content-type: PROCEDURE
[id="osdk-create-project_{context}"]
@@ -58,6 +63,9 @@ endif::[]
ifdef::helm[]
with the `helm` plug-in
endif::[]
ifdef::java[]
with the `quarkus` plug-in
endif::[]
to initialize the project:
+
[source,terminal,subs="attributes+"]
@@ -101,6 +109,14 @@ The `init` command creates the `nginx-operator` project specifically for watchin
. For Helm-based projects, the `init` command generates the RBAC rules in the `config/rbac/role.yaml` file based on the resources that would be deployed by the default manifest for the chart. Verify that the rules generated in this file meet the permission requirements of the Operator.
endif::[]
ifdef::java[]
----
$ operator-sdk init \
--plugins=quarkus \
--domain=example.com \
--project-name=memcached-operator
----
endif::[]
ifeval::["{context}" == "osdk-golang-tutorial"]
:!golang:
@@ -117,3 +133,8 @@ ifeval::["{context}" == "osdk-helm-tutorial"]
:!type:
:!app:
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:!java:
:!type:
:!app:
endif::[]

View File

@@ -11,6 +11,9 @@ endif::[]
ifeval::["{context}" == "osdk-working-bundle-images"]
:golang:
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:java:
endif::[]
:_content-type: PROCEDURE
[id="osdk-deploy-olm_{context}"]
@@ -64,3 +67,6 @@ endif::[]
ifeval::["{context}" == "osdk-working-bundle-images"]
:!golang:
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:!java:
endif::[]

View File

@@ -0,0 +1,19 @@
// Module included in the following assemblies:
//
// * operators/operator_sdk/java/osdk-java-tutorial.adoc
:_content-type: CONCEPT
[id="osdk-java-controller-labels-memcached_{context}"]
= Defining `labelsForMemcached`
`labelsForMemcached` is a utility to return a map of the labels to attach to the resources:
[source,java]
----
private Map<String, String> labelsForMemcached(Memcached m) {
Map<String, String> labels = new HashMap<>();
labels.put("app", "memcached");
labels.put("memcached_cr", m.getMetadata().getName());
return labels;
}
----

View File

@@ -0,0 +1,54 @@
// Module included in the following assemblies:
//
// * operators/operator_sdk/java/osdk-java-tutorial.adoc
:_content-type: CONCEPT
[id="osdk-java-controller-memcached-deployment_{context}"]
= Define the `createMemcachedDeployment`
The `createMemcachedDeployment` method uses the link:https://fabric8.io/[fabric8] `DeploymentBuilder` class:
[source,java]
----
private Deployment createMemcachedDeployment(Memcached m) {
return new DeploymentBuilder()
.withMetadata(
new ObjectMetaBuilder()
.withName(m.getMetadata().getName())
.withNamespace(m.getMetadata().getNamespace())
.withOwnerReferences(
new OwnerReferenceBuilder()
.withApiVersion("v1")
.withKind("Memcached")
.withName(m.getMetadata().getName())
.withUid(m.getMetadata().getUid())
.build())
.build())
.withSpec(
new DeploymentSpecBuilder()
.withReplicas(m.getSpec().getSize())
.withSelector(
new LabelSelectorBuilder().withMatchLabels(labelsForMemcached(m)).build())
.withTemplate(
new PodTemplateSpecBuilder()
.withMetadata(
new ObjectMetaBuilder().withLabels(labelsForMemcached(m)).build())
.withSpec(
new PodSpecBuilder()
.withContainers(
new ContainerBuilder()
.withImage("memcached:1.4.36-alpine")
.withName("memcached")
.withCommand("memcached", "-m=64", "-o", "modern", "-v")
.withPorts(
new ContainerPortBuilder()
.withContainerPort(11211)
.withName("memcached")
.build())
.build())
.build())
.build())
.build())
.build();
}
----

View File

@@ -0,0 +1,74 @@
// Module included in the following assemblies:
//
// * operators/operator_sdk/java/osdk-java-tutorial.adoc
:_content-type: CONCEPT
[id="osdk-java-controller-reconcile-loop_{context}"]
= Reconcile loop
. Every controller has a reconciler object with a `Reconcile()` method that implements the reconcile loop. The reconcile loop is passed the `Deployment` argument, as shown in the following example:
+
[source,java]
----
Deployment deployment = client.apps()
.deployments()
.inNamespace(resource.getMetadata().getNamespace())
.withName(resource.getMetadata().getName())
.get();
----
. As shown in the following example, if the `Deployment` is `null`, the deployment needs to be created. After you create the `Deployment`, you can determine if reconciliation is necessary. If there is no need of reconciliation, return the value of `UpdateControl.noUpdate()`, otherwise, return the value of `UpdateControl.updateStatus(resource):
+
[source, java]
----
if (deployment == null) {
Deployment newDeployment = createMemcachedDeployment(resource);
client.apps().deployments().create(newDeployment);
return UpdateControl.noUpdate();
}
----
. After getting the `Deployment`, get the current and required replicas, as shown in the following example:
+
[source,java]
----
int currentReplicas = deployment.getSpec().getReplicas();
int requiredReplicas = resource.getSpec().getSize();
----
. If `currentReplicas` does not match the `requiredReplicas`, you must update the `Deployment`, as shown in the following example:
+
[source,java]
----
if (currentReplicas != requiredReplicas) {
deployment.getSpec().setReplicas(requiredReplicas);
client.apps().deployments().createOrReplace(deployment);
return UpdateControl.noUpdate();
}
----
. The following example shows how to obtain the list of pods and their names:
+
[source,java]
----
List<Pod> pods = client.pods()
.inNamespace(resource.getMetadata().getNamespace())
.withLabels(labelsForMemcached(resource))
.list()
.getItems();
List<String> podNames =
pods.stream().map(p -> p.getMetadata().getName()).collect(Collectors.toList());
----
. Check if resources were created and verify podnames with the Memcached resources. If a mismatch exists in either of these conditions, perform a reconciliation as shown in the following example:
+
[source,java]
----
if (resource.getStatus() == null
|| !CollectionUtils.isEqualCollection(podNames, resource.getStatus().getNodes())) {
if (resource.getStatus() == null) resource.setStatus(new MemcachedStatus());
resource.getStatus().setNodes(podNames);
return UpdateControl.updateResource(resource);
}
----

View File

@@ -0,0 +1,57 @@
// Module included in the following assemblies:
//
// * operators/operator_sdk/java/osdk-java-tutorial.adoc
:_content-type: PROCEDURE
[id="osdk-java-create-api-controller_{context}"]
= Creating an API and controller
Use the Operator SDK CLI to create a custom resource definition (CRD) API and controller.
.Procedure
. Run the following command to create an API:
+
[source,terminal]
----
$ operator-sdk create api \
--plugins=quarkus \ <1>
--group=cache \ <2>
--version=v1 \ <3>
--kind=Memcached <4>
----
<1> Set the plug-in flag to `quarkus`.
<2> Set the group flag to `cache`.
<3> Set the version flag to `v1`.
<4> Set the kind flag to `Memcached`.
.Verification
. Run the `tree` command to view the file structure:
+
[source,terminal]
----
$ tree
----
+
.Example output
[source,terminal]
----
.
├── Makefile
├── PROJECT
├── pom.xml
└── src
└── main
├── java
│ └── com
│ └── example
│ ├── Memcached.java
│ ├── MemcachedReconciler.java
│ ├── MemcachedSpec.java
│ └── MemcachedStatus.java
└── resources
└── application.properties
6 directories, 8 files
----

View File

@@ -0,0 +1,23 @@
// Module included in the following assemblies:
//
// * operators/operator_sdk/java/osdk-java-tutorial.adoc
:_content-type: PROCEDURE
[id="osdk-java-create-cr_{context}"]
= Creating a Custom Resource
After generating the CRD manifests, you can create the Custom Resource (CR).
.Procedure
* Create a Memcached CR called `memcached-sample.yaml`:
+
[source,yaml]
----
apiVersion: cache.example.com/v1
kind: Memcached
metadata:
name: memcached-sample
spec:
# Add spec fields here
size: 1
----

View File

@@ -0,0 +1,70 @@
// Module included in the following assemblies:
//
// * operators/operator_sdk/java/osdk-java-tutorial.adoc
:_content-type: PROCEDURE
[id="osdk-java-define-api_{context}"]
= Defining the API
Define the API for the `Memcached` custom resource (CR).
.Procedure
* Edit the following files that were generated as part of the `create api` process:
.. Update the following attributes in the `MemcachedSpec.java` file to define the desired state of the `Memcached` CR:
+
[source,java]
----
public class MemcachedSpec {
private Integer size;
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
}
----
.. Update the following attributes in the `MemcachedStatus.java` file to define the observed state of the `Memcached` CR:
+
[NOTE]
====
The example below illustrates a Node status field. It is recommended that you use link:https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties[typical status properties] in practice.
====
+
[source,java]
----
import java.util.ArrayList;
import java.util.List;
public class MemcachedStatus {
// Add Status information here
// Nodes are the names of the memcached pods
private List<String> nodes;
public List<String> getNodes() {
if (nodes == null) {
nodes = new ArrayList<>();
}
return nodes;
}
public void setNodes(List<String> nodes) {
this.nodes = nodes;
}
}
----
.. Update the `Memcached.java` file to define the Schema for Memcached APIs that extends to both `MemcachedSpec.java` and `MemcachedStatus.java` files.
+
[source,java]
----
@Version("v1")
@Group("cache.example.com")
public class Memcached extends CustomResource<MemcachedSpec, MemcachedStatus> implements Namespaced {}
----

View File

@@ -0,0 +1,66 @@
// Module included in the following assemblies:
//
// * operators/operator_sdk/java/osdk-java-tutorial.adoc
:_content-type: PROCEDURE
[id="osdk-java-generate-crd_{context}"]
= Generating CRD manifests
After the API is defined with `MemcachedSpec` and `MemcachedStatus` files, you can generate CRD manifests.
.Procedure
* Run the following command from the `memcached-operator` directory to generate the CRD:
+
[source,terminal]
----
$ mvn clean install
----
.Verification
* Verify the contents of the CRD in the `target/kubernetes/memcacheds.cache.example.com-v1.yml` file as shown in the following example:
+
[source,terminal]
----
$ cat target/kubernetes/memcacheds.cache.example.com-v1.yaml
----
+
.Example output
[source,yaml]
----
# Generated by Fabric8 CRDGenerator, manual edits might get overwritten!
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: memcacheds.cache.example.com
spec:
group: cache.example.com
names:
kind: Memcached
plural: memcacheds
singular: memcached
scope: Namespaced
versions:
- name: v1
schema:
openAPIV3Schema:
properties:
spec:
properties:
size:
type: integer
type: object
status:
properties:
nodes:
items:
type: string
type: array
type: object
type: object
served: true
storage: true
subresources:
status: {}
----

View File

@@ -0,0 +1,166 @@
// Module included in the following assemblies:
//
// * operators/operator_sdk/java/osdk-java-tutorial.adoc
:_content-type: PROCEDURE
[id="osdk-java-implement-controller_{context}"]
= Implementing the controller
After creating a new API and controller, you can implement the controller logic.
.Procedure
. Append the following dependency to the `pom.xml` file:
+
[source,xml]
----
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
----
. For this example, replace the generated controller file `MemcachedReconciler.java` with following example implementation:
+
.Example `MemcachedReconciler.java`
[%collapsible]
====
[source,java]
----
package com.example;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
import io.fabric8.kubernetes.api.model.ContainerBuilder;
import io.fabric8.kubernetes.api.model.ContainerPortBuilder;
import io.fabric8.kubernetes.api.model.LabelSelectorBuilder;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.api.model.OwnerReferenceBuilder;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodSpecBuilder;
import io.fabric8.kubernetes.api.model.PodTemplateSpecBuilder;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.kubernetes.api.model.apps.DeploymentSpecBuilder;
import org.apache.commons.collections.CollectionUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class MemcachedReconciler implements Reconciler<Memcached> {
private final KubernetesClient client;
public MemcachedReconciler(KubernetesClient client) {
this.client = client;
}
// TODO Fill in the rest of the reconciler
@Override
public UpdateControl<Memcached> reconcile(
Memcached resource, Context context) {
// TODO: fill in logic
Deployment deployment = client.apps()
.deployments()
.inNamespace(resource.getMetadata().getNamespace())
.withName(resource.getMetadata().getName())
.get();
if (deployment == null) {
Deployment newDeployment = createMemcachedDeployment(resource);
client.apps().deployments().create(newDeployment);
return UpdateControl.noUpdate();
}
int currentReplicas = deployment.getSpec().getReplicas();
int requiredReplicas = resource.getSpec().getSize();
if (currentReplicas != requiredReplicas) {
deployment.getSpec().setReplicas(requiredReplicas);
client.apps().deployments().createOrReplace(deployment);
return UpdateControl.noUpdate();
}
List<Pod> pods = client.pods()
.inNamespace(resource.getMetadata().getNamespace())
.withLabels(labelsForMemcached(resource))
.list()
.getItems();
List<String> podNames =
pods.stream().map(p -> p.getMetadata().getName()).collect(Collectors.toList());
if (resource.getStatus() == null
|| !CollectionUtils.isEqualCollection(podNames, resource.getStatus().getNodes())) {
if (resource.getStatus() == null) resource.setStatus(new MemcachedStatus());
resource.getStatus().setNodes(podNames);
return UpdateControl.updateResource(resource);
}
return UpdateControl.noUpdate();
}
private Map<String, String> labelsForMemcached(Memcached m) {
Map<String, String> labels = new HashMap<>();
labels.put("app", "memcached");
labels.put("memcached_cr", m.getMetadata().getName());
return labels;
}
private Deployment createMemcachedDeployment(Memcached m) {
return new DeploymentBuilder()
.withMetadata(
new ObjectMetaBuilder()
.withName(m.getMetadata().getName())
.withNamespace(m.getMetadata().getNamespace())
.withOwnerReferences(
new OwnerReferenceBuilder()
.withApiVersion("v1")
.withKind("Memcached")
.withName(m.getMetadata().getName())
.withUid(m.getMetadata().getUid())
.build())
.build())
.withSpec(
new DeploymentSpecBuilder()
.withReplicas(m.getSpec().getSize())
.withSelector(
new LabelSelectorBuilder().withMatchLabels(labelsForMemcached(m)).build())
.withTemplate(
new PodTemplateSpecBuilder()
.withMetadata(
new ObjectMetaBuilder().withLabels(labelsForMemcached(m)).build())
.withSpec(
new PodSpecBuilder()
.withContainers(
new ContainerBuilder()
.withImage("memcached:1.4.36-alpine")
.withName("memcached")
.withCommand("memcached", "-m=64", "-o", "modern", "-v")
.withPorts(
new ContainerPortBuilder()
.withContainerPort(11211)
.withName("memcached")
.build())
.build())
.build())
.build())
.build())
.build();
}
}
----
====
+
The example controller runs the following reconciliation logic for each `Memcached` custom resource (CR):
+
--
* Creates a Memcached deployment if it does not exist.
* Ensures that the deployment size matches the size specified by the `Memcached` CR spec.
* Updates the `Memcached` CR status with the names of the `memcached` pods.
--

View File

@@ -0,0 +1,37 @@
// Module included in the following assemblies:
//
// * operators/operator_sdk/java/osdk-java-project-layout.adoc
:_content-type: REFERENCE
[id="osdk-java-project-layout_{context}"]
= Java-based project layout
Java-based Operator projects generated by the `operator-sdk init` command contain the following files and directories:
[options="header",cols="1,4"]
|===
|File or directory |Purpose
|`pom.xml`
|File that contains the dependencies required to run the Operator.
|`<domain>/`
|Directory that contains the files that represent the API. If the domain is `example.com`, this folder is called `example/`.
|`MemcachedReconciler.java`
|Java file that defines controller implementations.
|`MemcachedSpec.java`
|Java file that defines the desired state of the Memcached CR.
|`MemcachedStatus.java`
|Java file that defines the observed state of the Memcached CR.
|`Memcached.java`
|Java file that defines the Schema for Memcached APIs.
|`target/kubernetes/`
|Directory that contains the CRD yaml files.
|===

View File

@@ -3,6 +3,7 @@
// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc
// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc
// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc
// * operators/operator_sdk/java/osdk-java-tutorial.adoc
ifeval::["{context}" == "osdk-golang-tutorial"]
:golang:
@@ -19,6 +20,11 @@ ifeval::["{context}" == "osdk-helm-tutorial"]
:type: Helm
:app: nginx
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:java:
:type: Java
:app: memcached
endif::[]
[id="osdk-project-file_{context}"]
= PROJECT file
@@ -58,6 +64,15 @@ resources:
version: 3
----
endif::[]
ifdef::java[]
----
domain: example.com
layout:
- quarkus.javaoperatorsdk.io/v1-alpha
projectName: memcached-operator
version: "3"
----
endif::[]
ifeval::["{context}" == "osdk-golang-tutorial"]
:!golang:
@@ -74,3 +89,8 @@ ifeval::["{context}" == "osdk-helm-tutorial"]
:!type:
:!app:
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:!java:
:!type:
:!app:
endif::[]

View File

@@ -96,7 +96,8 @@ ifdef::java[]
----
$ operator-sdk init \
--plugins=quarkus \
--domain=example.com
--domain=example.com \
--project-name=memcached-operator
----
endif::[]

View File

@@ -8,6 +8,9 @@
ifeval::["{context}" == "osdk-golang-tutorial"]
:golang:
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:java:
endif::[]
:_content-type: PROCEDURE
[id="osdk-run-deployment_{context}"]
@@ -56,19 +59,69 @@ $ make docker-push IMG=<registry>/<user>/<image_name>:<tag>
The name and tag of the image, for example `IMG=<registry>/<user>/<image_name>:<tag>`, in both the commands can also be set in your Makefile. Modify the `IMG ?= controller:latest` value to set your default image name.
====
ifdef::java[]
. Run the following command to install the CRD to the default namespace:
+
[source,terminal]
----
$ oc apply -f target/kubernetes/memcacheds.cache.example.com-v1.yml
----
+
.Example output
[source,terminal]
----
customresourcedefinition.apiextensions.k8s.io/memcacheds.cache.example.com created
----
. Create a file called `rbac.yaml` as shown in the following example:
+
[source,yaml]
----
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: memcached-operator-admin
subjects:
- kind: ServiceAccount
name: memcached-quarkus-operator-operator
namespace: default
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: ""
----
+
[IMPORTANT]
====
The `rbac.yaml` file will be applied at a later step.
====
endif::[]
. Run the following command to deploy the Operator:
+
[source,terminal]
----
$ make deploy IMG=<registry>/<user>/<image_name>:<tag>
----
ifeval::["{context}" != "osdk-java-tutorial"]
+
By default, this command creates a namespace with the name of your Operator project in the form `<project_name>-system` and is used for the deployment. This command also installs the RBAC manifests from `config/rbac`.
endif::[]
. Verify that the Operator is running:
ifdef::java[]
. Run the following command to grant `cluster-admin` privileges to the `memcached-quarkus-operator-operator` by applying the `rbac.yaml` file created in a previous step:
+
[source,terminal]
----
$ oc apply -f rbac.yaml
----
endif::[]
. Run the following command to verify that the Operator is running:
+
ifeval::["{context}" != "osdk-java-tutorial"]
[source,terminal]
----
$ oc get deployment -n <project_name>-system
----
+
@@ -78,7 +131,53 @@ $ oc get deployment -n <project_name>-system
NAME READY UP-TO-DATE AVAILABLE AGE
<project_name>-controller-manager 1/1 1 1 8m
----
endif::[]
ifdef::java[]
[source,terminal]
----
$ oc get all -n default
----
+
.Example output
[source,terminal]
----
NAME READY UP-TO-DATE AVAILABLE AGE
pod/memcached-quarkus-operator-operator-7db86ccf58-k4mlm 0/1 Running 0 18s
----
. Run the following command to apply the `memcached-sample.yaml` and create the `memcached-sample` pod:
+
[source,terminal]
----
$ oc apply -f memcached-sample.yaml
----
+
.Example output
[source,terminal]
----
memcached.cache.example.com/memcached-sample created
----
.Verification
* Run the following command to confirm the pods have started:
+
[source,terminal]
----
$ oc get all
----
+
.Example output
[source,terminal]
----
NAME READY STATUS RESTARTS AGE
pod/memcached-quarkus-operator-operator-7b766f4896-kxnzt 1/1 Running 1 79s
pod/memcached-sample-6c765df685-mfqnz 1/1 Running 0 18s
----
endif::[]
ifeval::["{context}" == "osdk-golang-tutorial"]
:!golang:
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:!java:
endif::[]

View File

@@ -13,6 +13,10 @@ endif::[]
ifeval::["{context}" == "osdk-helm-tutorial"]
:helm:
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:java:
endif::[]
:_content-type: PROCEDURE
[id="osdk-run-locally_{context}"]
@@ -21,7 +25,7 @@ endif::[]
You can run your Operator project as a Go program outside of the cluster. This is useful for development purposes to speed up deployment and testing.
.Procedure
ifeval::["{context}" != "osdk-java-tutorial"]
* Run the following command to install the custom resource definitions (CRDs) in the cluster configured in your `~/.kube/config` file and run the Operator locally:
+
[source,terminal]
@@ -31,6 +35,7 @@ $ make install run
+
.Example output
[source,terminal]
endif::[]
ifdef::golang[]
----
...
@@ -64,7 +69,104 @@ ifdef::helm[]
{"level":"info","ts":1612652420.2309358,"logger":"controller-runtime.manager.controller.nginx-controller","msg":"Starting workers","worker count":8}
----
endif::[]
ifdef::java[]
. Run the following command to compile the Operator:
+
[source,terminal]
----
$ mvn clean install
----
+
.Example output
[source,terminal]
----
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.193 s
[INFO] Finished at: 2021-05-26T12:16:54-04:00
[INFO] ------------------------------------------------------------------------
----
. Run the following command to install the CRD to the default namespace:
+
[source,terminal]
----
$ oc apply -f target/kubernetes/memcacheds.cache.example.com-v1.yml
----
+
.Example output
[source,terminal]
----
customresourcedefinition.apiextensions.k8s.io/memcacheds.cache.example.com created
----
. Create a file called `rbac.yaml` as shown in the following example:
+
[source,yaml]
----
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: memcached-operator-admin
subjects:
- kind: ServiceAccount
name: memcached-quarkus-operator-operator
namespace: default
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: ""
----
. Run the following command to grant `cluster-admin` privileges to the `memcached-quarkus-operator-operator` by applying the `rbac.yaml` file:
+
[source,terminal]
----
$ oc apply -f rbac.yaml
----
. Enter the following command to run the Operator:
+
[source,terminal]
----
$ java -jar target/quarkus-app/quarkus-run.jar
----
+
[NOTE]
====
The `java` command will run the Operator and remain running until you end the process. You will need another terminal to complete the rest of these commands.
====
. Apply the `memcached-sample.yaml` file with the following command:
+
[source,terminal]
----
$ kubectl apply -f memcached-sample.yaml
----
+
.Example output
[source,terminal]
----
memcached.cache.example.com/memcached-sample created
----
.Verification
* Run the following command to confirm that the pod has started:
+
[source,terminal]
----
$ oc get all
----
+
.Example output
[source,terminal]
----
NAME READY STATUS RESTARTS AGE
pod/memcached-sample-6c765df685-mfqnz 1/1 Running 0 18s
----
endif::[]
ifeval::["{context}" == "osdk-golang-tutorial"]
:!golang:
endif::[]
@@ -74,3 +176,6 @@ endif::[]
ifeval::["{context}" == "osdk-helm-tutorial"]
:!helm:
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:!java:
endif::[]

View File

@@ -14,6 +14,9 @@ endif::[]
ifeval::["{context}" == "osdk-helm-tutorial"]
:helm:
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:java:
endif::[]
[id="osdk-run-operator_{context}"]
= Running the Operator
@@ -40,3 +43,6 @@ endif::[]
ifeval::["{context}" == "osdk-helm-tutorial"]
:!helm:
endif::[]
ifeval::["{context}" == "osdk-java-tutorial"]
:!java:
endif::[]

View File

@@ -10,4 +10,4 @@ toc::[]
The `operator-sdk` CLI can generate, or _scaffold_, a number of packages and files for each Operator project.
// need to create the module ../osdk-java-project-layout.adoc[leveloffset=+1]
include::modules/osdk-java-project-layout.adoc[leveloffset=+1]

View File

@@ -12,7 +12,7 @@ Operator developers can take advantage of Java programming language support in t
This process is accomplished using two centerpieces of the Operator Framework:
Operator SDK:: The `operator-sdk` CLI tool and `controller-runtime` library API
Operator SDK:: The `operator-sdk` CLI tool and `java-operator-sdk` library API
Operator Lifecycle Manager (OLM):: Installation, upgrade, and role-based access control (RBAC) of Operators on a cluster
@@ -23,43 +23,31 @@ This tutorial goes into greater detail than xref:../../../operators/operator_sdk
include::modules/osdk-common-prereqs.adoc[leveloffset=+1]
// needs ifevals:
// include::modules/osdk-create-project.adoc[leveloffset=+1]
// include::modules/osdk-project-file.adoc[leveloffset=+2]
include::modules/osdk-create-project.adoc[leveloffset=+1]
include::modules/osdk-project-file.adoc[leveloffset=+2]
// individual java modules go here
//
// include::modules/osdk-golang-manager.adoc[leveloffset=+2]
// include::modules/osdk-golang-multi-group-apis.adoc[leveloffset=+2]
//
// include::modules/osdk-golang-create-api-controller.adoc[leveloffset=+1]
// include::modules/osdk-golang-define-api.adoc[leveloffset=+2]
// include::modules/osdk-golang-generate-crd.adoc[leveloffset=+2]
// include::modules/osdk-about-openapi-validation.adoc[leveloffset=+3]
//
// include::modules/osdk-golang-implement-controller.adoc[leveloffset=+1]
//
// The next subsections explain how the controller in the example implementation watches resources and how the reconcile loop is triggered. You can skip these subsections to go directly to xref:../../../operators/operator_sdk/golang/osdk-golang-tutorial.adoc#osdk-run-operator_osdk-golang-tutorial[Running the Operator].
//
// include::modules/osdk-golang-controller-resources.adoc[leveloffset=+2]
// include::modules/osdk-golang-controller-configs.adoc[leveloffset=+2]
// include::modules/osdk-golang-controller-reconcile-loop.adoc[leveloffset=+2]
// include::modules/osdk-golang-controller-rbac-markers.adoc[leveloffset=+2]
include::modules/osdk-java-create-api-controller.adoc[leveloffset=+1]
include::modules/osdk-java-define-api.adoc[leveloffset=+2]
include::modules/osdk-java-generate-crd.adoc[leveloffset=+2]
include::modules/osdk-java-create-cr.adoc[leveloffset=+2]
// needs ifevals:
// include::modules/osdk-run-proxy.adoc[leveloffset=+1]
// include::modules/osdk-run-operator.adoc[leveloffset=+1]
// include::modules/osdk-run-locally.adoc[leveloffset=+2]
// include::modules/osdk-run-deployment.adoc[leveloffset=+2]
include::modules/osdk-java-implement-controller.adoc[leveloffset=+1]
The next subsections explain how the controller in the example implementation watches resources and how the reconcile loop is triggered. You can skip these subsections to go directly to xref:../../../operators/operator_sdk/java/osdk-java-tutorial.adoc#osdk-run-operator_osdk-java-tutorial[Running the Operator].
include::modules/osdk-java-controller-reconcile-loop.adoc[leveloffset=+2]
include::modules/osdk-java-controller-labels-memcached.adoc[leveloffset=+2]
include::modules/osdk-java-controller-memcached-deployment.adoc[leveloffset=+2]
include::modules/osdk-run-operator.adoc[leveloffset=+1]
include::modules/osdk-run-locally.adoc[leveloffset=+2]
include::modules/osdk-run-deployment.adoc[leveloffset=+2]
[id="osdk-bundle-deploy-olm_{context}"]
=== Bundling an Operator and deploying with Operator Lifecycle Manager
// need ifevals:
// include::modules/osdk-bundle-operator.adoc[leveloffset=+3]
// include::modules/osdk-deploy-olm.adoc[leveloffset=+3]
//
// include::modules/osdk-create-cr.adoc[leveloffset=+1]
include::modules/osdk-bundle-operator.adoc[leveloffset=+3]
include::modules/osdk-deploy-olm.adoc[leveloffset=+3]
[role="_additional-resources"]
[id="additional-resources_osdk-java-tutorial"]