diff --git a/deploy/helm/opensearch-operator/configs/properties.yaml b/deploy/helm/opensearch-operator/configs/properties.yaml new file mode 100644 index 0000000..9bd8c3b --- /dev/null +++ b/deploy/helm/opensearch-operator/configs/properties.yaml @@ -0,0 +1,5 @@ +--- +version: 0.1.0 +spec: + units: [] +properties: [] diff --git a/deploy/helm/opensearch-operator/crds/crds.yaml b/deploy/helm/opensearch-operator/crds/crds.yaml index 6772c15..e67d288 100644 --- a/deploy/helm/opensearch-operator/crds/crds.yaml +++ b/deploy/helm/opensearch-operator/crds/crds.yaml @@ -136,9 +136,10 @@ spec: nodeRoles: items: enum: + - cluster_manager + - coordinating_only - data - ingest - - cluster_manager - remote_cluster_client - warm - search @@ -327,9 +328,10 @@ spec: nodeRoles: items: enum: + - cluster_manager + - coordinating_only - data - ingest - - cluster_manager - remote_cluster_client - warm - search diff --git a/docs/antora.yml b/docs/antora.yml new file mode 100644 index 0000000..d522680 --- /dev/null +++ b/docs/antora.yml @@ -0,0 +1,3 @@ +--- +name: home +version: "nightly" diff --git a/docs/modules/opensearch/examples/getting_started/getting_started.sh b/docs/modules/opensearch/examples/getting_started/getting_started.sh new file mode 100755 index 0000000..3bccc1f --- /dev/null +++ b/docs/modules/opensearch/examples/getting_started/getting_started.sh @@ -0,0 +1,109 @@ +#! /usr/bin/env bash +set -euo pipefail + +# DO NOT EDIT THE SCRIPT +# Instead, update the j2 template, and regenerate it for dev with `make render-docs`. + +# This script contains all the code snippets from the guide, as well as some assert tests +# to test if the instructions in the guide work. The user *could* use it, but it is intended +# for testing only. +# The script will install the operators, create a OpenSearch instance and briefly open a port +# forward and connect to the OpenSearch instance to make sure it is up and running. +# No running processes are left behind (i.e. the port-forwarding is closed at the end) + +if [ $# -eq 0 ] +then + echo "Installation method argument ('helm' or 'stackablectl') required." + exit 1 +fi + +cd "$(dirname "$0")" + +case "$1" in +"helm") +echo "Installing Operators with Helm" +# tag::helm-install-operators[] +helm install --wait commons-operator oci://oci.stackable.tech/sdp-charts/commons-operator --version 0.0.0-dev +helm install --wait secret-operator oci://oci.stackable.tech/sdp-charts/secret-operator --version 0.0.0-dev +helm install --wait listener-operator oci://oci.stackable.tech/sdp-charts/listener-operator --version 0.0.0-dev +helm install --wait opensearch-operator oci://oci.stackable.tech/sdp-charts/opensearch-operator --version 0.0.0-dev +# end::helm-install-operators[] +;; +"stackablectl") +echo "installing Operators with stackablectl" +# tag::stackablectl-install-operators[] +stackablectl operator install \ + commons=0.0.0-dev \ + secret=0.0.0-dev \ + listener=0.0.0-dev \ + opensearch=0.0.0-dev +# end::stackablectl-install-operators[] +;; +*) +echo "Need to give 'helm' or 'stackablectl' as an argument for which installation method to use!" +exit 1 +;; +esac + +echo "Creating OpenSearch security plugin configuration" +# tag::apply-security-config[] +kubectl apply -f opensearch-security-config.yaml +# end::apply-security-config[] + +echo "Creating OpenSearch cluster" +# tag::apply-cluster[] +kubectl apply -f opensearch.yaml +# end::apply-cluster[] + +sleep 5 + +for (( i=1; i<=15; i++ )) +do + echo "Waiting for OpenSearchCluster to appear ..." + if eval kubectl get statefulset simple-opensearch-nodes-default; then + break + fi + + sleep 1 +done + +echo "Waiting on OpenSearch StatefulSet ..." +# tag::await-cluster[] +kubectl rollout status --watch statefulset/simple-opensearch-nodes-default --timeout 600s +# end::await-cluster[] + +# wait a bit for the port to open +sleep 10 + +echo "Starting port-forwarding of port 9200" +# tag::port-forwarding[] +kubectl port-forward services/simple-opensearch 9200 > /dev/null 2>&1 & +# end::port-forwarding[] +PORT_FORWARD_PID=$! +# shellcheck disable=2064 # we want the PID evaluated now, not at the time the trap is +trap "kill $PORT_FORWARD_PID" EXIT +sleep 5 + +echo "Using the REST API" +# tag::rest-api[] +export CREDENTIALS=admin:AJVFsGJBbpT6mChn + +curl \ + --insecure \ + --user $CREDENTIALS \ + --request PUT \ + --json '{"name": "Stackable"}' \ + https://localhost:9200/sample_index/_doc/1 + +# Output: +# {"_index":"sample_index","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1} + +curl \ + --insecure \ + --user $CREDENTIALS \ + --request GET \ + https://localhost:9200/sample_index/_doc/1 + +# Output: +# {"_index":"sample_index","_id":"1","_version":1,"_seq_no":0,"_primary_term":1,"found":true,"_source":{"name": "Stackable"}} +# end::rest-api[] diff --git a/docs/modules/opensearch/examples/getting_started/getting_started.sh.j2 b/docs/modules/opensearch/examples/getting_started/getting_started.sh.j2 new file mode 100755 index 0000000..8be395c --- /dev/null +++ b/docs/modules/opensearch/examples/getting_started/getting_started.sh.j2 @@ -0,0 +1,109 @@ +#! /usr/bin/env bash +set -euo pipefail + +# DO NOT EDIT THE SCRIPT +# Instead, update the j2 template, and regenerate it for dev with `make render-docs`. + +# This script contains all the code snippets from the guide, as well as some assert tests +# to test if the instructions in the guide work. The user *could* use it, but it is intended +# for testing only. +# The script will install the operators, create a OpenSearch instance and briefly open a port +# forward and connect to the OpenSearch instance to make sure it is up and running. +# No running processes are left behind (i.e. the port-forwarding is closed at the end) + +if [ $# -eq 0 ] +then + echo "Installation method argument ('helm' or 'stackablectl') required." + exit 1 +fi + +cd "$(dirname "$0")" + +case "$1" in +"helm") +echo "Installing Operators with Helm" +# tag::helm-install-operators[] +helm install --wait commons-operator oci://{{ helm.repo_url }}/{{ helm.repo_name }}/commons-operator --version {{ versions.commons }} +helm install --wait secret-operator oci://{{ helm.repo_url }}/{{ helm.repo_name }}/secret-operator --version {{ versions.secret }} +helm install --wait listener-operator oci://{{ helm.repo_url }}/{{ helm.repo_name }}/listener-operator --version {{ versions.listener }} +helm install --wait opensearch-operator oci://{{ helm.repo_url }}/{{ helm.repo_name }}/opensearch-operator --version {{ versions.opensearch }} +# end::helm-install-operators[] +;; +"stackablectl") +echo "installing Operators with stackablectl" +# tag::stackablectl-install-operators[] +stackablectl operator install \ + commons={{ versions.commons }} \ + secret={{ versions.secret }} \ + listener={{ versions.listener }} \ + opensearch={{ versions.opensearch }} +# end::stackablectl-install-operators[] +;; +*) +echo "Need to give 'helm' or 'stackablectl' as an argument for which installation method to use!" +exit 1 +;; +esac + +echo "Creating OpenSearch security plugin configuration" +# tag::apply-security-config[] +kubectl apply -f opensearch-security-config.yaml +# end::apply-security-config[] + +echo "Creating OpenSearch cluster" +# tag::apply-cluster[] +kubectl apply -f opensearch.yaml +# end::apply-cluster[] + +sleep 5 + +for (( i=1; i<=15; i++ )) +do + echo "Waiting for OpenSearchCluster to appear ..." + if eval kubectl get statefulset simple-opensearch-nodes-default; then + break + fi + + sleep 1 +done + +echo "Waiting on OpenSearch StatefulSet ..." +# tag::await-cluster[] +kubectl rollout status --watch statefulset/simple-opensearch-nodes-default --timeout 600s +# end::await-cluster[] + +# wait a bit for the port to open +sleep 10 + +echo "Starting port-forwarding of port 9200" +# tag::port-forwarding[] +kubectl port-forward services/simple-opensearch 9200 > /dev/null 2>&1 & +# end::port-forwarding[] +PORT_FORWARD_PID=$! +# shellcheck disable=2064 # we want the PID evaluated now, not at the time the trap is +trap "kill $PORT_FORWARD_PID" EXIT +sleep 5 + +echo "Using the REST API" +# tag::rest-api[] +export CREDENTIALS=admin:AJVFsGJBbpT6mChn + +curl \ + --insecure \ + --user $CREDENTIALS \ + --request PUT \ + --json '{"name": "Stackable"}' \ + https://localhost:9200/sample_index/_doc/1 + +# Output: +# {"_index":"sample_index","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1} + +curl \ + --insecure \ + --user $CREDENTIALS \ + --request GET \ + https://localhost:9200/sample_index/_doc/1 + +# Output: +# {"_index":"sample_index","_id":"1","_version":1,"_seq_no":0,"_primary_term":1,"found":true,"_source":{"name": "Stackable"}} +# end::rest-api[] diff --git a/docs/modules/opensearch/examples/getting_started/install_output.txt b/docs/modules/opensearch/examples/getting_started/install_output.txt new file mode 100644 index 0000000..52cd670 --- /dev/null +++ b/docs/modules/opensearch/examples/getting_started/install_output.txt @@ -0,0 +1,4 @@ +Installed commons=0.0.0-dev operator +Installed secret=0.0.0-dev operator +Installed listener=0.0.0-dev operator +Installed opensearch=0.0.0-dev operator diff --git a/docs/modules/opensearch/examples/getting_started/install_output.txt.j2 b/docs/modules/opensearch/examples/getting_started/install_output.txt.j2 new file mode 100644 index 0000000..0ad2d93 --- /dev/null +++ b/docs/modules/opensearch/examples/getting_started/install_output.txt.j2 @@ -0,0 +1,4 @@ +Installed commons={{ versions.commons }} operator +Installed secret={{ versions.secret }} operator +Installed listener={{ versions.listener }} operator +Installed opensearch={{ versions.opensearch }} operator diff --git a/docs/modules/opensearch/examples/getting_started/opensearch-security-config.yaml b/docs/modules/opensearch/examples/getting_started/opensearch-security-config.yaml new file mode 100644 index 0000000..116ea90 --- /dev/null +++ b/docs/modules/opensearch/examples/getting_started/opensearch-security-config.yaml @@ -0,0 +1,94 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: opensearch-security-config +stringData: + action_groups.yml: | + --- + _meta: + type: actiongroups + config_version: 2 + allowlist.yml: | + --- + _meta: + type: allowlist + config_version: 2 + + config: + enabled: false + audit.yml: | + --- + _meta: + type: audit + config_version: 2 + + config: + enabled: false + config.yml: | + --- + _meta: + type: config + config_version: 2 + + config: + dynamic: + authc: + basic_internal_auth_domain: + description: Authenticate via HTTP Basic against internal users database + http_enabled: true + transport_enabled: true + order: 1 + http_authenticator: + type: basic + challenge: true + authentication_backend: + type: intern + authz: {} + internal_users.yml: | + --- + _meta: + type: internalusers + config_version: 2 + + admin: + hash: $2y$10$xRtHZFJ9QhG9GcYhRpAGpufCZYsk//nxsuel5URh0GWEBgmiI4Q/e + reserved: true + backend_roles: + - admin + description: OpenSearch admin user + + kibanaserver: + hash: $2y$10$vPgQ/6ilKDM5utawBqxoR.7euhVQ0qeGl8mPTeKhmFT475WUDrfQS + reserved: true + description: OpenSearch Dashboards user + nodes_dn.yml: | + --- + _meta: + type: nodesdn + config_version: 2 + roles.yml: | + --- + _meta: + type: roles + config_version: 2 + roles_mapping.yml: | + --- + _meta: + type: rolesmapping + config_version: 2 + + all_access: + reserved: false + backend_roles: + - admin + + kibana_server: + reserved: true + users: + - kibanaserver + tenants.yml: | + --- + _meta: + type: tenants + config_version: 2 diff --git a/docs/modules/opensearch/examples/getting_started/opensearch.yaml b/docs/modules/opensearch/examples/getting_started/opensearch.yaml new file mode 100644 index 0000000..24c44f6 --- /dev/null +++ b/docs/modules/opensearch/examples/getting_started/opensearch.yaml @@ -0,0 +1,58 @@ +--- +apiVersion: opensearch.stackable.tech/v1alpha1 +kind: OpenSearchCluster +metadata: + name: simple-opensearch +spec: + image: + custom: opensearchproject/opensearch:3.1.0 + productVersion: 3.1.0 + nodes: + roleGroups: + default: + replicas: 3 + envOverrides: + DISABLE_INSTALL_DEMO_CONFIG: "true" + configOverrides: + opensearch.yml: + plugins.security.allow_default_init_securityindex: "true" + plugins.security.restapi.roles_enabled: all_access + plugins.security.ssl.transport.enabled: "true" + plugins.security.ssl.transport.pemcert_filepath: /usr/share/opensearch/config/tls/tls.crt + plugins.security.ssl.transport.pemkey_filepath: /usr/share/opensearch/config/tls/tls.key + plugins.security.ssl.transport.pemtrustedcas_filepath: /usr/share/opensearch/config/tls/ca.crt + plugins.security.ssl.http.enabled: "true" + plugins.security.ssl.http.pemcert_filepath: /usr/share/opensearch/config/tls/tls.crt + plugins.security.ssl.http.pemkey_filepath: /usr/share/opensearch/config/tls/tls.key + plugins.security.ssl.http.pemtrustedcas_filepath: /usr/share/opensearch/config/tls/ca.crt + podOverrides: + spec: + containers: + - name: opensearch + volumeMounts: + - name: security-config + mountPath: /usr/share/opensearch/config/opensearch-security + readOnly: true + - name: tls + mountPath: /usr/share/opensearch/config/tls + readOnly: true + securityContext: + fsGroup: 1000 + volumes: + - name: security-config + secret: + secretName: opensearch-security-config + - name: tls + ephemeral: + volumeClaimTemplate: + metadata: + annotations: + secrets.stackable.tech/class: tls + secrets.stackable.tech/scope: node,pod,service=simple-opensearch,service=simple-opensearch-nodes-default + spec: + storageClassName: secrets.stackable.tech + accessModes: + - ReadWriteOnce + resources: + requests: + storage: "1" diff --git a/docs/modules/opensearch/examples/getting_started/test_getting_started_helm.sh b/docs/modules/opensearch/examples/getting_started/test_getting_started_helm.sh new file mode 100755 index 0000000..046c986 --- /dev/null +++ b/docs/modules/opensearch/examples/getting_started/test_getting_started_helm.sh @@ -0,0 +1,5 @@ +#! /usr/bin/env bash +set -euo pipefail + +cd "$(dirname "$0")" +./getting_started.sh helm diff --git a/docs/modules/opensearch/examples/getting_started/test_getting_started_stackablectl.sh b/docs/modules/opensearch/examples/getting_started/test_getting_started_stackablectl.sh new file mode 100755 index 0000000..9bcbe91 --- /dev/null +++ b/docs/modules/opensearch/examples/getting_started/test_getting_started_stackablectl.sh @@ -0,0 +1,5 @@ +#! /usr/bin/env bash +set -euo pipefail + +cd "$(dirname "$0")" +./getting_started.sh stackablectl diff --git a/docs/modules/opensearch/images/opensearch_overview.drawio.svg b/docs/modules/opensearch/images/opensearch_overview.drawio.svg new file mode 100644 index 0000000..90da284 --- /dev/null +++ b/docs/modules/opensearch/images/opensearch_overview.drawio.svg @@ -0,0 +1,4 @@ + + + +
Pod
<name>-nodes-<rg1>-1
Pod...
OpenSearch
Operator
OpenSearch...
StatefulSet
<name>-nodes-<rg1>
StatefulSet...
Service
<name>-nodes-<rg1>-headless
Service...
Pod
<name>-nodes-<rg1>-0
Pod...
ConfigMap
<name>-nodes-<rg1>
ConfigMap...
OpenSearchCluster
<name>
OpenSearchCluster...
create
create
read
read
Legend
Legend
Operator
Operator
Resource
Resource
Custom
Resource
Custom...
role group
<rg1>
role group...
StatefulSet
<name>-nodes-<rg2>
StatefulSet...
Service
<name>-nodes-<rg2>-headless
Service...
ConfigMap
<name>-nodes-<rg2>
ConfigMap...
Service
<name>
Service...
role
nodes
role...
references
references
role group
<rg2>
role group...
Pod
<name>-nodes-<rg2>-0
Pod...
Text is not SVG - cannot display
diff --git a/docs/modules/opensearch/pages/getting_started/first_steps.adoc b/docs/modules/opensearch/pages/getting_started/first_steps.adoc new file mode 100644 index 0000000..d0475af --- /dev/null +++ b/docs/modules/opensearch/pages/getting_started/first_steps.adoc @@ -0,0 +1,83 @@ += First steps + +Once you have followed the steps in xref:getting_started/installation.adoc[] for the operator and its dependencies, you will now go through the steps to set up and connect to an OpenSearch instance. + +== Security plugin configuration + +The configuration for the OpenSearch security plugin must be provided in a separate resource, e.g. a Secret: + +[source,yaml] +---- +include::example$getting_started/opensearch-security-config.yaml[] +---- + +Apply the Secret: + +[source,bash] +---- +include::example$getting_started/getting_started.sh[tag=apply-security-config] +---- + +The passwords in `internal_users.yml` are hashes using the bcrypt algorithm. +Such a hash can be e.g. generated with `htpasswd`: + +[source,bash] +---- +$ htpasswd -nbBC 10 admin AJVFsGJBbpT6mChnq +admin:$2y$10$xRtHZFJ9QhG9GcYhRpAGpufCZYsk//nxsuel5URh0GWEBgmiI4Q/e +---- + +== Creation of OpenSearch nodes + +OpenSearch nodes must be created as a custom resource; Create a file called `opensearch.yaml`: + +[source,yaml] +---- +include::example$getting_started/opensearch.yaml[] +---- + +And apply it: + +[source,bash] +---- +include::example$getting_started/getting_started.sh[tag=apply-cluster] +---- + +`metadata.name` contains the name of the OpenSearch cluster. + +The previously created security plugin configuration must be referenced via `podOverrides`. + +You need to wait for the OpenSearch nodes to finish deploying. +You can do so with this command: + +[source,bash] +---- +include::example$getting_started/getting_started.sh[tag=await-cluster] +---- + +== Connecting to the HTTP endpoint + +Once the OpenSearch nodes are created, you can use the REST API of OpenSearch. + +To forward the HTTP port (`9200`) to localhost, run: + +[source,bash] +---- +include::example$getting_started/getting_started.sh[tag=port-forwarding] +---- + +== Using the REST API + +You can use the REST API as follows: + +[source,bash] +---- +include::example$getting_started/getting_started.sh[tag=rest-api] +---- + +Great! +Now you can create your own indexes, populate them with data and search for it. + +== What's next + +Check the xref:usage-guide/index.adoc[] to find out more about configuring your OpenSearch instance or have a look at the OpenSearch documentation to https://docs.opensearch.org/docs/latest/getting-started/[ingest, search or visualize your data with OpenSearch Dashboards]. diff --git a/docs/modules/opensearch/pages/getting_started/index.adoc b/docs/modules/opensearch/pages/getting_started/index.adoc new file mode 100644 index 0000000..f52430c --- /dev/null +++ b/docs/modules/opensearch/pages/getting_started/index.adoc @@ -0,0 +1,24 @@ += Getting started + +This guide helps you get started with OpenSearch using the Stackable Operator. +It covers the installation of the operator and its dependencies, setting up your first OpenSearch instance, connecting to it, and ingesting and searching for data. + +== Prerequisites + +You’ll need the following: + +* a Kubernetes cluster +* kubectl +* Helm + +Resource sizing depends on cluster type(s), usage and scope, but as a starting point we recommend a minimum of the following resources for this operator: + +* 0.2 cores (e.g. i5 or similar) +* 256MB RAM + +== What's next + +The guide is divided into two steps: + +* xref:getting_started/installation.adoc[Installing the Operators] +* xref:getting_started/first_steps.adoc[Setting up the OpenSearch instance and connecting to it] diff --git a/docs/modules/opensearch/pages/getting_started/installation.adoc b/docs/modules/opensearch/pages/getting_started/installation.adoc new file mode 100644 index 0000000..2dd6a3f --- /dev/null +++ b/docs/modules/opensearch/pages/getting_started/installation.adoc @@ -0,0 +1,55 @@ += Installation + +On this page you will install the Stackable OpenSearch Operator as well as the commons, secret and listener operators which are required by all Stackable Operators. + +== Stackable Operators + +There are multiple ways to install the Stackable Operator for OpenSearch. +`stackablectl` is the preferred way but Helm is also supported. +OpenShift users may prefer installing the operator from the RedHat Certified Operator catalog using the OpenShift web console. + +[tabs] +==== +stackablectl (recommended):: ++ +-- +`stackablectl` is the command line tool to interact with Stackable operators and our recommended way to install +Operators. Follow the xref:management:stackablectl:installation.adoc[installation steps] for your platform. + +After you have installed `stackablectl`, run the following command to install all Operators necessary for OpenSearch: + +[source,bash] +---- +include::example$getting_started/getting_started.sh[tag=stackablectl-install-operators] +---- + +The tool will show + +[source] +include::example$getting_started/install_output.txt[] + +TIP: Consult the xref:management:stackablectl:quickstart.adoc[] to learn more about how to use `stackablectl`. +For example, you can use the `--cluster kind` flag to create a Kubernetes cluster with link:https://kind.sigs.k8s.io/[kind]. +-- + +Helm:: ++ +-- +You can also use Helm to install the Operators. + +NOTE: `helm repo` subcommands are not supported for OCI registries. The operators are installed directly, without adding the Helm Chart repository first. + +Install the Stackable Operators: +[source,bash] +---- +include::example$getting_started/getting_started.sh[tag=helm-install-operators] +---- + +Helm will deploy the operators in a Kubernetes Deployment and apply the CRDs for the OpenSearch service (as well as the CRDs for the required operators). +You are now ready to deploy OpenSearch in Kubernetes. +-- +==== + +== What's next + +xref:getting_started/first_steps.adoc[Deploy an OpenSearch instance and connect to it] diff --git a/docs/modules/opensearch/pages/index.adoc b/docs/modules/opensearch/pages/index.adoc new file mode 100644 index 0000000..6999773 --- /dev/null +++ b/docs/modules/opensearch/pages/index.adoc @@ -0,0 +1,63 @@ += Stackable Operator for OpenSearch +:description: Stackable Operator for OpenSearch manages OpenSearch clusters on Kubernetes for data ingestion and search +:keywords: Stackable operator, OpenSearch, Kubernetes, operator, data science, data exploration, search +:opensearch: https://opensearch.org/ +:crs: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/ +:github: https://github.com/stackabletech/opensearch-operator/ +:crd: {crd-docs-base-url}/opensearch-operator/{crd-docs-version}/ +:crd-opensearchcluster: {crd-docs}/opensearch.stackable.tech/opensearchcluster/v1alpha1/ +:feature-tracker: https://features.stackable.tech/unified + +[.link-bar] +* {github}[GitHub {external-link-icon}^] +* {feature-tracker}[Feature Tracker {external-link-icon}^] +* {crd}[CRD documentation {external-link-icon}^] + +The Stackable operator for {opensearch}[OpenSearch] deploys and manages OpenSearch clusters on Kubernetes. +OpenSearch is a powerful search and analytics engine built on Apache Lucene. +This operator helps you manage your OpenSearch instances on Kubernetes efficiently. + +== Getting started + +Get started using OpenSearch with the Stackable operator by following the xref:getting_started/index.adoc[]. +It guides you through installing the operator, connecting to your OpenSearch instance and using the REST API to ingest and search for data. + +== Operator model + +The operator manages the _OpenSearchCluster_ resource. +It creates a number of different Kubernetes resources based on this {crs}[custom resource]. + +=== Custom resources + +The OpenSearchCluster is the resource for the configuration of the OpenSearch instance. +The resource defines only one xref:concepts:roles-and-role-groups.adoc#roles[role], the `nodes`. +The various configuration options are explained in the xref:usage-guide/index.adoc[]. +It helps you tune your cluster to your needs by configuring xref:usage-guide/storage-resource-configuration.adoc[resource usage] and more. + +=== Kubernetes resources + +Based on the custom resources you define, the operator creates ConfigMaps, StatefulSets and Services. + +image::opensearch_overview.drawio.svg[A diagram depicting the Kubernetes resources created by the operator] + +The diagram above depicts all the Kubernetes resources created by the operator, and how they relate to each other. + +For every xref:concepts:roles-and-role-groups.adoc#role-groups[role group] you define, the operator creates a StatefulSet with the amount of replicas defined in the role group. +For every role group, a Service is created, as well as one for the whole cluster that references the cluster manager nodes. + +Additionally, a ConfigMap is created for each role group. +These ConfigMaps contain configuration files like `opensearch.yml`. + +== Supported versions + +The Stackable operator for OpenSearch currently supports the OpenSearch versions listed below. +To use a specific OpenSearch version in your OpenSearchCluster, you have to specify an image - this is explained in the xref:concepts:product-image-selection.adoc[] documentation. +The operator also supports running images from a custom registry or running entirely customized images; both of these cases are explained under xref:concepts:product-image-selection.adoc[] as well. + +include::partial$supported-versions.adoc[] + +== Useful links + +* The {github}[opensearch-operator {external-link-icon}^] GitHub repository +* The operator feature overview in the {feature-tracker}[feature tracker {external-link-icon}^] +* The {crd-opensearchcluster}[OpenSearchCluster {external-link-icon}^] CRD documentation diff --git a/docs/modules/opensearch/pages/reference/commandline-parameters.adoc b/docs/modules/opensearch/pages/reference/commandline-parameters.adoc new file mode 100644 index 0000000..465caa7 --- /dev/null +++ b/docs/modules/opensearch/pages/reference/commandline-parameters.adoc @@ -0,0 +1,18 @@ += Command Line Parameters + +This operator accepts the following command line parameters: + +== watch-namespace + +*Default value*: All namespaces + +*Required*: false + +*Multiple values:* false + +The operator will **only** watch for resources in the provided namespace `test`: + +[source] +---- +stackable-opensearch-operator run --watch-namespace test +---- diff --git a/docs/modules/opensearch/pages/reference/crds.adoc b/docs/modules/opensearch/pages/reference/crds.adoc new file mode 100644 index 0000000..150f51b --- /dev/null +++ b/docs/modules/opensearch/pages/reference/crds.adoc @@ -0,0 +1,3 @@ += CRD Reference + +Find all CRD references for the Stackable Operator for OpenSearch at: {crd-docs-base-url}/opensearch-operator/{crd-docs-version} diff --git a/docs/modules/opensearch/pages/reference/environment-variables.adoc b/docs/modules/opensearch/pages/reference/environment-variables.adoc new file mode 100644 index 0000000..60bca30 --- /dev/null +++ b/docs/modules/opensearch/pages/reference/environment-variables.adoc @@ -0,0 +1,63 @@ += Environment variables + +This operator accepts the following environment variables: + +== KUBERNETES_CLUSTER_DOMAIN + +*Default value*: cluster.local + +*Required*: false + +*Multiple values*: false + +This instructs the operator, which value it should use for the Kubernetes `clusterDomain` setting. +Make sure to keep this in sync with whatever setting your cluster uses. +Please see the documentation xref:guides:kubernetes-cluster-domain.adoc[on configuring the Kubernetes cluster domain] for more information on this feature. + +[source] +---- +export KUBERNETES_CLUSTER_DOMAIN=mycluster.local +cargo run -- run +---- + +or via docker: + +[source] +---- +docker run \ +--name opensearch-operator \ +--network host \ +--env KUBECONFIG=/home/stackable/.kube/config \ +--env KUBERNETES_CLUSTER_DOMAIN=mycluster.local \ +--mount type=bind,source="$HOME/.kube/config",target="/home/stackable/.kube/config" \ +oci.stackable.tech/sdp/opensearch-operator:0.0.0-dev +---- + +== WATCH_NAMESPACE + +*Default value*: All namespaces + +*Required*: false + +*Multiple values*: false + +The operator will **only** watch for resources in the provided namespace `test`: + +[source] +---- +export WATCH_NAMESPACE=test +stackable-opensearch-operator run +---- + +or via docker: + +[source] +---- +docker run \ +--name opensearch-operator \ +--network host \ +--env KUBECONFIG=/home/stackable/.kube/config \ +--env WATCH_NAMESPACE=test \ +--mount type=bind,source="$HOME/.kube/config",target="/home/stackable/.kube/config" \ +oci.stackable.tech/sdp/opensearch-operator:0.0.0-dev +---- diff --git a/docs/modules/opensearch/pages/reference/index.adoc b/docs/modules/opensearch/pages/reference/index.adoc new file mode 100644 index 0000000..3cfa028 --- /dev/null +++ b/docs/modules/opensearch/pages/reference/index.adoc @@ -0,0 +1,6 @@ += Reference + +Consult the reference documentation section to find exhaustive information on: + +* Descriptions and default values of all properties in the CRDs used by this operator in the xref:reference/crds.adoc[]. +* The xref:reference/commandline-parameters.adoc[] and xref:reference/environment-variables.adoc[] accepted by the operator. diff --git a/docs/modules/opensearch/pages/usage-guide/configuration-environment-overrides.adoc b/docs/modules/opensearch/pages/usage-guide/configuration-environment-overrides.adoc new file mode 100644 index 0000000..ec12a53 --- /dev/null +++ b/docs/modules/opensearch/pages/usage-guide/configuration-environment-overrides.adoc @@ -0,0 +1,178 @@ += Configuration & Environment Overrides + +The cluster definition also supports overriding configuration properties, environment variables and CLI parameters, +either per role or per role group, where the more specific override (role group) has precedence over +the less specific one (role). + +IMPORTANT: Overriding certain properties which are set by the operator (such as the `network.host`) can interfere with the operator and can lead to problems. + +== Configuration Properties + +For a role or role group, at the same level of `config`, you can specify `configOverrides` for the `opensearch.yml`. +For example, if you want to enable role-based access to the REST management API for the role `all_access` (not to be confused with the OpenSearch node role), then adapt the cluster resource as follows: + +[source,yaml] +---- +nodes: + roleGroups: + default: + config: {} + configOverrides: + opensearch.yml: + plugins.security.restapi.roles_enabled: all_access +---- + +Just as for the `config`, it is possible to specify this at the role level as well: + +[source,yaml] +---- +nodes: + configOverrides: + opensearch.yml: + plugins.security.restapi.roles_enabled: all_access + roleGroups: + default: + config: {} +---- + +All override property values must be strings. +They are added unchanged to the configuration file. +Care must be taken to produce a valid configuration. + +For a list of configuration options, we refer to the +https://docs.opensearch.org/docs/latest/install-and-configure/configuring-opensearch/index/[Configuring OpenSearch] section in the OpenSearch documentation. + +The file `opensearch.yml` is a YAML file, where deep structures are possible. +On the other hand, `configOverrides` are only flat key-value pairs. +Fortunately, this is not a problem because the OpenSearch YAML parser allows both representations. +Keys can be flattened as follows: + +[source,yaml] +---- +# File: opensearch.yml + +plugins.security.restapi.roles_enabled: all_access + +# is equivalent to + +plugins: + security: + restapi: + roles_enabled: all_access +---- + +Lists can be flattened as follows: + +[source,yaml] +---- +# File: opensearch.yml + +# as a comma-separated list: <1> +plugins.security.restapi.roles_enabled: role1,role2,role3 + +# as a JSON list: <2> +plugins.security.restapi.roles_enabled: ["role1", "role2", "role3"] + +# as an indexed flat list: <3> +plugins.security.restapi.roles_enabled.0: role1 +plugins.security.restapi.roles_enabled.1: role2 +plugins.security.restapi.roles_enabled.2: role3 + +# All options above are equivalent to + +plugins: + security: + restapi: + roles_enabled: + - role1 + - role2 + - role3 +---- +<1> Commas in list entries cannot be escaped. +<2> The brackets must be escaped in `configOverrides` as follows: `"[\"role1\", \"role2\", \"role3\"]"` +<3> Indexed flat lists are considered "legacy" in the OpenSearch code. +// see https://github.com/opensearch-project/OpenSearch/blob/3.1.0/server/src/main/java/org/opensearch/common/settings/Settings.java#L1049 + +Other types can be set as strings in `configOverrides` because OpenSearch parses them: + +[source,yaml] +---- +# File: opensearch.yml + +# Boolean as string +cluster.blocks.read_only: "true" + +# Integer as string +cluster.max_shards_per_node: "10000" + +# Floating point as string +cluster.routing.allocation.balance.index: "0.6" + +# Time unit as string +cluster.info.update.interval: "10s" + +# The options above are equivalent to + +cluster.blocks.read_only: true +cluster.max_shards_per_node: 10000 +cluster.routing.allocation.balance.index: 0.6 +cluster.info.update.interval: 10s +---- + +== Environment Variables + +In a similar fashion, environment variables can be (over)written. +For example per role group: + +[source,yaml] +---- +nodes: + roleGroups: + default: + config: {} + envOverrides: + OPENSEARCH_PATH_CONF: /etc/opensearch +---- + +or per role: + +[source,yaml] +---- +nodes: + envOverrides: + OPENSEARCH_PATH_CONF: /etc/opensearch + roleGroups: + default: + config: {} +---- + +== CLI parameters + +CLI parameters can be set with `cliOverrides` per role group: + +[source,yaml] +---- +nodes: + roleGroups: + default: + config: {} + cliOverrides: + --pidfile: /tmp/mypidfile.pid +---- + +or per role: + +[source,yaml] +---- +nodes: + cliOverrides: + --pidfile: /tmp/mypidfile.pid + roleGroups: + default: + config: {} +---- + +== Pod overrides + +The OpenSearch operator also supports Pod overrides, allowing you to override any property that you can set on a Kubernetes Pod. +Read the xref:concepts:overrides.adoc#pod-overrides[Pod overrides documentation] to learn more about this feature. diff --git a/docs/modules/opensearch/pages/usage-guide/index.adoc b/docs/modules/opensearch/pages/usage-guide/index.adoc new file mode 100644 index 0000000..bba2c8e --- /dev/null +++ b/docs/modules/opensearch/pages/usage-guide/index.adoc @@ -0,0 +1,7 @@ += Usage guide +:page-aliases: usage.doc +:description: OpenSearch usage guide: configure resources and override configurations. + +The usage guide covers various aspects of configuring OpenSearch. + +Learn about xref:usage-guide/node-roles.adoc[] or defining the amount of xref:usage-guide/storage-resource-configuration.adoc[resources] OpenSearch uses. diff --git a/docs/modules/opensearch/pages/usage-guide/node-roles.adoc b/docs/modules/opensearch/pages/usage-guide/node-roles.adoc new file mode 100644 index 0000000..4734604 --- /dev/null +++ b/docs/modules/opensearch/pages/usage-guide/node-roles.adoc @@ -0,0 +1,68 @@ += Assigning roles to nodes +:description: Configure OpenSearch node roles + +An OpenSearch node can fulfill different roles, e.g. it can manage the operation of a cluster or store and search data. + +All nodes are defined under the role `nodes`. +The role configuration already defaults to a set of node roles: + +[source,yaml] +---- +nodes: + config: + nodeRoles: + - cluster_manager + - data + - ingest + - remote_cluster_client +---- + +If you deploy a cluster with the following specification, then 3 replicas with the roles `cluster_manager`, `data`, `ingest` and `remote_cluster_client` are deployed: + +[source,yaml] +---- +nodes: + roleGroups: + default: + replicas: 3 +---- + +In a production cluster, you probably want to assign different roles to the nodes. +This can be achieved by creating multiple role groups and configuring their node roles. +The node roles configured at the role group level override the ones from the role level. + +For instance, if you want to deploy https://docs.opensearch.org/docs/latest/tuning-your-cluster/[the sample cluster from the OpenSearch documentation] that has one dedicated cluster manager node, one dedicated coordinating node and two data nodes, you could configure the role groups as follows: + +[source,yaml] +---- +nodes: + roleGroups: + cluster-manager: + config: + nodeRoles: + - cluster_manager + replicas: 1 + coordinating: + config: + nodeRoles: + - coordinating_only + replicas: 1 + data: + config: + nodeRoles: + - data + - ingest + replicas: 2 +---- + +The following roles are currently supported by the operator: + +* `cluster_manager` +* `coordinating_only` +* `data` +* `ingest` +* `remote_cluster_client` +* `search` +* `warm` + +We refer to https://docs.opensearch.org/docs/latest/install-and-configure/configuring-opensearch/configuration-system/[the OpenSearch documentation] for an explanation of the roles. diff --git a/docs/modules/opensearch/pages/usage-guide/operations/cluster-operations.adoc b/docs/modules/opensearch/pages/usage-guide/operations/cluster-operations.adoc new file mode 100644 index 0000000..29482a3 --- /dev/null +++ b/docs/modules/opensearch/pages/usage-guide/operations/cluster-operations.adoc @@ -0,0 +1,4 @@ += Cluster Operation + +OpenSearch installations can be configured with different cluster operations like pausing reconciliation or stopping the cluster. +See xref:concepts:operations/cluster_operations.adoc[cluster operations] for more details. diff --git a/docs/modules/opensearch/pages/usage-guide/operations/graceful-shutdown.adoc b/docs/modules/opensearch/pages/usage-guide/operations/graceful-shutdown.adoc new file mode 100644 index 0000000..48ecd8a --- /dev/null +++ b/docs/modules/opensearch/pages/usage-guide/operations/graceful-shutdown.adoc @@ -0,0 +1,34 @@ += Graceful shutdown + +You can configure the graceful shutdown as described in xref:concepts:operations/graceful_shutdown.adoc[]. + +== Nodes + +As a default, OpenSearch nodes have 2 minutes to shut down gracefully. + +The OpenSearch node process will receive a `SIGTERM` signal when Kubernetes wants to terminate the Pod. +It will log the received signal as shown in the log below and initiate a graceful shutdown. +After the graceful shutdown timeout runs out, and the process still did not exit, Kubernetes will issue a `SIGKILL` signal. + +[source,text] +---- +[o.o.s.a.r.AuditMessageRouter] Closing AuditMessageRouter +[o.o.n.Node ] stopping ... +[o.o.s.a.s.SinkProvider ] Closing DebugSink +[o.o.c.c.FollowersChecker ] FollowerChecker{discoveryNode={simple-opensearch-nodes-default-3}{jcXCasAwSf6wTxND431bnw}{KFX1ua4GQpOZc1wdfY5RdA}{10.244.0.22}{10.244.0.22:9300}{dimr}{shard_indexing_pressure_enabled=true}, failureCountSinceLastSuccess=0, [cluster.fault_detection.follower_check.retry_count]=3} disconnected +[o.o.c.c.FollowersChecker ] FollowerChecker{discoveryNode={simple-opensearch-nodes-default-0}{_HWwfRHWSk-0l2FIYWZerw}{voEOdPrxRsifVO0fema60Q}{10.244.0.26}{10.244.0.26:9300}{dimr}{shard_indexing_pressure_enabled=true}, failureCountSinceLastSuccess=0, [cluster.fault_detection.follower_check.retry_count]=3} disconnected +[o.o.c.c.FollowersChecker ] FollowerChecker{discoveryNode={simple-opensearch-nodes-default-3}{jcXCasAwSf6wTxND431bnw}{KFX1ua4GQpOZc1wdfY5RdA}{10.244.0.22}{10.244.0.22:9300}{dimr}{shard_indexing_pressure_enabled=true}, failureCountSinceLastSuccess=0, [cluster.fault_detection.follower_check.retry_count]=3} marking + +[o.o.c.c.FollowersChecker ] FollowerChecker{discoveryNode={simple-opensearch-nodes-default-2}{NudYVGdNSbClz-e09TVElg}{MmWiswEsQo6MpuDG47a6Ag}{10.244.0.24}{10.244.0.24:9300}{dimr}{shard_indexing_pressure_enabled=true}, failureCountSinceLastSuccess=0, [cluster.fault_detection.follower_check.retry_count]=3} disconnected +[o.o.c.c.FollowersChecker ] FollowerChecker{discoveryNode={simple-opensearch-nodes-default-1}{NSxqrrevSIOtCIWz9Hd9vw}{qHNTBP4NTqe09_-9ZqnUJQ}{10.244.0.25}{10.244.0.25:9300}{dimr}{shard_indexing_pressure_enabled=true}, failureCountSinceLastSuccess=0, [cluster.fault_detection.follower_check.retry_count]=3} disconnected +[o.o.c.c.FollowersChecker ] FollowerChecker{discoveryNode={simple-opensearch-nodes-default-0}{_HWwfRHWSk-0l2FIYWZerw}{voEOdPrxRsifVO0fema60Q}{10.244.0.26}{10.244.0.26:9300}{dimr}{shard_indexing_pressure_enabled=true}, failureCountSinceLastSuccess=0, [cluster.fault_detection.follower_check.retry_count]=3} marking + +[o.o.c.c.FollowersChecker ] FollowerChecker{discoveryNode={simple-opensearch-nodes-default-1}{NSxqrrevSIOtCIWz9Hd9vw}{qHNTBP4NTqe09_-9ZqnUJQ}{10.244.0.25}{10.244.0.25:9300}{dimr}{shard_indexing_pressure_enabled=true}, failureCountSinceLastSuccess=0, [cluster.fault_detection.follower_check.retry_count]=3} marking + +[o.o.c.c.FollowersChecker ] FollowerChecker{discoveryNode={simple-opensearch-nodes-default-2}{NudYVGdNSbClz-e09TVElg}{MmWiswEsQo6MpuDG47a6Ag}{10.244.0.24}{10.244.0.24:9300}{dimr}{shard_indexing_pressure_enabled=true}, failureCountSinceLastSuccess=0, [cluster.fault_detection.follower_check.retry_count]=3} marking + +[o.o.n.Node ] stopped +[o.o.n.Node ] closing ... +[o.o.s.a.i.AuditLogImpl ] Closing AuditLogImpl +[o.o.n.Node ] closed +---- diff --git a/docs/modules/opensearch/pages/usage-guide/operations/index.adoc b/docs/modules/opensearch/pages/usage-guide/operations/index.adoc new file mode 100644 index 0000000..21d170f --- /dev/null +++ b/docs/modules/opensearch/pages/usage-guide/operations/index.adoc @@ -0,0 +1,5 @@ += Operations + +This section of the documentation is intended for the operations teams that maintain a Stackable Data Platform installation. + +Please read the xref:concepts:operations/index.adoc[Concepts page on Operations] that contains the necessary details to operate the platform in a production environment. diff --git a/docs/modules/opensearch/pages/usage-guide/operations/pod-disruptions.adoc b/docs/modules/opensearch/pages/usage-guide/operations/pod-disruptions.adoc new file mode 100644 index 0000000..82c059f --- /dev/null +++ b/docs/modules/opensearch/pages/usage-guide/operations/pod-disruptions.adoc @@ -0,0 +1,9 @@ += Allowed Pod disruptions + +You can configure the permitted Pod disruptions for OpenSearch nodes as described in xref:concepts:operations/pod_disruptions.adoc[]. + +Unless you configure something else or disable the provided PodDisruptionBudgets (PDBs), the following PDBs are written: + +== Nodes + +The provided PDBs only allow a single node to be offline at any given time, regardless of the number of replicas or role groups. diff --git a/docs/modules/opensearch/pages/usage-guide/operations/pod-placement.adoc b/docs/modules/opensearch/pages/usage-guide/operations/pod-placement.adoc new file mode 100644 index 0000000..d697db5 --- /dev/null +++ b/docs/modules/opensearch/pages/usage-guide/operations/pod-placement.adoc @@ -0,0 +1,7 @@ += Pod Placement + +You can configure the Pod placement of the OpenSearch pods as described in xref:concepts:operations/pod_placement.adoc[]. + +The default affinities created by the operator are: + +1. Distribute all the OpenSearch pods (weight 1) diff --git a/docs/modules/opensearch/pages/usage-guide/storage-resource-configuration.adoc b/docs/modules/opensearch/pages/usage-guide/storage-resource-configuration.adoc new file mode 100644 index 0000000..5991474 --- /dev/null +++ b/docs/modules/opensearch/pages/usage-guide/storage-resource-configuration.adoc @@ -0,0 +1,57 @@ += Storage and resource configuration +:description: Configure storage and resource allocation for OpenSearch nodes using Stackable Operator, including PersistentVolumeClaims, CPU, memory, and storage defaults. + +== Storage for data volumes + +You can mount volumes where data is stored by specifying https://kubernetes.io/docs/concepts/storage/persistent-volumes[PersistentVolumeClaims] for each individual role group: + +[source,yaml] +---- +nodes: + roleGroups: + data: + config: + resources: + storage: + logDirs: + capacity: 50Gi +---- + +In the example above, all OpenSearch nodes in the data role group store data (the location of the property `path.data`) on a `50Gi` volume. + +If nothing is configured in the custom resource for a certain role group, then by default each Pod has an `8Gi` large local volume mount for the data location. + +On role groups with only the `cluster_manager` node role, you probably want to decrease this value, but increase it on role groups with the `data` node role. + +== Resource Requests + +include::home:concepts:stackable_resource_requests.adoc[] + +A minimal HA setup consisting of 3 nodes has the following https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/[resource requirements]: + +* `300m` CPU request +* `1200m` CPU limit +* `4800Mi` memory request and limit + +Of course, additional services require additional resources. +For Stackable components, see the corresponding documentation on further resource requirements. + +Corresponding to the values above, the operator uses the following resource defaults: + +[source,yaml] +---- +nodes: + roleGroups: + default: + config: + resources: + cpu: + min: "1" + max: "4" + memory: + limit: 2Gi + storage: + data: 8Gi +---- + +WARNING: The default values are _most likely_ not sufficient to run a production cluster. Please adapt according to your requirements. diff --git a/docs/modules/opensearch/partials/nav.adoc b/docs/modules/opensearch/partials/nav.adoc new file mode 100644 index 0000000..c21e7d5 --- /dev/null +++ b/docs/modules/opensearch/partials/nav.adoc @@ -0,0 +1,17 @@ +* xref:opensearch:getting_started/index.adoc[] +** xref:opensearch:getting_started/installation.adoc[] +** xref:opensearch:getting_started/first_steps.adoc[] +* xref:opensearch:usage-guide/index.adoc[] +** xref:opensearch:usage-guide/node-roles.adoc[] +** xref:opensearch:usage-guide/storage-resource-configuration.adoc[] +** xref:opensearch:usage-guide/configuration-environment-overrides.adoc[] +** xref:opensearch:usage-guide/operations/index.adoc[] +*** xref:opensearch:usage-guide/operations/cluster-operations.adoc[] +*** xref:opensearch:usage-guide/operations/pod-placement.adoc[] +*** xref:opensearch:usage-guide/operations/pod-disruptions.adoc[] +*** xref:opensearch:usage-guide/operations/graceful-shutdown.adoc[] +* xref:opensearch:reference/index.adoc[] +** xref:opensearch:reference/crds.adoc[] +*** {crd-docs}/opensearch.stackable.tech/opensearchcluster/v1alpha1/[OpenSearchCluster {external-link-icon}^] +** xref:opensearch:reference/commandline-parameters.adoc[] +** xref:opensearch:reference/environment-variables.adoc[] diff --git a/docs/modules/opensearch/partials/supported-versions.adoc b/docs/modules/opensearch/partials/supported-versions.adoc new file mode 100644 index 0000000..4286ea8 --- /dev/null +++ b/docs/modules/opensearch/partials/supported-versions.adoc @@ -0,0 +1,5 @@ +// The version ranges supported by OpenSearch-Operator +// This is a separate file, since it is used by both the direct OpenSearch documentation, and the overarching +// Stackable Platform documentation. + +- 3.1.0 (LTS) diff --git a/docs/templating_vars.yaml b/docs/templating_vars.yaml new file mode 100644 index 0000000..91114a9 --- /dev/null +++ b/docs/templating_vars.yaml @@ -0,0 +1,9 @@ +--- +helm: + repo_name: sdp-charts + repo_url: oci.stackable.tech +versions: + commons: 0.0.0-dev + secret: 0.0.0-dev + listener: 0.0.0-dev + opensearch: 0.0.0-dev diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 1c5c69d..ce1eabb 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -84,12 +84,14 @@ pub mod versioned { // see https://github.com/opensearch-project/OpenSearch/blob/3.0.0/server/src/main/java/org/opensearch/cluster/node/DiscoveryNodeRole.java#L341-L346 // TODO https://github.com/Peternator7/strum/issues/113 + #[strum(serialize = "cluster_manager")] + ClusterManager, + #[strum(serialize = "coordinating_only")] + CoordinatingOnly, #[strum(serialize = "data")] Data, #[strum(serialize = "ingest")] Ingest, - #[strum(serialize = "cluster_manager")] - ClusterManager, #[strum(serialize = "remote_cluster_client")] RemoteClusterClient, #[strum(serialize = "warm")]