{"id":27945177,"url":"https://github.com/metal-stack/gardener-extension-ontap","last_synced_at":"2026-01-17T06:12:28.299Z","repository":{"id":272909128,"uuid":"918107550","full_name":"metal-stack/gardener-extension-ontap","owner":"metal-stack","description":"Gardener extension controller for the Netapp Ontap CSI Plugin.","archived":false,"fork":false,"pushed_at":"2025-10-28T14:31:19.000Z","size":471,"stargazers_count":0,"open_issues_count":10,"forks_count":0,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-10-28T16:27:08.760Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/metal-stack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-01-17T09:09:38.000Z","updated_at":"2025-10-28T10:27:52.000Z","dependencies_parsed_at":"2025-05-07T12:56:18.303Z","dependency_job_id":"857dec11-17cb-4f91-a255-345f11c749ae","html_url":"https://github.com/metal-stack/gardener-extension-ontap","commit_stats":null,"previous_names":["metal-stack/gardener-extension-ontap"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/metal-stack/gardener-extension-ontap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metal-stack%2Fgardener-extension-ontap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metal-stack%2Fgardener-extension-ontap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metal-stack%2Fgardener-extension-ontap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metal-stack%2Fgardener-extension-ontap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metal-stack","download_url":"https://codeload.github.com/metal-stack/gardener-extension-ontap/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metal-stack%2Fgardener-extension-ontap/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285258051,"owners_count":27140780,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-19T02:00:05.673Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-07T12:56:16.907Z","updated_at":"2025-11-19T14:03:25.478Z","avatar_url":"https://github.com/metal-stack.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Gardener Extension for NetApp ONTAP CSI Plugin\n\nThis repository contains the Gardener extension controller for managing the NetApp ONTAP CSI Plugin.\n\n## Table of Contents\n\n- [Prerequisites](#prerequisites)\n- [Development Workflow](#development-workflow)\n- [Test Environment Setup](#test-environment-setup)\n- [Known Issues](#known-issues)\n- [TODO List](#todo-list)\n\n## Prerequisites\n\n- A local Gardener setup\n\n## Development Workflow\n\n### Setup Gardener Locally\n\n1. Clone the Gardener Repository:\n\n```bash\ngit clone git@github.com:gardener/gardener.git\n```\n\n2. Start a local Kubernetes cluster:\n\n```bash\nmake kind-up\n```\n\n3. Deploy Gardener:\n\n```bash\nmake gardener-up\n```\n\n4. Generate Helm Charts:\n\n```bash\nmake generate\n```\n\n### Deploy the Extension\n\n1. Apply the example configuration:\n\n```bash\nkubectl apply -k example/\n```\n\n2. Apply the shoot cluster configuration:\n\n```bash\nkubectl apply -f example/shoot.yaml\n```\n\n### Update Code Changes\n\nWhen making changes to the code, build and deploy locally using:\n\n```bash\nmake push-to-gardener-local\n```\n\n### Access the Shoot Cluster\n\n1. Adjust your `/etc/hosts` file:\n\n```bash\ncat \u003c\u003cEOF | sudo tee -a /etc/hosts\n# Begin of Gardener local setup section\n# Shoot API server domains\n172.18.255.1 api.local.local.external.local.gardener.cloud\n172.18.255.1 api.local.local.internal.local.gardener.cloud\n# Ingress\n172.18.255.1 p-seed.ingress.local.seed.local.gardener.cloud\n172.18.255.1 g-seed.ingress.local.seed.local.gardener.cloud\n172.18.255.1 gu-local--local.ingress.local.seed.local.gardener.cloud\n172.18.255.1 p-local--local.ingress.local.seed.local.gardener.cloud\n172.18.255.1 v-local--local.ingress.local.seed.local.gardener.cloud\n# End of Gardener local setup section\nEOF\n```\n\n2. Generate the kubeconfig for the shoot cluster:\n\n```bash\n./hack/usage/generate-admin-kubeconf.sh \u003e admin-kubeconf.yaml\n```\n\n3. Trigger a reconciliation if needed:\n\n```bash\nkubectl -n garden-\u003cproject-name\u003e annotate shoot \u003cshoot-name\u003e gardener.cloud/operation=reconcile\n```\n\n## Test Environment Setup\n\nTo properly set up the test environment, we need to configure network translation between the external IPs (10.x) and internal KVM network (192.168.x).\n\n### Simulator Host Machine Configuration\n\n#### Cluster Management Interface\n\n```bash\n# Port Forward rules\nsudo iptables -t nat -A PREROUTING -i lan0 -p tcp --dport 443 -d 10.130.184.5 -j DNAT --to-destination 192.168.10.11\nsudo iptables -t nat -A PREROUTING -i lan1 -p tcp --dport 443 -d 10.130.184.5 -j DNAT --to-destination 192.168.10.11\n\n# NAT rules\nsudo iptables -t nat -A POSTROUTING -o lan0 -p tcp --dport 443 -d 192.168.10.11 -j SNAT --to-source 10.130.184.5\nsudo iptables -t nat -A POSTROUTING -o lan1 -p tcp --dport 443 -d 192.168.10.11 -j SNAT --to-source 10.130.184.5\n\n# Forward rules\nsudo iptables -I FORWARD 1 -i lan0 -o br-ontap-data -d 192.168.10.11 -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT\nsudo iptables -I FORWARD 2 -i lan1 -o br-ontap-data -d 192.168.10.11 -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT\nsudo iptables -I FORWARD 3 -i br-ontap-data -o lan0 -s 192.168.10.11 -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\nsudo iptables -I FORWARD 4 -i br-ontap-data -o lan1 -s 192.168.10.11 -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n```\n\n#### SVM Management Interface\n\n```bash\n# Port Forward rules\nsudo iptables -t nat -A PREROUTING -i lan0 -p tcp --dport 443 -d 10.130.184.6 -j DNAT --to-destination 192.168.10.29\nsudo iptables -t nat -A PREROUTING -i lan1 -p tcp --dport 443 -d 10.130.184.6 -j DNAT --to-destination 192.168.10.29\n\n# NAT rules\nsudo iptables -t nat -A POSTROUTING -o lan0 -p tcp --dport 443 -d 192.168.10.29 -j SNAT --to-source 10.130.184.6\nsudo iptables -t nat -A POSTROUTING -o lan1 -p tcp --dport 443 -d 192.168.10.29 -j SNAT --to-source 10.130.184.6\n\n# Forward rules\nsudo iptables -I FORWARD 1 -i lan0 -o br-ontap-data -d 192.168.10.29 -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT\nsudo iptables -I FORWARD 2 -i lan1 -o br-ontap-data -d 192.168.10.29 -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT\nsudo iptables -I FORWARD 3 -i br-ontap-data -o lan0 -s 192.168.10.29 -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\nsudo iptables -I FORWARD 4 -i br-ontap-data -o lan1 -s 192.168.10.29 -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n```\n\n#### SVM Data Interface\n\n```bash\n# Port Forward rules\nsudo iptables -t nat -A PREROUTING -i lan0 -p tcp --dport 4420 -d 10.130.184.7 -j DNAT --to-destination 192.168.10.30\nsudo iptables -t nat -A PREROUTING -i lan1 -p tcp --dport 4420 -d 10.130.184.7 -j DNAT --to-destination 192.168.10.30\n\n# NAT rules\nsudo iptables -t nat -A POSTROUTING -o lan0 -p tcp --dport 4420 -j SNAT --to-source 10.130.184.7\nsudo iptables -t nat -A POSTROUTING -o lan1 -p tcp --dport 4420 -d 192.168.10.30 -j SNAT --to-source 10.130.184.7\n\n# Forward rules\nsudo iptables -I FORWARD 1 -i lan0 -o br-ontap-data -d 192.168.10.30 -p tcp --dport 4420 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT\nsudo iptables -I FORWARD 2 -i lan1 -o br-ontap-data -d 192.168.10.30 -p tcp --dport 4420 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT\nsudo iptables -I FORWARD 3 -i br-ontap-data -o lan0 -s 192.168.10.30 -p tcp --sport 4420 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\nsudo iptables -I FORWARD 4 -i br-ontap-data -o lan1 -s 192.168.10.30 -p tcp --sport 4420 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n```\n\n### Worker Node Configuration\n\nConfigure the worker node with these rules:\n\n```bash\niptables -t nat -A OUTPUT -d 192.168.10.30 -j DNAT --to-destination 10.130.184.7\niptables -t nat -A OUTPUT -d 192.168.10.30 -p tcp --dport 4420 -j DNAT --to-destination 10.130.184.7:4420\niptables -t nat -A POSTROUTING -d 10.130.184.7 -j MASQUERADE\n\necho \"10.130.184.7 192.168.10.30\" \u003e\u003e /etc/hosts\n```\n\n### Required Network Policies\n\n#### Clusterwidewide Network Policy in Shoot:\n\n```bash\napiVersion: metal-stack.io/v1\nkind: ClusterwideNetworkPolicy\nmetadata:\n  namespace: firewall\n  name: allow-nvme-port\nspec:\n  egress:\n  - to:\n    - cidr: 10.130.184.7/32\n    ports:\n    - protocol: TCP\n      port: 4420\n```\n\n#### Clusterwidewide Network Policy in Seed:\n\n```bash\napiVersion: metal-stack.io/v1\nkind: ClusterwideNetworkPolicy\nmetadata:\n  namespace: firewall\n  name: allow-mgmt-port\nspec:\n  egress:\n  - to:\n    - cidr: 10.130.184.5/32\n    ports:\n    - protocol: TCP\n      port: 443\n```\n\n## Known Issues\n\n- In local environments, using the \"Default\" broadcast domain can result in \"no route to host\" errors. Using \"Default-1\" broadcast domain resolves this issue.\n- On test environments, the opposite is true - \"Default\" works but \"Default-1\" fails.\n- In the simulator, ports e0c and e0d are not functional. Use only e0a and e0b.\n- The Trident NVMe driver automatically uses network interfaces that are internally assigned. See [Trident issue #1007](https://github.com/NetApp/trident/issues/1007) for details.\n- When an SVM already exists, the secret in the shoot isn't created because it assumes the secret is already in the seed.\n\n## TODO List\n\n- Fix SVM secret creation when SVM already exists\n- Implement proper SVM deletion logic\n- Add default gateway/routing configuration for SVMs\n- Fix hardcoded password in the `GenerateSecurePassword` function\n- Implement network route creation after SVM setup\n- Add monitoring and alerting for SVM health\n- Create proper cleanup and lifecycle management\n\n## Creating ONTAP Encrypted Volumes\n\nTo create an encrypted volume using NetApp Trident CSI, you need three components:\n\n1. Secret with LUKS Passphrase\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: storage-encryption-key\n  namespace: \u003cnamespace-of-the-pvc\u003e\nstringData:\n  luks-passphrase-name: A\n  luks-passphrase: secretA\n```\n\n2. StorageClass with Encryption Annotations\n\nThe StorageClass must include CSI node stage secret annotations:\n\n```yaml\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n  name: ontap-encrypted\nprovisioner: csi.trident.netapp.io\nparameters:\n  selector: \"luks=true\"\n  csi.storage.k8s.io/node-stage-secret-name: storage-encryption-key\n  csi.storage.k8s.io/node-stage-secret-namespace: ${pvc.namespace}\n  backendType: \"ontap-san\"\n  provisioningType: \"thin\"\n  fsType: \"ext4\"\nallowVolumeExpansion: true\n```\n\n3. PVC Using the Encrypted StorageClass\n\n```yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ontap-encrypted-volume\nspec:\n  storageClassName: ontap-encrypted\n  accessModes:\n    - ReadWriteOnce\n  resources:\n    requests:\n      storage: 1Gi\n```\n\n### Key Requirements\n\n- Secret name in StorageClass must match actual secret name\n- Secret namespace in StorageClass must match where secret is created\n- PVC must reference the StorageClass with encryption annotations\n\n### **Reconcile State Matrix**\n\n| SVM | Data LIFs | Mgmt LIF | ONTAP User | Seed Secret | Action Taken                                   | Code Path                                                            |\n| --- | --------- | -------- | ---------- | ----------- | ---------------------------------------------- | -------------------------------------------------------------------- |\n| ❌  | ❌        | ❌       | ❌         | ❌          | Create complete SVM from scratch               | `EnsureCompleteSVM()` → `CreateSVM()`                                |\n| ✅  | ❌        | ❌       | ❌         | ❌          | Validate SVM + Create all LIFs + Create User   | `validateAndEnsureCompleteSVMState()`                                |\n| ✅  | ✅        | ❌       | ❌         | ❌          | Create missing data LIFs + Mgmt LIF + User     | `validateAndEnsureDataLIFs()` + `validateAndEnsureManagementLIF()`   |\n| ✅  | ✅        | ❌       | ❌         | ❌          | Create management LIF + Complete user creation | `validateAndEnsureManagementLIF()` → `createCompleteUserAndSecret()` |\n| ✅  | ✅        | ✅       | ❌         | ❌          | Create ONTAP user and K8s secret               | `createCompleteUserAndSecret()`                                      |\n| ✅  | ✅        | ✅       | ✅         | ❌          | Reset ONTAP password + Create K8s secret       | `resetONTAPUserPassword()` → `buildAndCreateSecretInSeed()`          |\n| ✅  | ✅        | ✅       | ❌         | ✅          | Create ONTAP user with existing K8s password   | `createONTAPUserWithPassword()`                                      |\n| ✅  | ✅        | ✅       | ✅         | ✅          | Validate password consistency                  | `validatePasswordConsistency()`                                      |\n| ✅  | ✅        | ✅       | ✅         | ❌          | Fix corrupted secret (empty password)          | `resetONTAPUserPassword()` → `updateSecretInSeed()`                  |\n\n### **Legend**\n\n- ✅ = Resource exists and is correct\n- ❌ = Resource missing or not functional\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetal-stack%2Fgardener-extension-ontap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetal-stack%2Fgardener-extension-ontap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetal-stack%2Fgardener-extension-ontap/lists"}