From 26ca58419ff3d6ec75a4b3767b3bb6fc6e3c4a5b Mon Sep 17 00:00:00 2001
From: Peter Metz <petermetz@users.noreply.github.com>
Date: Mon, 25 Feb 2019 22:45:30 -0800
Subject: [PATCH] feat(external-provisioner): adds support for
 local-path-provisioner (#4232)

* feat(external-provisioner/local-path-provisioner): adds support for local path provisioner

Helpful for local development but also in production workloads (once the
permission model is worked out) where you have redundancy built into the
software uses the PVCs (e.g. database cluster with synchronous
replication)

* feat(local-path-provisioner): adds debug flag, image tag group var

* fix(local-path-provisioner): moves image repo/tag to download role

* test(gce_centos7-flannel): enables local-path-provisioner in test case

* fix(addons): add image repo/tag to commented default values

* fix(local-path-provisioner): typo in jinja template for local path provisioner

* style(local-path-provisioner): debug flag condition re-formatted

* fix(local-path-provisioner): adds missing default value for debug flag

* fix(local-path-provisioner): syntax fix for debug if condition end

* fix(local-path-provisioner): jinja template syntax: if condition white space
---
 Vagrantfile                                   |   6 +-
 .../sample/group_vars/k8s-cluster/addons.yml  |  10 ++
 roles/download/defaults/main.yml              |  11 ++
 .../local_path_provisioner/defaults/main.yml  |   7 ++
 .../local_path_provisioner/tasks/main.yml     |  40 +++++++
 .../templates/local-path-storage.yaml.j2      | 111 ++++++++++++++++++
 .../external_provisioner/meta/main.yml        |   7 ++
 tests/files/gce_centos7-flannel-addons.yml    |   1 +
 8 files changed, 192 insertions(+), 1 deletion(-)
 create mode 100644 roles/kubernetes-apps/external_provisioner/local_path_provisioner/defaults/main.yml
 create mode 100644 roles/kubernetes-apps/external_provisioner/local_path_provisioner/tasks/main.yml
 create mode 100644 roles/kubernetes-apps/external_provisioner/local_path_provisioner/templates/local-path-storage.yaml.j2

diff --git a/Vagrantfile b/Vagrantfile
index da3d50e81..8ecaf246d 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -52,6 +52,8 @@ $kube_node_instances_with_disks_size = "20G"
 $kube_node_instances_with_disks_number = 2
 $override_disk_size = false
 $disk_size = "20GB"
+$local_path_provisioner_enabled = false
+$local_path_provisioner_claim_root = "/opt/local-path-provisioner/"
 
 $playbook = "cluster.yml"
 
@@ -180,7 +182,9 @@ Vagrant.configure("2") do |config|
         "kube_network_plugin_multus": $multi_networking,
         "docker_keepcache": "1",
         "download_run_once": "True",
-        "download_localhost": "False"
+        "download_localhost": "False",
+        "local_path_provisioner_enabled": "#{$local_path_provisioner_enabled}",
+        "local_path_provisioner_claim_root": "#{$local_path_provisioner_claim_root}"
       }
 
       # Only execute the Ansible provisioner once, when all the machines are up and ready.
diff --git a/inventory/sample/group_vars/k8s-cluster/addons.yml b/inventory/sample/group_vars/k8s-cluster/addons.yml
index 269513c7f..ee6bdfc3a 100644
--- a/inventory/sample/group_vars/k8s-cluster/addons.yml
+++ b/inventory/sample/group_vars/k8s-cluster/addons.yml
@@ -17,6 +17,16 @@ metrics_server_enabled: false
 # metrics_server_metric_resolution: 60s
 # metrics_server_kubelet_preferred_address_types: "InternalIP"
 
+# Rancher Local Path Provisioner
+local_path_provisioner_enabled: false
+# local_path_provisioner_namespace: "local-path-storage"
+# local_path_provisioner_storage_class: "local-path"
+# local_path_provisioner_reclaim_policy: Delete
+# local_path_provisioner_claim_root: /opt/local-path-provisioner/
+# local_path_provisioner_debug: false
+# local_path_provisioner_image_repo: "rancher/local-path-provisioner"
+# local_path_provisioner_image_tag: "v0.0.2"
+
 # Local volume provisioner deployment
 local_volume_provisioner_enabled: false
 # local_volume_provisioner_namespace: kube-system
