diff --git a/README.md b/README.md index 09dbd77..3debc25 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,28 @@ The CSI driver needs to map OpenNebula virtual machines to Kubernetes nodes in a try to find out the OpenNebula VM ID in the list of its arguments. If it fails, the driver will try to read the VM ID from a file located at `/var/lib/cloud/vm-id`. -The recommended approach is to add the contents of the `contrib/one-context.sh` script to the start-up script of the -virtual machine. The script will take care of creating the `/var/lib/cloud/vm-id` file and populating its contents with -the correct VM ID. +#### VM ID Discovery -> [!NOTE] -> After adding the code from `contrib/one-context.sh` to the start-up script of a virtual machine, the virtual machine -> must be restarted for the new start-up script to be executed. +The CSI driver now automatically discovers the VM ID using an initContainer that queries the OpenNebula API. This eliminates the need for manual VM configuration scripts. + +The initContainer (`one-vmid:latest`) runs before the main CSI containers and: +1. Connects to the OpenNebula API using credentials from the `sp-one` secret +2. Queries the VM pool to find the VM matching the Kubernetes node name +3. Writes the VM ID to `/var/lib/cloud/vm-id` for the main container to use + +#### Required Secret + +Create a secret named `sp-one` in the `kube-system` namespace with the following keys: +- `ONE_API_ENDPOINT`: The OpenNebula API endpoint URL +- `ONE_API_USERNAME`: OpenNebula API username +- `ONE_API_PASSWORD`: OpenNebula API password + +```shell +kubectl create secret generic sp-one -n kube-system \ + --from-literal=ONE_API_ENDPOINT=http://your-opennebula-endpoint:2633/RPC2 \ + --from-literal=ONE_API_USERNAME=your-username \ + --from-literal=ONE_API_PASSWORD=your-password +``` ### Starting the CSI driver diff --git a/manifests/opennebula-csi-controllerplugin-deployment.yaml b/manifests/opennebula-csi-controllerplugin-deployment.yaml index 384a9f5..56c0297 100644 --- a/manifests/opennebula-csi-controllerplugin-deployment.yaml +++ b/manifests/opennebula-csi-controllerplugin-deployment.yaml @@ -13,6 +13,21 @@ spec: labels: name: storpool-csi-controllerplugin spec: + initContainers: + - image: one-vmid:latest + name: one-vmid-init + env: + - name: SP_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + envFrom: + - secretRef: + name: sp-one + volumeMounts: + - mountPath: /var/lib/cloud + name: cloud-dir containers: - args: - python3 @@ -29,6 +44,9 @@ spec: fieldPath: spec.nodeName - name: PYTHONUNBUFFERED value: "1" + envFrom: + - secretRef: + name: sp-one image: cts.storpool.com/opennebula-csi/pre-release:v0.0.24 name: opennebula-csi-plugin ports: @@ -136,9 +154,7 @@ spec: serviceAccountName: opennebula-csi-controller-sa terminationGracePeriodSeconds: 30 volumes: - - hostPath: - path: /var/lib/cloud - type: Directory + - emptyDir: {} name: cloud-dir - emptyDir: {} name: socket-dir diff --git a/manifests/opennebula-csi-nodeplugin.yaml b/manifests/opennebula-csi-nodeplugin.yaml index 3348b2e..8f480ef 100644 --- a/manifests/opennebula-csi-nodeplugin.yaml +++ b/manifests/opennebula-csi-nodeplugin.yaml @@ -12,6 +12,21 @@ spec: labels: name: opennebula-csi-nodeplugin spec: + initContainers: + - image: one-vmid:latest + name: one-vmid-init + env: + - name: SP_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + envFrom: + - secretRef: + name: sp-one + volumeMounts: + - mountPath: /var/lib/cloud + name: cloud-dir containers: - args: - python3 @@ -28,6 +43,9 @@ spec: fieldPath: spec.nodeName - name: PYTHONUNBUFFERED value: "1" + envFrom: + - secretRef: + name: sp-one image: cts.storpool.com/opennebula-csi/pre-release:v0.0.24 livenessProbe: failureThreshold: 5 @@ -64,7 +82,7 @@ spec: readOnly: true - args: - --csi-address=/csi/csi.sock - - --kubelet-registration-path=/var/lib/kubelet/plugins/csi.storpool.com/csi.sock + - --kubelet-registration-path=/var/lib/kubelet/plugins/csi.opennebula.com/csi.sock image: registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.8.0 imagePullPolicy: IfNotPresent name: node-driver-registrar @@ -97,9 +115,7 @@ spec: path: /dev type: Directory name: dev-dir - - hostPath: - path: /var/lib/cloud - type: Directory + - emptyDir: {} name: cloud-dir - hostPath: path: /var/lib/kubelet/plugins/csi.opennebula.io diff --git a/vmid-discover/Dockerfile b/vmid-discover/Dockerfile new file mode 100644 index 0000000..fcbe93a --- /dev/null +++ b/vmid-discover/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.10-slim-bookworm + +WORKDIR /app +RUN pip install pyone +ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_x86_64 /usr/sbin/dumb-init +RUN chmod +x /usr/sbin/dumb-init + +COPY vmid-discover.py . + +VOLUME ["/var/lib/cloud"] + +ENTRYPOINT ["/usr/sbin/dumb-init", "--"] + +CMD [ "python3", "vmid-discover.py" ] diff --git a/vmid-discover/vmid-discover.py b/vmid-discover/vmid-discover.py new file mode 100644 index 0000000..813b98c --- /dev/null +++ b/vmid-discover/vmid-discover.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 + +import os +import sys +import pyone + + +def get_config(): + """Get configuration from environment variables.""" + config = {} + required_vars = [ + "SP_NODE_NAME", + "ONE_API_ENDPOINT", + "ONE_API_USERNAME", + "ONE_API_PASSWORD", + ] + + missing_vars = [] + for var in required_vars: + value = os.environ.get(var) + if not value: + missing_vars.append(var) + else: + config[var] = value + + if missing_vars: + print( + f"Error: Missing required environment variables: {', '.join(missing_vars)}", + file=sys.stderr, + ) + sys.exit(1) + + return config + + +if __name__ == "__main__": + config = get_config() + + # Create API proxy + api = pyone.OneServer( + config["ONE_API_ENDPOINT"], + session=f"{config['ONE_API_USERNAME']}:{config['ONE_API_PASSWORD']}", + ) + + try: + for vm in api.vmpool.info(-1, -1, -1, 3).VM: + if vm.get_NAME() == config["SP_NODE_NAME"]: + vmid = vm.get_ID() + print("Found VM ID:", vmid) + with open("/var/lib/cloud/vm-id", "w") as f: + f.write(str(vmid)) + # Add a newline for consistency with contrib/one-context.sh + f.write("\n") + break + else: + print( + f"Error: No VM found with name {config['SP_NODE_NAME']}", + file=sys.stderr, + ) + sys.exit(1) + except pyone.OneException as e: + print(f"Error from the OpenNebula API: {e}", file=sys.stderr) + sys.exit(1) + finally: + api.server_close()