From df34e00014210e756ec92bf6f7f9e44fb18ae8db Mon Sep 17 00:00:00 2001 From: Mike Wilson Date: Mon, 14 May 2018 15:57:30 -0400 Subject: [PATCH] NFS support for default storage --- .../juju/layers/kubernetes-worker/layer.yaml | 1 + .../layers/kubernetes-worker/metadata.yaml | 3 + .../reactive/kubernetes_worker.py | 62 +++++++++++++++++++ .../templates/nfs-provisioner.yaml | 39 ++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 cluster/juju/layers/kubernetes-worker/templates/nfs-provisioner.yaml diff --git a/cluster/juju/layers/kubernetes-worker/layer.yaml b/cluster/juju/layers/kubernetes-worker/layer.yaml index 79fbdf117a3..d8ee6489845 100644 --- a/cluster/juju/layers/kubernetes-worker/layer.yaml +++ b/cluster/juju/layers/kubernetes-worker/layer.yaml @@ -14,6 +14,7 @@ includes: - 'interface:kube-control' - 'interface:aws' - 'interface:gcp' + - 'interface:mount' config: deletes: - install_from_upstream diff --git a/cluster/juju/layers/kubernetes-worker/metadata.yaml b/cluster/juju/layers/kubernetes-worker/metadata.yaml index 187106ce608..df4a823c90c 100644 --- a/cluster/juju/layers/kubernetes-worker/metadata.yaml +++ b/cluster/juju/layers/kubernetes-worker/metadata.yaml @@ -7,6 +7,7 @@ maintainers: - Konstantinos Tsakalozos - Charles Butler - Matthew Bruzek + - Mike Wilson description: | Kubernetes is an open-source platform for deploying, scaling, and operations of application containers across a cluster of hosts. Kubernetes is portable @@ -32,6 +33,8 @@ requires: interface: aws gcp: interface: gcp + nfs: + interface: mount provides: cni: interface: kubernetes-cni diff --git a/cluster/juju/layers/kubernetes-worker/reactive/kubernetes_worker.py b/cluster/juju/layers/kubernetes-worker/reactive/kubernetes_worker.py index 798c2ad7bce..82b7d3abca9 100644 --- a/cluster/juju/layers/kubernetes-worker/reactive/kubernetes_worker.py +++ b/cluster/juju/layers/kubernetes-worker/reactive/kubernetes_worker.py @@ -1174,3 +1174,65 @@ def _write_gcp_snap_config(component): daemon_env += '{}={}\n'.format(gcp_creds_env_key, creds_path) daemon_env_path.parent.mkdir(parents=True, exist_ok=True) daemon_env_path.write_text(daemon_env) + + +def get_first_mount(mount_relation): + mount_relation_list = mount_relation.mounts() + if mount_relation_list and len(mount_relation_list) > 0: + # mount relation list is a list of the mount layer relations + # for now we just use the first one that is nfs + for mount in mount_relation_list: + # for now we just check the first mount and use that. + # the nfs charm only supports one for now. + if ('mounts' in mount and + mount['mounts'][0]['fstype'] == 'nfs'): + return mount['mounts'][0] + return None + + +@when('nfs.available') +def nfs_state_control(mount): + ''' Determine if we should remove the state that controls the re-render + and execution of the nfs-relation-changed event because there + are changes in the relationship data, and we should re-render any + configs ''' + + mount_data = get_first_mount(mount) + if mount_data: + nfs_relation_data = { + 'options': mount_data['options'], + 'host': mount_data['hostname'], + 'mountpoint': mount_data['mountpoint'], + 'fstype': mount_data['fstype'] + } + + # Re-execute the rendering if the data has changed. + if data_changed('nfs-config', nfs_relation_data): + hookenv.log('reconfiguring nfs') + remove_state('nfs.configured') + + +@when('nfs.available') +@when_not('nfs.configured') +def nfs_storage(mount): + '''NFS on kubernetes requires nfs config rendered into a deployment of + the nfs client provisioner. That will handle the persistent volume claims + with no persistent volume to back them.''' + + mount_data = get_first_mount(mount) + if not mount_data: + return + + addon_path = '/root/cdk/addons/{}' + # Render the NFS deployment + manifest = addon_path.format('nfs-provisioner.yaml') + render('nfs-provisioner.yaml', manifest, mount_data) + hookenv.log('Creating the nfs provisioner.') + try: + kubectl('apply', '-f', manifest) + except CalledProcessError as e: + hookenv.log(e) + hookenv.log('Failed to create nfs provisioner. Will attempt again next update.') # noqa + return + + set_state('nfs.configured') diff --git a/cluster/juju/layers/kubernetes-worker/templates/nfs-provisioner.yaml b/cluster/juju/layers/kubernetes-worker/templates/nfs-provisioner.yaml new file mode 100644 index 00000000000..de3023a657e --- /dev/null +++ b/cluster/juju/layers/kubernetes-worker/templates/nfs-provisioner.yaml @@ -0,0 +1,39 @@ +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: default + annotations: + storageclass.kubernetes.io/is-default-class: "true" +provisioner: fuseim.pri/ifs +--- +kind: Deployment +apiVersion: extensions/v1beta1 +metadata: + name: nfs-client-provisioner +spec: + replicas: 1 + strategy: + type: Recreate + template: + metadata: + labels: + app: nfs-client-provisioner + spec: + containers: + - name: nfs-client-provisioner + image: quay.io/external_storage/nfs-client-provisioner:latest + volumeMounts: + - name: nfs-client-root + mountPath: /persistentvolumes + env: + - name: PROVISIONER_NAME + value: fuseim.pri/ifs + - name: NFS_SERVER + value: {{ hostname }} + - name: NFS_PATH + value: {{ mountpoint }} + volumes: + - name: nfs-client-root + nfs: + server: {{ hostname }} + path: {{ mountpoint }}