diff --git a/roles/download/defaults/main.yml b/roles/download/defaults/main.yml
index 0955242f1..31752bd67 100644
--- a/roles/download/defaults/main.yml
+++ b/roles/download/defaults/main.yml
@@ -291,6 +291,8 @@ local_volume_provisioner_image_repo: "quay.io/external_storage/local-volume-prov
 local_volume_provisioner_image_tag: "v2.1.0"
 cephfs_provisioner_image_repo: "quay.io/external_storage/cephfs-provisioner"
 cephfs_provisioner_image_tag: "v2.1.0-k8s1.11"
+local_path_provisioner_image_repo: "rancher/local-path-provisioner"
+local_path_provisioner_image_tag: "v0.0.2"
 ingress_nginx_controller_image_repo: "quay.io/kubernetes-ingress-controller/nginx-ingress-controller"
 ingress_nginx_controller_image_tag: "0.21.0"
 cert_manager_version: "v0.5.2"
@@ -700,6 +702,15 @@ downloads:
     groups:
       - kube-node
 
+  local_path_provisioner:
+    enabled: "{{ local_volume_provisioner_enabled }}"
+    container: true
+    repo: "{{ local_path_provisioner_image_repo }}"
+    tag: "{{ local_path_provisioner_image_tag }}"
+    sha256: "{{ local_path_provisioner_digest_checksum|default(None) }}"
+    groups:
+      - kube-node
+
   ingress_nginx_controller:
     enabled: "{{ ingress_nginx_enabled }}"
     container: true
