diff --git a/_topic_map.yml b/_topic_map.yml index b9a31c31c0..74b6a3a637 100644 --- a/_topic_map.yml +++ b/_topic_map.yml @@ -1125,18 +1125,44 @@ Topics: File: osdk-about - Name: Installing the CLI File: osdk-installing-cli - - Name: Creating Go-based Operators + - Name: Go-based Operators Dir: golang Topics: - Name: Quickstart File: osdk-golang-quickstart - Name: Tutorial File: osdk-golang-tutorial - - Name: Creating Ansible-based Operators - File: osdk-ansible - - Name: Creating Helm-based Operators - File: osdk-helm - - Name: Generating a cluster service version (CSV) + - Name: Project layout + File: osdk-golang-project-layout + - Name: Ansible-based Operators + Dir: ansible + Topics: + - Name: Quickstart + File: osdk-ansible-quickstart + - Name: Tutorial + File: osdk-ansible-tutorial + - Name: Project layout + File: osdk-ansible-project-layout + - Name: Ansible support + File: osdk-ansible-support + - Name: Kubernetes Collection for Ansible + File: osdk-ansible-k8s-collection + - Name: Using Ansible inside an Operator + File: osdk-ansible-inside-operator + - Name: Custom resource status management + File: osdk-ansible-cr-status + - Name: Helm-based Operators + Dir: helm + Topics: + - Name: Quickstart + File: osdk-helm-quickstart + - Name: Tutorial + File: osdk-helm-tutorial + - Name: Project layout + File: osdk-helm-project-layout + - Name: Helm support + File: osdk-helm-support + - Name: Defining cluster service versions (CSVs) File: osdk-generating-csvs - Name: Working with bundle images File: osdk-working-bundle-images @@ -1151,8 +1177,6 @@ Topics: - Name: Migrating to Operator SDK v0.1.0 File: osdk-migrating-to-v0-1-0 Distros: openshift-origin - - Name: Appendices - File: osdk-appendices - Name: Red Hat Operators reference File: operator-reference --- diff --git a/modules/osdk-about-openapi-validation.adoc b/modules/osdk-about-openapi-validation.adoc index 9dc6738c5f..49408283ce 100644 --- a/modules/osdk-about-openapi-validation.adoc +++ b/modules/osdk-about-openapi-validation.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-about-openapi-validation_{context}"] = About OpenAPI validation diff --git a/modules/osdk-ansible-managing-cr-status.adoc b/modules/osdk-ansible-cr-status-about.adoc similarity index 50% rename from modules/osdk-ansible-managing-cr-status.adoc rename to modules/osdk-ansible-cr-status-about.adoc index 43cce29dec..13291154c5 100644 --- a/modules/osdk-ansible-managing-cr-status.adoc +++ b/modules/osdk-ansible-cr-status-about.adoc @@ -1,9 +1,9 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-ansible.adoc +// * operators/operator_sdk/ansible/osdk-ansible-cr-status.adoc -[id="osdk-ansible-managing-cr-status_{context}"] -= Managing custom resource status using the `operator_sdk.util` Ansible collection +[id="osdk-ansible-cr-status-about_{context}"] += About custom resource status in Ansible-based Operators Ansible-based Operators automatically update custom resource (CR) link:https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#status-subresource[`status` subresources] with generic information about the previous Ansible run. This includes the number of successful and failed tasks and relevant error messages as shown: @@ -11,7 +11,7 @@ Ansible-based Operators automatically update custom resource (CR) link:https://k ---- status: conditions: - - ansibleResult: + - ansibleResult: changed: 3 completion: 2018-12-03T13:45:57.13329 failures: 1 @@ -33,51 +33,3 @@ status: Ansible-based Operators also allow Operator authors to supply custom status values with the `k8s_status` Ansible module, which is included in the link:https://galaxy.ansible.com/operator_sdk/util[`operator_sdk.util` collection]. This allows the author to update the `status` from within Ansible with any key-value pair as desired. By default, Ansible-based Operators always include the generic Ansible run output as shown above. If you would prefer your application did _not_ update the status with Ansible output, you can track the status manually from your application. - -.Procedure - -. To track CR status manually from your application, update the `watches.yaml` file with a `manageStatus` field set to `false`: -+ -[source,yaml] ----- -- version: v1 - group: api.example.com - kind: Test1 - role: Test1 - manageStatus: false ----- - -. Use the `operator_sdk.util.k8s_status` Ansible module to update the subresource. For example, to update with key `test1` and value `test2`, `operator_sdk.util` can be used as shown: -+ -[source,yaml] ----- -- operator_sdk.util.k8s_status: - api_version: app.example.com/v1 - kind: Test1 - name: "{{ meta.name }}" - namespace: "{{ meta.namespace }}" - status: - test1: test2 ----- -+ -Collections can also be declared in the `meta/main.yml` for the role, which is included for new scaffolded Ansible Operators: -+ -[source,yaml] ----- -collections: - - operator_sdk.util ----- -+ -Declaring collections in the role meta allows you to invoke the `k8s_status` module directly: -+ -[source,yaml] ----- -k8s_status: - - status: - test1: test2 ----- - -.Additional resources - -- For more details about user-driven status management from Ansible-based Operators, see the link:https://github.com/operator-framework/operator-sdk/blob/master/proposals/ansible-operator-status.md[Ansible-based Operator Status Proposal for Operator SDK]. diff --git a/modules/osdk-ansible-cr-status-manual.adoc b/modules/osdk-ansible-cr-status-manual.adoc new file mode 100644 index 0000000000..12eaf30c3b --- /dev/null +++ b/modules/osdk-ansible-cr-status-manual.adoc @@ -0,0 +1,56 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/ansible/osdk-ansible-cr-status.adoc + +[id="osdk-ansible-cr-status-manual_{context}"] += Tracking custom resource status manually + +You can use the `operator_sdk.util` collection to modify your Ansible-based Operator to track custom resource (CR) status manually from your application. + +.Prerequisites + +* Ansible-based Operator project created by using the Operator SDK + +.Procedure + +. Update the `watches.yaml` file with a `manageStatus` field set to `false`: ++ +[source,yaml] +---- +- version: v1 + group: api.example.com + kind: + role: + manageStatus: false +---- + +. Use the `operator_sdk.util.k8s_status` Ansible module to update the subresource. For example, to update with key `test` and value `data`, `operator_sdk.util` can be used as shown: ++ +[source,yaml] +---- +- operator_sdk.util.k8s_status: + api_version: app.example.com/v1 + kind: + name: "{{ ansible_operator_meta.name }}" + namespace: "{{ ansible_operator_meta.namespace }}" + status: + test: data +---- + +. You can declare collections in the `meta/main.yml` file for the role, which is included for scaffolded Ansible-based Operators: ++ +[source,yaml] +---- +collections: + - operator_sdk.util +---- + +. After declaring collections in the role meta, you can invoke the `k8s_status` module directly: ++ +[source,yaml] +---- +k8s_status: + ... + status: + key1: value1 +---- diff --git a/modules/osdk-ansible-create-api.adoc b/modules/osdk-ansible-create-api.adoc new file mode 100644 index 0000000000..19d7363fbe --- /dev/null +++ b/modules/osdk-ansible-create-api.adoc @@ -0,0 +1,33 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc + +[id="osdk-ansible-create-api-controller_{context}"] += Creating an API + +Use the Operator SDK CLI to create a Memcached API. + +.Procedure + +* Run the following command to create an API with group `cache`, version, `v1`, and kind `Memcached`: ++ +[source,terminal] +---- +$ operator-sdk create api \ + --group cache \ + --version v1 \ + --kind Memcached \ + --generate-role <1> +---- +<1> Generates an Ansible role for the API. + +After creating the API, your Operator project updates with the following structure: + +Memcached CRD:: Includes a sample `Memcached` resource + +Manager:: Program that reconciles the state of the cluster to the desired state by using: ++ +-- +* A reconciler, either an Ansible role or playbook +* A `watches.yaml` file, which connects the `Memcached` resource to the `memcached` Ansible role +-- diff --git a/modules/osdk-ansible-custom-resource-files.adoc b/modules/osdk-ansible-custom-resource-files.adoc index 36969bc394..d94ed33786 100644 --- a/modules/osdk-ansible-custom-resource-files.adoc +++ b/modules/osdk-ansible-custom-resource-files.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-ansible.adoc +// * operators/operator_sdk/ansible/osdk-ansible-support.adoc [id="osdk-ansible-custom-resource-files_{context}"] = Custom resource files diff --git a/modules/osdk-ansible-extra-variables.adoc b/modules/osdk-ansible-extra-variables.adoc index c651148260..fc8d00022f 100644 --- a/modules/osdk-ansible-extra-variables.adoc +++ b/modules/osdk-ansible-extra-variables.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-ansible.adoc +// * operators/operator_sdk/ansible/osdk-ansible-support.adoc [id="osdk-ansible-extra-variables_{context}"] = Extra variables sent to Ansible @@ -42,6 +42,7 @@ The `message` and `newParameter` fields are set in the top level as extra variab [source,yaml] ---- +--- - debug: - msg: "name: {{ meta.name }}, {{ meta.namespace }}" + msg: "name: {{ ansible_operator_meta.name }}, {{ ansible_operator_meta.namespace }}" ---- diff --git a/modules/osdk-ansible-inside-operator-local.adoc b/modules/osdk-ansible-inside-operator-local.adoc new file mode 100644 index 0000000000..bc6604dcfb --- /dev/null +++ b/modules/osdk-ansible-inside-operator-local.adoc @@ -0,0 +1,123 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/ansible/osdk-ansible-inside-operator.adoc + +[id="osdk-ansible-inside-operator-local_{context}"] += Testing an Ansible-based Operator locally + +You can test the logic inside of an Ansible-based Operator running locally by using the `make run` command from the top-level directory of your Operator project. The `make run` Makefile target runs the `ansible-operator` binary locally, which reads from the `watches.yaml` file and uses your `~/.kube/config` file to communicate with a Kubernetes cluster just as the `k8s` modules do. + +[NOTE] +==== +You can customize the roles path by setting the environment variable `ANSIBLE_ROLES_PATH` or by using the `ansible-roles-path` flag. If the role is not found in the `ANSIBLE_ROLES_PATH` value, the Operator looks for it in `{{current directory}}/roles`. +==== + +.Prerequisites + +- link:https://ansible-runner.readthedocs.io/en/latest/install.html[Ansible Runner] version v1.1.0+ +- link:https://github.com/ansible/ansible-runner-http[Ansible Runner HTTP Event Emitter plug-in] version v1.0.0+ +- Performed the previous steps for testing the Kubernetes Collection locally + +.Procedure + +. Install your custom resource definition (CRD) and proper role-based access control (RBAC) definitions for your custom resource (CR): ++ +[source,terminal] +---- +$ make install +---- ++ +.Example output +[source,terminal] +---- +/usr/bin/kustomize build config/crd | kubectl apply -f - +customresourcedefinition.apiextensions.k8s.io/memcacheds.cache.example.com created +---- + +. Run the `make run` command: ++ +[source,terminal] +---- +$ make run +---- ++ +.Example output +[source,terminal] +---- +/home/user/memcached-operator/bin/ansible-operator run +{"level":"info","ts":1612739145.2871568,"logger":"cmd","msg":"Version","Go Version":"go1.15.5","GOOS":"linux","GOARCH":"amd64","ansible-operator":"v1.3.0","commit":"1abf57985b43bf6a59dcd18147b3c574fa57d3f6"} +... +{"level":"info","ts":1612739148.347306,"logger":"controller-runtime.metrics","msg":"metrics server is starting to listen","addr":":8080"} +{"level":"info","ts":1612739148.3488882,"logger":"watches","msg":"Environment variable not set; using default value","envVar":"ANSIBLE_VERBOSITY_MEMCACHED_CACHE_EXAMPLE_COM","default":2} +{"level":"info","ts":1612739148.3490262,"logger":"cmd","msg":"Environment variable not set; using default value","Namespace":"","envVar":"ANSIBLE_DEBUG_LOGS","ANSIBLE_DEBUG_LOGS":false} +{"level":"info","ts":1612739148.3490646,"logger":"ansible-controller","msg":"Watching resource","Options.Group":"cache.example.com","Options.Version":"v1","Options.Kind":"Memcached"} +{"level":"info","ts":1612739148.350217,"logger":"proxy","msg":"Starting to serve","Address":"127.0.0.1:8888"} +{"level":"info","ts":1612739148.3506632,"logger":"controller-runtime.manager","msg":"starting metrics server","path":"/metrics"} +{"level":"info","ts":1612739148.350784,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting EventSource","source":"kind source: cache.example.com/v1, Kind=Memcached"} +{"level":"info","ts":1612739148.5511978,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting Controller"} +{"level":"info","ts":1612739148.5512562,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting workers","worker count":8} +---- ++ +With the Operator now watching your CR for events, the creation of a CR will trigger your Ansible role to run. ++ +[NOTE] +==== +Consider an example `config/samples/.yaml` CR manifest: + +[source,yaml] +---- +apiVersion: .example.com/v1alpha1 +kind: +metadata: + name: "-sample" +---- + +Because the `spec` field is not set, Ansible is invoked with no extra variables. Passing extra variables from a CR to Ansible is covered in another section. It is important to set reasonable defaults for the Operator. +==== + +. Create an instance of your CR with the default variable `state` set to `present`: ++ +[source,terminal] +---- +$ oc apply -f config/samples/.yaml +---- + +. Check that the `example-config` config map was created: ++ +[source,terminal] +---- +$ oc get configmaps +---- ++ +.Example output +[source,terminal] +---- +NAME STATUS AGE +example-config Active 3s +---- + +. Modify your `config/samples/.yaml` file to set the `state` field to `absent`. For example: ++ +[source,yaml] +---- +apiVersion: cache.example.com/v1 +kind: Memcached +metadata: + name: memcached-sample +spec: + state: absent +---- + +. Apply the changes: ++ +[source,terminal] +---- +$ oc apply -f config/samples/.yaml +---- + +. Confirm that the config map is deleted: ++ +[source,terminal] +---- +$ oc get configmap +---- diff --git a/modules/osdk-ansible-inside-operator-logs-full-result.adoc b/modules/osdk-ansible-inside-operator-logs-full-result.adoc new file mode 100644 index 0000000000..4594a7e669 --- /dev/null +++ b/modules/osdk-ansible-inside-operator-logs-full-result.adoc @@ -0,0 +1,21 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/ansible/osdk-ansible-inside-operator.adoc + +[id="osdk-ansible-inside-operator-logs-full-result_{context}"] += Enabling full Ansible results in logs + +You can set the environment variable `ANSIBLE_DEBUG_LOGS` to `True` to enable checking the full Ansible result in logs, which can be helpful when debugging. + +.Procedure + +* Edit the `config/manager/manager.yaml` and `config/default/manager_auth_proxy_patch.yaml` files to include the following configuration: ++ +[source,terminal] +---- + containers: + - name: manager + env: + - name: ANSIBLE_DEBUG_LOGS + value: "True" +---- diff --git a/modules/osdk-ansible-inside-operator-logs-verbose.adoc b/modules/osdk-ansible-inside-operator-logs-verbose.adoc new file mode 100644 index 0000000000..3eda07a023 --- /dev/null +++ b/modules/osdk-ansible-inside-operator-logs-verbose.adoc @@ -0,0 +1,24 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/ansible/osdk-ansible-inside-operator.adoc + +[id="osdk-ansible-inside-operator-logs-verbose_{context}"] += Enabling verbose debugging in logs + +While developing an Ansible-based Operator, it can be helpful to enable additional debugging in logs. + +.Procedure + +* Add the `ansible.sdk.operatorframework.io/verbosity` annotation to your custom resource to enable the verbosity level that you want. For example: ++ +[source,terminal] +---- +apiVersion: "cache.example.com/v1alpha1" +kind: "Memcached" +metadata: + name: "example-memcached" + annotations: + "ansible.sdk.operatorframework.io/verbosity": "4" +spec: + size: 4 +---- diff --git a/modules/osdk-ansible-inside-operator-logs-view.adoc b/modules/osdk-ansible-inside-operator-logs-view.adoc new file mode 100644 index 0000000000..6c8d08e59a --- /dev/null +++ b/modules/osdk-ansible-inside-operator-logs-view.adoc @@ -0,0 +1,42 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/ansible/osdk-ansible-inside-operator.adoc + +[id="osdk-ansible-inside-operator-logs-view_{context}"] += Viewing Ansible logs + +.Prerequisites + +* Ansible-based Operator running as a deployment on a cluster + +.Procedure + +* To view logs from an Ansible-based Operator, run the following command: ++ +[source,terminal] +---- +$ oc logs deployment/-controller-manager \ + -c manager \//<1> + -n <2> +---- +<1> View logs from the `manager` container. +<2> If you used the `make deploy` command to run the Operator as a deployment, use the `-system` namespace. ++ +.Example output +[source,terminal] +---- +{"level":"info","ts":1612732105.0579333,"logger":"cmd","msg":"Version","Go Version":"go1.15.5","GOOS":"linux","GOARCH":"amd64","ansible-operator":"v1.3.0","commit":"1abf57985b43bf6a59dcd18147b3c574fa57d3f6"} +{"level":"info","ts":1612732105.0587437,"logger":"cmd","msg":"WATCH_NAMESPACE environment variable not set. Watching all namespaces.","Namespace":""} +I0207 21:08:26.110949 7 request.go:645] Throttling request took 1.035521578s, request: GET:https://172.30.0.1:443/apis/flowcontrol.apiserver.k8s.io/v1alpha1?timeout=32s +{"level":"info","ts":1612732107.768025,"logger":"controller-runtime.metrics","msg":"metrics server is starting to listen","addr":"127.0.0.1:8080"} +{"level":"info","ts":1612732107.768796,"logger":"watches","msg":"Environment variable not set; using default value","envVar":"ANSIBLE_VERBOSITY_MEMCACHED_CACHE_EXAMPLE_COM","default":2} +{"level":"info","ts":1612732107.7688773,"logger":"cmd","msg":"Environment variable not set; using default value","Namespace":"","envVar":"ANSIBLE_DEBUG_LOGS","ANSIBLE_DEBUG_LOGS":false} +{"level":"info","ts":1612732107.7688901,"logger":"ansible-controller","msg":"Watching resource","Options.Group":"cache.example.com","Options.Version":"v1","Options.Kind":"Memcached"} +{"level":"info","ts":1612732107.770032,"logger":"proxy","msg":"Starting to serve","Address":"127.0.0.1:8888"} +I0207 21:08:27.770185 7 leaderelection.go:243] attempting to acquire leader lease memcached-operator-system/memcached-operator... +{"level":"info","ts":1612732107.770202,"logger":"controller-runtime.manager","msg":"starting metrics server","path":"/metrics"} +I0207 21:08:27.784854 7 leaderelection.go:253] successfully acquired lease memcached-operator-system/memcached-operator +{"level":"info","ts":1612732107.7850506,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting EventSource","source":"kind source: cache.example.com/v1, Kind=Memcached"} +{"level":"info","ts":1612732107.8853772,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting Controller"} +{"level":"info","ts":1612732107.8854098,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting workers","worker count":4} +---- diff --git a/modules/osdk-ansible-inside-operator-logs.adoc b/modules/osdk-ansible-inside-operator-logs.adoc new file mode 100644 index 0000000000..37ee2096fb --- /dev/null +++ b/modules/osdk-ansible-inside-operator-logs.adoc @@ -0,0 +1,8 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/ansible/osdk-ansible-inside-operator.adoc + +[id="osdk-ansible-inside-operator-logs_{context}"] += Ansible logs + +Ansible-based Operators provide logs about the Ansible run, which can be useful for debugging your Ansible tasks. The logs can also contain detailed information about the internals of the Operator and its interactions with Kubernetes. diff --git a/modules/osdk-ansible-k8s-install.adoc b/modules/osdk-ansible-k8s-install.adoc new file mode 100644 index 0000000000..89011a4298 --- /dev/null +++ b/modules/osdk-ansible-k8s-install.adoc @@ -0,0 +1,42 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/ansible/osdk-ansible-k8s-collection.adoc + +[id="osdk-ansible-installing-k8s-collection_{context}"] += Installing the Kubernetes Collection for Ansible + +You can install the Kubernetes Collection for Ansible on your local workstation. + +.Procedure + +. Install Ansible 2.9+: ++ +[source,terminal] +---- +$ sudo dnf install ansible +---- + +. Install the link:https://github.com/openshift/openshift-restclient-python[OpenShift python client] package: ++ +[source,terminal] +---- +$ pip3 install openshift +---- + +. Install the Kubernetes Collection using one of the following methods: + +* You can install the collection directly from Ansible Galaxy: ++ +[source,terminal] +---- +$ ansible-galaxy collection install community.kubernetes +---- + +* If you have already initialized your Operator, you might have a `requirements.yml` file at the top level of your project. This file specifies Ansible dependencies that must be installed for your Operator to function. By default, this file installs the `community.kubernetes` collection as well as the `operator_sdk.util` collection, which provides modules and plug-ins for Operator-specific fuctions. ++ +To install the dependent modules from the `requirements.yml` file: ++ +[source,terminal] +---- +$ ansible-galaxy collection install -r requirements.yml +---- diff --git a/modules/osdk-ansible-k8s-local.adoc b/modules/osdk-ansible-k8s-local.adoc new file mode 100644 index 0000000000..8805147827 --- /dev/null +++ b/modules/osdk-ansible-k8s-local.adoc @@ -0,0 +1,122 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/ansible/osdk-ansible-k8s-collection.adoc + +[id="osdk-ansible-k8s-local_{context}"] += Testing the Kubernetes Collection locally + +Operator developers can run the Ansible code from their local machine as opposed to running and rebuilding the Operator each time. + +.Prerequisites + +* Initialize an Ansible-based Operator project and create an API that has a generated Ansible role by using the Operator SDK +* Install the Kubernetes Collection for Ansible + +.Procedure + +. In your Ansible-based Operator project directory, modify the `roles//tasks/main.yml` file with the Ansible logic that you want. The `roles//` directory is created when you use the `--generate-role` flag while creating an API. The `` replaceable matches the kind that you specified for the API. ++ +The following example creates and deletes a config map based on the value of a variable named `state`: ++ +[source,yaml] +---- +--- +- name: set ConfigMap example-config to {{ state }} + community.kubernetes.k8s: + api_version: v1 + kind: ConfigMap + name: example-config + namespace: default <1> + state: "{{ state }}" + ignore_errors: true <2> +---- +<1> Change this value if you want the config map to be created in a different namespace from `default`. +<2> Setting `ignore_errors: true` ensures that deleting a nonexistent config map does not fail. + +. Modify the `roles//defaults/main.yml` file to set `state` to `present` by default: ++ +[source,yaml] +---- +--- +state: present +---- + +. Create an Ansible playbook by creating a `playbook.yml` file in the top-level of your project directory, and include your `` role: ++ +[source,yaml] +---- +--- +- hosts: localhost + roles: + - +---- + +. Run the playbook: ++ +[source,terminal] +---- +$ ansible-playbook playbook.yml +---- ++ +.Example output +[source,terminal] +---- +[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' + +PLAY [localhost] ******************************************************************************** + +TASK [Gathering Facts] ******************************************************************************** +ok: [localhost] + +TASK [memcached : set ConfigMap example-config to present] ******************************************************************************** +changed: [localhost] + +PLAY RECAP ******************************************************************************** +localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 + +---- + +. Verify that the config map was created: ++ +[source,terminal] +---- +$ oc get configmaps +---- ++ +.Example output +[source,terminal] +---- +NAME DATA AGE +example-config 0 2m1s +---- + +. Rerun the playbook setting `state` to `absent`: ++ +[source,terminal] +---- +$ ansible-playbook playbook.yml --extra-vars state=absent +---- ++ +.Example output +[source,terminal] +---- +[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' + +PLAY [localhost] ******************************************************************************** + +TASK [Gathering Facts] ******************************************************************************** +ok: [localhost] + +TASK [memcached : set ConfigMap example-config to absent] ******************************************************************************** +changed: [localhost] + +PLAY RECAP ******************************************************************************** +localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +---- + +. Verify that the config map was deleted: ++ +[source,terminal] +---- +$ oc get configmaps +---- diff --git a/modules/osdk-ansible-k8s-module-inside-operator.adoc b/modules/osdk-ansible-k8s-module-inside-operator.adoc deleted file mode 100644 index 3dae8f45ca..0000000000 --- a/modules/osdk-ansible-k8s-module-inside-operator.adoc +++ /dev/null @@ -1,226 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/osdk-ansible.adoc - -[id="osdk-ansible-k8s-module-inside-operator_{context}"] -= Testing the k8s Ansible module inside an Operator - -After you are familiar with using the `k8s` Ansible module locally, you can trigger the same Ansible logic inside of an Operator when a custom resource (CR) changes. This example maps an Ansible role to a specific Kubernetes resource that the Operator watches. This mapping is done in the `watches.yaml` file. - -[id="osdk-ansible-k8s-module-inside-operator-testing-local_{context}"] -== Testing an Ansible-based Operator locally - -After getting comfortable testing Ansible workflows locally, you can test the logic inside of an Ansible-based Operator running locally. - -To do so, use the `operator-sdk run --local` command from the top-level directory of your Operator project. This command reads from the `watches.yaml` file and uses the `~/.kube/config` file to communicate with a Kubernetes cluster just as the `k8s` Ansible module does. - -//// -Possible .Prerequisites list item: - -This section assumes the developer has read the Ansible Operator user guide and has the proper dependencies installed. -//// - -.Procedure - -. Because the `run --local` command reads from the `watches.yaml` file, there are options available to the Operator author. If `role` is left alone (by default, `/opt/ansible/roles/`) you must copy the role over to the `/opt/ansible/roles/` directory from the Operator directly. -+ -This is cumbersome because changes are not reflected from the current directory. Instead, change the `role` field to point to the current directory and comment out the existing line: -+ -[source,yaml] ----- -- version: v1alpha1 - group: test1.example.com - kind: Test1 - # role: /opt/ansible/roles/Test1 - role: /home/user/test1-operator/Test1 ----- - -. Create a custom resource definition (CRD) and proper role-based access control -(RBAC) definitions for the custom resource (CR) `Test1`. The `operator-sdk` -command autogenerates these files inside of the `deploy/` directory: -+ -[source,terminal] ----- -$ oc create -f deploy/crds/test1_v1alpha1_test1_crd.yaml ----- -+ -[source,terminal] ----- -$ oc create -f deploy/service_account.yaml ----- -+ -[source,terminal] ----- -$ oc create -f deploy/role.yaml ----- -+ -[source,terminal] ----- -$ oc create -f deploy/role_binding.yaml ----- - -. Run the `run --local` command: -+ -[source,terminal] ----- -$ operator-sdk run --local ----- -+ -.Example output -[source,terminal] ----- -[...] -INFO[0000] Starting to serve on 127.0.0.1:8888 -INFO[0000] Watching test1.example.com/v1alpha1, Test1, default ----- - -. Now that the Operator is watching the resource `Test1` for events, the creation of a CR triggers your Ansible role to execute. View the `deploy/cr.yaml` file: -+ -[source,yaml] ----- -apiVersion: "test1.example.com/v1alpha1" -kind: "Test1" -metadata: - name: "example" ----- -+ -Because the `spec` field is not set, Ansible is invoked with no extra variables. The next section covers how extra variables are passed from a CR to Ansible. This is why it is important to set reasonable defaults for the Operator. - -. Create a CR instance of `Test1` with the default variable `state` set to `present`: -+ -[source,terminal] ----- -$ oc create -f deploy/cr.yaml ----- - -. Check that the namespace `test` was created: -+ -[source,terminal] ----- -$ oc get namespace ----- -+ -.Example output -[source,terminal] ----- -NAME STATUS AGE -default Active 28d -kube-public Active 28d -kube-system Active 28d -test Active 3s ----- - -. Modify the `deploy/cr.yaml` file to set the `state` field to `absent`: -+ -[source,yaml] ----- -apiVersion: "test1.example.com/v1alpha1" -kind: "Test1" -metadata: - name: "example" -spec: - state: "absent" ----- - -. Apply the changes and confirm that the namespace is deleted: -+ -[source,terminal] ----- -$ oc apply -f deploy/cr.yaml ----- -+ -[source,terminal] ----- -$ oc get namespace ----- -+ -.Example output -[source,terminal] ----- -NAME STATUS AGE -default Active 28d -kube-public Active 28d -kube-system Active 28d ----- - -[id="osdk-ansible-k8s-module-inside-operator-testing-cluster_{context}"] -== Testing an Ansible-based Operator on a cluster - -After getting familiar running Ansible logic inside of an Ansible-based Operator locally, you can test the Operator inside of a pod on a Kubernetes cluster, such as {product-title}. Running as a pod on a cluster is preferred for production use. - -.Procedure - -. Build the `test1-operator` image and push it to a registry: -+ -[source,terminal] ----- -$ operator-sdk build quay.io/example/test1-operator:v0.0.1 ----- -+ -[source,terminal] ----- -$ podman push quay.io/example/test1-operator:v0.0.1 ----- - -. Deployment manifests are generated in the `deploy/operator.yaml` file. The deployment image in this file must be modified from the placeholder `REPLACE_IMAGE` to the previously-built image. To do so, run the following command: -+ -[source,terminal] ----- -$ sed -i 's|REPLACE_IMAGE|quay.io/example/test1-operator:v0.0.1|g' deploy/operator.yaml ----- -+ -If you are performing these steps on macOS, use the following command instead: -+ -[source,terminal] ----- -$ sed -i "" 's|REPLACE_IMAGE|quay.io/example/test1-operator:v0.0.1|g' deploy/operator.yaml ----- - -. Deploy the `test1-operator`: -+ -[source,terminal] ----- -$ oc create -f deploy/crds/test1_v1alpha1_test1_crd.yaml <1> ----- -<1> Only required if the CRD does not exist already. -+ -[source,terminal] ----- -$ oc create -f deploy/service_account.yaml ----- -+ -[source,terminal] ----- -$ oc create -f deploy/role.yaml ----- -+ -[source,terminal] ----- -$ oc create -f deploy/role_binding.yaml ----- -+ -[source,terminal] ----- -$ oc create -f deploy/operator.yaml ----- - -. Verify that the `test1-operator` is up and running: -+ -[source,terminal] ----- -$ oc get deployment ----- -+ -.Example output -[source,terminal] ----- -NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE -test1-operator 1 1 1 1 1m ----- - -. You can now view the Ansible logs for the `test1-operator`: -+ -[source,terminal] ----- -$ oc logs deployment/test1-operator ----- diff --git a/modules/osdk-ansible-k8s-module-installing.adoc b/modules/osdk-ansible-k8s-module-installing.adoc deleted file mode 100644 index 5a5b92d1a8..0000000000 --- a/modules/osdk-ansible-k8s-module-installing.adoc +++ /dev/null @@ -1,29 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/osdk-ansible.adoc - -[id="osdk-ansible-k8s-module-installing_{context}"] -= Installing the k8s Ansible module - -To install the `k8s` Ansible module on your local workstation: - -.Procedure - -. Install Ansible 2.9+: -+ -[source,terminal] ----- -$ sudo yum install ansible ----- - -. Install the link:https://github.com/openshift/openshift-restclient-python[OpenShift python client] package using `pip`: -+ -[source,terminal] ----- -$ sudo pip install openshift ----- -+ -[source,terminal] ----- -$ sudo pip install kubernetes ----- diff --git a/modules/osdk-ansible-k8s-module-testing-locally.adoc b/modules/osdk-ansible-k8s-module-testing-locally.adoc deleted file mode 100644 index 303f7efce4..0000000000 --- a/modules/osdk-ansible-k8s-module-testing-locally.adoc +++ /dev/null @@ -1,161 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/osdk-ansible.adoc - -[id="osdk-ansible-k8s-module-testing-locally_{context}"] -= Testing the k8s Ansible module locally - -Sometimes, it is beneficial for a developer to run the Ansible code from their local machine as opposed to running and rebuilding the Operator each time. - -.Procedure - -. Install the `community.kubernetes` collection: -+ -[source,terminal] ----- -$ ansible-galaxy collection install community.kubernetes ----- - -. Initialize a new Ansible-based Operator project: -+ -[source,terminal] ----- -$ operator-sdk new --type ansible \ - --kind Test1 \ - --api-version test1.example.com/v1alpha1 test1-operator ----- -+ -.Example output -[source,terminal] ----- -Create test1-operator/tmp/init/galaxy-init.sh -Create test1-operator/tmp/build/Dockerfile -Create test1-operator/tmp/build/test-framework/Dockerfile -Create test1-operator/tmp/build/go-test.sh -Rendering Ansible Galaxy role [test1-operator/roles/test1]... -Cleaning up test1-operator/tmp/init -Create test1-operator/watches.yaml -Create test1-operator/deploy/rbac.yaml -Create test1-operator/deploy/crd.yaml -Create test1-operator/deploy/cr.yaml -Create test1-operator/deploy/operator.yaml -Run git init ... -Initialized empty Git repository in /home/user/go/src/github.com/user/opsdk/test1-operator/.git/ -Run git init done ----- -+ -[source,terminal] ----- -$ cd test1-operator ----- - -. Modify the `roles/test1/tasks/main.yml` file with the Ansible logic that you want. This example creates and deletes a namespace with the switch of a variable. -+ -[source,yaml] ----- -- name: set test namespace to "{{ state }}" - community.kubernetes.k8s: - api_version: v1 - kind: Namespace - state: "{{ state }}" - name: test - ignore_errors: true <1> ----- -<1> Setting `ignore_errors: true` ensures that deleting a nonexistent project does not fail. - -. Modify the `roles/test1/defaults/main.yml` file to set `state` to `present` by default: -+ -[source,yaml] ----- -state: present ----- - -. Create an Ansible playbook `playbook.yml` in the top-level directory, which includes the `test1` role: -+ -[source,yaml] ----- -- hosts: localhost - roles: - - test1 ----- - -. Run the playbook: -+ -[source,terminal] ----- -$ ansible-playbook playbook.yml ----- -+ -.Example output -[source,terminal] ----- - [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' - -PLAY [localhost] *************************************************************************** - -PROCEDURE [Gathering Facts] ********************************************************************* -ok: [localhost] - -Task [test1 : set test namespace to present] -changed: [localhost] - -PLAY RECAP ********************************************************************************* -localhost : ok=2 changed=1 unreachable=0 failed=0 ----- - -. Check that the namespace was created: -+ -[source,terminal] ----- -$ oc get namespace ----- -+ -.Example output -[source,terminal] ----- -NAME STATUS AGE -default Active 28d -kube-public Active 28d -kube-system Active 28d -test Active 3s ----- - -. Rerun the playbook setting `state` to `absent`: -+ -[source,terminal] ----- -$ ansible-playbook playbook.yml --extra-vars state=absent ----- -+ -.Example output -[source,terminal] ----- - [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' - -PLAY [localhost] *************************************************************************** - -PROCEDURE [Gathering Facts] ********************************************************************* -ok: [localhost] - -Task [test1 : set test namespace to absent] -changed: [localhost] - -PLAY RECAP ********************************************************************************* -localhost : ok=2 changed=1 unreachable=0 failed=0 ----- - -. Check that the namespace was deleted: -+ -[source,terminal] ----- -$ oc get namespace ----- -+ -.Example output -[source,terminal] ----- -NAME STATUS AGE -default Active 28d -kube-public Active 28d -kube-system Active 28d ----- diff --git a/modules/osdk-ansible-modify-manager.adoc b/modules/osdk-ansible-modify-manager.adoc new file mode 100644 index 0000000000..853780a1b1 --- /dev/null +++ b/modules/osdk-ansible-modify-manager.adoc @@ -0,0 +1,78 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc + +[id="osdk-ansible-modify-manager_{context}"] += Modifying the manager + +Update your Operator project to provide the reconcile logic, in the form of an Ansible role, which runs every time a `Memcached` resource is created, updated, or deleted. + +.Procedure + +. Update the `roles/memcached/tasks/main.yml` file with the following structure: ++ +[source,yaml] +---- +--- +- name: start memcached + community.kubernetes.k8s: + definition: + kind: Deployment + apiVersion: apps/v1 + metadata: + name: '{{ ansible_operator_meta.name }}-memcached' + namespace: '{{ ansible_operator_meta.namespace }}' + spec: + replicas: "{{size}}" + selector: + matchLabels: + app: memcached + template: + metadata: + labels: + app: memcached + spec: + containers: + - name: memcached + command: + - memcached + - -m=64 + - -o + - modern + - -v + image: "docker.io/memcached:1.4.36-alpine" + ports: + - containerPort: 11211 +---- ++ +This `memcached` role ensures a `memcached` deployment exist and sets the deployment size. + +. Set default values for variables used in your Ansible role by editing the `roles/memcached/defaults/main.yml` file: ++ +[source,yaml] +---- +--- +# defaults file for Memcached +size: 1 +---- + +. Update the `Memcached` sample resource in the `config/samples/cache_v1_memcached.yaml` file with the following structure: ++ +[source,yaml] +---- +apiVersion: cache.example.com/v1 +kind: Memcached +metadata: + name: memcached-sample +spec: + size: 3 +---- ++ +The key-value pairs in the custom resource (CR) spec are passed to Ansible as extra variables. + +[NOTE] +==== +The names of all variables in the `spec` field are converted to snake case, meaning lowercase with an underscore, by the Operator before running Ansible. For example, `serviceAccount` in the spec becomes `service_account` in Ansible. + +You can disable this case conversion by setting the `snakeCaseParameters` option to `false` in your `watches.yaml` file. It is recommended that you perform some type validation in Ansible on the variables to ensure that your application is receiving expected input. +==== diff --git a/modules/osdk-ansible-project-layout.adoc b/modules/osdk-ansible-project-layout.adoc new file mode 100644 index 0000000000..04cbcd601b --- /dev/null +++ b/modules/osdk-ansible-project-layout.adoc @@ -0,0 +1,60 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/ansible/osdk-ansible-project-layout.adoc + +[id="osdk-ansible-project-layout_{context}"] += Ansible-based project layout + +Ansible-based Operator projects generated using the `operator-sdk init --plugins ansible` command contain the following directories and files: + +[options="header",cols="1,4"] +|=== + +|File or directory |Purpose + +|`Dockerfile` +|Dockerfile for building the container image for the Operator. + +|`Makefile` +|Targets for building, publishing, deploying the container image that wraps the Operator binary, and targets for installing and uninstalling the custom resource definition (CRD). + +|`PROJECT` +|YAML file containing metadata information for the Operator. + +|`config/crd` +|Base CRD files and the `kustomization.yaml` file settings. + +|`config/default` +|Collects all Operator manifests for deployment. Use by the `make deploy` command. + +|`config/manager` +|Controller manager deployment. + +|`config/prometheus` +|`ServiceMonitor` resource for monitoring the Operator. + +|`config/rbac` +|Role and role binding for leader election and authentication proxy. + +|`config/samples` +|Sample resources created for the CRDs. + +|`config/testing` +|Sample configurations for testing. + +|`playbooks/` +|A subdirectory for the playbooks to run. + +|`roles/` +|Subdirectory for the roles tree to run. + +|`watches.yaml` +|Group/version/kind (GVK) of the resources to watch, and the Ansible invocation method. New entries are added by using the `create api` command. + +|`requirements.yml` +|YAML file containing the Ansible collections and role dependencies to install during a build. + +|`molecule/` +|Molecule scenarios for end-to-end testing of your role and Operator. + +|=== diff --git a/modules/osdk-ansible-runner-directory.adoc b/modules/osdk-ansible-runner-directory.adoc index d45d9653c3..757b8116a5 100644 --- a/modules/osdk-ansible-runner-directory.adoc +++ b/modules/osdk-ansible-runner-directory.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-ansible.adoc +// * operators/operator_sdk/ansible/osdk-ansible-support.adoc [id="osdk-ansible-runner-directory_{context}"] = Ansible Runner directory diff --git a/modules/osdk-ansible-support.adoc b/modules/osdk-ansible-support.adoc deleted file mode 100644 index 0f5a37d608..0000000000 --- a/modules/osdk-ansible-support.adoc +++ /dev/null @@ -1,8 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/osdk-ansible.adoc - -[id="osdk-ansible-support_{context}"] -= Ansible support in the Operator SDK - -One of the Operator SDK options for generating an Operator project includes leveraging existing Ansible playbooks and modules to deploy Kubernetes resources as a unified application, without having to write any Go code. diff --git a/modules/osdk-ansible-watches-file.adoc b/modules/osdk-ansible-watches-file.adoc index 40c02f728d..9bfc105a52 100644 --- a/modules/osdk-ansible-watches-file.adoc +++ b/modules/osdk-ansible-watches-file.adoc @@ -1,9 +1,9 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-ansible.adoc +// * operators/operator_sdk/ansible/osdk-ansible-support.adoc [id="osdk-ansible-watches-file_{context}"] -= `watches.yaml` file += watches.yaml file A _group/version/kind (GVK)_ is a unique identifier for a Kubernetes API. The `watches.yaml` file contains a list of mappings from custom resources (CRs), identified by its GVK, to an Ansible role or playbook. The Operator expects this mapping file in a predefined location at `/opt/ansible/watches.yaml`. @@ -66,7 +66,7 @@ Advanced features can be enabled by adding them to your `watches.yaml` file per Some features can be overridden per resource using an annotation on that CR. The options that can be overridden have the annotation specified below. -.Advanced `watches.yaml` file options +.Advanced watches.yaml file options [cols="3,2,4,2,1",options="header"] |=== |Feature @@ -106,7 +106,7 @@ Some features can be overridden per resource using an annotation on that CR. The |`20` |=== -.Example `watches.yml` file with advanced options +.Example watches.yml file with advanced options [source,yaml] ---- - version: v1alpha1 diff --git a/modules/osdk-building-ansible-operator.adoc b/modules/osdk-building-ansible-operator.adoc deleted file mode 100644 index c927443d70..0000000000 --- a/modules/osdk-building-ansible-operator.adoc +++ /dev/null @@ -1,367 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/osdk-ansible.adoc - -[id="osdk-building-ansible-operator_{context}"] -= Building an Ansible-based Operator using the Operator SDK - -This procedure walks through an example of building a simple Memcached Operator powered by Ansible playbooks and modules using tools and libraries provided by the Operator SDK. - -.Prerequisites - -- Operator SDK CLI installed on the development workstation -- Access to a Kubernetes-based cluster v1.11.3+ (for example {product-title} {product-version}) using an account with `cluster-admin` permissions -- OpenShift CLI (`oc`) v{product-version}+ installed -- link:https://docs.ansible.com/ansible/latest/index.html[`ansible`] v2.9.0+ -- link:https://ansible-runner.readthedocs.io/en/latest/install.html[`ansible-runner`] v1.1.0+ -- link:https://github.com/ansible/ansible-runner-http[`ansible-runner-http`] v1.0.0+ - -.Procedure - -. *Create a new Operator project.* A namespace-scoped Operator watches and manages resources in a single namespace. Namespace-scoped Operators are preferred because of their flexibility. They enable decoupled upgrades, namespace isolation for failures and monitoring, and differing API definitions. -+ -To create a new Ansible-based, namespace-scoped `memcached-operator` project and change to the new directory, use the following commands: -+ -[source,terminal] ----- -$ operator-sdk new memcached-operator \ - --api-version=cache.example.com/v1alpha1 \ - --kind=Memcached \ - --type=ansible ----- -+ -[source,terminal] ----- -$ cd memcached-operator ----- -+ -This creates the `memcached-operator` project specifically for watching the `Memcached` resource with API version `example.com/v1apha1` and kind `Memcached`. - -. *Customize the Operator logic.* -+ -For this example, the `memcached-operator` executes the following reconciliation logic for each `Memcached` custom resource (CR): -+ --- -* Create a `memcached` deployment if it does not exist. -* Ensure that the deployment size is the same as specified by the `Memcached` CR. --- -+ -By default, the `memcached-operator` watches `Memcached` resource events as shown in the `watches.yaml` file and executes the Ansible role `Memcached`: -+ -[source,yaml] ----- -- version: v1alpha1 - group: cache.example.com - kind: Memcached ----- -+ -You can optionally customize the following logic in the `watches.yaml` file: - -.. Specifying a `role` option configures the Operator to use this specified path when launching `ansible-runner` with an Ansible role. By default, the `operator-sdk new` command fills in an absolute path to where your role should go: -+ -[source,yaml] ----- -- version: v1alpha1 - group: cache.example.com - kind: Memcached - role: /opt/ansible/roles/memcached ----- - -.. Specifying a `playbook` option in the `watches.yaml` file configures the Operator to use this specified path when launching `ansible-runner` with an Ansible playbook: -+ -[source,yaml] ----- -- version: v1alpha1 - group: cache.example.com - kind: Memcached - playbook: /opt/ansible/playbook.yaml ----- - -. *Build the Memcached Ansible role.* -+ -Modify the generated Ansible role under the `roles/memcached/` directory. This Ansible role controls the logic that is executed when a resource is modified. - -.. *Define the `Memcached` spec.* -+ -Defining the spec for an Ansible-based Operator can be done entirely in Ansible. The Ansible Operator passes all key-value pairs listed in the CR spec field along to Ansible as link:https://docs.ansible.com/ansible/2.5/user_guide/playbooks_variables.html#passing-variables-on-the-command-line[variables]. The names of all variables in the spec field are converted to snake case (lowercase with an underscore) by the Operator before running Ansible. For example, `serviceAccount` in the spec becomes `service_account` in Ansible. -+ -[TIP] -==== -You should perform some type validation in Ansible on the variables to ensure that your application is receiving expected input. -==== -+ -In case the user does not set the `spec` field, set a default by modifying the `roles/memcached/defaults/main.yml` file: -+ -[source,yaml] ----- -size: 1 ----- - -.. *Define the `Memcached` deployment.* -+ -With the `Memcached` spec now defined, you can define what Ansible is actually executed on resource changes. Because this is an Ansible role, the default behavior executes the tasks in the `roles/memcached/tasks/main.yml` file. -+ -The goal is for Ansible to create a deployment if it does not exist, which runs the `memcached:1.4.36-alpine` image. Ansible 2.7+ supports the link:https://docs.ansible.com/ansible/2.7/modules/k8s_module.html[k8s Ansible module], which this example leverages to control the deployment definition. -+ -Modify the `roles/memcached/tasks/main.yml` to match the following: -+ -[source,yaml] ----- -- name: start memcached - k8s: - definition: - kind: Deployment - apiVersion: apps/v1 - metadata: - name: '{{ meta.name }}-memcached' - namespace: '{{ meta.namespace }}' - spec: - replicas: "{{size}}" - selector: - matchLabels: - app: memcached - template: - metadata: - labels: - app: memcached - spec: - containers: - - name: memcached - command: - - memcached - - -m=64 - - -o - - modern - - -v - image: "docker.io/memcached:1.4.36-alpine" - ports: - - containerPort: 11211 ----- -+ -[NOTE] -==== -This example used the `size` variable to control the number of replicas of the `Memcached` deployment. This example sets the default to `1`, but any user can create a CR that overwrites the default. -==== - -. *Deploy the CRD.* -+ -Before running the Operator, Kubernetes needs to know about the new custom resource definition (CRD) that the Operator will be watching. Deploy the `Memcached` CRD: -+ -[source,terminal] ----- -$ oc create -f deploy/crds/cache.example.com_memcacheds_crd.yaml ----- - -. *Build and run the Operator.* -+ -There are two ways to build and run the Operator: -+ --- -* As a pod inside a Kubernetes cluster. -* As a Go program outside the cluster using the `operator-sdk up` command. --- -+ -Choose one of the following methods: - -.. *Run as a pod* inside a Kubernetes cluster. This is the preferred method for production use. - -... Build the `memcached-operator` image and push it to a registry: -+ -[source,terminal] ----- -$ operator-sdk build quay.io/example/memcached-operator:v0.0.1 ----- -+ -[source,terminal] ----- -$ podman push quay.io/example/memcached-operator:v0.0.1 ----- - -... Deployment manifests are generated in the `deploy/operator.yaml` file. The deployment image in this file needs to be modified from the placeholder `REPLACE_IMAGE` to the previous built image. To do this, run: -+ -[source,terminal] ----- -$ sed -i 's|REPLACE_IMAGE|quay.io/example/memcached-operator:v0.0.1|g' deploy/operator.yaml ----- - -... Deploy the `memcached-operator` manifests: -+ -[source,terminal] ----- -$ oc create -f deploy/service_account.yaml ----- -+ -[source,terminal] ----- -$ oc create -f deploy/role.yaml ----- -+ -[source,terminal] ----- -$ oc create -f deploy/role_binding.yaml ----- -+ -[source,terminal] ----- -$ oc create -f deploy/operator.yaml ----- - -... Verify that the `memcached-operator` deployment is up and running: -+ -[source,terminal] ----- -$ oc get deployment ----- -+ -[source,terminal] ----- -NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE -memcached-operator 1 1 1 1 1m ----- - -.. *Run outside the cluster.* This method is preferred during the development cycle to speed up deployment and testing. -+ -Ensure that Ansible Runner and Ansible Runner HTTP Plug-in are installed or else you will see unexpected errors from Ansible Runner when a CR is created. -+ -It is also important that the role path referenced in the `watches.yaml` file exists on your machine. Because normally a container is used where the role is put on disk, the role must be manually copied to the configured Ansible roles path (for example `/etc/ansible/roles`). - -... To run the Operator locally with the default Kubernetes configuration file present at `$HOME/.kube/config`: -+ -[source,terminal] ----- -$ operator-sdk run --local ----- -+ -To run the Operator locally with a provided Kubernetes configuration file: -+ -[source,terminal] ----- -$ operator-sdk run --local --kubeconfig=config ----- - -. *Create a `Memcached` CR.* - -.. Modify the `deploy/crds/cache_v1alpha1_memcached_cr.yaml` file as shown and create a `Memcached` CR: -+ -[source,terminal] ----- -$ cat deploy/crds/cache_v1alpha1_memcached_cr.yaml ----- -+ -.Example output -[source,yaml] ----- -apiVersion: "cache.example.com/v1alpha1" -kind: "Memcached" -metadata: - name: "example-memcached" -spec: - size: 3 ----- -+ -[source,terminal] ----- -$ oc apply -f deploy/crds/cache_v1alpha1_memcached_cr.yaml ----- - -.. Ensure that the `memcached-operator` creates the deployment for the CR: -+ -[source,terminal] ----- -$ oc get deployment ----- -+ -.Example output -[source,terminal] ----- -NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE -memcached-operator 1 1 1 1 2m -example-memcached 3 3 3 3 1m ----- - -.. Check the pods to confirm three replicas were created: -+ -[source,terminal] ----- -$ oc get pods ----- -+ -[source,terminal] ----- -NAME READY STATUS RESTARTS AGE -example-memcached-6fd7c98d8-7dqdr 1/1 Running 0 1m -example-memcached-6fd7c98d8-g5k7v 1/1 Running 0 1m -example-memcached-6fd7c98d8-m7vn7 1/1 Running 0 1m -memcached-operator-7cc7cfdf86-vvjqk 1/1 Running 0 2m ----- - -. *Update the size.* - -.. Change the `spec.size` field in the `memcached` CR from `3` to `4` and apply the change: -+ -[source,terminal] ----- -$ cat deploy/crds/cache_v1alpha1_memcached_cr.yaml ----- -+ -.Example output -[source,yaml] ----- -apiVersion: "cache.example.com/v1alpha1" -kind: "Memcached" -metadata: - name: "example-memcached" -spec: - size: 4 ----- -+ -[source,terminal] ----- -$ oc apply -f deploy/crds/cache_v1alpha1_memcached_cr.yaml ----- - -.. Confirm that the Operator changes the deployment size: -+ -[source,terminal] ----- -$ oc get deployment ----- -+ -.Example output -[source,terminal] ----- -NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE -example-memcached 4 4 4 4 5m ----- - -. *Clean up the resources:* -+ -[source,terminal] ----- -$ oc delete -f deploy/crds/cache_v1alpha1_memcached_cr.yaml ----- -+ -[source,terminal] ----- -$ oc delete -f deploy/operator.yaml ----- -+ -[source,terminal] ----- -$ oc delete -f deploy/role_binding.yaml ----- -+ -[source,terminal] ----- -$ oc delete -f deploy/role.yaml ----- -+ -[source,terminal] ----- -$ oc delete -f deploy/service_account.yaml ----- -+ -[source,terminal] ----- -$ oc delete -f deploy/crds/cache_v1alpha1_memcached_crd.yaml ----- diff --git a/modules/osdk-bundling-deploying-using-olm.adoc b/modules/osdk-bundle-deploy-olm.adoc similarity index 50% rename from modules/osdk-bundling-deploying-using-olm.adoc rename to modules/osdk-bundle-deploy-olm.adoc index cb29ba310a..4ae81c6e81 100644 --- a/modules/osdk-bundling-deploying-using-olm.adoc +++ b/modules/osdk-bundle-deploy-olm.adoc @@ -1,11 +1,17 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc +// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc -[id="osdk-bundling-deploying-using-olm_{context}"] -= Bundling and deploying your Operator by using OLM +ifeval::["{context}" == "osdk-golang-tutorial"] +:golang: +endif::[] -Operator Lifecycle Manager (OLM) helps you to install, update, and generally manage the lifecycle of Operators and their associated services on a Kubernetes cluster. OLM is installed by default on {product-title} and runs as an Kubernetes extension, which allows you to use the {product-title} web console and the OpenShift CLI (`oc`) for all the lifecycle management functions without any additional tools. +[id="osdk-bundle-deploy-olm_{context}"] += Bundling and deploying with OLM + +Operator Lifecycle Manager (OLM) helps you to install, update, and generally manage the lifecycle of Operators and their associated services on a Kubernetes cluster. OLM is installed by default on {product-title} and runs as a Kubernetes extension so that you can use the web console and the OpenShift CLI (`oc`) for all Operator lifecycle management functions without any additional tools. This example walks through getting an Operator ready for OLM that uses the Bundle Format, the default packaging format for Operator SDK and OLM. @@ -15,19 +21,40 @@ This example walks through getting an Operator ready for OLM that uses the Bundl - OpenShift CLI (`oc`) v{product-version}+ installed - Operator Lifecycle Manager (OLM) installed on a Kubernetes-based cluster (v1.16.0 or later if you use `apiextensions.k8s.io/v1` CRDs, for example {product-title} {product-version}) - Logged into the cluster with `oc` using an account with `cluster-admin` permissions -- Memcached Operator built by using Operator SDK. +- Operator built by using the Operator SDK +ifdef::golang[] +- Prepared your Go-based Operator to run on {product-title} by updating the project to use supported images +endif::[] .Procedure -. Check the status of OLM on your cluster by using the following Operator SDK command: +. Run the following `make` commands to build and push your Operator image. Modify the `IMG` argument in the following steps to reference a repository that you have access to. You can obtain an account for storing containers at repository sites such as Quay.io. + +.. Build the image: + [source,terminal] ---- -$ operator-sdk olm status \ - --olm-namespace=openshift-operator-lifecycle-manager +$ make docker-build IMG=//: ---- -. Create the Memcached bundle manifest by running the `make bundle` command, which invokes several commands, including the Operator SDK `generate bundle` and `bundle validate` subcommands: +.. Push the image to a repository: ++ +[source,terminal] +---- +$ make docker-push IMG=//: +---- + +. Update your `Makefile` by setting the `IMG` URL to your Operator image name and tag that you pushed: ++ +[source,terminal] +---- +$ # Image URL to use all building/pushing image targets +IMG ?= //: +---- ++ +This value is used for subsequent operations. + +. Create your Operator bundle manifest by running the `make bundle` command, which invokes several commands, including the Operator SDK `generate bundle` and `bundle validate` subcommands: + [source,terminal] ---- @@ -45,28 +72,39 @@ Bundle manifests for an Operator describe how to display, create, and manage an + These files are then automatically validated by using `operator-sdk bundle validate` to ensure the on-disk bundle representation is correct. -. Build and push a `memcached-operator` bundle image by running the following commands. OLM consumes Operator bundles using an index image, which reference one or more bundle images. +. Build and push your bundle image by running the following commands. OLM consumes Operator bundles using an index image, which reference one or more bundle images. .. Build the bundle image. Set `BUNDLE_IMAGE` with the details for the registry, user namespace, and image tag where you intend to push the image: + [source,terminal] ---- -$ make bundle-build BUNDLE_IMG=//memcached-operator-bundle: +$ make bundle-build BUNDLE_IMG=//: ---- .. Push the bundle image: + [source,terminal] ---- -$ docker push //memcached-operator-bundle: +$ docker push //: ---- -. Run your Operator on your cluster by using OLM: +. Check the status of OLM on your cluster by using the following Operator SDK command: + [source,terminal] ---- -$ operator-sdk run bundle //memcached-operator-bundle: +$ operator-sdk olm status \ + --olm-namespace=openshift-operator-lifecycle-manager ---- + +. Run the Operator on your cluster by using the OLM integration in Operator SDK: ++ +[source,terminal] +---- +$ operator-sdk run bundle \ + [-n ] \//<1> + //: +---- +<1> By default, the command installs the Operator in the currently active project in your `~/.kube/config` file. You can add the `-n` flag to set a different namespace scope for the installation. + This command performs the following actions: + @@ -75,3 +113,7 @@ This command performs the following actions: * Create a catalog source that points to your new index image, which enables OperatorHub to discover your Operator. * Deploy your Operator to your cluster by creating an Operator group, subscription, install plan, and all other required objects, including RBAC. -- + +ifeval::["{context}" == "osdk-golang-tutorial"] +:!golang: +endif::[] diff --git a/modules/osdk-create-cr.adoc b/modules/osdk-create-cr.adoc new file mode 100644 index 0000000000..3fa369a9b7 --- /dev/null +++ b/modules/osdk-create-cr.adoc @@ -0,0 +1,226 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc +// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc + +ifeval::["{context}" == "osdk-golang-tutorial"] +:golang: +:app-proper: Memcached +:app: memcached +:group: cache +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:ansible: +:app-proper: Memcached +:app: memcached +:group: cache +endif::[] +ifeval::["{context}" == "osdk-helm-tutorial"] +:helm: +:app-proper: Nginx +:app: nginx +:group: demo +endif::[] + +[id="osdk-create-cr_{context}"] += Creating a custom resource + +After your Operator is installed, you can test it by creating a custom resource (CR) that is now provided on the cluster by the Operator. + +.Prerequisites + +* Example {app-proper} Operator, which provides the `{app-proper}` CR, installed on a cluster + +.Procedure + +. Change to the namespace where your Operator is installed. For example, if you deployed the Operator using the `make deploy` command: ++ +[source,terminal,subs="attributes+"] +---- +$ oc project {app}-operator-system +---- + +. Edit the sample `{app-proper}` CR manifest at `config/samples/{group}_v1_{app}.yaml` to contain the following specification: ++ +[source,yaml,subs="attributes+"] +---- +apiVersion: {group}.example.com/v1 +kind: {app-proper} +metadata: + name: {app}-sample +... +spec: +... +ifdef::helm[] + replicaCount: 3 +endif::[] +ifndef::helm[] + size: 3 +endif::[] +---- + +. Create the CR: ++ +[source,terminal,subs="attributes+"] +---- +$ oc apply -f config/samples/{group}_v1_{app}.yaml +---- + +. Ensure that the `{app-proper}` Operator creates the deployment for the sample CR with the correct size: ++ +[source,terminal] +---- +$ oc get deployments +---- ++ +.Example output +[source,terminal] +ifdef::helm[] +---- +NAME READY UP-TO-DATE AVAILABLE AGE +nginx-operator-controller-manager 1/1 1 1 8m +nginx-sample 3/3 3 3 1m +---- +endif::[] +ifndef::helm[] +---- +NAME READY UP-TO-DATE AVAILABLE AGE +memcached-operator-controller-manager 1/1 1 1 8m +memcached-sample 3/3 3 3 1m +---- +endif::[] + +. Check the pods and CR status to confirm the status is updated with the {app-proper} pod names. + +.. Check the pods: ++ +[source,terminal] +---- +$ oc get pods +---- ++ +.Example output +[source,terminal] +ifdef::helm[] +---- +NAME READY STATUS RESTARTS AGE +nginx-sample-6fd7c98d8-7dqdr 1/1 Running 0 1m +nginx-sample-6fd7c98d8-g5k7v 1/1 Running 0 1m +nginx-sample-6fd7c98d8-m7vn7 1/1 Running 0 1m +---- +endif::[] +ifndef::helm[] +---- +NAME READY STATUS RESTARTS AGE +memcached-sample-6fd7c98d8-7dqdr 1/1 Running 0 1m +memcached-sample-6fd7c98d8-g5k7v 1/1 Running 0 1m +memcached-sample-6fd7c98d8-m7vn7 1/1 Running 0 1m +---- +endif::[] + +.. Check the CR status: ++ +[source,terminal,subs="attributes+"] +---- +$ oc get {app}/{app}-sample -o yaml +---- ++ +.Example output +[source,yaml,subs="attributes+"] +---- +apiVersion: {group}.example.com/v1 +kind: {app-proper} +metadata: +... + name: {app}-sample +... +spec: +ifdef::helm[] + replicaCount: 3 +endif::[] +ifndef::helm[] + size: 3 +endif::[] +status: + nodes: + - {app}-sample-6fd7c98d8-7dqdr + - {app}-sample-6fd7c98d8-g5k7v + - {app}-sample-6fd7c98d8-m7vn7 +---- + +. Update the deployment size. + +.. Update `config/samples/{group}_v1_{app}.yaml` file to change the `spec.size` field in the `{app-proper}` CR from `3` to `5`: ++ +[source,terminal,subs="attributes+"] +---- +$ oc patch {app} {app}-sample \ +ifdef::helm[] + -p '{"spec":{"replicaCount": 5}}' \ +endif::[] +ifndef::helm[] + -p '{"spec":{"size": 5}}' \ +endif::[] + --type=merge +---- + +.. Confirm that the Operator changes the deployment size: ++ +[source,terminal] +---- +$ oc get deployments +---- ++ +.Example output +[source,terminal] +ifdef::helm[] +---- +NAME READY UP-TO-DATE AVAILABLE AGE +nginx-operator-controller-manager 1/1 1 1 10m +nginx-sample 5/5 5 5 3m +---- +endif::[] +ifndef::helm[] +---- +NAME READY UP-TO-DATE AVAILABLE AGE +memcached-operator-controller-manager 1/1 1 1 10m +memcached-sample 5/5 5 5 3m +---- +endif::[] + +. Clean up the resources that have been created as part of this tutorial. + +* If you used the `make deploy` command to test the Operator, run the following command: ++ +[source,terminal] +---- +$ make undeploy +---- + +* If you used the `operator-sdk run bundle` command to test the Operator, run the following command: ++ +[source,terminal] +---- +$ operator-sdk cleanup +---- + + +ifeval::["{context}" == "osdk-golang-tutorial"] +:!golang: +:!app-proper: +:!app: +:!group: +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:!ansible: +:!app-proper: +:!app: +:!group: +endif::[] +ifeval::["{context}" == "osdk-helm-tutorial"] +:!helm: +:!app-proper: +:!app: +:!group: +endif::[] diff --git a/modules/osdk-create-operator-prereqs.adoc b/modules/osdk-create-operator-prereqs.adoc new file mode 100644 index 0000000000..3df7196fbf --- /dev/null +++ b/modules/osdk-create-operator-prereqs.adoc @@ -0,0 +1,40 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/golang/osdk-golang-quickstart.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc +// * operators/operator_sdk/ansible/osdk-ansible-quickstart.adoc +// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc +// * operators/operator_sdk/helm/osdk-helm-quickstart.adoc +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc + +ifeval::["{context}" == "osdk-ansible-quickstart"] +:ansible: +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:ansible: +endif::[] + +[id="osdk-create-operator-prereqs_{context}"] += Prerequisites + +- xref:../../../operators/operator_sdk/osdk-installing-cli.adoc#osdk-installing-cli[Operator SDK CLI installed] +- xref:../../../cli_reference/openshift_cli/getting-started-cli.adoc#getting-started-cli[OpenShift CLI (`oc`) v{product-version}+ installed] +ifdef::golang[] +- link:https://golang.org/dl/[Go] v1.13+ +- link:https://www.mercurial-scm.org/downloads[Mercurial] v3.9+ +endif::[] +ifdef::ansible[] +- link:https://docs.ansible.com/ansible/latest/index.html[Ansible] version v2.9.0+ +- link:https://ansible-runner.readthedocs.io/en/latest/install.html[Ansible Runner] version v1.1.0+ +- link:https://github.com/ansible/ansible-runner-http[Ansible Runner HTTP Event Emitter plug-in] version v1.0.0+ +- link:https://pypi.org/project/openshift/[OpenShift Python client] version v0.11.2+ +endif::[] +- Logged into an {product-title} {product-version} cluster with `oc` with an account that has `cluster-admin` permissions +- To allow the cluster pull the image, the repository where you push your image must be set as public, or you must configure an image pull secret. + +ifeval::["{context}" == "osdk-ansible-quickstart"] +:!ansible: +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:!ansible: +endif::[] diff --git a/modules/osdk-create-project.adoc b/modules/osdk-create-project.adoc new file mode 100644 index 0000000000..06c43a0181 --- /dev/null +++ b/modules/osdk-create-project.adoc @@ -0,0 +1,137 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc +// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc + +ifeval::["{context}" == "osdk-golang-tutorial"] +:golang: +:type: Go +:app: memcached +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:ansible: +:type: Ansible +:app: memcached +endif::[] +ifeval::["{context}" == "osdk-helm-tutorial"] +:helm: +:type: Helm +:app: nginx +endif::[] + +[id="osdk-create-project_{context}"] += Creating a project + +Use the Operator SDK CLI to create a project called `{app}-operator`. + +.Procedure + +. Create a directory for the project: ++ +[source,terminal,subs="attributes+"] +---- +$ mkdir -p $HOME/projects/{app}-operator +---- + +. Change to the directory: ++ +[source,terminal,subs="attributes+"] +---- +$ cd $HOME/projects/{app}-operator +---- + +ifdef::golang[] +. Activate support for Go modules: ++ +[source,terminal] +---- +$ export GO111MODULE=on +---- +endif::[] + +. Run the `operator-sdk init` command +ifdef::ansible[] +with the `ansible` plug-in +endif::[] +ifdef::helm[] +with the `helm` plug-in +endif::[] +to initialize the project: ++ +[source,terminal,subs="attributes+"] +ifdef::golang[] +---- +$ operator-sdk init \ + --domain=example.com \ + --repo=github.com/example-inc/{app}-operator +---- ++ +[NOTE] +==== +The `operator-sdk init` command uses the Go plug-in by default. +==== ++ +The `operator-sdk init` command generates a `go.mod` file to be used with link:https://golang.org/ref/mod[Go modules]. The `--repo` flag is required when creating a project outside of `$GOPATH/src/`, because generated files require a valid module path. + +. To enable your Go-based Operator to run on {product-title}, edit the `config/manager/manager.yaml` file and replace the following line: ++ +[source,yaml] +---- +runAsUser: 65532 +---- ++ +with: ++ +[source,yaml] +---- +runAsNonRoot: true +---- ++ +[NOTE] +==== +This step is a temporary workaround required for Go-based Operators only. For more information, see link:https://bugzilla.redhat.com/show_bug.cgi?id=1914406#c1[BZ#1914406]. +==== +endif::[] +ifdef::ansible[] +---- +$ operator-sdk init \ + --plugins=ansible \ + --domain=example.com +---- +endif::[] +ifdef::helm[] +---- +$ operator-sdk init \ + --plugins=helm \ + --domain=example.com \ + --group=demo \ + --version=v1 \ + --kind=Nginx +---- ++ +[NOTE] +==== +By default, the `helm` plug-in initializes a project using a boilerplate Helm chart. You can use additional flags, such as the `--helm-chart` flag, to initialize a project using an existing Helm chart. +==== ++ +The `init` command creates the `nginx-operator` project specifically for watching a resource with API version `example.com/v1` and kind `Nginx`. + +. For Helm-based projects, the `init` subcommand 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::[] + +ifeval::["{context}" == "osdk-golang-tutorial"] +:!golang: +:!type: +:!app: +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:!ansible: +:!type: +:!app: +endif::[] +ifeval::["{context}" == "osdk-helm-tutorial"] +:!helm: +:!type: +:!app: +endif::[] diff --git a/modules/osdk-golang-build-run.adoc b/modules/osdk-golang-build-run.adoc deleted file mode 100644 index f828866953..0000000000 --- a/modules/osdk-golang-build-run.adoc +++ /dev/null @@ -1,43 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/osdk-golang-tutorial.adoc - -[id="osdk-golang-build-run_{context}"] -= Build and run the Operator - -After implementing the new controller, you can build and run your Operator. - -.Procedure - -. Register the CRD with the Kubernetes API server: -+ -[source,terminal] ----- -$ make install ----- - -. Update the default unit tests. By default, Go-based Operator projects provide unit tests that use the `envtest` framework from the `controller-runtime` libraries to simulate the API portions of a real cluster. These tests require certain Kubernetes server binaries be present locally, including `kubectl`, `kube-apiserver`, and etcd. - -.. Use the link:https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/master/hack/setup-envtest.sh[provided script] to download these binaries into the `testbin/` directory and configure your environment to use them. - -.. Update your Makefile by replacing your `test` target with the following target: -+ -[source,go] ----- -# Run tests -ENVTEST_ASSETS_DIR=$(shell pwd)/testbin -test: generate fmt vet manifests - mkdir -p ${ENVTEST_ASSETS_DIR} - test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/master/hack/setup-envtest.sh - source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./... -coverprofile cover.out ----- - -.. If you use Git, add `testbin/*` to your `.gitignore` file to avoid committing these binaries. - -.Next steps - -After completing this procedure, you can choose from the following options to run your Operator, as described in the following subsections: - -* Run locally outside the cluster as a Go program. -* Run as a deployment inside the cluster. -* Deploy by using Operator Lifecycle Manager (OLM). diff --git a/modules/osdk-golang-controller-configs.adoc b/modules/osdk-golang-controller-configs.adoc index b36756fa9c..ad3974d94e 100644 --- a/modules/osdk-golang-controller-configs.adoc +++ b/modules/osdk-golang-controller-configs.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-golang-controller-configs_{context}"] = Controller configurations @@ -13,7 +13,7 @@ You can initialize a controller by using many other useful configurations. For e ---- func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&cachev1alpha1.Memcached{}). + For(&cachev1.Memcached{}). Owns(&appsv1.Deployment{}). WithOptions(controller.Options{ MaxConcurrentReconciles: 2, diff --git a/modules/osdk-golang-controller-rbac-markers.adoc b/modules/osdk-golang-controller-rbac-markers.adoc index b2dd416016..5288edd8af 100644 --- a/modules/osdk-golang-controller-rbac-markers.adoc +++ b/modules/osdk-golang-controller-rbac-markers.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-golang-controller-rbac-markers_{context}"] = Permissions and RBAC manifests diff --git a/modules/osdk-golang-controller-reconcile-loop.adoc b/modules/osdk-golang-controller-reconcile-loop.adoc index abb7ab6a74..0dfed92cec 100644 --- a/modules/osdk-golang-controller-reconcile-loop.adoc +++ b/modules/osdk-golang-controller-reconcile-loop.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-golang-controller-reconcile-loop_{context}"] = Reconcile loop @@ -12,13 +12,13 @@ Every controller has a reconciler object with a `Reconcile()` method that implem import ( ctrl "sigs.k8s.io/controller-runtime" - cachev1alpha1 "github.com/example-inc/memcached-operator/api/v1alpha1" + cachev1 "github.com/example-inc/memcached-operator/api/v1" ... ) func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { // Lookup the Memcached instance for this reconcile request - memcached := &cachev1alpha1.Memcached{} + memcached := &cachev1.Memcached{} err := r.Get(ctx, req.NamespacedName, memcached) ... } diff --git a/modules/osdk-golang-controller-resources.adoc b/modules/osdk-golang-controller-resources.adoc index 4e155b0c37..8843455cd9 100644 --- a/modules/osdk-golang-controller-resources.adoc +++ b/modules/osdk-golang-controller-resources.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-golang-controller-resources_{context}"] = Resources watched by the controller @@ -17,7 +17,7 @@ import ( func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&cachev1alpha1.Memcached{}). + For(&cachev1.Memcached{}). Owns(&appsv1.Deployment{}). Complete(r) } @@ -25,6 +25,6 @@ func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error { `NewControllerManagedBy()` provides a controller builder that allows various controller configurations. -`For(&cachev1alpha1.Memcached{})` specifies the `Memcached` type as the primary resource to watch. For each Add, Update, or Delete event for a `Memcached` type, the reconcile loop is sent a reconcile `Request` argument, which consists of a namespace and name key, for that `Memcached` object. +`For(&cachev1.Memcached{})` specifies the `Memcached` type as the primary resource to watch. For each Add, Update, or Delete event for a `Memcached` type, the reconcile loop is sent a reconcile `Request` argument, which consists of a namespace and name key, for that `Memcached` object. `Owns(&appsv1.Deployment{})` specifies the `Deployment` type as the secondary resource to watch. For each `Deployment` type Add, Update, or Delete event, the event handler maps each event to a reconcile request for the owner of the deployment. In this case, the owner is the `Memcached` object for which the deployment was created. diff --git a/modules/osdk-golang-create-api-controller.adoc b/modules/osdk-golang-create-api-controller.adoc index c4d928b771..ea119d0754 100644 --- a/modules/osdk-golang-create-api-controller.adoc +++ b/modules/osdk-golang-create-api-controller.adoc @@ -1,21 +1,21 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-golang-create-api-controller_{context}"] -= Creating a new API and controller += Creating an API and controller -Use the Operator SDK CLI to create a custom resource definition (CRD) API. +Use the Operator SDK CLI to create a custom resource definition (CRD) API and controller. .Procedure -. Run the following command to create an API with group `cache`, version, `v1alpha1` and Kind `Memcached`: +. Run the following command to create an API with group `cache`, version, `v1`, and kind `Memcached`: + [source,terminal] ---- $ operator-sdk create api \ --group=cache \ - --version=v1alpha1 \ + --version=v1 \ --kind=Memcached ---- @@ -33,9 +33,9 @@ y [source,terminal] ---- Writing scaffold for you to edit... -api/v1alpha1/memcached_types.go +api/v1/memcached_types.go controllers/memcached_controller.go ... ---- -This process generates the `Memcached` resource API at `api/v1alpha1/memcached_types.go` and the controller at `controllers/memcached_controller.go`. +This process generates the `Memcached` resource API at `api/v1/memcached_types.go` and the controller at `controllers/memcached_controller.go`. diff --git a/modules/osdk-golang-create-cr.adoc b/modules/osdk-golang-create-cr.adoc deleted file mode 100644 index 070cd19a8e..0000000000 --- a/modules/osdk-golang-create-cr.adoc +++ /dev/null @@ -1,132 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/osdk-golang-tutorial.adoc - -[id="osdk-golang-create-cr_{context}"] -= Creating a Memcached resource - -To test that your Operator is installed, you can create a `Memcached` resource, which is now provided on your cluster by your Operator. - -.Procedure - -. Change to the `memcached-operator-system` namespace: -+ -[source,terminal] ----- -$ oc project memcached-operator-system ----- - -. Edit the sample `Memcached` custom resource (CR) manifest at `config/samples/cache_v1alpha1_memcached.yaml` to contain the following specification: -+ -[source,yaml] ----- -apiVersion: cache.example.com/v1alpha1 -kind: Memcached -metadata: - name: memcached-sample -spec: - size: 3 ----- - -. Create the CR: -+ -[source,terminal] ----- -$ oc apply -f config/samples/cache_v1alpha1_memcached.yaml ----- - -. Ensure that the Memcached Operator creates the deployment for the sample CR with the correct size: -+ -[source,terminal] ----- -$ oc get deployments ----- -+ -.Example output -[source,terminal] ----- -NAME READY UP-TO-DATE AVAILABLE AGE -memcached-operator-controller-manager 1/1 1 1 8m -memcached-sample 3/3 3 3 1m ----- - -. Check the pods and CR status to confirm the status is updated with the Memcached pod names. - -.. Check the pods: -+ -[source,terminal] ----- -$ oc get pods ----- -+ -.Example output -[source,terminal] ----- -NAME READY STATUS RESTARTS AGE -memcached-sample-6fd7c98d8-7dqdr 1/1 Running 0 1m -memcached-sample-6fd7c98d8-g5k7v 1/1 Running 0 1m -memcached-sample-6fd7c98d8-m7vn7 1/1 Running 0 1m ----- - -.. Check the CR status: -+ -[source,terminal] ----- -$ oc get memcached/memcached-sample -o yaml ----- -+ -.Example output -[source,yaml] ----- -apiVersion: cache.example.com/v1alpha1 -kind: Memcached -metadata: - clusterName: "" - creationTimestamp: 2018-03-31T22:51:08Z - generation: 0 - name: memcached-sample - namespace: default - resourceVersion: "245453" - selfLink: /apis/cache.example.com/v1alpha1/namespaces/default/memcacheds/memcached-sample - uid: 0026cc97-3536-11e8-bd83-0800274106a1 -spec: - size: 3 -status: - nodes: - - memcached-sample-6fd7c98d8-7dqdr - - memcached-sample-6fd7c98d8-g5k7v - - memcached-sample-6fd7c98d8-m7vn7 ----- - -. Update the deployment size. - -.. Update `config/samples/cache_v1alpha1_memcached.yaml` file to change the `spec.size` field in the `Memcached` CR from `3` to `5`: -+ -[source,terminal] ----- -$ oc patch memcached memcached-sample \ - -p '{"spec":{"size": 5}}'\ - --type=merge ----- - -.. Confirm that the Operator changes the deployment size: -+ -[source,terminal] ----- -$ oc get deployments ----- -+ -.Example output -[source,terminal] ----- -NAME READY UP-TO-DATE AVAILABLE AGE -memcached-operator-controller-manager 1/1 1 1 10m -memcached-sample 5/5 5 5 3m ----- - -. Clean up the resources that have been created as part of this tutorial by using the following command: -+ -[source,terminal] ----- -$ make undeploy ----- diff --git a/modules/osdk-golang-create-deploy.adoc b/modules/osdk-golang-create-deploy.adoc deleted file mode 100644 index 09980bb0c9..0000000000 --- a/modules/osdk-golang-create-deploy.adoc +++ /dev/null @@ -1,130 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/golang/osdk-quickstart.adoc - -[id="osdk-golang-create-deploy_{context}"] -= Creating and deploying a Go-based Operator - -You can build and deploy a simple Memcached Operator. - -.Prerequisites - -- Operator SDK CLI installed on a development workstation -- OpenShift CLI (`oc`) v{product-version}+ installed -- Logged into a {product-title} {product-version} cluster with `oc` with an account that has `cluster-admin` permissions -- To allow the cluster pull the image, the repository where you push your image must be set as public, or you must configure an image pull secret. - -.Procedure - -. *Create a project.* - -.. Create your project: -+ -[source,terminal] ----- -$ mkdir memcached-operator ----- - -.. Change into the project directory: -+ -[source,terminal] ----- -$ cd memcached-operator ----- - -.. Run the `operator-sdk init` command to initialize the project: -+ -[source,terminal] ----- -$ operator-sdk init \ - --domain=example.com \ - --repo=github.com/example-inc/memcached-operator ----- -+ -The command uses the Go plug-in by default. - -.. To enable your Operator to run on {product-title}, edit the `config/manager/manager.yaml` file and replace the following line: -+ -[source,yaml] ----- -runAsUser: 65532 ----- -+ -with: -+ -[source,yaml] ----- -runAsNonRoot: true ----- -+ -[NOTE] -==== -This step is a temporary workaround. For more information, see link:https://bugzilla.redhat.com/show_bug.cgi?id=1914406#c1[BZ#1914406]. -==== - -. *Create an API.* -+ -Create a simple Memcached API: -+ -[source,terminal] ----- -$ operator-sdk create api \ - --group cache \ - --version v1 \ - --kind Memcached \ - --resource=true \ - --controller=true ----- - -. *Build and push the Operator image.* -+ -Use the default `Makefile` targets to build and push your Operator. Set `IMG` with a pull spec for your image that uses a registry you can push to: -+ -[source,terminal] ----- -$ make docker-build docker-push IMG=//: ----- - -. *Run the Operator.* - -.. Install the CRD: -+ -[source,terminal] ----- -$ make install ----- - -.. Deploy the project to the cluster. Set `IMG` to the image that you pushed: -+ -[source,terminal] ----- -$ make deploy IMG=//: ----- - -. *Create a sample custom resource (CR).* - -.. Create a sample CR: -+ -[source,terminal] ----- -$ oc apply -f config/samples/cache_v1_memcached.yaml \ - -n memcached-operator-system ----- - -.. Watch for the CR to reconcile the Operator: -+ -[source,terminal] ----- -$ oc logs deployment.apps/memcached-operator-controller-manager \ - -n memcached-operator-system \ - -c manager ----- - -. *Clean up.* -+ -Run the following command to clean up the resources that have been created as part of this quickstart: -+ -[source,terminal] ----- -$ make undeploy ----- diff --git a/modules/osdk-golang-create-project.adoc b/modules/osdk-golang-create-project.adoc deleted file mode 100644 index 7faa1e629e..0000000000 --- a/modules/osdk-golang-create-project.adoc +++ /dev/null @@ -1,54 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/osdk-golang-tutorial.adoc - -[id="osdk-golang-create-project_{context}"] -= Creating a project - -Use the CLI to create a `memcached-operator` project. - -.Procedure - -. Create a directory for the project: -+ -[source,terminal] ----- -$ mkdir -p $HOME/projects/memcached-operator ----- - -. Change to the directory: -+ -[source,terminal] ----- -$ cd $HOME/projects/memcached-operator ----- - -. Initialize the new project: -+ -[source,terminal] ----- -$ operator-sdk init \ - --domain=example.com \ - --repo=github.com/example-inc/memcached-operator ----- -+ -This example uses a domain of `example.com`; all API groups will be `.example.com`. - -. To enable your Operator to run on {product-title}, edit the `config/manager/manager.yaml` file and replace the following line: -+ -[source,yaml] ----- -runAsUser: 65532 ----- -+ -with: -+ -[source,yaml] ----- -runAsNonRoot: true ----- -+ -[NOTE] -==== -This step is a temporary workaround. For more information, see link:https://bugzilla.redhat.com/show_bug.cgi?id=1914406#c1[BZ#1914406]. -==== diff --git a/modules/osdk-golang-define-api.adoc b/modules/osdk-golang-define-api.adoc index f9b3a7ce00..cbca2750f7 100644 --- a/modules/osdk-golang-define-api.adoc +++ b/modules/osdk-golang-define-api.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-golang-define-api_{context}"] = Defining the API @@ -9,7 +9,7 @@ Define the API for the `Memcached` custom resource (CR). .Procedure -. Modify the Go type definitions at `api/v1alpha1/memcached_types.go` to have the following `spec` and `status`: +. Modify the Go type definitions at `api/v1/memcached_types.go` to have the following `spec` and `status`: + [source,go] ---- @@ -32,7 +32,7 @@ type MemcachedStatus struct { [source,go] ---- // Memcached is the Schema for the memcacheds API -// +kubebuilder:subresource:status +// +kubebuilder:subresource:status <1> type Memcached struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -41,6 +41,7 @@ type Memcached struct { Status MemcachedStatus `json:"status,omitempty"` } ---- +<1> Add this line. + This enables the controller to update the CR status without changing the rest of the CR object. @@ -56,4 +57,4 @@ $ make generate After you modify a `*_types.go` file, you must run the `make generate` command to update the generated code for that resource type. ==== + -The above Makefile target invokes the `controller-gen` utility to update the `api/v1alpha1/zz_generated.deepcopy.go` file. This ensures your API Go type definitions implement the `runtime.Object` interface that all Kind types must implement. +The above Makefile target invokes the `controller-gen` utility to update the `api/v1/zz_generated.deepcopy.go` file. This ensures your API Go type definitions implement the `runtime.Object` interface that all Kind types must implement. diff --git a/modules/osdk-golang-generate-crd.adoc b/modules/osdk-golang-generate-crd.adoc index 67b42e3de0..14a0e6ee28 100644 --- a/modules/osdk-golang-generate-crd.adoc +++ b/modules/osdk-golang-generate-crd.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-golang-generate-crd_{context}"] = Generating CRD manifests diff --git a/modules/osdk-golang-implement-controller.adoc b/modules/osdk-golang-implement-controller.adoc index 3c64bb2a83..e97e6c2bef 100644 --- a/modules/osdk-golang-implement-controller.adoc +++ b/modules/osdk-golang-implement-controller.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-golang-implement-controller_{context}"] = Implementing the controller @@ -9,7 +9,7 @@ After creating a new API and controller, you can implement the controller logic. .Procedure -* For this example, replace the generated controller file `controllers/memcached_controller.go` with the `memcached_controller.go` link:https://github.com/operator-framework/operator-sdk/blob/v1.2.0/testdata/go/memcached-operator/controllers/memcached_controller.go[example implementation]. +* For this example, replace the generated controller file `controllers/memcached_controller.go` with the `memcached_controller.go` link:https://github.com/operator-framework/operator-sdk/blob/v1.3.0/testdata/go/v2/memcached-operator/controllers/memcached_controller.go[example implementation]. + The example controller runs the following reconciliation logic for each `Memcached` custom resource (CR): + diff --git a/modules/osdk-golang-manager.adoc b/modules/osdk-golang-manager.adoc index 85910cf7eb..1c2a727ca4 100644 --- a/modules/osdk-golang-manager.adoc +++ b/modules/osdk-golang-manager.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-golang-manager_{context}"] = About the Manager diff --git a/modules/osdk-golang-multi-group-apis.adoc b/modules/osdk-golang-multi-group-apis.adoc index 7d09748f4c..2c8fd722c5 100644 --- a/modules/osdk-golang-multi-group-apis.adoc +++ b/modules/osdk-golang-multi-group-apis.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-golang-multi-group-apis_{context}"] = About multi-group APIs diff --git a/modules/osdk-golang-project-layout.adoc b/modules/osdk-golang-project-layout.adoc new file mode 100644 index 0000000000..6f3e25dbcd --- /dev/null +++ b/modules/osdk-golang-project-layout.adoc @@ -0,0 +1,36 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/golang/osdk-golang-project-layout.adoc + +[id="osdk-golang-project-layout_{context}"] += Go-based project layout + +Go-based Operator projects, the default type, generated using the `operator-sdk init` command contain the following files and directories: + +[options="header",cols="1,4"] +|=== + +|File or directory |Purpose + +|`main.go` +|Main program of the Operator. This instantiates a new manager that registers all custom resource definitions (CRDs) in the `apis/` directory and starts all controllers in the `controllers/` directory. + +|`apis/` +|Directory tree that defines the APIs of the CRDs. You must edit the `apis//_types.go` files to define the API for each resource type and import these packages in your controllers to watch for these resource types. + +|`controllers/` +|Controller implementations. Edit the `controller/_controller.go` files to define the reconcile logic of the controller for handling a resource type of the specified kind. + +|`config/` +|Kubernetes manifests used to deploy your controller on a cluster, including CRDs, RBAC, and certificates. + +|`Makefile` +|Targets used to build and deploy your controller. + +|`Dockerfile` +|Instructions used by a container engine to build your Operator. + +|`manifests/` +|Kubernetes manifests for registering CRDs, setting up RBAC, and deploying the Operator as a deployment. + +|=== diff --git a/modules/osdk-golang-run-in-cluster.adoc b/modules/osdk-golang-run-in-cluster.adoc deleted file mode 100644 index 9814ac7bfd..0000000000 --- a/modules/osdk-golang-run-in-cluster.adoc +++ /dev/null @@ -1,112 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/osdk-golang-tutorial.adoc - -[id="osdk-golang-run-in-cluster_{context}"] -= Running as a deployment inside the cluster - -You can run your Operator project as a deployment inside of your cluster. - -.Procedure - -. Update the following lines in the project root-level Dockerfile to use supported images. - -.. Change the default builder image reference from: -+ -[source,terminal] ----- -golang:1.15 ----- -+ -to: -+ -[source,terminal] ----- -registry.redhat.io/openshift4/builder:rhel-8-golang-1.15-openshift-4.7 ----- - -.. Change the default runner image reference from: -+ -[source,terminal] ----- -gcr.io/distroless/static:nonroot ----- -+ -to: -+ -[source,terminal] ----- -registry.access.redhat.com/ubi8/ubi-minimal:latest ----- - -.. Remove the `USER: nonroot:nonroot` directive, as it is not required by the supported image. - -. In the `config/default/manager_auth_proxy_patch.yaml` file, change the `image` value from: -+ -[source,terminal] ----- -gcr.io/kubebuilder/kube-rbac-proxy: ----- -+ -to use the supported image: -+ -[source,terminal,subs="attributes+"] ----- -registry.redhat.io/openshift4/ose-kube-rbac-proxy:v{product-version} ----- - -. Run the following `make` commands to build and push the Operator image. Modify the `IMG` argument in the following steps to reference a repository that you have access to. You can obtain an account for storing containers at repository sites such as Quay.io, which this example uses. - -.. Set your Quay.io user name: -+ -[source,terminal] ----- -$ export USERNAME= ----- - -.. Build the image: -+ -[source,terminal] ----- -$ make docker-build IMG=quay.io/$USERNAME/memcached-operator:v0.0.1 ----- - -.. Push the image to a repository: -+ -[source,terminal] ----- -$ make docker-push IMG=quay.io/$USERNAME/memcached-operator:v0.0.1 ----- -+ -[NOTE] -==== -The name and tag of the image, for example `IMG=//:`, in both the commands can also be set in your Makefile. Modify the `IMG ?= controller:latest` value to set your default image name. -==== - -. Run the following command to deploy the Operator: -+ -[source,terminal] ----- -$ make deploy IMG=quay.io/$USERNAME/memcached-operator:v0.0.1 ----- -+ -By default, this command creates a namespace named `-system`, for example `memcached-operator-system`, and is used for the deployment. This command also installs the RBAC manifests from `config/rbac`. -+ -[NOTE] -==== -If you enabled webhooks in your deployments, you must have `cert-manager` already installed in the cluster or the `make deploy` command will fail when it attempts to create the `cert-manager` resources. -==== - -. Verify that the `memcached-operator` is running: -+ -[source,terminal] ----- -$ oc get deployment -n memcached-operator-system ----- -+ -.Example output -[source,terminal] ----- -NAME READY UP-TO-DATE AVAILABLE AGE -memcached-operator-controller-manager 1/1 1 1 8m ----- diff --git a/modules/osdk-golang-run-locally.adoc b/modules/osdk-golang-run-locally.adoc deleted file mode 100644 index d05518b4b2..0000000000 --- a/modules/osdk-golang-run-locally.adoc +++ /dev/null @@ -1,31 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/osdk-golang-tutorial.adoc - -[id="osdk-golang-run-locally_{context}"] -= Running locally outside the cluster - -You can run your Operator project as a Go program outside of your cluster. - -.Procedure - -* To run the Operator locally, run the following command: -+ -[source,terminal] ----- -$ make run ENABLE_WEBHOOKS=false ----- -+ -.Example output -[source,terminal] ----- -... -go run ./main.go -... -2021-01-10T21:09:29.016-0700 INFO controller-runtime.metrics metrics server is starting to listen {"addr": ":8080"} -2021-01-10T21:09:29.017-0700 INFO setup starting manager -2021-01-10T21:09:29.017-0700 INFO controller-runtime.manager starting metrics server {"path": "/metrics"} -2021-01-10T21:09:29.018-0700 INFO controller-runtime.manager.controller.memcached Starting EventSource {"reconciler group": "cache.example.com", "reconciler kind": "Memcached", "source": "kind source: /, Kind="} -2021-01-10T21:09:29.218-0700 INFO controller-runtime.manager.controller.memcached Starting Controller {"reconciler group": "cache.example.com", "reconciler kind": "Memcached"} -2021-01-10T21:09:29.218-0700 INFO controller-runtime.manager.controller.memcached Starting workers {"reconciler group": "cache.example.com", "reconciler kind": "Memcached", "worker count": 1} ----- diff --git a/modules/osdk-helm-chart-support.adoc b/modules/osdk-helm-charts.adoc similarity index 94% rename from modules/osdk-helm-chart-support.adoc rename to modules/osdk-helm-charts.adoc index a14994cac5..ae752a6d16 100644 --- a/modules/osdk-helm-chart-support.adoc +++ b/modules/osdk-helm-charts.adoc @@ -1,9 +1,9 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-helm.adoc +// * operators/operator_sdk/helm/osdk-helm-support.adoc -[id="osdk-helm-chart-support_{context}"] -= Helm chart support in the Operator SDK +[id="osdk-helm-charts_{context}"] += Helm charts One of the Operator SDK options for generating an Operator project includes leveraging an existing Helm chart to deploy Kubernetes resources as a unified application, without having to write any Go code. Such Helm-based Operators are designed to excel at stateless applications that require very little logic when rolled out, because changes should be applied to the Kubernetes objects that are generated as part of the chart. This may sound limiting, but can be sufficient for a surprising amount of use-cases as shown by the proliferation of Helm charts built by the Kubernetes community. diff --git a/modules/osdk-helm-existing-chart.adoc b/modules/osdk-helm-existing-chart.adoc new file mode 100644 index 0000000000..8e59d06a5f --- /dev/null +++ b/modules/osdk-helm-existing-chart.adoc @@ -0,0 +1,65 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc + +[id="osdk-helm-existing-chart_{context}"] += Existing Helm charts + +Instead of creating your project with a boilerplate Helm chart, you can alternatively use an existing chart, either from your local file system or a remote chart repository, by using the following flags: + +* `--helm-chart` +* `--helm-chart-repo` +* `--helm-chart-version` + +If the `--helm-chart` flag is specified, the `--group`, `--version`, and `--kind` flags become optional. If left unset, the following default values are used: + +[options="header"] +|=== +|Flag |Value + +|`--domain` +|`my.domain` + +|`--group` +|`charts` + +|`--version` +|`v1` + +|`--kind` +|Deduced from the specified chart +|=== + +If the `--helm-chart` flag specifies a local chart archive, for example `example-chart-1.2.0.tgz`, or directory, the chart is validated and unpacked or copied into the project. Otherwise, the Operator SDK attempts to fetch the chart from a remote repository. + +If a custom repository URL is not specified by the `--helm-chart-repo` flag, the following chart reference formats are supported: + +[cols="1,4",options="header"] +|=== +|Format |Description + +|`/` +|Fetch the Helm chart named `` from the helm chart repository named ``, as specified in the `$HELM_HOME/repositories/repositories.yaml` file. Use the `helm repo add` command to configure this file. + +|`` +|Fetch the Helm chart archive at the specified URL. +|=== + +If a custom repository URL is specified by `--helm-chart-repo`, the following chart reference format is supported: + +[cols="1,4",options="header"] +|=== +|Format |Description + +|`` +|Fetch the Helm chart named `` in the Helm chart repository specified by the `--helm-chart-repo` URL value. +|=== + +If the `--helm-chart-version` flag is unset, the Operator SDK fetches the latest available version of the Helm chart. Otherwise, it fetches the specified version. The optional `--helm-chart-version` flag is not used when the chart specified with the `--helm-chart` flag refers to a specific version, for example when it is a local path or a URL. + +For more details and examples, run: + +[source,terminal] +---- +$ operator-sdk init --plugins helm --help +---- diff --git a/modules/osdk-helm-logic.adoc b/modules/osdk-helm-logic.adoc new file mode 100644 index 0000000000..e50f41b3fb --- /dev/null +++ b/modules/osdk-helm-logic.adoc @@ -0,0 +1,25 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc + +[id="osdk-helm-logic_{context}"] += Understanding the Operator logic + +For this example, the `nginx-operator` project executes the following reconciliation logic for each `Nginx` custom resource (CR): + +* Create an Nginx deployment if it does not exist. +* Create an Nginx service if it does not exist. +* Create an Nginx ingress if it is enabled and does not exist. +* Ensure that the deployment, service, and optional ingress match the desired configuration as specified by the `Nginx` CR, for example the replica count, image, and service type. + +By default, the `nginx-operator` project watches `Nginx` resource events as shown in the `watches.yaml` file and executes Helm releases using the specified chart: + +[source,yaml] +---- +# Use the 'create api' subcommand to add watches to this file. +- group: demo + version: v1 + kind: Nginx + chart: helm-charts/nginx +# +kubebuilder:scaffold:watch +---- diff --git a/modules/osdk-helm-modify-cr.adoc b/modules/osdk-helm-modify-cr.adoc new file mode 100644 index 0000000000..45d0322e7a --- /dev/null +++ b/modules/osdk-helm-modify-cr.adoc @@ -0,0 +1,44 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc + +[id="osdk-helm-modify-cr_{context}"] += Modifying the custom resource spec + +Helm uses a concept called link:https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing[values] to provide customizations to the defaults of a Helm chart, which are defined in the `values.yaml` file. + +You can override these defaults by setting the desired values in the custom resource (CR) spec. You can use the number of replicas as an example. + +.Procedure + +. The `helm-charts/nginx/values.yaml` file has a value called `replicaCount` set to `1` by default. To have two Nginx instances in your deployment, your CR spec must contain `replicaCount: 2`. ++ +Edit the `config/samples/demo_v1_nginx.yaml` file to set `replicaCount: 2`: ++ +[source,yaml] +---- +apiVersion: demo.example.com/v1 +kind: Nginx +metadata: + name: nginx-sample +... +spec: +... + replicaCount: 2 +---- + +. Similarly, the default service port is set to `80`. To use `8080`, edit the `config/samples/demo_v1_nginx.yaml` file to set `spec.port: 8080`,which adds the service port override: ++ +[source,yaml] +---- +apiVersion: demo.example.com/v1 +kind: Nginx +metadata: + name: nginx-sample +spec: + replicaCount: 2 + service: + port: 8080 +---- + +The Helm Operator applies the entire spec as if it was the contents of a values file, just like the `helm install -f ./overrides.yaml` command. diff --git a/modules/osdk-helm-project-layout.adoc b/modules/osdk-helm-project-layout.adoc new file mode 100644 index 0000000000..79fd4ee44d --- /dev/null +++ b/modules/osdk-helm-project-layout.adoc @@ -0,0 +1,33 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/helm/osdk-helm-project-layout.adoc + +[id="osdk-helm-project-layout_{context}"] += Helm-based project layout + +Helm-based Operator projects generated using the `operator-sdk init --plugins helm` command contain the following directories and files: + +[options="header",cols="1,4"] +|=== + +|File/folders |Purpose + +|`config` +|link:https://kustomize.io/[Kustomize] manifests for deploying the Operator on a Kubernetes cluster. + +|`helm-charts/` +|Helm chart initialized with the `operator-sdk create api` command. + +|`Dockerfile` +|Used to build the Operator image with the `make docker-build` command. + +|`watches.yaml` +|Group/version/kind (GVK) and Helm chart location. + +|`Makefile` +|Targets used to manage the project. + +|`PROJECT` +|YAML file containing metadata information for the Operator. + +|=== diff --git a/modules/osdk-helm-sample-chart.adoc b/modules/osdk-helm-sample-chart.adoc new file mode 100644 index 0000000000..b8b576e065 --- /dev/null +++ b/modules/osdk-helm-sample-chart.adoc @@ -0,0 +1,12 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc + +[id="osdk-helm-sample-chart_{context}"] += Sample Helm chart + +When a Helm Operator project is created, the Operator SDK creates a sample Helm chart that contains a set of templates for a simple Nginx release. + +For this example, templates are available for deployment, service, and ingress resources, along with a `NOTES.txt` template, which Helm chart developers use to convey helpful information about a release. + +If you are not already familiar with Helm charts, review the link:https://docs.helm.sh/developing_charts/[Helm developer documentation]. diff --git a/modules/osdk-how-csv-gen-works.adoc b/modules/osdk-how-csv-gen-works.adoc index dfcae010e9..e8ae10e91e 100644 --- a/modules/osdk-how-csv-gen-works.adoc +++ b/modules/osdk-how-csv-gen-works.adoc @@ -9,13 +9,13 @@ The `manifests/` directory of an Operator project is the standard location for a The following resource kinds are typically included in a CSV: -`Role`:: Define Operator permissions within a namespace +Role:: Define Operator permissions within a namespace -`ClusterRole`:: Define cluster-wide Operator permissions +ClusterRole:: Define cluster-wide Operator permissions -`Deployment`:: Define how an Operator operand is run in pods +Deployment:: Define how an Operator operand is run in pods -`CustomResourceDefinition`:: Definitions of custom objects your Operator reconciles +CustomResourceDefinition (CRD):: Definitions of custom objects your Operator reconciles Custom resource examples:: Examples of objects adhering to the spec of a particular CRD diff --git a/modules/osdk-manager-file.adoc b/modules/osdk-manager-file.adoc index bdbfa8c98d..47e21fd96d 100644 --- a/modules/osdk-manager-file.adoc +++ b/modules/osdk-manager-file.adoc @@ -1,6 +1,6 @@ // Module included in the following assemblies: // -// * operators/operator_sdk/osdk-golang-tutorial.adoc +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc [id="osdk-manager-file_{context}"] = Manager file diff --git a/modules/osdk-prepare-supported-images.adoc b/modules/osdk-prepare-supported-images.adoc new file mode 100644 index 0000000000..06baa78e17 --- /dev/null +++ b/modules/osdk-prepare-supported-images.adoc @@ -0,0 +1,56 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc + +[id="osdk-prepare-supported-images_{context}"] += Preparing your Operator use supported images + +Before running your Go-based Operator on {product-title}, update your project to use supported images. + +.Procedure + +. Update the following lines in the project root-level Dockerfile to use supported images. + +.. Change the default builder image reference from: ++ +[source,terminal] +---- +golang:1.15 +---- ++ +to: ++ +[source,terminal] +---- +registry.redhat.io/openshift4/builder:rhel-8-golang-1.15-openshift-4.7 +---- + +.. Change the default runner image reference from: ++ +[source,terminal] +---- +gcr.io/distroless/static:nonroot +---- ++ +to: ++ +[source,terminal] +---- +registry.access.redhat.com/ubi8/ubi-minimal:latest +---- + +.. Remove the `USER: nonroot:nonroot` directive, as it is not required by the supported image. + +. In the `config/default/manager_auth_proxy_patch.yaml` file, change the `image` value from: ++ +[source,terminal] +---- +gcr.io/kubebuilder/kube-rbac-proxy: +---- ++ +to use the supported image: ++ +[source,terminal,subs="attributes+"] +---- +registry.redhat.io/openshift4/ose-kube-rbac-proxy:v{product-version} +---- diff --git a/modules/osdk-project-file.adoc b/modules/osdk-project-file.adoc new file mode 100644 index 0000000000..5d6040b7e7 --- /dev/null +++ b/modules/osdk-project-file.adoc @@ -0,0 +1,76 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc +// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc + +ifeval::["{context}" == "osdk-golang-tutorial"] +:golang: +:type: Go +:app: memcached +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:ansible: +:type: Ansible +:app: memcached +endif::[] +ifeval::["{context}" == "osdk-helm-tutorial"] +:helm: +:type: Helm +:app: nginx +endif::[] + +[id="osdk-project-file_{context}"] += PROJECT file + +Among the files generated by the `init` subcommand is a Kubebuilder `PROJECT` file. Subsequent `operator-sdk` commands, as well as `help` output, that are run from the project root read this file and are aware that the project type is {type}. For example: + +[source,yaml] +ifdef::golang[] +---- +domain: example.com +layout: go.kubebuilder.io/v3 +projectName: memcached-operator +repo: github.com/example-inc/memcached-operator +version: 3-alpha +plugins: + manifests.sdk.operatorframework.io/v2: {} + scorecard.sdk.operatorframework.io/v2: {} +---- +endif::[] +ifdef::ansible[] +---- +domain: example.com +layout: ansible.sdk.operatorframework.io/v1 +projectName: memcached-operator +version: 3-alpha +---- +endif::[] +ifdef::helm[] +---- +domain: example.com +layout: helm.sdk.operatorframework.io/v1 +projectName: helm-operator +resources: +- group: demo + kind: Nginx + version: v1 +version: 3-alpha +---- +endif::[] + +ifeval::["{context}" == "osdk-golang-tutorial"] +:!golang: +:!type: +:!app: +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:!ansible: +:!type: +:!app: +endif::[] +ifeval::["{context}" == "osdk-helm-tutorial"] +:!helm: +:!type: +:!app: +endif::[] diff --git a/modules/osdk-project-scaffolding-layout.adoc b/modules/osdk-project-scaffolding-layout.adoc deleted file mode 100644 index 74a9a55da7..0000000000 --- a/modules/osdk-project-scaffolding-layout.adoc +++ /dev/null @@ -1,65 +0,0 @@ -// Module included in the following assemblies: -// -// * operators/operator_sdk/osdk-appendices.adoc - -[id="osdk-project-scaffolding-layout_{context}"] -= Operator project scaffolding layout - -The `operator-sdk` CLI generates a number of packages for each Operator project. The following sections describes a basic rundown of each generated file and directory. - -[id="osdk-project-scaffolding-layout-go_{context}"] -== Go-based projects - -Go-based Operator projects, the default type, generated using the `operator-sdk init` command contain the following files and directories: - -[options="header",cols="1,2"] -|=== - -|File or directory |Purpose - -|`main.go` -|The main program of the Operator. This instantiates a new manager that registers all custom resource definitions (CRDs) in the `apis/` directory and starts all controllers in the `controllers/` directory. - -|`apis/` -|The directory tree that defines the APIs of the CRDs. You must edit the `apis//_types.go` files to define the API for each resource type and import these packages in your controllers to watch for these resource types. - -|`controllers/` -|The controller implementations. You must edit the `controller/_controller.go` files to define the reconcile logic of the controller for handling a resource type of the specified kind. - -|`config/` -|Kubernetes manifests used to deploy your controller on a cluster, including CRDs, RBAC, and certificates. - -|`Makefile` -|Targets used to build and deploy your controller. - -|`Dockerfile` -|Instructions used by a container engine to build your Operator. - -|`manifests/` -|Kubernetes manifests for registering CRDs, setting up RBAC, and deploying the Operator as a deployment. - -|=== - -[id="osdk-project-scaffolding-layout-helm_{context}"] -== Helm-based projects - -Helm-based Operator projects generated using the `operator-sdk new --type helm` command contain the following directories and files: - -[options="header",cols="1,2"] -|=== - -|File/folders |Purpose - -|`deploy/` -|Contains various YAML manifests for registering CRDs, setting up RBAC, and deploying the Operator as a Deployment. - -|`helm-charts/` -|Contains a Helm chart initialized using the equivalent of the `helm create` command. - -|`build/` -|Contains the Dockerfile and build scripts used to build the Operator. - -|`watches.yaml` -|Contains group/version/kind (GVK) and Helm chart location. - -|=== diff --git a/modules/osdk-quickstart.adoc b/modules/osdk-quickstart.adoc new file mode 100644 index 0000000000..6dc4b3e0b9 --- /dev/null +++ b/modules/osdk-quickstart.adoc @@ -0,0 +1,225 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/golang/osdk-golang-quickstart.adoc +// * operators/operator_sdk/ansible/osdk-ansible-quickstart.adoc +// * operators/operator_sdk/helm/osdk-helm-quickstart.adoc + +ifeval::["{context}" == "osdk-golang-quickstart"] +:golang: +:type: Go +:app-proper: Memcached +:app: memcached +:group: cache +endif::[] +ifeval::["{context}" == "osdk-ansible-quickstart"] +:ansible: +:type: Ansible +:app-proper: Memcached +:app: memcached +:group: cache +endif::[] +ifeval::["{context}" == "osdk-helm-quickstart"] +:helm: +:type: Helm +:app-proper: Nginx +:app: nginx +:group: demo +endif::[] + +[id="osdk-quickstart_{context}"] += Creating and deploying {type}-based Operators + +You can build and deploy a simple {type}-based Operator for {app-proper} by using the Operator SDK. + +.Procedure + +. *Create a project.* + +.. Create your project: ++ +[source,terminal,subs="attributes+"] +---- +$ mkdir {app}-operator +---- + +.. Change into the project directory: ++ +[source,terminal,subs="attributes+"] +---- +$ cd {app}-operator +---- + +.. Run the `operator-sdk init` command +ifdef::ansible[] +with the `ansible` plug-in +endif::[] +ifdef::helm[] +with the `helm` plug-in +endif::[] +to initialize the project: ++ +[source,terminal,subs="attributes+"] +ifdef::golang[] +---- +$ operator-sdk init \ + --domain=example.com \ + --repo=github.com/example-inc/{app}-operator +---- ++ +The command uses the Go plug-in by default. +endif::[] +ifdef::ansible[] +---- +$ operator-sdk init \ + --plugins=ansible \ + --domain=example.com +---- +endif::[] +ifdef::helm[] +---- +$ operator-sdk init \ + --plugins=helm +---- +endif::[] + +ifdef::golang[] +.. To enable your Go-based Operator to run on {product-title}, edit the `config/manager/manager.yaml` file and replace the following line: ++ +[source,yaml] +---- +runAsUser: 65532 +---- ++ +with: ++ +[source,yaml] +---- +runAsNonRoot: true +---- ++ +[NOTE] +==== +This step is a temporary workaround required for Go-based Operators only. For more information, see link:https://bugzilla.redhat.com/show_bug.cgi?id=1914406#c1[BZ#1914406]. +==== +endif::[] + +. *Create an API.* ++ +Create a simple {app-proper} API: ++ +[source,terminal,subs="attributes+"] +ifdef::golang[] +---- +$ operator-sdk create api \ + --resource=true \ + --controller=true \ + --group {group} \ + --version v1 \ + --kind {app-proper} +---- +endif::[] +ifdef::ansible[] +---- +$ operator-sdk create api \ + --group {group} \ + --version v1 \ + --kind {app-proper} \ + --generate-role <1> +---- +<1> Generates an Ansible role for the API. +endif::[] +ifdef::helm[] +---- +$ operator-sdk create api \ + --group {group} \ + --version v1 \ + --kind {app-proper} +---- ++ +This API uses the built-in Helm chart boilerplate from the `helm create` command. +endif::[] + +. *Build and push the Operator image.* ++ +Use the default `Makefile` targets to build and push your Operator. Set `IMG` with a pull spec for your image that uses a registry you can push to: ++ +[source,terminal] +---- +$ make docker-build docker-push IMG=//: +---- + +. *Run the Operator.* + +.. Install the CRD: ++ +[source,terminal] +---- +$ make install +---- + +.. Deploy the project to the cluster. Set `IMG` to the image that you pushed: ++ +[source,terminal] +---- +$ make deploy IMG=//: +---- + +. *Create a sample custom resource (CR).* + +.. Create a sample CR: ++ +[source,terminal,subs="attributes+"] +---- +$ oc apply -f config/samples/{group}_v1_{app}.yaml \ + -n {app}-operator-system +---- + +.. Watch for the CR to reconcile the Operator: ++ +[source,terminal,subs="attributes+"] +---- +$ oc logs deployment.apps/{app}-operator-controller-manager \ + -c manager \ + -n {app}-operator-system +---- +ifdef::ansible[] ++ +.Example output +[source,terminal] +---- +... +I0205 17:48:45.881666 7 leaderelection.go:253] successfully acquired lease memcached-operator-system/memcached-operator +{"level":"info","ts":1612547325.8819902,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting EventSource","source":"kind source: cache.example.com/v1, Kind=Memcached"} +{"level":"info","ts":1612547325.98242,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting Controller"} +{"level":"info","ts":1612547325.9824686,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting workers","worker count":4} +{"level":"info","ts":1612547348.8311093,"logger":"runner","msg":"Ansible-runner exited successfully","job":"4037200794235010051","name":"memcached-sample","namespace":"memcached-operator-system"} +---- +endif::[] + +. *Clean up.* ++ +Run the following command to clean up the resources that have been created as part of this quickstart: ++ +[source,terminal] +---- +$ make undeploy +---- + +ifeval::["{context}" == "osdk-golang-quickstart"] +:!golang: +:!type: +:!app-proper: +:!app: +endif::[] +ifeval::["{context}" == "osdk-ansible-quickstart"] +:!ansible: +:!type: +:!app-proper: +:!app: +endif::[] +ifeval::["{context}" == "osdk-helm-quickstart"] +:!helm: +:!type: +:!app-proper: +:!app: +endif::[] diff --git a/modules/osdk-run-deployment.adoc b/modules/osdk-run-deployment.adoc new file mode 100644 index 0000000000..a5441c95a5 --- /dev/null +++ b/modules/osdk-run-deployment.adoc @@ -0,0 +1,83 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc +// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc +// * operators/operator_sdk/ansible/osdk-ansible-inside-operator.adoc +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc + +ifeval::["{context}" == "osdk-golang-tutorial"] +:golang: +endif::[] + +[id="osdk-run-deployment_{context}"] +ifeval::["{context}" != "osdk-ansible-inside-operator"] += Running as a deployment on the cluster +endif::[] +ifeval::["{context}" == "osdk-ansible-inside-operator"] += Testing an Ansible-based Operator on the cluster + +After you have tested your custom Ansible logic locally inside of an Operator, you can test the Operator inside of a pod on an {product-title} cluster, which is prefered for production use. +endif::[] + +You can run your Operator project as a deployment on your cluster. + +ifdef::golang[] +.Prerequisites + +* Prepared your Go-based Operator to run on {product-title} by updating the project to use supported images +endif::[] + +.Procedure + +. Run the following `make` commands to build and push the Operator image. Modify the `IMG` argument in the following steps to reference a repository that you have access to. You can obtain an account for storing containers at repository sites such as Quay.io. + +.. Build the image: ++ +[source,terminal] +---- +$ make docker-build IMG=//: +---- + +.. Push the image to a repository: ++ +[source,terminal] +---- +$ make docker-push IMG=//: +---- ++ +[NOTE] +==== +The name and tag of the image, for example `IMG=//:`, in both the commands can also be set in your Makefile. Modify the `IMG ?= controller:latest` value to set your default image name. +==== + +. Run the following command to deploy the Operator: ++ +[source,terminal] +---- +$ make deploy IMG=//: +---- ++ +By default, this command creates a namespace with the name of your Operator project in the form `-system` and is used for the deployment. This command also installs the RBAC manifests from `config/rbac`. ++ +[NOTE] +==== +If you enabled webhooks in your deployments, you must have `cert-manager` already installed in the cluster or the `make deploy` command will fail when it attempts to create the `cert-manager` resources. +==== + +. Verify that the Operator is running: ++ +[source,terminal] +---- +$ oc get deployment -n -system +---- ++ +.Example output +[source,terminal] +---- +NAME READY UP-TO-DATE AVAILABLE AGE +-controller-manager 1/1 1 1 8m +---- + +ifeval::["{context}" == "osdk-golang-tutorial"] +:!golang: +endif::[] diff --git a/modules/osdk-run-locally.adoc b/modules/osdk-run-locally.adoc new file mode 100644 index 0000000000..1ef9724587 --- /dev/null +++ b/modules/osdk-run-locally.adoc @@ -0,0 +1,75 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc +// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc + +ifeval::["{context}" == "osdk-golang-tutorial"] +:golang: +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:ansible: +endif::[] +ifeval::["{context}" == "osdk-helm-tutorial"] +:helm: +endif::[] + +[id="osdk-run-locally_{context}"] += Running locally outside the cluster + +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 + +* 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] +---- +$ make install run +---- ++ +.Example output +[source,terminal] +ifdef::golang[] +---- +... +2021-01-10T21:09:29.016-0700 INFO controller-runtime.metrics metrics server is starting to listen {"addr": ":8080"} +2021-01-10T21:09:29.017-0700 INFO setup starting manager +2021-01-10T21:09:29.017-0700 INFO controller-runtime.manager starting metrics server {"path": "/metrics"} +2021-01-10T21:09:29.018-0700 INFO controller-runtime.manager.controller.memcached Starting EventSource {"reconciler group": "cache.example.com", "reconciler kind": "Memcached", "source": "kind source: /, Kind="} +2021-01-10T21:09:29.218-0700 INFO controller-runtime.manager.controller.memcached Starting Controller {"reconciler group": "cache.example.com", "reconciler kind": "Memcached"} +2021-01-10T21:09:29.218-0700 INFO controller-runtime.manager.controller.memcached Starting workers {"reconciler group": "cache.example.com", "reconciler kind": "Memcached", "worker count": 1} +---- +endif::[] +ifdef::ansible[] +---- +... +{"level":"info","ts":1612589622.7888272,"logger":"ansible-controller","msg":"Watching resource","Options.Group":"cache.example.com","Options.Version":"v1","Options.Kind":"Memcached"} +{"level":"info","ts":1612589622.7897573,"logger":"proxy","msg":"Starting to serve","Address":"127.0.0.1:8888"} +{"level":"info","ts":1612589622.789971,"logger":"controller-runtime.manager","msg":"starting metrics server","path":"/metrics"} +{"level":"info","ts":1612589622.7899997,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting EventSource","source":"kind source: cache.example.com/v1, Kind=Memcached"} +{"level":"info","ts":1612589622.8904517,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting Controller"} +{"level":"info","ts":1612589622.8905244,"logger":"controller-runtime.manager.controller.memcached-controller","msg":"Starting workers","worker count":8} +---- +endif::[] +ifdef::helm[] +---- +... +{"level":"info","ts":1612652419.9289865,"logger":"controller-runtime.metrics","msg":"metrics server is starting to listen","addr":":8080"} +{"level":"info","ts":1612652419.9296563,"logger":"helm.controller","msg":"Watching resource","apiVersion":"demo.example.com/v1","kind":"Nginx","namespace":"","reconcilePeriod":"1m0s"} +{"level":"info","ts":1612652419.929983,"logger":"controller-runtime.manager","msg":"starting metrics server","path":"/metrics"} +{"level":"info","ts":1612652419.930015,"logger":"controller-runtime.manager.controller.nginx-controller","msg":"Starting EventSource","source":"kind source: demo.example.com/v1, Kind=Nginx"} +{"level":"info","ts":1612652420.2307851,"logger":"controller-runtime.manager.controller.nginx-controller","msg":"Starting Controller"} +{"level":"info","ts":1612652420.2309358,"logger":"controller-runtime.manager.controller.nginx-controller","msg":"Starting workers","worker count":8} +---- +endif::[] + +ifeval::["{context}" == "osdk-golang-tutorial"] +:!golang: +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:!ansible: +endif::[] +ifeval::["{context}" == "osdk-helm-tutorial"] +:!helm: +endif::[] diff --git a/modules/osdk-run-operator.adoc b/modules/osdk-run-operator.adoc new file mode 100644 index 0000000000..699da565ee --- /dev/null +++ b/modules/osdk-run-operator.adoc @@ -0,0 +1,41 @@ +// Module included in the following assemblies: +// +// * operators/operator_sdk/golang/osdk-golang-tutorial.adoc +// * operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc +// * operators/operator_sdk/helm/osdk-helm-tutorial.adoc + +ifeval::["{context}" == "osdk-golang-tutorial"] +:golang: +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:ansible: +endif::[] +ifeval::["{context}" == "osdk-helm-tutorial"] +:helm: +endif::[] + +[id="osdk-run-operator_{context}"] += Running the Operator + +There are three ways you can use the Operator SDK CLI to build and run your Operator: + +* Run locally outside the cluster as a Go program. +* Run as a deployment on the cluster. +* Bundle your Operator and use Operator Lifecycle Manager (OLM) to deploy on the cluster. + +ifdef::golang[] +[NOTE] +==== +Before running your Go-based Operator as either a deployment on {product-title} or as a bundle that uses OLM, ensure that your project has been updated to use supported images. +==== +endif::[] + +ifeval::["{context}" == "osdk-golang-tutorial"] +:!golang: +endif::[] +ifeval::["{context}" == "osdk-ansible-tutorial"] +:!ansible: +endif::[] +ifeval::["{context}" == "osdk-helm-tutorial"] +:!helm: +endif::[] diff --git a/operators/operator_sdk/ansible/images b/operators/operator_sdk/ansible/images new file mode 120000 index 0000000000..5fa6987088 --- /dev/null +++ b/operators/operator_sdk/ansible/images @@ -0,0 +1 @@ +../../images \ No newline at end of file diff --git a/operators/operator_sdk/ansible/modules b/operators/operator_sdk/ansible/modules new file mode 120000 index 0000000000..8b0e854007 --- /dev/null +++ b/operators/operator_sdk/ansible/modules @@ -0,0 +1 @@ +../../modules \ No newline at end of file diff --git a/operators/operator_sdk/ansible/osdk-ansible-cr-status.adoc b/operators/operator_sdk/ansible/osdk-ansible-cr-status.adoc new file mode 100644 index 0000000000..d99175f646 --- /dev/null +++ b/operators/operator_sdk/ansible/osdk-ansible-cr-status.adoc @@ -0,0 +1,9 @@ +[id="osdk-ansible-cr-status"] += Custom resource status management +include::modules/common-attributes.adoc[] +:context: osdk-ansible-cr-mgmt + +toc::[] + +include::modules/osdk-ansible-cr-status-about.adoc[leveloffset=+1] +include::modules/osdk-ansible-cr-status-manual.adoc[leveloffset=+1] diff --git a/operators/operator_sdk/ansible/osdk-ansible-inside-operator.adoc b/operators/operator_sdk/ansible/osdk-ansible-inside-operator.adoc new file mode 100644 index 0000000000..2d978f6f0f --- /dev/null +++ b/operators/operator_sdk/ansible/osdk-ansible-inside-operator.adoc @@ -0,0 +1,16 @@ +[id="osdk-ansible-inside-operator"] += Using Ansible inside an Operator +include::modules/common-attributes.adoc[] +:context: osdk-ansible-inside-operator + +toc::[] + +After you are familiar with xref:../../../operators/operator_sdk/ansible/osdk-ansible-k8s-collection.adoc#osdk-ansible-k8s-collection[using the Kubernetes Collection for Ansible locally], you can trigger the same Ansible logic inside of an Operator when a custom resource (CR) changes. This example maps an Ansible role to a specific Kubernetes resource that the Operator watches. This mapping is done in the `watches.yaml` file. + +include::modules/osdk-ansible-custom-resource-files.adoc[leveloffset=+1] +include::modules/osdk-ansible-inside-operator-local.adoc[leveloffset=+1] +include::modules/osdk-run-deployment.adoc[leveloffset=+1] +include::modules/osdk-ansible-inside-operator-logs.adoc[leveloffset=+1] +include::modules/osdk-ansible-inside-operator-logs-view.adoc[leveloffset=+2] +include::modules/osdk-ansible-inside-operator-logs-full-result.adoc[leveloffset=+2] +include::modules/osdk-ansible-inside-operator-logs-verbose.adoc[leveloffset=+2] diff --git a/operators/operator_sdk/ansible/osdk-ansible-k8s-collection.adoc b/operators/operator_sdk/ansible/osdk-ansible-k8s-collection.adoc new file mode 100644 index 0000000000..8f14b8ffdc --- /dev/null +++ b/operators/operator_sdk/ansible/osdk-ansible-k8s-collection.adoc @@ -0,0 +1,20 @@ +[id="osdk-ansible-k8s-collection"] += Kubernetes Collection for Ansible +include::modules/common-attributes.adoc[] +:context: osdk-ansible-k8s-collection + +toc::[] + +To manage the lifecycle of your application on Kubernetes using Ansible, you can use the link:https://galaxy.ansible.com/community/kubernetes[Kubernetes Collection for Ansible]. This collection of Ansible modules allows a developer to either leverage their existing Kubernetes resource files written in YAML or express the lifecycle management in native Ansible. + +One of the biggest benefits of using Ansible in conjunction with existing Kubernetes resource files is the ability to use Jinja templating so that you can customize resources with the simplicity of a few variables in Ansible. + +This section goes into detail on usage of the Kubernetes Collection. To get started, install the collection on your local workstation and test it using a playbook before moving on to using it within an Operator. + +include::modules/osdk-ansible-k8s-install.adoc[leveloffset=+1] +include::modules/osdk-ansible-k8s-local.adoc[leveloffset=+1] + +[id="osdk-ansible-k8s-collection-next-steps"] +== Next steps + +* See xref:../../../operators/operator_sdk/ansible/osdk-ansible-inside-operator.adoc#osdk-ansible-inside-operator[Using Ansible inside an Operator] for details on triggering your custom Ansible logic inside of an Operator when a custom resource (CR) changes. diff --git a/operators/operator_sdk/ansible/osdk-ansible-project-layout.adoc b/operators/operator_sdk/ansible/osdk-ansible-project-layout.adoc new file mode 100644 index 0000000000..b78db0dd7c --- /dev/null +++ b/operators/operator_sdk/ansible/osdk-ansible-project-layout.adoc @@ -0,0 +1,10 @@ +[id="osdk-ansible-project-layout"] += Project layout for Ansible-based Operators +include::modules/common-attributes.adoc[] +:context: osdk-ansible-project-layout + +toc::[] + +The `operator-sdk` CLI can generate, or _scaffold_, a number of packages and files for each Operator project. + +include::modules/osdk-ansible-project-layout.adoc[leveloffset=+1] diff --git a/operators/operator_sdk/ansible/osdk-ansible-quickstart.adoc b/operators/operator_sdk/ansible/osdk-ansible-quickstart.adoc new file mode 100644 index 0000000000..0cfa39f3f7 --- /dev/null +++ b/operators/operator_sdk/ansible/osdk-ansible-quickstart.adoc @@ -0,0 +1,18 @@ +[id="osdk-ansible-quickstart"] += Operator SDK quickstart for Ansible-based Operators +include::modules/common-attributes.adoc[] +:context: osdk-ansible-quickstart + +toc::[] + +The Operator SDK includes options for generating an Operator project that leverages existing Ansible playbooks and modules to deploy Kubernetes resources as a unified application, without having to write any Go code. + +To demonstrate the basics of setting up and running an link:https://docs.ansible.com/ansible/latest/index.html[Ansible]-based Operator using tools and libraries provided by the Operator SDK, Operator developers can build an example Ansible-based Operator for Memcached, a distributed key-value store, and deploy it to a cluster. + +include::modules/osdk-create-operator-prereqs.adoc[leveloffset=+1] +include::modules/osdk-quickstart.adoc[leveloffset=+1] + +[id="osdk-ansible-quickstart-next-steps"] +== Next steps + +* See xref:../../../operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc#osdk-ansible-tutorial[Operator SDK tutorial for Ansible-based Operators] for a more in-depth walkthrough on building an Ansible-based Operator. diff --git a/operators/operator_sdk/ansible/osdk-ansible-support.adoc b/operators/operator_sdk/ansible/osdk-ansible-support.adoc new file mode 100644 index 0000000000..67304f29d9 --- /dev/null +++ b/operators/operator_sdk/ansible/osdk-ansible-support.adoc @@ -0,0 +1,11 @@ +[id="osdk-ansible-support"] += Ansible support in Operator SDK +include::modules/common-attributes.adoc[] +:context: osdk-ansible-support + +toc::[] + +include::modules/osdk-ansible-custom-resource-files.adoc[leveloffset=+1] +include::modules/osdk-ansible-watches-file.adoc[leveloffset=+1] +include::modules/osdk-ansible-extra-variables.adoc[leveloffset=+1] +include::modules/osdk-ansible-runner-directory.adoc[leveloffset=+1] diff --git a/operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc b/operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc new file mode 100644 index 0000000000..a164397d06 --- /dev/null +++ b/operators/operator_sdk/ansible/osdk-ansible-tutorial.adoc @@ -0,0 +1,43 @@ +[id="osdk-ansible-tutorial"] += Operator SDK tutorial for Ansible-based Operators +include::modules/common-attributes.adoc[] +:context: osdk-ansible-tutorial + +toc::[] + +Operator developers can take advantage of link:https://docs.ansible.com/ansible/latest/index.html[Ansible] support in the Operator SDK to build an example Ansible-based Operator for Memcached, a distributed key-value store, and manage its lifecycle. This tutorial walks through the following process: + +* Create a Memcached deployment +* Ensure that the deployment size is the same as specified by the `Memcached` custom resource (CR) spec +* Update the `Memcached` CR status using the status writer with the names of the `memcached` pods + +This process is accomplished by using two centerpieces of the Operator Framework: + +Operator SDK:: The `operator-sdk` CLI tool and `controller-runtime` library API + +Operator Lifecycle Manager (OLM):: Installation, upgrade, and role-based access control (RBAC) of Operators on a cluster + +[NOTE] +==== +This tutorial goes into greater detail than xref:../../../operators/operator_sdk/ansible/osdk-ansible-quickstart.adoc#osdk-ansible-quickstart[Operator SDK quickstart for Ansible-based Operators]. +==== + +include::modules/osdk-create-operator-prereqs.adoc[leveloffset=+1] + +include::modules/osdk-create-project.adoc[leveloffset=+1] +include::modules/osdk-project-file.adoc[leveloffset=+2] + +include::modules/osdk-ansible-create-api.adoc[leveloffset=+1] +include::modules/osdk-ansible-modify-manager.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-bundle-deploy-olm.adoc[leveloffset=+2] + +include::modules/osdk-create-cr.adoc[leveloffset=+1] + +[id="osdk-ansible-tutorial-addtl-resources"] +== Additional resources + +- See xref:../../../operators/operator_sdk/ansible/osdk-ansible-project-layout.adoc#osdk-ansible-project-layout_osdk-ansible-project-layout[Appendices] to learn about the project directory structures created by the Operator SDK. diff --git a/operators/operator_sdk/golang/osdk-golang-project-layout.adoc b/operators/operator_sdk/golang/osdk-golang-project-layout.adoc new file mode 100644 index 0000000000..e9c89c1352 --- /dev/null +++ b/operators/operator_sdk/golang/osdk-golang-project-layout.adoc @@ -0,0 +1,10 @@ +[id="osdk-golang-project-layout"] += Project layout for Go-based Operators +include::modules/common-attributes.adoc[] +:context: osdk-golang-project-layout + +toc::[] + +The `operator-sdk` CLI can generate, or _scaffold_, a number of packages and files for each Operator project. + +include::modules/osdk-golang-project-layout.adoc[leveloffset=+1] diff --git a/operators/operator_sdk/golang/osdk-golang-quickstart.adoc b/operators/operator_sdk/golang/osdk-golang-quickstart.adoc index f994e981fe..e874158e19 100644 --- a/operators/operator_sdk/golang/osdk-golang-quickstart.adoc +++ b/operators/operator_sdk/golang/osdk-golang-quickstart.adoc @@ -1,5 +1,5 @@ [id="osdk-golang-quickstart"] -= Quickstart for Go-based Operators += Operator SDK quickstart for Go-based Operators include::modules/common-attributes.adoc[] :context: osdk-golang-quickstart @@ -7,9 +7,10 @@ toc::[] To demonstrate the basics of setting up and running a Go-based Operator using tools and libraries provided by the Operator SDK, Operator developers can build an example Go-based Operator for Memcached, a distributed key-value store, and deploy it to a cluster. -include::modules/osdk-golang-create-deploy.adoc[leveloffset=+1] +include::modules/osdk-create-operator-prereqs.adoc[leveloffset=+1] +include::modules/osdk-quickstart.adoc[leveloffset=+1] [id="osdk-golang-quickstart-next-steps"] == Next steps -* See xref:../../../operators/operator_sdk/golang/osdk-golang-tutorial.adoc#osdk-golang-tutorial[Tutorial for Go-based Operators] for a more in-depth walkthrough on building a Go-based Operator. +* See xref:../../../operators/operator_sdk/golang/osdk-golang-tutorial.adoc#osdk-golang-tutorial[Operator SDK tutorial for Go-based Operators] for a more in-depth walkthrough on building a Go-based Operator. diff --git a/operators/operator_sdk/golang/osdk-golang-tutorial.adoc b/operators/operator_sdk/golang/osdk-golang-tutorial.adoc index a61e8c82a4..47f9f7fa9c 100644 --- a/operators/operator_sdk/golang/osdk-golang-tutorial.adoc +++ b/operators/operator_sdk/golang/osdk-golang-tutorial.adoc @@ -1,25 +1,27 @@ [id="osdk-golang-tutorial"] -= Tutorial for Go-based Operators += Operator SDK tutorial for Go-based Operators include::modules/common-attributes.adoc[] :context: osdk-golang-tutorial toc::[] -Operator developers can take advantage of Go programming language support in the Operator SDK to build an example Go-based Operator for Memcached, a distributed key-value store, and manage its lifecycle. This process is accomplished using two centerpieces of the Operator Framework: Operator SDK (the `operator-sdk` CLI tool and `controller-runtime` library API) and Operator Lifecycle Manager (OLM). +Operator developers can take advantage of Go programming language support in the Operator SDK to build an example Go-based Operator for Memcached, a distributed key-value store, and manage its lifecycle. + +This process is accomplished using two centerpieces of the Operator Framework: + +Operator SDK:: The `operator-sdk` CLI tool and `controller-runtime` library API + +Operator Lifecycle Manager (OLM):: Installation, upgrade, and role-based access control (RBAC) of Operators on a cluster [NOTE] ==== -This tutorial goes into greater detail than xref:../../../operators/operator_sdk/golang/osdk-golang-quickstart.adoc#osdk-golang-quickstart[Quickstart for Go-based Operators]. +This tutorial goes into greater detail than xref:../../../operators/operator_sdk/golang/osdk-golang-quickstart.adoc#osdk-golang-quickstart[Operator SDK quickstart for Go-based Operators]. ==== -[id="osdk-golang-tutorial-prereqs"] -== Prerequisites +include::modules/osdk-create-operator-prereqs.adoc[leveloffset=+1] -- Operator SDK CLI installed on a development workstation -- OpenShift CLI (`oc`) v{product-version}+ installed -- Logged into a {product-title} {product-version} cluster with `oc` with an account that has `cluster-admin` permissions - -include::modules/osdk-golang-create-project.adoc[leveloffset=+1] +include::modules/osdk-create-project.adoc[leveloffset=+1] +include::modules/osdk-project-file.adoc[leveloffset=+2] include::modules/osdk-golang-manager.adoc[leveloffset=+2] include::modules/osdk-golang-multi-group-apis.adoc[leveloffset=+2] @@ -34,14 +36,15 @@ 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-golang-build-run.adoc[leveloffset=+1] -include::modules/osdk-golang-run-locally.adoc[leveloffset=+2] -include::modules/osdk-golang-run-in-cluster.adoc[leveloffset=+2] -include::modules/osdk-bundling-deploying-using-olm.adoc[leveloffset=+2] +include::modules/osdk-run-operator.adoc[leveloffset=+1] +include::modules/osdk-run-locally.adoc[leveloffset=+2] +include::modules/osdk-prepare-supported-images.adoc[leveloffset=+2] +include::modules/osdk-run-deployment.adoc[leveloffset=+2] +include::modules/osdk-bundle-deploy-olm.adoc[leveloffset=+2] -include::modules/osdk-golang-create-cr.adoc[leveloffset=+1] +include::modules/osdk-create-cr.adoc[leveloffset=+1] [id="osdk-golang-tutorial-addtl-resources"] == Additional resources -- See xref:../../../operators/operator_sdk/osdk-appendices.adoc#osdk-project-scaffolding-layout_operator-appendices[Appendices] to learn about the project directory structures created by the Operator SDK. +- See xref:../../../operators/operator_sdk/golang/osdk-golang-project-layout.adoc#osdk-golang-project-layout_osdk-golang-project-layout[Appendices] to learn about the project directory structures created by the Operator SDK. diff --git a/operators/operator_sdk/helm/images b/operators/operator_sdk/helm/images new file mode 120000 index 0000000000..5fa6987088 --- /dev/null +++ b/operators/operator_sdk/helm/images @@ -0,0 +1 @@ +../../images \ No newline at end of file diff --git a/operators/operator_sdk/helm/modules b/operators/operator_sdk/helm/modules new file mode 120000 index 0000000000..8b0e854007 --- /dev/null +++ b/operators/operator_sdk/helm/modules @@ -0,0 +1 @@ +../../modules \ No newline at end of file diff --git a/operators/operator_sdk/helm/osdk-helm-project-layout.adoc b/operators/operator_sdk/helm/osdk-helm-project-layout.adoc new file mode 100644 index 0000000000..eac580b93e --- /dev/null +++ b/operators/operator_sdk/helm/osdk-helm-project-layout.adoc @@ -0,0 +1,10 @@ +[id="osdk-helm-project-layout"] += Project layout for Helm-based Operators +include::modules/common-attributes.adoc[] +:context: osdk-helm-project-layout + +toc::[] + +The `operator-sdk` CLI can generate, or _scaffold_, a number of packages and files for each Operator project. + +include::modules/osdk-helm-project-layout.adoc[leveloffset=+1] diff --git a/operators/operator_sdk/helm/osdk-helm-quickstart.adoc b/operators/operator_sdk/helm/osdk-helm-quickstart.adoc new file mode 100644 index 0000000000..ed14d4ea17 --- /dev/null +++ b/operators/operator_sdk/helm/osdk-helm-quickstart.adoc @@ -0,0 +1,18 @@ +[id="osdk-helm-quickstart"] += Operator SDK quickstart for Helm-based Operators +include::modules/common-attributes.adoc[] +:context: osdk-helm-quickstart + +toc::[] + +The Operator SDK includes options for generating an Operator project that leverages existing link:https://helm.sh/docs/[Helm] charts to deploy Kubernetes resources as a unified application, without having to write any Go code. + +To demonstrate the basics of setting up and running an link:https://helm.sh/docs/[Helm]-based Operator using tools and libraries provided by the Operator SDK, Operator developers can build an example Helm-based Operator for Nginx and deploy it to a cluster. + +include::modules/osdk-create-operator-prereqs.adoc[leveloffset=+1] +include::modules/osdk-quickstart.adoc[leveloffset=+1] + +[id="osdk-helm-quickstart-next-steps"] +== Next steps + +* See xref:../../../operators/operator_sdk/helm/osdk-helm-tutorial.adoc#osdk-helm-tutorial[Operator SDK tutorial for Helm-based Operators] for a more in-depth walkthrough on building a Helm-based Operator. diff --git a/operators/operator_sdk/helm/osdk-helm-support.adoc b/operators/operator_sdk/helm/osdk-helm-support.adoc new file mode 100644 index 0000000000..00ce0a5e63 --- /dev/null +++ b/operators/operator_sdk/helm/osdk-helm-support.adoc @@ -0,0 +1,8 @@ +[id="osdk-helm-support"] += Helm support in Operator SDK +include::modules/common-attributes.adoc[] +:context: osdk-helm-support + +toc::[] + +include::modules/osdk-helm-charts.adoc[leveloffset=+1] diff --git a/operators/operator_sdk/helm/osdk-helm-tutorial.adoc b/operators/operator_sdk/helm/osdk-helm-tutorial.adoc new file mode 100644 index 0000000000..c9c03aee2e --- /dev/null +++ b/operators/operator_sdk/helm/osdk-helm-tutorial.adoc @@ -0,0 +1,45 @@ +[id="osdk-helm-tutorial"] += Operator SDK tutorial for Helm-based Operators +include::modules/common-attributes.adoc[] +:context: osdk-helm-tutorial + +toc::[] + +Operator developers can take advantage of link:https://helm.sh/docs/[Helm] support in the Operator SDK to build an example Helm-based Operator for Nginx and manage its lifecycle. This tutorial walks through the following process: + +* Create a Nginx deployment +* Ensure that the deployment size is the same as specified by the `Nginx` custom resource (CR) spec +* Update the `Nginx` CR status using the status writer with the names of the `nginx` pods + +This process is accomplished using two centerpieces of the Operator Framework: + +Operator SDK:: The `operator-sdk` CLI tool and `controller-runtime` library API + +Operator Lifecycle Manager (OLM):: Installation, upgrade, and role-based access control (RBAC) of Operators on a cluster + +[NOTE] +==== +This tutorial goes into greater detail than xref:../../../operators/operator_sdk/helm/osdk-helm-quickstart.adoc#osdk-helm-quickstart[Operator SDK quickstart for Helm-based Operators]. +==== + +include::modules/osdk-create-operator-prereqs.adoc[leveloffset=+1] + +include::modules/osdk-create-project.adoc[leveloffset=+1] +include::modules/osdk-helm-existing-chart.adoc[leveloffset=+2] +include::modules/osdk-project-file.adoc[leveloffset=+2] + +include::modules/osdk-helm-logic.adoc[leveloffset=+1] +include::modules/osdk-helm-sample-chart.adoc[leveloffset=+2] +include::modules/osdk-helm-modify-cr.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] +include::modules/osdk-bundle-deploy-olm.adoc[leveloffset=+2] + +include::modules/osdk-create-cr.adoc[leveloffset=+1] + +[id="osdk-helm-tutorial-addtl-resources"] +== Additional resources + +- See xref:../../../operators/operator_sdk/helm/osdk-helm-project-layout.adoc#osdk-helm-project-layout_osdk-helm-project-layout[Appendices] to learn about the project directory structures created by the Operator SDK. diff --git a/operators/operator_sdk/osdk-ansible.adoc b/operators/operator_sdk/osdk-ansible.adoc deleted file mode 100644 index f705f40bb2..0000000000 --- a/operators/operator_sdk/osdk-ansible.adoc +++ /dev/null @@ -1,38 +0,0 @@ -[id="osdk-ansible"] -= Creating Ansible-based Operators -include::modules/common-attributes.adoc[] -:context: osdk-ansible - -toc::[] - -This guide outlines Ansible support in the Operator SDK and walks Operator authors through examples building and running Ansible-based Operators with the `operator-sdk` CLI tool that use Ansible playbooks and modules. - -include::modules/osdk-ansible-support.adoc[leveloffset=+1] -include::modules/osdk-ansible-custom-resource-files.adoc[leveloffset=+2] -include::modules/osdk-ansible-watches-file.adoc[leveloffset=+2] -include::modules/osdk-ansible-extra-variables.adoc[leveloffset=+2] -include::modules/osdk-ansible-runner-directory.adoc[leveloffset=+2] -include::modules/osdk-building-ansible-operator.adoc[leveloffset=+1] - -[id="osdk-ansible-k8s-module"] -== Managing application lifecycle using the k8s Ansible module - -To manage the lifecycle of your application on Kubernetes using Ansible, you can use the link:https://docs.ansible.com/ansible/2.7/modules/k8s_module.html[`k8s` Ansible module]. This Ansible module allows a developer to either leverage their existing Kubernetes resource files (written in YAML) or express the lifecycle management in native Ansible. - -One of the biggest benefits of using Ansible in conjunction with existing Kubernetes resource files is the ability to use Jinja templating so that you can customize resources with the simplicity of a few variables in Ansible. - -This section goes into detail on usage of the `k8s` Ansible module. To get started, install the module on your local workstation and test it using a playbook before moving on to using it within an Operator. - -include::modules/osdk-ansible-k8s-module-installing.adoc[leveloffset=+2] -include::modules/osdk-ansible-k8s-module-testing-locally.adoc[leveloffset=+2] -include::modules/osdk-ansible-k8s-module-inside-operator.adoc[leveloffset=+2] - -include::modules/osdk-ansible-managing-cr-status.adoc[leveloffset=+1] - -[id="osdk-ansible-addtl-resources"] -== Additional resources - -- See xref:../../operators/operator_sdk/osdk-appendices.adoc#osdk-project-scaffolding-layout_operator-appendices[Appendices] to learn about the project directory structures created by the Operator SDK. -- link:https://blog.openshift.com/reaching-for-the-stars-with-ansible-operator/[Reaching for the Stars with Ansible Operator] - Red Hat OpenShift Blog - -- link:https://operators.gitbook.io/operator-developer-guide-for-red-hat-partners/[Operator Development Guide for Red Hat Partners] diff --git a/operators/operator_sdk/osdk-appendices.adoc b/operators/operator_sdk/osdk-appendices.adoc deleted file mode 100644 index 398317d4ac..0000000000 --- a/operators/operator_sdk/osdk-appendices.adoc +++ /dev/null @@ -1,8 +0,0 @@ -[id="operator-appendices"] -= Appendices -include::modules/common-attributes.adoc[] -:context: operator-appendices - -toc::[] - -include::modules/osdk-project-scaffolding-layout.adoc[leveloffset=+1] diff --git a/operators/operator_sdk/osdk-generating-csvs.adoc b/operators/operator_sdk/osdk-generating-csvs.adoc index c59b3dcebc..fd5aa99907 100644 --- a/operators/operator_sdk/osdk-generating-csvs.adoc +++ b/operators/operator_sdk/osdk-generating-csvs.adoc @@ -1,5 +1,5 @@ [id="osdk-generating-csvs"] -= Generating a cluster service version (CSV) += Defining cluster service versions (CSVs) include::modules/common-attributes.adoc[] :context: osdk-generating-csvs @@ -25,7 +25,7 @@ This action is idempotent and only updates the CSV file when a new version is su include::modules/osdk-how-csv-gen-works.adoc[leveloffset=+1] .Additional resources -* See xref:../../operators/operator_sdk/golang/osdk-golang-tutorial.html#osdk-bundling-deploying-using-olm_osdk-golang-tutorial[Bundling and deploying your Operator by using OLM] for a tutorial that includes generating a CSV. +* See xref:../../operators/operator_sdk/golang/osdk-golang-tutorial.html#osdk-bundle-deploy-olm_osdk-golang-tutorial[Bundling and deploying your Operator by using OLM] for a tutorial that includes generating a CSV. //// include::modules/osdk-csv-composition-configuration.adoc[leveloffset=+1] diff --git a/operators/operator_sdk/osdk-helm.adoc b/operators/operator_sdk/osdk-helm.adoc deleted file mode 100644 index c17e60ffc5..0000000000 --- a/operators/operator_sdk/osdk-helm.adoc +++ /dev/null @@ -1,18 +0,0 @@ -[id="osdk-helm"] -= Creating Helm-based Operators -include::modules/common-attributes.adoc[] -:context: osdk-helm - -toc::[] - -This guide outlines Helm chart support in the Operator SDK and walks Operator authors through an example of building and running an Nginx Operator with the `operator-sdk` CLI tool that uses an existing Helm chart. - -include::modules/osdk-helm-chart-support.adoc[leveloffset=+1] -include::modules/osdk-building-helm-operator.adoc[leveloffset=+1] - -[id="osdk-helm-addtl-resources"] -== Additional resources - -- See xref:../../operators/operator_sdk/osdk-appendices.adoc#osdk-project-scaffolding-layout_operator-appendices[Appendices] to learn about the project directory structures created by the Operator SDK. - -- link:https://operators.gitbook.io/operator-developer-guide-for-red-hat-partners/[Operator Development Guide for Red Hat Partners] diff --git a/operators/operator_sdk/osdk-scorecard.adoc b/operators/operator_sdk/osdk-scorecard.adoc index be914a9526..813e3b7f36 100644 --- a/operators/operator_sdk/osdk-scorecard.adoc +++ b/operators/operator_sdk/osdk-scorecard.adoc @@ -27,4 +27,4 @@ include::modules/osdk-running-scorecard.adoc[leveloffset=+1] include::modules/osdk-scorecard-olm.adoc[leveloffset=+1] .Additional resources -* xref:../../operators/operator_sdk/golang/osdk-golang-tutorial.html#osdk-bundling-deploying-using-olm_osdk-golang-tutorial[Bundling and deploying your Operator by using OLM] +* xref:../../operators/operator_sdk/golang/osdk-golang-tutorial.html#osdk-bundle-deploy-olm_osdk-golang-tutorial[Bundling and deploying your Operator by using OLM] diff --git a/operators/understanding/olm/olm-webhooks.adoc b/operators/understanding/olm/olm-webhooks.adoc index 9e5438d6e6..84884c3bf3 100644 --- a/operators/understanding/olm/olm-webhooks.adoc +++ b/operators/understanding/olm/olm-webhooks.adoc @@ -7,7 +7,7 @@ toc::[] Webhooks allow Operator authors to intercept, modify, and accept or reject resources before they are saved to the object store and handled by the Operator controller. Operator Lifecycle Manager (OLM) can manage the lifecycle of these webhooks when they are shipped alongside your Operator. -See xref:../../../operators/operator_sdk/osdk-generating-csvs.adoc#olm-defining-csv-webhook_osdk-generating-csvs[Generating a cluster service version (CSV)] for details on how an Operator developer can define webhooks for their Operator, as well as considerations when running on OLM. +See xref:../../../operators/operator_sdk/osdk-generating-csvs.adoc#olm-defining-csv-webhook_osdk-generating-csvs[Defining cluster service versions (CSVs)] for details on how an Operator developer can define webhooks for their Operator, as well as considerations when running on OLM. [id="olm-webhooks-additional-resources"] == Additional resources diff --git a/welcome/index.adoc b/welcome/index.adoc index a74d0bf178..9c27eb98d4 100644 --- a/welcome/index.adoc +++ b/welcome/index.adoc @@ -133,8 +133,8 @@ Use the Workloads page or `oc` CLI to xref:../applications/deployments/managing- - **xref:../openshift_images/using-templates.adoc#using-templates[Create templates]**: Use existing templates or create your own templates that describe how an application is built or deployed. A template can combine images with descriptions, parameters, replicas, exposed ports and other content that defines how an application can be run or built. ifdef::openshift-enterprise,openshift-webscale,openshift-origin[] -- **xref:../operators/operator_sdk/osdk-about.adoc#osdk-about[Develop Operators]**: Operators are the preferred method for creating on-cluster applications for {product-title} {product-version}. Learn the workflow for building, testing, and deploying Operators. Then create your own Operators based on xref:../operators/operator_sdk/osdk-ansible.adoc#osdk-ansible[Ansible] or -xref:../operators/operator_sdk/osdk-helm.adoc#osdk-helm[Helm], or configure xref:../operators/operator_sdk/osdk-monitoring-prometheus.adoc#osdk-monitoring-prometheus[built-in Prometheus monitoring] using the Operator SDK. +- **xref:../operators/operator_sdk/osdk-about.adoc#osdk-about[Develop Operators]**: Operators are the preferred method for creating on-cluster applications for {product-title} {product-version}. Learn the workflow for building, testing, and deploying Operators. Then create your own Operators based on xref:../operators/operator_sdk/ansible/osdk-ansible-support.adoc#osdk-ansible-support[Ansible] or +xref:../operators/operator_sdk/helm/osdk-helm-support.adoc#osdk-helm-support[Helm], or configure xref:../operators/operator_sdk/osdk-monitoring-prometheus.adoc#osdk-monitoring-prometheus[built-in Prometheus monitoring] using the Operator SDK. - **xref:../rest_api/index.adoc#api-index[REST API reference]**: Lists {product-title} application programming interface endpoints. endif::[]