Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions documentdb-kubectl-plugin/cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ func (o *statusOptions) run(ctx context.Context, cmd *cobra.Command) error {
if err != nil {
return fmt.Errorf("failed to read spec.clusterReplication.primary: %w", err)
}
clusterNames, found, err := unstructured.NestedStringSlice(document.Object, "spec", "clusterReplication", "clusterList")
clusterListRaw, found, err := unstructured.NestedSlice(document.Object, "spec", "clusterReplication", "clusterList")
if err != nil {
return fmt.Errorf("failed to read spec.clusterReplication.clusterList: %w", err)
}
if !found || len(clusterNames) == 0 {
if !found || len(clusterListRaw) == 0 {
return errors.New("DocumentDB spec.clusterReplication.clusterList is empty")
}

Expand All @@ -120,8 +120,9 @@ func (o *statusOptions) run(ctx context.Context, cmd *cobra.Command) error {
}
fmt.Fprintln(cmd.OutOrStdout())

statuses := make([]clusterStatus, 0, len(clusterNames))
for _, cluster := range clusterNames {
statuses := make([]clusterStatus, 0, len(clusterListRaw))
for _, clusterObj := range clusterListRaw {
cluster := clusterObj.(map[string]interface{})["name"].(string)
role := "Replica"
if cluster == primaryCluster {
role = "Primary"
Expand Down
6 changes: 5 additions & 1 deletion documentdb-kubectl-plugin/cmd/status_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ func TestStatusRunRendersClusterTable(t *testing.T) {
docName := "documentdb-sample"

hubDoc := newDocument(docName, namespace, "cluster-a", "Ready")
if err := unstructured.SetNestedStringSlice(hubDoc.Object, []string{"cluster-a", "cluster-b"}, "spec", "clusterReplication", "clusterList"); err != nil {
clusterList := []interface{}{
map[string]interface{}{"name": "cluster-a"},
map[string]interface{}{"name": "cluster-b"},
}
if err := unstructured.SetNestedSlice(hubDoc.Object, clusterList, "spec", "clusterReplication", "clusterList"); err != nil {
t.Fatalf("failed to set clusterList: %v", err)
}
if err := unstructured.SetNestedField(hubDoc.Object, "PrimaryConn", "status", "connectionString"); err != nil {
Expand Down
12 changes: 12 additions & 0 deletions documentdb-playground/aws-setup/scripts/delete-cluster.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ REGION="us-west-2"
DELETE_CLUSTER="${DELETE_CLUSTER:-true}"
DELETE_OPERATOR="${DELETE_OPERATOR:-true}"
DELETE_INSTANCE="${DELETE_INSTANCE:-true}"
SKIP_CONFIRMATION="false"

# Parse command line arguments
while [[ $# -gt 0 ]]; do
Expand All @@ -37,6 +38,10 @@ while [[ $# -gt 0 ]]; do
REGION="$2"
shift 2
;;
-y|--yes)
SKIP_CONFIRMATION="true"
shift
;;
-h|--help)
echo "Usage: $0 [OPTIONS]"
echo ""
Expand All @@ -45,12 +50,14 @@ while [[ $# -gt 0 ]]; do
echo " --instance-and-operator Delete instances and operator (keep cluster)"
echo " --cluster-name NAME EKS cluster name (default: documentdb-cluster)"
echo " --region REGION AWS region (default: us-west-2)"
echo " -y, --yes Skip confirmation prompt"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0 # Delete everything (default)"
echo " $0 --instance-only # Delete only DocumentDB instances"
echo " $0 --instance-and-operator # Delete instances and operator, keep cluster"
echo " $0 --yes # Delete everything without confirmation"
exit 0
;;
*)
Expand Down Expand Up @@ -86,6 +93,11 @@ error() {

# Confirmation prompt
confirm_deletion() {
if [ "$SKIP_CONFIRMATION" == "true" ]; then
log "Skipping confirmation (--yes flag provided)"
return 0
fi

echo ""
echo "======================================="
echo " DELETION WARNING"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ possible and will be documented as they are tested.
- Two kubernetes clusters that are network connected to each other. For example using
- [Azure VPN Gatway](https://learn.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-about-vpngateways)
- [Azure ExpressRoute](https://learn.microsoft.com/en-us/azure/expressroute/expressroute-introduction)
- ENV variables `$AZURE_MEMBER` and `$ON_PREM_MEMBER` with the kubectl context names for your clusters
- ENV variables `$CLOUD_MEMBER` and `$ON_PREM_MEMBER` with the kubectl context names for your clusters
- (e.g. "azure-documentdb-cluster", "k3s-cluster-context")

## Architecture Overview
Expand Down Expand Up @@ -94,7 +94,7 @@ Run `kubectl get membercluster -A` again and see `True` under `JOINED` to confir

```bash
# Install on primary
kubectl config use-context $AZURE_MEMBER
kubectl config use-context $CLOUD_MEMBER
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set installCRDs=true
Expand Down Expand Up @@ -251,7 +251,7 @@ kubectl apply -f ./documentdb-base.yaml
After a few seconds, ensure that the operator is running on both of the clusters

```sh
kubectl config use-context $AZURE_MEMBER
kubectl config use-context $CLOUD_MEMBER
kubectl get deployment -n documentdb-operator
kubectl config use-context $ON_PREM_MEMBER
kubectl get deployment -n documentdb-operator
Expand All @@ -274,21 +274,21 @@ Physical replication provides high availability and disaster recovery capabiliti
```bash
kubectl config use-context $ON_PREM_MEMBER
kubectl create configmap cluster-name -n kube-system --from-literal=name=on-prem-cluster-name
kubectl config use-context $AZURE_MEMBER
kubectl create configmap cluster-name -n kube-system --from-literal=name=azure-cluster-name
kubectl config use-context $CLOUD_MEMBER
kubectl create configmap cluster-name -n kube-system --from-literal=name=cloud-cluster-name
```

OR

```bash
cat <<EOF > azure-cluster-name.yaml
cat <<EOF > cloud-cluster-name.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-name
namespace: kube-system
data:
name: "azure-cluster-name"
name: "cloud-cluster-name"
EOF

cat <<EOF > on-prem-name.yaml
Expand All @@ -301,7 +301,7 @@ data:
name: "on-prem-cluster-name"
EOF

kubectl config use-context $AZURE_MEMBER
kubectl config use-context $CLOUD_MEMBER
kubectl apply -f ./primary-name.yaml
kubectl config use-context $ON_PREM_MEMBER
kubectl apply -f ./replica-name.yaml
Expand Down Expand Up @@ -332,10 +332,10 @@ spec:
storage:
pvcSize: 10Gi
clusterReplication:
primary: azure-cluster-name
primary: cloud-cluster-name
clusterList:
- azure-cluster-name
- on-prem-cluster-name
- name: cloud-cluster-name
- name: on-prem-cluster-name
exposeViaService:
serviceType: ClusterIP

Expand Down Expand Up @@ -364,7 +364,7 @@ kubectl apply -f ./documentdb-resource.yaml
After a few seconds, ensure that the operator is running on both of the clusters

```sh
kubectl config use-context $AZURE_MEMBER
kubectl config use-context $CLOUD_MEMBER
kubectl get pods -n documentdb-operator-ns
kubectl config use-context $ON_PREM_MEMBER
kubectl get pods -n documentdb-operator-ns
Expand All @@ -374,16 +374,16 @@ Output:

```text
NAME READY STATUS RESTARTS AGE
azure-cluster-name-1 2/2 Running 0 3m33s
cloud-cluster-name-1 2/2 Running 0 3m33s
```

## Testing and Verification

1. Test connection to DocumentDB:

```bash
# Get the service IP from primary (azure)
kubectl config use-context $AZURE_MEMBER
# Get the service IP from primary (cloud)
kubectl config use-context $CLOUD_MEMBER
service_ip=$(kubectl get service documentdb-service-documentdb-preview -n documentdb-preview-ns -o jsonpath="{.status.loadBalancer.ingress[0].ip}")

# Connect using mongosh
Expand All @@ -410,7 +410,7 @@ kubectl config use-context hub
kubectl patch documentdb documentdb-preview -n documentdb-preview-ns \
--type='json' -p='[
{"op": "replace", "path": "/spec/clusterReplication/primary", "value":"on-prem-cluster-name"},
{"op": "replace", "path": "/spec/clusterReplication/clusterList", "value":["on-prem-cluster-name"]}
{"op": "replace", "path": "/spec/clusterReplication/clusterList", "value":[{"name": "on-prem-cluster-name"}]}
]'
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,36 @@ spec:
description: ClusterList is the list of clusters participating
in replication.
items:
type: string
properties:
environment:
description: |-
EnvironmentOverride is the cloud environment of the member cluster.
Will default to the global setting
enum:
- eks
- aks
- gke
type: string
name:
description: Name is the name of the member cluster.
type: string
storageClass:
description: StorageClassOverride specifies the storage
class for DocumentDB persistent volumes in this member
cluster.
type: string
required:
- name
type: object
type: array
enableFleetForCrossCloud:
description: EnableFleetForCrossCloud determines whether to use
KubeFleet mechanics for the replication
type: boolean
crossCloudNetworkingStrategy:
description: CrossCloudNetworking determines which type of networking
mechanics for the replication
enum:
- AzureFleet
- Istio
- None
type: string
highAvailability:
description: Whether or not to have replicas on the primary cluster.
type: boolean
Expand Down Expand Up @@ -279,14 +303,14 @@ spec:
properties:
connectionString:
type: string
localPrimary:
type: string
status:
description: Status reflects the status field from the underlying
CNPG Cluster.
type: string
targetPrimary:
type: string
localPrimary:
type: string
tls:
description: TLS reports gateway TLS provisioning status (Phase 1).
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,4 @@ metadata:
labels:
app.kubernetes.io/name: wal-replia-manager
app.kubernetes.io/managed-by: kustomize
{{- end }}
{{- end }}
18 changes: 15 additions & 3 deletions operator/src/api/preview/documentdb_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,28 @@ type StorageConfiguration struct {
}

type ClusterReplication struct {
// EnableFleetForCrossCloud determines whether to use KubeFleet mechanics for the replication
EnableFleetForCrossCloud bool `json:"enableFleetForCrossCloud,omitempty"`
// CrossCloudNetworking determines which type of networking mechanics for the replication
// +kubebuilder:validation:Enum=AzureFleet;Istio;None
CrossCloudNetworkingStrategy string `json:"crossCloudNetworkingStrategy,omitempty"`
// Primary is the name of the primary cluster for replication.
Primary string `json:"primary"`
// ClusterList is the list of clusters participating in replication.
ClusterList []string `json:"clusterList"`
ClusterList []MemberCluster `json:"clusterList"`
// Whether or not to have replicas on the primary cluster.
HighAvailability bool `json:"highAvailability,omitempty"`
}

type MemberCluster struct {
// Name is the name of the member cluster.
Name string `json:"name"`
// EnvironmentOverride is the cloud environment of the member cluster.
// Will default to the global setting
// +kubebuilder:validation:Enum=eks;aks;gke
EnvironmentOverride string `json:"environment,omitempty"`
// StorageClassOverride specifies the storage class for DocumentDB persistent volumes in this member cluster.
StorageClassOverride string `json:"storageClass,omitempty"`
}

type ExposeViaService struct {
// ServiceType determines the type of service to expose for DocumentDB.
// +kubebuilder:validation:Enum=LoadBalancer;ClusterIP
Expand Down
Loading
Loading