diff --git a/roles/kubernetes-apps/external_provisioner/local_path_provisioner/defaults/main.yml b/roles/kubernetes-apps/external_provisioner/local_path_provisioner/defaults/main.yml
new file mode 100644
index 000000000..0f24ac0b9
--- /dev/null
+++ b/roles/kubernetes-apps/external_provisioner/local_path_provisioner/defaults/main.yml
@@ -0,0 +1,7 @@
+---
+local_path_provisioner_namespace: "local-path-storage"
+local_path_provisioner_storage_class: "local-path"
+local_path_provisioner_reclaim_policy: Delete
+local_path_provisioner_claim_root: /opt/local-path-provisioner/
+local_path_provisioner_is_default_storageclass: "true"
+local_path_provisioner_debug: false
diff --git a/roles/kubernetes-apps/external_provisioner/local_path_provisioner/tasks/main.yml b/roles/kubernetes-apps/external_provisioner/local_path_provisioner/tasks/main.yml
new file mode 100644
index 000000000..27d52ad7c
--- /dev/null
+++ b/roles/kubernetes-apps/external_provisioner/local_path_provisioner/tasks/main.yml
@@ -0,0 +1,40 @@
+---
+
+- name: Local Path Provisioner | Create addon dir
+  file:
+    path: "{{ kube_config_dir }}/addons/local_path_provisioner"
+    state: directory
+    owner: root
+    group: root
+    mode: 0755
+  when:
+    - inventory_hostname == groups['kube-master'][0]
+
+- name: Local Path Provisioner | Create claim root dir
+  file:
+    path: "{{ local_path_provisioner_claim_root }}"
+    state: directory
+
+- name: Local Path Provisioner | Render Template
+  set_fact:
+    local_path_provisioner_templates:
+      - { name: local-path-storage, file: local-path-storage.yaml, type: sc }
+
+- name: Local Path Provisioner | Create manifests
+  template:
+    src: "{{ item.file }}.j2"
+    dest: "{{ kube_config_dir }}/addons/local_path_provisioner/{{ item.file }}"
+  with_items: "{{ local_path_provisioner_templates }}"
+  register: local_path_provisioner_manifests
+  when: inventory_hostname == groups['kube-master'][0]
+
+- name: Local Path Provisioner | Apply manifests
+  kube:
+    name: "{{ item.item.name }}"
+    namespace: "{{ local_path_provisioner_namespace }}"
+    kubectl: "{{ bin_dir }}/kubectl"
+    resource: "{{ item.item.type }}"
+    filename: "{{ kube_config_dir }}/addons/local_path_provisioner/{{ item.item.file }}"
+    state: "latest"
+  with_items: "{{ local_path_provisioner_manifests.results }}"
+  when: inventory_hostname == groups['kube-master'][0]
diff --git a/roles/kubernetes-apps/external_provisioner/local_path_provisioner/templates/local-path-storage.yaml.j2 b/roles/kubernetes-apps/external_provisioner/local_path_provisioner/templates/local-path-storage.yaml.j2
new file mode 100644
index 000000000..7ea18ab14
--- /dev/null
+++ b/roles/kubernetes-apps/external_provisioner/local_path_provisioner/templates/local-path-storage.yaml.j2
@@ -0,0 +1,111 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: {{ local_path_provisioner_namespace }}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: local-path-provisioner-service-account
+  namespace: {{ local_path_provisioner_namespace }}
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRole
+metadata:
+  name: local-path-provisioner-role
+  namespace: {{ local_path_provisioner_namespace }}
+rules:
+- apiGroups: [""]
+  resources: ["nodes", "persistentvolumeclaims"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: [""]
+  resources: ["endpoints", "persistentvolumes", "pods"]
+  verbs: ["*"]
+- apiGroups: [""]
+  resources: ["events"]
+  verbs: ["create", "patch"]
+- apiGroups: ["storage.k8s.io"]
+  resources: ["storageclasses"]
+  verbs: ["get", "list", "watch"]
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRoleBinding
+metadata:
+  name: local-path-provisioner-bind
+  namespace: {{ local_path_provisioner_namespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: local-path-provisioner-role
+subjects:
+- kind: ServiceAccount
+  name: local-path-provisioner-service-account
+  namespace: {{ local_path_provisioner_namespace }}
+---
+apiVersion: apps/v1beta2
+kind: Deployment
+metadata:
+  name: local-path-provisioner
+  namespace: {{ local_path_provisioner_namespace }}
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: local-path-provisioner
+  template:
+    metadata:
+      labels:
+        app: local-path-provisioner
+    spec:
+      serviceAccountName: local-path-provisioner-service-account
+      containers:
+      - name: local-path-provisioner
+        image: {{ local_path_provisioner_image_repo }}:{{ local_path_provisioner_image_tag }}
+        imagePullPolicy: Always
+        command:
+        - local-path-provisioner
+        - start
+        - --config
+        - /etc/config/config.json
+{% if local_path_provisioner_debug|default(false) %}
+        - --debug
+{% endif %}
+        volumeMounts:
+        - name: config-volume
+          mountPath: /etc/config/
+        env:
+        - name: POD_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+      volumes:
+        - name: config-volume
+          configMap:
+            name: local-path-config
+---
+apiVersion: storage.k8s.io/v1
+kind: StorageClass
+metadata:
+  name: {{ local_path_provisioner_storage_class }}
+  annotations:
+    storageclass.kubernetes.io/is-default-class: {{ local_path_provisioner_is_default_storageclass }}
+provisioner: rancher.io/local-path
+volumeBindingMode: WaitForFirstConsumer
+reclaimPolicy: {{ local_path_provisioner_reclaim_policy }}
+---
+kind: ConfigMap
+apiVersion: v1
+metadata:
+  name: local-path-config
+  namespace: {{ local_path_provisioner_namespace }}
+data:
+  config.json: |-
+        {
+                "nodePathMap":[
+                {
+                        "node":"DEFAULT_PATH_FOR_NON_LISTED_NODES",
+                        "paths":["{{ local_path_provisioner_claim_root }}"]
+                }
+                ]
+        }
+
diff --git a/roles/kubernetes-apps/external_provisioner/meta/main.yml b/roles/kubernetes-apps/external_provisioner/meta/main.yml
index 92aad2c72..8b3dbdee1 100644
--- a/roles/kubernetes-apps/external_provisioner/meta/main.yml
+++ b/roles/kubernetes-apps/external_provisioner/meta/main.yml
@@ -15,3 +15,10 @@ dependencies:
       - apps
       - cephfs-provisioner
       - external-provisioner
+
+  - role: kubernetes-apps/external_provisioner/local_path_provisioner
+    when: local_path_provisioner_enabled
+    tags:
+      - apps
+      - local-path-provisioner
+      - external-provisioner
diff --git a/tests/files/gce_centos7-flannel-addons.yml b/tests/files/gce_centos7-flannel-addons.yml
index 98702cf90..c073d3d67 100644
--- a/tests/files/gce_centos7-flannel-addons.yml
+++ b/tests/files/gce_centos7-flannel-addons.yml
@@ -21,3 +21,4 @@ metrics_server_enabled: true
 kube_token_auth: true
 kube_basic_auth: true
 enable_nodelocaldns: true
+local_path_provisioner_enabled: true
-- 
GitLab