diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 29def4b28..f2e46a729 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -67,6 +67,12 @@ jobs:
kubectl create -f https://github.com/kubedb/installer/raw/master/crds/kubedb-crds.yaml
kubectl create -f https://github.com/kubernetes-csi/external-snapshotter/raw/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
kubectl create -f https://github.com/kubestash/installer/raw/master/crds/kubestash-crds.yaml
+ # recommendation
+ kubectl create -f https://github.com/kubeops/supervisor/raw/master/crds/supervisor.appscode.com_approvalpolicies.yaml
+ kubectl create -f https://github.com/kubeops/supervisor/raw/master/crds/supervisor.appscode.com_clustermaintenancewindows.yaml
+ kubectl create -f https://github.com/kubeops/supervisor/raw/master/crds/supervisor.appscode.com_maintenancewindows.yaml
+ kubectl create -f https://github.com/kubeops/supervisor/raw/master/crds/supervisor.appscode.com_recommendations.yaml
+ # gateway
kubectl create -f https://github.com/appscode-cloud/catalog/raw/master/crds/catalog.appscode.com_mongodbbindings.yaml
kubectl create -f https://raw.githubusercontent.com/envoyproxy/gateway/refs/heads/main/charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
kubectl create -f https://github.com/voyagermesh/installer/raw/master/charts/gateway-api/crds/gateway.networking.k8s.io_gatewayclasses.yaml
diff --git a/docs/README.md b/docs/README.md
index d4aeca9cd..fe84a26d7 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -25,6 +25,10 @@ From here you can learn all about KubeDB's architecture and how to deploy and us
- [Guides](/docs/guides/). Guides to show you how to perform tasks with KubeDB.
+<<<<<<< om
+- [Operator Manual](/docs/operatormanual/). Guides to show you how to perform tasks with KubeDB.
+=======
+>>>>>>> master
- Detailed exhaustive lists of command-line options, configuration options, API definitions, and procedures. Specially, [CLI](/docs/reference/cli/), [operator](/docs/reference/operator/) & [webhook-server](/docs/reference/webhook-server/).
diff --git a/docs/guides/cassandra/quickstart/guide/quickstart.md b/docs/guides/cassandra/quickstart/guide/quickstart.md
index 82a37a640..d86d2ce43 100644
--- a/docs/guides/cassandra/quickstart/guide/quickstart.md
+++ b/docs/guides/cassandra/quickstart/guide/quickstart.md
@@ -37,7 +37,7 @@ NAME STATUS AGE
demo Active 9s
```
-> Note: YAML files used in this tutorial are stored in [guides/cassandra/quickstart/overview/yamls](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/guides/cassandra/quickstart/overview/yamls) folder in GitHub repository [kubedb/docs](https://github.com/kubedb/docs).
+> Note: YAML files used in this tutorial are stored in [guides/cassandra/quickstart](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/guides/cassandra/quickstart) folder in GitHub repository [kubedb/docs](https://github.com/kubedb/docs).
## Find Available StorageClass
diff --git a/docs/guides/elasticsearch/quickstart/overview/elasticsearch/index.md b/docs/guides/elasticsearch/quickstart/overview/elasticsearch/index.md
index c57905e0f..3d2370690 100644
--- a/docs/guides/elasticsearch/quickstart/overview/elasticsearch/index.md
+++ b/docs/guides/elasticsearch/quickstart/overview/elasticsearch/index.md
@@ -46,9 +46,9 @@ demo Active 9s
We will have to provide `StorageClass` in Elasticsearch CRD specification. Check available `StorageClass` in your cluster using the following command,
```bash
-$ kubectl get storageclass
-NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
-standard (default) rancher.io/local-path Delete WaitForFirstConsumer false 14h
+$ kubectl get storageclass
+NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
+local-path (default) rancher.io/local-path Delete WaitForFirstConsumer false 5d2h
```
Here, we have `standard` StorageClass in our cluster from [Local Path Provisioner](https://github.com/rancher/local-path-provisioner).
@@ -63,7 +63,7 @@ NAME VERSION DISTRIBUTION DB_IMAGE
kubedb-searchguard-5.6.16 5.6.16 KubeDB kubedb/elasticsearch:5.6.16-searchguard-v2022.02.22 4h24m
kubedb-xpack-7.12.0 7.12.0 KubeDB kubedb/elasticsearch:7.12.0-xpack-v2021.08.23 4h24m
kubedb-xpack-7.13.2 7.13.2 KubeDB kubedb/elasticsearch:7.13.2-xpack-v2021.08.23 4h24m
-xpack-8.19.9 7.14.0 KubeDB kubedb/elasticsearch:7.14.0-xpack-v2021.08.23 4h24m
+xpack-8.19.9 7.14.0 KubeDB kubedb/elasticsearch:7.14.0-xpack-v2021.08.23 4h24m
kubedb-xpack-8.19.9 7.16.2 KubeDB kubedb/elasticsearch:7.16.2-xpack-v2021.12.24 4h24m
kubedb-xpack-7.9.1 7.9.1 KubeDB kubedb/elasticsearch:7.9.1-xpack-v2021.08.23 4h24m
kubedb-xpack-8.2.3 8.2.0 KubeDB kubedb/elasticsearch:8.2.0-xpack-v2022.05.24 4h24m
@@ -99,12 +99,12 @@ searchguard-7.0.1-v1 7.0.1 SearchGuard floragunncom/sg-elasticsear
searchguard-7.1.1 7.1.1 SearchGuard floragunncom/sg-elasticsearch:7.1.1-oss-35.0.0 4h24m
searchguard-7.1.1-v1 7.1.1 SearchGuard floragunncom/sg-elasticsearch:7.1.1-oss-35.0.0 4h24m
searchguard-7.10.2 7.10.2 SearchGuard floragunncom/sg-elasticsearch:7.10.2-oss-49.0.0 4h24m
-xpack-8.19.9 7.14.2 SearchGuard floragunncom/sg-elasticsearch:7.14.2-52.3.0 4h24m
+xpack-8.19.9 7.14.2 SearchGuard floragunncom/sg-elasticsearch:7.14.2-52.3.0 4h24m
searchguard-7.3.2 7.3.2 SearchGuard floragunncom/sg-elasticsearch:7.3.2-oss-37.0.0 4h24m
searchguard-7.5.2 7.5.2 SearchGuard floragunncom/sg-elasticsearch:7.5.2-oss-40.0.0 4h24m
-xpack-8.19.9 7.5.2 SearchGuard floragunncom/sg-elasticsearch:7.5.2-oss-40.0.0 4h24m
+xpack-8.19.9 7.5.2 SearchGuard floragunncom/sg-elasticsearch:7.5.2-oss-40.0.0 4h24m
searchguard-7.8.1 7.8.1 SearchGuard floragunncom/sg-elasticsearch:7.8.1-oss-43.0.0 4h24m
-xpack-8.19.9 7.9.3 SearchGuard floragunncom/sg-elasticsearch:7.9.3-oss-47.1.0 4h24m
+xpack-8.19.9 7.9.3 SearchGuard floragunncom/sg-elasticsearch:7.9.3-oss-47.1.0 4h24m
xpack-6.8.10-v1 6.8.10 ElasticStack elasticsearch:6.8.10 4h24m
xpack-6.8.16 6.8.16 ElasticStack elasticsearch:6.8.16 4h24m
xpack-6.8.22 6.8.22 ElasticStack elasticsearch:6.8.22 4h24m
@@ -123,7 +123,7 @@ xpack-7.5.2-v1 7.5.2 ElasticStack elasticsearch:7.5.2
xpack-7.6.2-v1 7.6.2 ElasticStack elasticsearch:7.6.2 4h24m
xpack-7.7.1-v1 7.7.1 ElasticStack elasticsearch:7.7.1 4h24m
xpack-7.8.0-v1 7.8.0 ElasticStack elasticsearch:7.8.0 4h24m
-xpack-8.19.9 7.9.1 ElasticStack elasticsearch:7.9.1 4h24m
+xpack-8.19.9 7.9.1 ElasticStack elasticsearch:7.9.1 4h24m
xpack-7.9.1-v2 7.9.1 ElasticStack elasticsearch:7.9.1 4h24m
xpack-8.2.3 8.2.0 ElasticStack elasticsearch:8.2.0 4h24m
xpack-8.5.2 8.5.2 ElasticStack elasticsearch:8.5.2 4h24m
diff --git a/docs/guides/elasticsearch/recommendation/index.md b/docs/guides/elasticsearch/recommendation/index.md
new file mode 100644
index 000000000..3f529f875
--- /dev/null
+++ b/docs/guides/elasticsearch/recommendation/index.md
@@ -0,0 +1,193 @@
+---
+title: Elasticsearch Recommendation
+menu:
+ docs_{{ .version }}:
+ identifier: es-recommendation-elasticsearch
+ name: Recommendation
+ parent: es-elasticsearch-guides
+ weight: 130
+menu_name: docs_{{ .version }}
+section_menu_id: guides
+---
+
+> New to KubeDB? Please start [here](/docs/README.md).
+
+---
+
+## Elasticsearch Recommendation
+
+### Overview
+
+`Elasticsearch Recommendation` is a Kubernetes Custom Resource Definition (CRD) generated by the KubeDB Ops Manager. It continuously analyzes managed Elasticsearch clusters and produces actionable recommendations for essential maintenance and lifecycle operations.
+
+These recommendations help operators proactively manage their database systems by identifying when to perform tasks such as:
+- Version upgrades
+- TLS certificate rotation
+- Authentication credential rotation
+
+Each recommendation can be reviewed and executed manually or integrated into automated operational workflows, improving overall system reliability, security, and maintainability.
+
+
+
+
+
+---
+
+## Prerequisites
+
+Before proceeding, ensure that the following requirements are met:
+
+- A running Kubernetes cluster
+- `kubectl` configured to communicate with the cluster
+- A cluster provisioned using tools like [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) (if not already available)
+
+- KubeDB operator installed following the guide [here](/docs/setup/install/_index.md)
+
+- Supervisor component enabled during installation:
+```bash
+ --set supervisor.enabled=true
+````
+
+* A dedicated namespace for running examples:
+
+```bash
+$ kubectl create namespace demo
+$ kubectl get namespace
+
+```
+
+## Find Available StorageClass
+
+We will have to provide `StorageClass` in Elasticsearch CRD specification. Check available `StorageClass` in your cluster using the following command,
+
+```bash
+$ kubectl get storageclass
+NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
+local-path (default) rancher.io/local-path Delete WaitForFirstConsumer false 5d2h
+```
+
+Here, we have `local-path` StorageClass in our cluster from [Local Path Provisioner](https://github.com/rancher/local-path-provisioner).
+
+> This document provides a high-level overview with illustrative examples. To fully understand and apply these recommendations in your database, follow the linked guides and the [Recommendation Overview](/docs/operatormanual/recommendation/overview.md)
+---
+
+## Recommendation Types
+
+KubeDB currently supports the following recommendation categories for Elasticsearch:
+
+1. [Version Update Recommendation](/docs/operatormanual/recommendation/version-update-recommendation.md)
+2. [TLS Certificate Rotation Recommendation](/docs/operatormanual/recommendation/rotate-tls-recommendation.md)
+3. [Authentication Secret Rotation Recommendation](/docs/operatormanual/recommendation/rotate-auth-recommendation.md)
+
+These recommendations are generated based on cluster configuration, resource lifecycle, and predefined thresholds.
+
+---
+
+## How Recommendations Are Generated
+
+The recommendation engine evaluates specific fields within the Elasticsearch resource specification and triggers recommendations when defined thresholds are reached. In most cases, recommendations are generated after approximately two-thirds (2/3) of a resource’s lifecycle has elapsed.
+
+---
+
+## Authentication Secret Rotation
+
+```yaml
+apiVersion: kubedb.com/v1
+kind: Elasticsearch
+metadata:
+ name: es-combined
+ namespace: demo
+spec:
+ version: xpack-9.1.9
+ authSecret:
+ kind: secret
+ name: es-auth
+ rotateAfter: 1h
+ replicas: 1
+ storageType: Durable
+ storage:
+ storageClassName: local-path
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ deletionPolicy: WipeOut
+```
+
+In this configuration:
+
+* The `rotateAfter` field defines the validity period of the authentication secret
+* A rotation recommendation is generated after approximately **40 minutes** (i.e., 2/3 of 1 hour)
+
+---
+
+## TLS Certificate Rotation
+
+```yaml
+apiVersion: kubedb.com/v1
+kind: Elasticsearch
+metadata:
+ name: es-combined
+ namespace: demo
+spec:
+ version: xpack-9.1.9
+ enableSSL: true
+ tls:
+ issuerRef:
+ apiGroup: cert-manager.io
+ kind: Issuer
+ name: ca-issuer
+ certificates:
+ - alias: client
+ duration: 1h20m
+ - alias: http
+ duration: 2h10m
+ replicas: 1
+ storageType: Durable
+ storage:
+ storageClassName: local-path
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ deletionPolicy: WipeOut
+```
+
+In this case:
+
+* Certificate durations define their lifecycle
+* Recommendations are generated after approximately 2/3 of each certificate’s validity period
+* For example, a `1h20m` certificate triggers a recommendation after roughly `54 minutes`
+
+---
+
+## Version Update Recommendation
+
+```yaml
+apiVersion: kubedb.com/v1
+kind: Elasticsearch
+metadata:
+ name: es-combined
+ namespace: demo
+spec:
+ version: xpack-9.1.9
+ enableSSL: true
+ replicas: 1
+ storageType: Durable
+ storage:
+ storageClassName: local-path
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ deletionPolicy: WipeOut
+```
+
+For version updates:
+
+* The recommendation engine continuously monitors the running version
+* It suggests upgrades when newer, supported, or more secure versions become available
+
diff --git a/docs/guides/ferretdb/concepts/catalog.md b/docs/guides/ferretdb/concepts/catalog.md
index b28df36fb..d3b322bcd 100644
--- a/docs/guides/ferretdb/concepts/catalog.md
+++ b/docs/guides/ferretdb/concepts/catalog.md
@@ -16,7 +16,7 @@ section_menu_id: guides
## What is FerretDBVersion
-`FerretDBVersion` is a Kubernetes `Custom Resource Definitions` (CRD). It provides a declarative configuration to specify the docker images to be used for [FerretDB](https://ferretdb.com/) server deployed with KubeDB in a Kubernetes native way.
+`FerretDBVersion` is a Kubernetes `Custom Resource Definitions` (CRD). It provides a declarative configuration to specify the docker images to be used for [FerretDB](https://docs.ferretdb.io/) server deployed with KubeDB in a Kubernetes native way.
When you install KubeDB, a `FerretDBVersion` custom resource will be created automatically for every supported FerretDB release versions. You have to specify the name of `FerretDBVersion` crd in `spec.version` field of [FerretDB](/docs/guides/ferretdb/concepts/ferretdb.md) crd. Then, KubeDB will use the docker images specified in the `FerretDBVersion` crd to create your expected FerretDB instance.
diff --git a/docs/guides/ferretdb/concepts/ferretdb.md b/docs/guides/ferretdb/concepts/ferretdb.md
index 6999d2c2e..0b490ef85 100644
--- a/docs/guides/ferretdb/concepts/ferretdb.md
+++ b/docs/guides/ferretdb/concepts/ferretdb.md
@@ -16,7 +16,7 @@ section_menu_id: guides
## What is FerretDB
-`FerretDB` is a Kubernetes `Custom Resource Definitions` (CRD). It provides declarative configuration for [FerretDB](https://www.ferretdb.com/) in a Kubernetes native way. You only need to describe the desired configuration in a `FerretDB`object, and the KubeDB operator will create Kubernetes objects in the desired state for you.
+`FerretDB` is a Kubernetes `Custom Resource Definitions` (CRD). It provides declarative configuration for [FerretDB](https://docs.ferretdb.io/) in a Kubernetes native way. You only need to describe the desired configuration in a `FerretDB`object, and the KubeDB operator will create Kubernetes objects in the desired state for you.
## FerretDB Spec
diff --git a/docs/operatormanual/README.md b/docs/operatormanual/README.md
new file mode 100644
index 000000000..86bb4ce7a
--- /dev/null
+++ b/docs/operatormanual/README.md
@@ -0,0 +1,14 @@
+---
+title: operatormanual | KubeDB
+menu:
+ docs_{{ .version }}:
+ identifier: operatormanual-readme
+ name: Readme
+ parent: operatormanual
+ weight: -1
+menu_name: docs_{{ .version }}
+section_menu_id: operatormanual
+url: /docs/{{ .version }}/operatormanual/
+aliases:
+ - /docs/{{ .version }}/operatormanual/README/
+---
diff --git a/docs/operatormanual/_index.md b/docs/operatormanual/_index.md
new file mode 100644
index 000000000..eefd92397
--- /dev/null
+++ b/docs/operatormanual/_index.md
@@ -0,0 +1,11 @@
+---
+title: Operator Manual
+description: KubeDB Operator Manual
+menu:
+ docs_{{ .version }}:
+ identifier: operatormanual
+ name: Operator Manual
+ weight: 2000
+ pre: dropdown
+menu_name: docs_{{ .version }}
+---
diff --git a/docs/operatormanual/recommendation/README.md b/docs/operatormanual/recommendation/README.md
new file mode 100644
index 000000000..d42d1aee5
--- /dev/null
+++ b/docs/operatormanual/recommendation/README.md
@@ -0,0 +1,14 @@
+---
+title: Recommendation
+menu:
+ docs_{{ .version }}:
+ identifier: readme-recommendation
+ name: Recommendation
+ parent: recommendation
+ weight: 10
+menu_name: docs_{{ .version }}
+section_menu_id: operatormanual
+url: /docs/{{ .version }}/operatormanual/recommendation/
+aliases:
+ - /docs/{{ .version }}/operatormanual/recommendation/README/
+---
diff --git a/docs/operatormanual/recommendation/_index.md b/docs/operatormanual/recommendation/_index.md
new file mode 100644
index 000000000..b1aafc157
--- /dev/null
+++ b/docs/operatormanual/recommendation/_index.md
@@ -0,0 +1,10 @@
+---
+title: Recommendation
+menu:
+ docs_{{ .version }}:
+ identifier: recommendation
+ name: Recommendation
+ weight: 10
+ parent: Operatormanual
+menu_name: docs_{{ .version }}
+---
diff --git a/docs/operatormanual/recommendation/images/recommendation-generation.png b/docs/operatormanual/recommendation/images/recommendation-generation.png
new file mode 100644
index 000000000..dd96452a2
Binary files /dev/null and b/docs/operatormanual/recommendation/images/recommendation-generation.png differ
diff --git a/docs/operatormanual/recommendation/overview.md b/docs/operatormanual/recommendation/overview.md
new file mode 100644
index 000000000..9bb1def08
--- /dev/null
+++ b/docs/operatormanual/recommendation/overview.md
@@ -0,0 +1,34 @@
+---
+title: Recommendation overview
+menu:
+ docs_{{ .version }}:
+ identifier: overview
+ name: Overview
+ parent: recommendation
+ weight: 10
+menu_name: docs_{{ .version }}
+section_menu_id: operatormanual
+---
+
+> New to KubeDB? Please start [here](/docs/README.md).
+
+# Recommendation for KubeDB
+Databases on Kubernetes in production grade infrastructure often need to go through several administrative operations depending on specific resource requirements. Such operations include vertical scaling (cpu, memory) and storage expansion. Autoscaling support for KubeDB managed databases takes care of it. However, databases also need to go through some maintenance operations in order to ensure security, enhance performance, getting bug fixes and new features etc. Such operations mostly require organization's manual intervention. Even if these operations are automated, they need to be done in surveillance. KubeDB simplifies this by generating K8s Native Recommendations.
+
+## Overview
+
+Recommendation is a custom resource definition (CRD) object which is created by KubeDB ops-manager controller and managed by supervisor. So, You need to have KubeDB and Supervisor installed first. You can simply install supervisor along with other KubeDB components using `--set supervisor.enabled=true` flag while installing KubeDB via helm chart.
+
+
+
+
+
+KubeDB provisioner watches user provided database custom resource spec and creates/sync all the necessary DB resources. Once the Database is ready KubeDB Ops-manager watches the DB and creates Recommendation if it requires. KubeDB Supervisor then watches the Recommendation, updates status of the recommendation, creates recommended operation via OpsRequest if deadline reaches or manually triggered and watches the OpsRequest status to update accordingly in Recommendation custom resource.
+
+KubeDB provides Three types of recommendation for KubeDB Databases:
+1. [Version Update Recommendation](/docs/operatormanual/recommendation/version-update-recommendation.md)
+2. [TLS Certificate Rotation Recommendation](/docs/operatormanual/recommendation/rotate-tls-recommendation.md)
+3. [Authentication Secret Rotation Recommendation](/docs/operatormanual/recommendation/rotate-auth-recommendation.md)
+
+The next page describes these recommendations, how to approve/reject them, their generation mechanism and usability.
+
diff --git a/docs/operatormanual/recommendation/rotate-auth-recommendation.md b/docs/operatormanual/recommendation/rotate-auth-recommendation.md
new file mode 100644
index 000000000..50e6ca627
--- /dev/null
+++ b/docs/operatormanual/recommendation/rotate-auth-recommendation.md
@@ -0,0 +1,296 @@
+---
+title: Rotate Auth Recommendation
+menu:
+ docs_{{ .version }}:
+ identifier: rotate-auth-recommendation
+ name: Rotate Auth
+ parent: recommendation
+ weight: 20
+menu_name: docs_{{ .version }}
+section_menu_id: recommendation
+---
+
+> New to KubeDB? Please start [here](/docs/README.md).
+
+# Authentication Rotate Recommendation
+
+Rotating authentication secrets in database management is vital to mitigate security risks, such as credential leakage or unauthorized access, and to comply with regulatory requirements. Regular rotation limits the exposure of compromised credentials, reduces the risk of insider threats, and enforces updated security policies like stronger passwords or algorithms. It also ensures operational resilience by testing the rotation process and revoking stale or unused credentials. KubeDB provides `RotateAuth` which reduces manual errors, and strengthens database security with minimal effort. KubeDB Ops-manager generates Recommendation for rotating authentication secrets via this OpsRequest.
+
+> Note: We provide support for `Recommendation` across most database systems. Below is an example demonstrating how recommendations are applied for the `Elasticsearch` database.
+
+`Recommendation` is a Kubernetes `Custom Resource Definitions` (CRD). It provides a declarative recommendation for KubeDB managed databases like [Elasticsearch](https://www.elastic.co/products/elasticsearch) and [OpenSearch](https://opensearch.org/) in a Kubernetes native way. The recommendation will only be created if `.spec.authSecret.rotateAfter` is set. KubeDB generates Elasticsearch/Opensearch Rotate Auth recommendation regarding two particular cases.
+
+1. AuthSecret lifespan is more than one month and, less than one month remaining till expiry
+2. AuthSecret lifespan is less than one month and, less than one third of lifespan remaining till expiry
+
+Let's go through a demo to see `RotateAuth` recommendations being generated. First, get the available versions provided by KubeDB.
+
+```bash
+$ kubectl get elasticsearchversions | grep xpack
+xpack-6.8.23 6.8.23 ElasticStack ghcr.io/appscode-images/elastic:6.8.23 12d
+xpack-7.17.15 7.17.15 ElasticStack ghcr.io/appscode-images/elastic:7.17.15 12d
+xpack-7.17.28 7.17.28 ElasticStack ghcr.io/appscode-images/elastic:7.17.28 12d
+xpack-8.17.10 8.17.10 ElasticStack ghcr.io/appscode-images/elastic:8.17.10 12d
+xpack-8.17.6 8.17.6 ElasticStack ghcr.io/appscode-images/elastic:8.17.6 12d
+xpack-8.18.2 8.18.2 ElasticStack ghcr.io/appscode-images/elastic:8.18.2 12d
+xpack-8.18.8 8.18.8 ElasticStack ghcr.io/appscode-images/elastic:8.18.8 12d
+xpack-8.19.9 8.19.9 ElasticStack ghcr.io/appscode-images/elastic:8.19.9 12d
+xpack-8.2.3 8.2.3 ElasticStack ghcr.io/appscode-images/elastic:8.2.3 12d
+xpack-8.5.3 8.5.3 ElasticStack ghcr.io/appscode-images/elastic:8.5.3 12d
+xpack-9.0.2 9.0.2 ElasticStack ghcr.io/appscode-images/elastic:9.0.2 12d
+xpack-9.0.8 9.0.8 ElasticStack ghcr.io/appscode-images/elastic:9.0.8 12d
+xpack-9.1.4 9.1.4 ElasticStack ghcr.io/appscode-images/elastic:9.1.4 12d
+xpack-9.1.9 9.1.9 ElasticStack ghcr.io/appscode-images/elastic:9.1.9 12d
+xpack-9.2.3 9.2.3 ElasticStack ghcr.io/appscode-images/elastic:9.2.3 12d
+```
+
+Let's deploy an cluster with version `xpack-9.1.9`. We are going to create a cluster topology with 2 master nodes, 3 data nodes and 2 ingest node. We also have to provide an available storageclass for each of the node types.
+
+```yaml
+ apiVersion: kubedb.com/v1
+ kind: Elasticsearch
+ metadata:
+ name: elastic
+ namespace: es
+ spec:
+ version: xpack-9.1.9
+ storageType: Durable
+ deletionPolicy: WipeOut
+ authSecret:
+ kind: secret
+ name: es-auth
+ rotateAfter: 1h
+ topology:
+ master:
+ replicas: 2
+ storage:
+ storageClassName: "local-path"
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ data:
+ replicas: 2
+ storage:
+ storageClassName: "local-path"
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ ingest:
+ replicas: 1
+ storage:
+ storageClassName: "local-path"
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+```
+
+Wait for a while till elasicsearch cluster gets into `Ready` state. Required time depends on image pulling and node's physical specifications.
+
+```bash
+$ kubectl get es elastic -n es -w
+NAME VERSION STATUS AGE
+elastic xpack-9.1.9 Provisioning 98s
+elastic xpack-9.1.9 Provisioning 5m43s
+elastic xpack-9.1.9 Provisioning 8m7s
+.
+.
+.
+elastic xpack-9.1.9 Ready 10m
+elastic xpack-9.1.9 Ready 10m
+```
+
+Since, `.spec.authSecret.rotateAfter` is set as `1h`, it is expected that the recommendation engine will generate a rotate-auth recommendation at least after 40 minutes (two-third of lifespan) of the authsecret creation. Once generated you will get a similar recommendation as follows.
+
+```bash
+$ kubectl get recommendation -n es | grep rotate-auth
+NAME STATUS OUTDATED AGE
+elastic-x-elasticsearch-x-rotate-auth-2juuee Pending false 10m
+```
+
+The `Recommendation` custom resource will be named as `-x--x--`. Initially, the KubeDB `Supervisor` controller will mark the `Status` of this object to `Pending`. Let's check the complete Recommendation custom resource manifest:
+
+```yaml
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-rotate-auth-2juuee -oyaml
+apiVersion: supervisor.appscode.com/v1alpha1
+kind: Recommendation
+metadata:
+ creationTimestamp: "2025-02-25T09:12:29Z"
+ generation: 1
+ labels:
+ app.kubernetes.io/instance: elastic
+ app.kubernetes.io/managed-by: kubedb.com
+ app.kubernetes.io/type: rotate-auth
+ name: elastic-x-elasticsearch-x-rotate-auth-2juuee
+ namespace: es
+ resourceVersion: "80116"
+ uid: 12f24cf6-2f02-420f-863d-3523e32a08dd
+spec:
+ backoffLimit: 5
+ deadline: "2025-02-25T09:20:53Z"
+ description: Recommending AuthSecret rotation,elastic-auth AuthSecret needs to be
+ rotated before 2025-02-25 09:30:53 +0000 UTC
+ operation:
+ apiVersion: ops.kubedb.com/v1alpha1
+ kind: ElasticsearchOpsRequest
+ metadata:
+ name: rotate-auth
+ namespace: es
+ spec:
+ databaseRef:
+ name: elastic
+ type: RotateAuth
+ status: {}
+ recommender:
+ name: kubedb-ops-manager
+ rules:
+ failed: has(self.status) && has(self.status.phase) && self.status.phase == 'Failed'
+ inProgress: has(self.status) && has(self.status.phase) && self.status.phase ==
+ 'Progressing'
+ success: has(self.status) && has(self.status.phase) && self.status.phase == 'Successful'
+ target:
+ apiGroup: kubedb.com
+ kind: Elasticsearch
+ name: elastic
+status:
+ approvalStatus: Pending
+ failedAttempt: 0
+ outdated: false
+ parallelism: Namespace
+ phase: Pending
+ reason: WaitingForApproval
+```
+
+In the generated Recommendation you will find a description, targeted db object, recommended operation or Ops-Request manifest, current status of the recommendation etc. Let's just focus on the recommendation description first.
+
+```shell
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-rotate-auth-2juuee -o jsonpath='{.spec.operation}' | yq -y
+apiVersion: ops.kubedb.com/v1alpha1
+kind: ElasticsearchOpsRequest
+metadata:
+ name: rotate-auth
+ namespace: es
+spec:
+ databaseRef:
+ name: elastic
+ type: RotateAuth
+status: {}
+```
+
+Let's check the status part of this recommendation.
+
+```bash
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-rotate-auth-2juuee -o jsonpath='{.status}' | yq -y
+approvalStatus: Pending
+failedAttempt: 0
+outdated: false
+parallelism: Namespace
+phase: Pending
+reason: WaitingForApproval
+```
+
+Now, This recommendation can be approved and operation can be executed immediately by setting `ApprovalStatus` to `Approved` and Setting `approvedWindow` to `Immediate`. You can approve this easily through Appscode UI or edit it manually. Also, You can use kubectl CLI for this -
+
+```bash
+$ kubectl patch Recommendation elastic-x-elasticsearch-x-rotate-auth-2juuee \
+ -n es \
+ --type merge \
+ --subresource='status' \
+ -p '{"status":{"approvalStatus":"Approved","approvedWindow":{"window":"Immediate"}}}'
+recommendation.supervisor.appscode.com/elastic-x-elasticsearch-x-rotate-auth-2juuee patched
+```
+
+Now, check the status part again. You will find a condition have appeared which says `OpsRequest is successfully created`.
+
+```bash
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-rotate-auth-2juuee -o jsonpath='{.status}' | yq -y
+approvalStatus: Approved
+approvedWindow:
+ window: Immediate
+conditions:
+ - lastTransitionTime: '2025-02-25T09:23:29Z'
+ message: OpsRequest is successfully created
+ reason: SuccessfullyCreatedOperation
+ status: 'True'
+ type: SuccessfullyCreatedOperation
+createdOperationRef:
+ name: elastic-1740475409-rotate-auth-auto
+failedAttempt: 0
+outdated: false
+parallelism: Namespace
+phase: InProgress
+reason: StartedExecutingOperation
+```
+
+You will find an `ElasticsearchOpsRequest` custom resource have been created and, it is rotating the authsecret of `elastic` cluster with negligible downtime. Let's wait for it to reach `Successful` status.
+
+```bash
+$ kubectl get elasticsearchopsrequest -n es elastic-1740475409-rotate-auth-auto -w
+NAME TYPE STATUS AGE
+elastic-1740475409-rotate-auth-auto UpdateVersion Progressing 3m12s
+elastic-1740475409-rotate-auth-auto UpdateVersion Progressing 3m34s
+.
+.
+elastic-1740475409-rotate-auth-auto UpdateVersion Successful 11m
+```
+
+Let's recheck the recommendation for one last time. We should find that `.status.phase` has been marked as `Succeeded`.
+
+```bash
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-rotate-auth-2juuee
+NAME STATUS OUTDATED AGE
+elastic-x-elasticsearch-x-rotate-auth-2juuee Succeeded false 78m
+```
+
+You may not want to do trigger recommended operations manually. Rather, trigger them autonomously in a preferred schedule when infrastructure is idle or traffic rate is at the lowest. For this purpose, You can create a `MaintenanceWindow` custom resource where you can set your desired schedule/period for triggering these recommended operations automatically. Here's a sample one:
+
+```yaml
+apiVersion: supervisor.appscode.com/v1alpha1
+kind: MaintenanceWindow
+metadata:
+ name: elastic-maintenance
+ namespace: es
+spec:
+ timezone: Asia/Dhaka
+ days:
+ Wednesday:
+ - start: 5:40AM
+ end: 7:00PM
+ dates:
+ - start: 2025-01-25T00:00:18Z
+ end: 2025-01-25T23:41:18Z
+```
+
+You can now create a `ApprovalPolicy` custom resource to refer this `MaintenanceWindow` for particular DB type. Following is a sample `ApprovalPolicy` for any `Elasticsearch` custom resource deployed in `es` namespace. This `ApprovalPolicy` custom resource is referring to the `elastic-maintenance` MaintenanceWindow created in the same namespace. You can also create `ClusterMaintenanceWindow` instead which is effective for cluster-wide operations and refer it here. The following ApprovalPolicy will trigger recommended operations when referred maintenance window timeframe is reached.
+
+```yaml
+apiVersion: supervisor.appscode.com/v1alpha1
+kind: ApprovalPolicy
+metadata:
+ name: es-policy
+ namespace: es
+maintenanceWindowRef:
+ name: elastic-maintenance
+targets:
+ - group: kubedb.com
+ kind: Elasticsearch
+ operations:
+ - group: ops.kubedb.com
+ kind: ElasticsearchOpsRequest
+```
+
+Lastly, If you want to reject a recommendation, you can just set `ApprovalStatus` to `Rejected` in the recommendation status section. Here's how you can do it using kubectl cli.
+
+```bash
+$ kubectl patch Recommendation elastic-x-elasticsearch-x-rotate-auth-2juuee \
+ -n es \
+ --type merge \
+ --subresource='status' \
+ -p '{"status":{"approvalStatus":"Rejected"}}'
+recommendation.supervisor.appscode.com/elastic-x-elasticsearch-x-rotate-auth-2juuee patched
+```
diff --git a/docs/operatormanual/recommendation/rotate-tls-recommendation.md b/docs/operatormanual/recommendation/rotate-tls-recommendation.md
new file mode 100644
index 000000000..0f77c2243
--- /dev/null
+++ b/docs/operatormanual/recommendation/rotate-tls-recommendation.md
@@ -0,0 +1,357 @@
+---
+title: Rotate TLS Recommendation
+menu:
+ docs_{{ .version }}:
+ identifier: rotate-tls-recommendation
+ name: Rotate TLS
+ parent: recommendation
+ weight: 30
+menu_name: docs_{{ .version }}
+section_menu_id: operatormanual
+---
+
+> New to KubeDB? Please start [here](/docs/README.md).
+
+# Rotate TLS Recommendation
+
+TLS certificate rotation in databases is essential for maintaining security, ensuring compliance, and preventing service disruptions. Regular rotation mitigates risks like certificate expiry and key compromise, adapts to evolving cryptographic standards, and maintains trust relationships with Certificate Authorities. It also enhances operational resilience by testing renewal processes and ensures smooth auditing and monitoring. To minimize risks and streamline the process, KubeDB provides ReconfigureTLS OpsRequest support. KubeDB Ops-manager generates Recommendation to rotate TLS certificates via this OpsRequest when their expiry is near.
+
+> Note: We provide support for `Recommendation` across most database systems. Below is an example demonstrating how recommendations are applied for the `Elasticsearch` database.
+
+`Recommendation` is a Kubernetes `Custom Resource Definitions` (CRD). It provides a declarative recommendation for KubeDB managed databases like [Elasticsearch](https://www.elastic.co/products/elasticsearch) and [OpenSearch](https://opensearch.org/) in a Kubernetes native way. KubeDB generates Elasticsearch/Opensearch Rotate TLS recommendation regarding if:
+
+- At least one of its certificate’s lifespan is more than one month and less than one month remaining till expiry
+
+- At least one of its certificates has one-third of its lifespan remaining till expiry.
+
+Let's go through a demo to see `RotateTLS` recommendations being generated. First, get the available Elasticsearch versions provided by KubeDB.
+
+```bash
+$ kubectl get elasticsearchversions | grep xpack
+xpack-6.8.23 6.8.23 ElasticStack ghcr.io/appscode-images/elastic:6.8.23 12d
+xpack-7.17.15 7.17.15 ElasticStack ghcr.io/appscode-images/elastic:7.17.15 12d
+xpack-7.17.28 7.17.28 ElasticStack ghcr.io/appscode-images/elastic:7.17.28 12d
+xpack-8.17.10 8.17.10 ElasticStack ghcr.io/appscode-images/elastic:8.17.10 12d
+xpack-8.17.6 8.17.6 ElasticStack ghcr.io/appscode-images/elastic:8.17.6 12d
+xpack-8.18.2 8.18.2 ElasticStack ghcr.io/appscode-images/elastic:8.18.2 12d
+xpack-8.18.8 8.18.8 ElasticStack ghcr.io/appscode-images/elastic:8.18.8 12d
+xpack-8.19.9 8.19.9 ElasticStack ghcr.io/appscode-images/elastic:8.19.9 12d
+xpack-8.2.3 8.2.3 ElasticStack ghcr.io/appscode-images/elastic:8.2.3 12d
+xpack-8.5.3 8.5.3 ElasticStack ghcr.io/appscode-images/elastic:8.5.3 12d
+xpack-9.0.2 9.0.2 ElasticStack ghcr.io/appscode-images/elastic:9.0.2 12d
+xpack-9.0.8 9.0.8 ElasticStack ghcr.io/appscode-images/elastic:9.0.8 12d
+xpack-9.1.4 9.1.4 ElasticStack ghcr.io/appscode-images/elastic:9.1.4 12d
+xpack-9.1.9 9.1.9 ElasticStack ghcr.io/appscode-images/elastic:9.1.9 12d
+xpack-9.2.3 9.2.3 ElasticStack ghcr.io/appscode-images/elastic:9.2.3 12d
+```
+
+Let's deploy an Elasticsearch cluster with version `xpack-9.1.9`. We are going to create a cluster topology with 2 master nodes, 3 data nodes and 2 ingest node. We also have to provide an available storageclass for each of the node types. Make sure to have an issuer/clusterIssuer to refer in the manifest. Though KubeDB managed elasticsearch supports TLS in both cert-manager provisioned and Operator provisioned ways, rotate tls only works when certificates are provisioned via cert-manager.
+
+```yaml
+apiVersion: kubedb.com/v1
+kind: Elasticsearch
+metadata:
+ name: elastic
+ namespace: es
+spec:
+ deletionPolicy: WipeOut
+ kernelSettings:
+ disableDefaults: false
+ storageType: Durable
+ enableSSL: true
+ tls:
+ issuerRef:
+ apiGroup: "cert-manager.io"
+ kind: Issuer
+ name: ca-issuer
+ certificates:
+ - alias: client
+ duration: 1h20m
+ - alias: http
+ duration: 2h10m
+ topology:
+ data:
+ podTemplate:
+ spec:
+ containers:
+ - name: elasticsearch
+ resources:
+ limits:
+ cpu: 500m
+ memory: 1536Mi
+ requests:
+ cpu: 500m
+ memory: 1536Mi
+ nodeSelector:
+ kubernetes.io/os: linux
+ podPlacementPolicy:
+ name: default
+ replicas: 3
+ storage:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 5Gi
+ storageClassName: local-path
+ ingest:
+ podTemplate:
+ spec:
+ containers:
+ - name: elasticsearch
+ resources:
+ limits:
+ cpu: 500m
+ memory: 1536Mi
+ requests:
+ cpu: 500m
+ memory: 1536Mi
+ nodeSelector:
+ kubernetes.io/os: linux
+ podPlacementPolicy:
+ name: default
+ replicas: 2
+ storage:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ storageClassName: local-path
+ master:
+ podTemplate:
+ spec:
+ containers:
+ - name: elasticsearch
+ resources:
+ limits:
+ cpu: 500m
+ memory: 1536Mi
+ requests:
+ cpu: 500m
+ memory: 1536Mi
+ nodeSelector:
+ kubernetes.io/os: linux
+ podPlacementPolicy:
+ name: default
+ replicas: 2
+ storage:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 3Gi
+ storageClassName: local-path
+ version: xpack-9.1.9
+```
+
+Wait for a while till elasicsearch cluster gets into `Ready` state. Required time depends on image pulling and node's physical specifications.
+
+```bash
+$ kubectl get es elastic -n es -w
+NAME VERSION STATUS AGE
+elastic xpack-9.1.9 Provisioning 98s
+elastic xpack-9.1.9 Provisioning 5m43s
+elastic xpack-9.1.9 Provisioning 8m7s
+.
+.
+.
+elastic xpack-9.1.9 Ready 10m
+elastic xpack-9.1.9 Ready 10m
+```
+
+Since,duration for client certificate is set as `1h20min`, it is expected that the recommendation engine will generate a reconfigure-tls recommendation at least after 54 minutes (two-third of lifespan) of the client certificate creation. Once generated you will get a similar recommendation as follows.
+
+```bash
+$ kubectl get recommendation -n es | grep rotate-tls
+NAME STATUS OUTDATED AGE
+elastic-x-elasticsearch-x-rotate-tls-6ujvez Pending false 74s
+```
+
+The `Recommendation` custom resource will be named as `-x--x--`. Initially, the KubeDB `Supervisor` controller will mark the `Status` of this object to `Pending`. Let's check the complete Recommendation custom resource manifest:
+
+```yaml
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-rotate-tls-6ujvez -oyaml
+apiVersion: supervisor.appscode.com/v1alpha1
+kind: Recommendation
+metadata:
+ creationTimestamp: "2025-02-27T11:50:04Z"
+ generation: 1
+ labels:
+ app.kubernetes.io/instance: elastic
+ app.kubernetes.io/managed-by: kubedb.com
+ app.kubernetes.io/type: rotate-tls
+ name: elastic-x-elasticsearch-x-rotate-tls-6ujvez
+ namespace: es
+ resourceVersion: "309401"
+ uid: d208df6b-5fbf-4122-b7b7-18e73a4e1d6c
+spec:
+ backoffLimit: 5
+ deadline: "2025-02-27T11:59:43Z"
+ description: Recommending TLS certificate rotation,elastic-client-cert Certificate
+ is going to be expire on 2025-02-27 12:04:43 +0000 UTC
+ operation:
+ apiVersion: ops.kubedb.com/v1alpha1
+ kind: ElasticsearchOpsRequest
+ metadata:
+ name: rotate-tls
+ namespace: es
+ spec:
+ databaseRef:
+ name: elastic
+ tls:
+ rotateCertificates: true
+ type: ReconfigureTLS
+ status: {}
+ recommender:
+ name: kubedb-ops-manager
+ rules:
+ failed: has(self.status) && has(self.status.phase) && self.status.phase == 'Failed'
+ inProgress: has(self.status) && has(self.status.phase) && self.status.phase ==
+ 'Progressing'
+ success: has(self.status) && has(self.status.phase) && self.status.phase == 'Successful'
+ target:
+ apiGroup: kubedb.com
+ kind: Elasticsearch
+ name: elastic
+status:
+ approvalStatus: Pending
+ failedAttempt: 0
+ outdated: false
+ parallelism: Namespace
+ phase: Pending
+ reason: WaitingForApproval
+```
+
+In the generated Recommendation you will find a description, targeted db object, recommended operation or Ops-Request manifest, current status of the recommendation etc. Let's just focus on the recommendation description first.
+
+```shell
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-rotate-tls-6ujvez -o jsonpath='{.spec.operation}' | yq -y
+apiVersion: ops.kubedb.com/v1alpha1
+kind: ElasticsearchOpsRequest
+metadata:
+ name: rotate-tls
+ namespace: es
+spec:
+ databaseRef:
+ name: elastic
+ tls:
+ rotateCertificates: true
+ type: ReconfigureTLS
+status: {}
+```
+
+Let's check the status part of this recommendation.
+
+```bash
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-rotate-tls-6ujvez -o jsonpath='{.status}' | yq -y
+approvalStatus: Pending
+failedAttempt: 0
+outdated: false
+parallelism: Namespace
+phase: Pending
+reason: WaitingForApproval
+```
+
+Now, This recommendation can be approved and operation can be executed immediately by setting `ApprovalStatus` to `Approved` and Setting `approvedWindow` to `Immediate`. You can approve this easily through Appscode UI or edit it manually. Also, You can use kubectl CLI for this -
+
+```bash
+$ kubectl patch Recommendation elastic-x-elasticsearch-x-rotate-tls-6ujvez \
+ -n es \
+ --type merge \
+ --subresource='status' \
+ -p '{"status":{"approvalStatus":"Approved","approvedWindow":{"window":"Immediate"}}}'
+recommendation.supervisor.appscode.com/elastic-x-elasticsearch-x-rotate-tls-6ujvez patched
+```
+
+Now, check the status part again. You will find a condition have appeared which says `OpsRequest is successfully created`.
+
+```bash
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-rotate-tls-6ujvez -o jsonpath='{.status}' | yq -y
+approvalStatus: Approved
+approvedWindow:
+ window: Immediate
+conditions:
+ - lastTransitionTime: '2025-02-27T11:54:50Z'
+ message: OpsRequest is successfully created
+ reason: SuccessfullyCreatedOperation
+ status: 'True'
+ type: SuccessfullyCreatedOperation
+createdOperationRef:
+ name: elastic-1740657290-rotate-tls-auto
+failedAttempt: 0
+outdated: false
+parallelism: Namespace
+phase: InProgress
+reason: StartedExecutingOperation
+```
+
+You will find an `ElasticsearchOpsRequest` custom resource have been created and, it is rotating the authsecret of `elastic` cluster with negligible downtime. Let's wait for it to reach `Successful` status.
+
+```bash
+$ kubectl get elasticsearchopsrequest -n es elastic-1740657290-rotate-tls-auto -w
+NAME TYPE STATUS AGE
+elastic-1740657290-rotate-tls-auto ReconfigureTLS Progressing 60s
+elastic-1740657290-rotate-tls-auto ReconfigureTLS Progressing 114s
+.
+.
+elastic-1740657290-rotate-tls-auto ReconfigureTLS Successful 12m
+
+```
+
+Let's recheck the recommendation for one last time. We should find that `.status.phase` has been marked as `Succeeded`.
+
+```bash
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-rotate-tls-6ujvez
+NAME STATUS OUTDATED AGE
+elastic-x-elasticsearch-x-rotate-tls-6ujvez Succeeded false 78m
+```
+
+You may not want to do trigger recommended operations manually. Rather, trigger them autonomously in a preferred schedule when infrastructure is idle or traffic rate is at the lowest. For this purpose, You can create a `MaintenanceWindow` custom resource where you can set your desired schedule/period for triggering these recommended operations automatically. Here's a sample one:
+
+```yaml
+apiVersion: supervisor.appscode.com/v1alpha1
+kind: MaintenanceWindow
+metadata:
+ name: elastic-maintenance
+ namespace: es
+spec:
+ timezone: Asia/Dhaka
+ days:
+ Wednesday:
+ - start: 5:40AM
+ end: 7:00PM
+ dates:
+ - start: 2025-01-25T00:00:18Z
+ end: 2025-01-25T23:41:18Z
+```
+
+You can now create a `ApprovalPolicy` custom resource to refer this `MaintenanceWindow` for particular DB type. Following is a sample `ApprovalPolicy` for any `Elasticsearch` custom resource deployed in `es` namespace. This `ApprovalPolicy` custom resource is referring to the `elastic-maintenance` MaintenanceWindow created in the same namespace. You can also create `ClusterMaintenanceWindow` instead which is effective for cluster-wide operations and refer it here. The following ApprovalPolicy will trigger recommended operations when referred maintenance window timeframe is reached.
+
+```yaml
+apiVersion: supervisor.appscode.com/v1alpha1
+kind: ApprovalPolicy
+metadata:
+ name: es-policy
+ namespace: es
+maintenanceWindowRef:
+ name: elastic-maintenance
+targets:
+ - group: kubedb.com
+ kind: Elasticsearch
+ operations:
+ - group: ops.kubedb.com
+ kind: ElasticsearchOpsRequest
+```
+
+Lastly, If you want to reject a recommendation, you can just set `ApprovalStatus` to `Rejected` in the recommendation status section. Here's how you can do it using kubectl cli.
+
+```bash
+$ kubectl patch Recommendation elastic-x-elasticsearch-x-rotate-tls-6ujvez \
+ -n es \
+ --type merge \
+ --subresource='status' \
+ -p '{"status":{"approvalStatus":"Rejected"}}'
+recommendation.supervisor.appscode.com/elastic-x-elasticsearch-x-rotate-tls-6ujvez patched
+```
+
diff --git a/docs/operatormanual/recommendation/version-update-recommendation.md b/docs/operatormanual/recommendation/version-update-recommendation.md
new file mode 100644
index 000000000..d2db14a60
--- /dev/null
+++ b/docs/operatormanual/recommendation/version-update-recommendation.md
@@ -0,0 +1,319 @@
+---
+title: Elasticsearch Version Update Recommendation
+menu:
+ docs_{{ .version }}:
+ identifier: es-version-update-recommendation
+ name: Version Update
+ parent: recommendation
+ weight: 40
+menu_name: docs_{{ .version }}
+section_menu_id: operatormanual
+---
+
+> New to KubeDB? Please start [here](/docs/README.md).
+
+# Elasticsearch Version Update Recommendation
+
+Database versions often need to be updated due to several reasons. Older database versions may have vulnerabilities that hackers can exploit. New versions often include optimizations for query execution, indexing, and storage mechanisms. Modern databases frequently introduce new features, such as better data types, improved indexing methods, or advanced analytics capabilities. Database vendors release patches and updates to address these issues and introduce new features.
+
+> Note: We provide support for `Recommendation` across most database systems. Below is an example demonstrating how recommendations are applied for the `Elasticsearch` database.
+
+
+`Recommendation` is a Kubernetes `Custom Resource Definitions` (CRD). It provides a declarative recommendation for KubeDB managed databases like [Elasticsearch](https://www.elastic.co/products/elasticsearch) and [OpenSearch](https://opensearch.org/) in a Kubernetes native way. KubeDB generates Elasticsearch/Opensearch Version Update recommendation regarding three particular cases.
+
+1. There's been an update in the current version image
+2. There's a new major/minor version available
+3. There's a version available with patch fix
+
+Let's go through a demo to see version update recommendations being generated. First, get the available Elasticsearch versions provided by KubeDB.
+
+```bash
+$ kubectl get elasticsearchversions | grep xpack
+xpack-6.8.23 6.8.23 ElasticStack ghcr.io/appscode-images/elastic:6.8.23 12d
+xpack-7.17.15 7.17.15 ElasticStack ghcr.io/appscode-images/elastic:7.17.15 12d
+xpack-7.17.28 7.17.28 ElasticStack ghcr.io/appscode-images/elastic:7.17.28 12d
+xpack-8.17.10 8.17.10 ElasticStack ghcr.io/appscode-images/elastic:8.17.10 12d
+xpack-8.17.6 8.17.6 ElasticStack ghcr.io/appscode-images/elastic:8.17.6 12d
+xpack-8.18.2 8.18.2 ElasticStack ghcr.io/appscode-images/elastic:8.18.2 12d
+xpack-8.18.8 8.18.8 ElasticStack ghcr.io/appscode-images/elastic:8.18.8 12d
+xpack-8.19.9 8.19.9 ElasticStack ghcr.io/appscode-images/elastic:8.19.9 12d
+xpack-8.2.3 8.2.3 ElasticStack ghcr.io/appscode-images/elastic:8.2.3 12d
+xpack-8.5.3 8.5.3 ElasticStack ghcr.io/appscode-images/elastic:8.5.3 12d
+xpack-9.0.2 9.0.2 ElasticStack ghcr.io/appscode-images/elastic:9.0.2 12d
+xpack-9.0.8 9.0.8 ElasticStack ghcr.io/appscode-images/elastic:9.0.8 12d
+xpack-9.1.4 9.1.4 ElasticStack ghcr.io/appscode-images/elastic:9.1.4 12d
+xpack-9.1.9 9.1.9 ElasticStack ghcr.io/appscode-images/elastic:9.1.9 12d
+xpack-9.2.3 9.2.3 ElasticStack ghcr.io/appscode-images/elastic:9.2.3 12d
+```
+
+Let's deploy an Elasticsearch cluster with version `xpack-9.1.9`. We are going to create a cluster topology with 2 master nodes, 3 data nodes and 2 ingest node. We also have to provide an available storageclass for each of the node types.
+
+```yaml
+apiVersion: kubedb.com/v1
+kind: Elasticsearch
+metadata:
+ name: elastic
+ namespace: es
+spec:
+ version: xpack-9.1.9
+ storageType: Durable
+ deletionPolicy: WipeOut
+ topology:
+ master:
+ replicas: 2
+ storage:
+ storageClassName: "local-path"
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ data:
+ replicas: 3
+ storage:
+ storageClassName: "local-path"
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+ ingest:
+ replicas: 2
+ storage:
+ storageClassName: "local-path"
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+```
+
+Wait for a while till elasicsearch cluster gets into `Ready` state. Required time depends on image pulling and node's physical specifications.
+
+```bash
+$ kubectl get es elastic -n es -w
+NAME VERSION STATUS AGE
+elastic xpack-9.1.9 Provisioning 98s
+elastic xpack-9.1.9 Provisioning 5m43s
+elastic xpack-9.1.9 Provisioning 8m7s
+.
+.
+.
+elastic xpack-9.1.9 Ready 10m
+elastic xpack-9.1.9 Ready 10m
+```
+
+Once elastic instance is `Ready`, a `Recommendation` instance will be automatically generated by KubeDB `Ops-Manager` controller. Might take a few minutes to trigger an event for the database creation in the controller.
+
+```bash
+$ kubectl get recommendation -n es
+NAME STATUS OUTDATED AGE
+elastic-x-elasticsearch-x-update-version-2juuee Pending false 10m
+```
+
+The `Recommendation` custom resource will be named as `-x--x--`. Initially, the KubeDB `Supervisor` controller will mark the `Status` of this object to `Pending`. Let's check the complete Recommendation custom resource manifest:
+
+```yaml
+apiVersion: supervisor.appscode.com/v1alpha1
+kind: Recommendation
+metadata:
+ annotations:
+ kubedb.com/recommendation-for-version: xpack-9.1.9
+ creationTimestamp: "2025-01-29T12:06:43Z"
+ generation: 5
+ labels:
+ app.kubernetes.io/instance: elastic
+ app.kubernetes.io/managed-by: kubedb.com
+ app.kubernetes.io/type: version-update
+ kubedb.com/version-update-recommendation-type: major-minor
+ name: elastic-x-elasticsearch-x-update-version-2juuee
+ namespace: es
+ resourceVersion: "783271"
+ uid: 3026d740-64fd-4ac4-8f33-2bd305ab0e69
+spec:
+ backoffLimit: 5
+ description: Latest Major/Minor version is available. Recommending version Update
+ from xpack-9.1.9 to xpack-9.2.3.
+ operation:
+ apiVersion: ops.kubedb.com/v1alpha1
+ kind: ElasticsearchOpsRequest
+ metadata:
+ name: update-version
+ namespace: es
+ spec:
+ databaseRef:
+ name: elastic
+ type: UpdateVersion
+ updateVersion:
+ targetVersion: xpack-9.2.3
+ status: {}
+ recommender:
+ name: kubedb-ops-manager
+ requireExplicitApproval: true
+ rules:
+ failed: has(self.status) && has(self.status.phase) && self.status.phase == 'Failed'
+ inProgress: has(self.status) && has(self.status.phase) && self.status.phase ==
+ 'Progressing'
+ success: has(self.status) && has(self.status.phase) && self.status.phase == 'Successful'
+ target:
+ apiGroup: kubedb.com
+ kind: Elasticsearch
+ name: elastic
+ vulnerabilityReport:
+ message: 'ImageScanRequest phase is not Current: timed out waiting for the condition'
+ status: Failure
+status:
+ approvalStatus: Pending
+ failedAttempt: 0
+ outdated: false
+ parallelism: Namespace
+ phase: Pending
+ reason: WaitingForApproval
+```
+
+In the generated Recommendation you will find a description, targeted db object, recommended operation or Ops-Request manifest, current status of the recommendation etc. Let's just focus on the recommendation description first.
+
+```shell
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-update-version-2juuee -o jsonpath='{.spec.description}'
+Latest Major/Minor version is available. Recommending version Update from xpack-9.1.9 to xpack-9.2.3.
+```
+
+The recommendation says current version `xpack-9.1.9` should be upgraded to latest upgradable version `xpack-9.2.3`. You can also find the recommended operation which is a `ElasticsearchOpsRequest` of `UpdateVersion` type in this case.
+
+```shell
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-update-version-2juuee -o jsonpath='{.spec.operation}' | yq -y
+apiVersion: ops.kubedb.com/v1alpha1
+kind: ElasticsearchOpsRequest
+metadata:
+ name: update-version
+ namespace: es
+spec:
+ databaseRef:
+ name: elastic
+ type: UpdateVersion
+ updateVersion:
+ targetVersion: xpack-9.2.3
+status: {}
+```
+
+Let's check the status part of this recommendation.
+
+```bash
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-update-version-2juuee -o jsonpath='{.status}' | yq -y
+approvalStatus: Pending
+failedAttempt: 0
+outdated: false
+parallelism: Namespace
+phase: Pending
+reason: WaitingForApproval
+```
+
+Now, This recommendation can be approved and operation can be executed immediately by setting `ApprovalStatus` to `Approved` and Setting `approvedWindow` to `Immediate`. You can approve this easily through Appscode UI or edit it manually. Also, You can use kubectl CLI for this -
+
+```bash
+$ kubectl patch Recommendation elastic-x-elasticsearch-x-update-version-2juuee \
+ -n es \
+ --type merge \
+ --subresource='status' \
+ -p '{"status":{"approvalStatus":"Approved","approvedWindow":{"window":"Immediate"}}}'
+recommendation.supervisor.appscode.com/elastic-x-elasticsearch-x-update-version-2juuee patched
+```
+
+Now, check the status part again. You will find a condition have appeared which says `OpsRequest is successfully created`.
+
+```bash
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-update-version-2juuee -o jsonpath='{.status}' | yq -y
+approvalStatus: Approved
+approvedWindow:
+ window: Immediate
+conditions:
+ - lastTransitionTime: '2025-01-29T13:01:40Z'
+ message: OpsRequest is successfully created
+ reason: SuccessfullyCreatedOperation
+ status: 'True'
+ type: SuccessfullyCreatedOperation
+createdOperationRef:
+ name: elastic-1738155700-update-version-auto
+failedAttempt: 0
+outdated: false
+parallelism: Namespace
+phase: InProgress
+reason: StartedExecutingOperation
+```
+
+You will find an `ElasticsearchOpsRequest` custom resource have been created and, it is updating the `elastic` cluster version to `xpack-9.2.3` with negligible downtime. Let's wait for it to reach `Successful` status.
+
+```bash
+$ kubectl get elasticsearchopsrequest -n es elastic-1738155700-update-version-auto -w
+NAME TYPE STATUS AGE
+elastic-1738155700-update-version-auto UpdateVersion Progressing 3m12s
+elastic-1738155700-update-version-auto UpdateVersion Progressing 3m34s
+.
+.
+elastic-1738155700-update-version-auto UpdateVersion Successful 11m
+```
+
+Let's recheck the recommendation for one last time. We should find that `.status.phase` has been marked as `Succeeded`.
+
+```bash
+$ kubectl get recommendation -n es elastic-x-elasticsearch-x-update-version-2juuee
+NAME STATUS OUTDATED AGE
+elastic-x-elasticsearch-x-update-version-2juuee Succeeded false 78m
+```
+
+Finally, You can check `elastic` cluster version now, which should be upgraded to version `xpack-9.2.3`.
+
+```bash
+$ kubectl get es elastic -n es
+NAME VERSION STATUS AGE
+elastic xpack-9.2.3 Ready 85m
+```
+
+You may not want to do trigger recommended operations manually. Rather, trigger them autonomously in a preferred schedule when infrastructure is idle or traffic rate is at the lowest. For this purpose, You can create a `MaintenanceWindow` custom resource where you can set your desired schedule/period for triggering these recommended operations automatically. Here's a sample one:
+
+```yaml
+apiVersion: supervisor.appscode.com/v1alpha1
+kind: MaintenanceWindow
+metadata:
+ name: elastic-maintenance
+ namespace: es
+spec:
+ timezone: Asia/Dhaka
+ days:
+ Wednesday:
+ - start: 5:40AM
+ end: 7:00PM
+ dates:
+ - start: 2025-01-25T00:00:18Z
+ end: 2025-01-25T23:41:18Z
+```
+
+You can now create a `ApprovalPolicy` custom resource to refer this `MaintenanceWindow` for particular DB type. Following is a sample `ApprovalPolicy` for any `Elasticsearch` custom resource deployed in `es` namespace. This `ApprovalPolicy` custom resource is referring to the `elastic-maintenance` MaintenanceWindow created in the same namespace. You can also create `ClusterMaintenanceWindow` instead which is effective for cluster-wide operations and refer it here. The following ApprovalPolicy will trigger recommended operations when referred maintenance window timeframe is reached.
+
+```yaml
+apiVersion: supervisor.appscode.com/v1alpha1
+kind: ApprovalPolicy
+metadata:
+ name: es-policy
+ namespace: es
+maintenanceWindowRef:
+ name: elastic-maintenance
+targets:
+ - group: kubedb.com
+ kind: Elasticsearch
+ operations:
+ - group: ops.kubedb.com
+ kind: ElasticsearchOpsRequest
+```
+
+Lastly, If you want to reject a recommendation, you can just set `ApprovalStatus` to `Rejected` in the recommendation status section. Here's how you can do it using kubectl cli.
+
+```bash
+$ kubectl patch Recommendation elastic-x-elasticsearch-x-update-version-2juuee \
+ -n es \
+ --type merge \
+ --subresource='status' \
+ -p '{"status":{"approvalStatus":"Rejected"}}'
+recommendation.supervisor.appscode.com/elastic-x-elasticsearch-x-update-version-2juuee patched
+```
+
diff --git a/docs/reference/cli/_index.md b/docs/reference/cli/_index.md
index 7b08bb6f0..7bcc7151e 100644
--- a/docs/reference/cli/_index.md
+++ b/docs/reference/cli/_index.md
@@ -9,3 +9,4 @@ menu:
parent: reference
menu_name: docs_{{ .version }}
---
+
\ No newline at end of file
diff --git a/docs/reference/operator/kubedb-operator.md b/docs/reference/operator/kubedb-operator.md
index f628e7242..8e18d6517 100644
--- a/docs/reference/operator/kubedb-operator.md
+++ b/docs/reference/operator/kubedb-operator.md
@@ -6,7 +6,6 @@ menu:
name: Kubedb-Operator
parent: reference-operator
weight: 0
-
menu_name: docs_{{ .version }}
section_menu_id: reference
url: /docs/{{ .version }}/reference/operator/