From 9f8da6c2253abb3b7f2df7fdb0c57650afc5566c Mon Sep 17 00:00:00 2001
From: "teuto.net Netzdienste GmbH" <github@teuto.net>
Date: Tue, 29 Mar 2016 14:50:22 +0200
Subject: [PATCH] Implemented cloud-provider integration for OpenStack.
 Currently kubespray does not install kubernetes in a way that allows cinder
 volumes to be used. This commit provides the necessary cloud configuration
 file and configures kubelet and kube-apiserver to use it.

---
 inventory/group_vars/all.yml                  |  4 ++-
 .../master/templates/kube-apiserver.j2        | 10 +++++++-
 .../templates/kube-apiserver.service.j2       |  3 ++-
 roles/kubernetes/node/templates/kubelet.j2    |  9 ++++++-
 .../node/templates/kubelet.service.j2         |  3 ++-
 roles/kubernetes/preinstall/defaults/main.yml | 10 ++++++++
 roles/kubernetes/preinstall/tasks/main.yml    | 15 +++++++++--
 .../tasks/openstack-credential-check.yml      | 25 +++++++++++++++++++
 .../templates/openstack-cloud-config.j2       |  6 +++++
 9 files changed, 78 insertions(+), 7 deletions(-)
 create mode 100644 roles/kubernetes/preinstall/tasks/openstack-credential-check.yml
 create mode 100644 roles/kubernetes/preinstall/templates/openstack-cloud-config.j2

diff --git a/inventory/group_vars/all.yml b/inventory/group_vars/all.yml
index 0fe6b5d86..5ed2035a9 100644
--- a/inventory/group_vars/all.yml
+++ b/inventory/group_vars/all.yml
@@ -103,7 +103,9 @@ dns_server: "{{ kube_service_addresses|ipaddr('net')|ipaddr(2)|ipaddr('address')
 
 # There are some changes specific to the cloud providers
 # for instance we need to encapsulate packets with some network plugins
-# If set the possible values are either 'gce' or 'aws'
+# If set the possible values are either 'gce', 'aws' or 'openstack'
+# When openstack is used make sure to source in the openstack credentials
+# like you would do when using nova-client before starting the playbook.
 # cloud_provider:
 
 # For multi masters architecture:
diff --git a/roles/kubernetes/master/templates/kube-apiserver.j2 b/roles/kubernetes/master/templates/kube-apiserver.j2
index b45fa46f2..a19687f30 100644
--- a/roles/kubernetes/master/templates/kube-apiserver.j2
+++ b/roles/kubernetes/master/templates/kube-apiserver.j2
@@ -38,7 +38,15 @@ KUBE_TLS_CONFIG="--tls_cert_file={{ kube_cert_dir }}/apiserver.pem --tls_private
 # Add you own!
 KUBE_API_ARGS="--token_auth_file={{ kube_token_dir }}/known_tokens.csv --basic-auth-file={{ kube_users_dir }}/known_users.csv --service_account_key_file={{ kube_cert_dir }}/apiserver-key.pem"
 
+{% if cloud_provider is defined and cloud_provider == "openstack" %}
+KUBELET_CLOUDPROVIDER="--cloud-provider={{ cloud_provider }} --cloud-config={{ kube_config_dir }}/cloud_config"
+{% else %}
+{# TODO: gce and aws don't need the cloud provider to be set? #}
+KUBELET_CLOUDPROVIDER=""
+{% endif %}
+
 {% if ansible_service_mgr in ["sysvinit","upstart"] %}
 DAEMON_ARGS="$KUBE_LOGGING $KUBE_LOG_LEVEL $KUBE_ALLOW_PRIV $KUBE_API_PORT $KUBE_SERVICE_ADDRESSES \
-$KUBE_ETCD_SERVERS $KUBE_ADMISSION_CONTROL $KUBE_RUNTIME_CONFIG $KUBE_TLS_CONFIG $KUBE_API_ARGS"
+$KUBE_ETCD_SERVERS $KUBE_ADMISSION_CONTROL $KUBE_RUNTIME_CONFIG $KUBE_TLS_CONFIG $KUBE_API_ARGS \
+$KUBELET_CLOUDPROVIDER"
 {% endif %}
diff --git a/roles/kubernetes/master/templates/kube-apiserver.service.j2 b/roles/kubernetes/master/templates/kube-apiserver.service.j2
index dbfd58f1c..90bc8e688 100644
--- a/roles/kubernetes/master/templates/kube-apiserver.service.j2
+++ b/roles/kubernetes/master/templates/kube-apiserver.service.j2
@@ -19,7 +19,8 @@ ExecStart={{ bin_dir }}/kube-apiserver \
         $KUBE_ADMISSION_CONTROL \
         $KUBE_RUNTIME_CONFIG \
         $KUBE_TLS_CONFIG \
-        $KUBE_API_ARGS
+        $KUBE_API_ARGS \
+        $KUBELET_CLOUDPROVIDER
 Restart=on-failure
 Type=notify
 LimitNOFILE=65536
diff --git a/roles/kubernetes/node/templates/kubelet.j2 b/roles/kubernetes/node/templates/kubelet.j2
index b7fc61d57..fe22c7688 100644
--- a/roles/kubernetes/node/templates/kubelet.j2
+++ b/roles/kubernetes/node/templates/kubelet.j2
@@ -32,7 +32,14 @@ DOCKER_SOCKET="--docker-endpoint=unix:/var/run/weave/weave.sock"
 {% endif %}
 # Should this cluster be allowed to run privileged docker containers
 KUBE_ALLOW_PRIV="--allow_privileged=true"
+{% if cloud_provider is defined and cloud_provider == "openstack" %}
+KUBELET_CLOUDPROVIDER="--cloud-provider={{ cloud_provider }} --cloud-config={{ kube_config_dir }}/cloud_config"
+{% else %}
+{# TODO: gce and aws don't need the cloud provider to be set? #}
+KUBELET_CLOUDPROVIDER=""
+{% endif %}
 {% if ansible_service_mgr in ["sysvinit","upstart"] %}
 DAEMON_ARGS="$KUBE_LOGGING $KUBE_LOG_LEVEL $KUBE_ALLOW_PRIV $KUBELET_API_SERVER $KUBELET_ADDRESS \
-$KUBELET_HOSTNAME $KUBELET_REGISTER_NODE $KUBELET_ARGS $DOCKER_SOCKET $KUBELET_ARGS $KUBELET_NETWORK_PLUGIN"
+$KUBELET_HOSTNAME $KUBELET_REGISTER_NODE $KUBELET_ARGS $DOCKER_SOCKET $KUBELET_ARGS $KUBELET_NETWORK_PLUGIN \
+$KUBELET_CLOUDPROVIDER"
 {% endif %}
diff --git a/roles/kubernetes/node/templates/kubelet.service.j2 b/roles/kubernetes/node/templates/kubelet.service.j2
index 6ffa07309..9fa47bf13 100644
--- a/roles/kubernetes/node/templates/kubelet.service.j2
+++ b/roles/kubernetes/node/templates/kubelet.service.j2
@@ -20,7 +20,8 @@ ExecStart={{ bin_dir }}/kubelet \
 		$KUBELET_ARGS \
 		$DOCKER_SOCKET \
 		$KUBELET_REGISTER_NODE \
-		$KUBELET_NETWORK_PLUGIN
+		$KUBELET_NETWORK_PLUGIN \
+		$KUBELET_CLOUDPROVIDER
 Restart=on-failure
 
 [Install]
diff --git a/roles/kubernetes/preinstall/defaults/main.yml b/roles/kubernetes/preinstall/defaults/main.yml
index cc1027a14..49f9b7c0e 100644
--- a/roles/kubernetes/preinstall/defaults/main.yml
+++ b/roles/kubernetes/preinstall/defaults/main.yml
@@ -8,3 +8,13 @@ common_required_pkgs:
   - rsync
   - bash-completion
 
+
+
+# For the openstack integration kubelet will need credentials to access
+# openstack apis like nova and cinder. Per default this values will be
+# read from the environment.
+openstack_auth_url: "{{ lookup('env','OS_AUTH_URL')  }}"
+openstack_username: "{{ lookup('env','OS_USERNAME')  }}"
+openstack_password: "{{ lookup('env','OS_PASSWORD')  }}"
+openstack_region: "{{ lookup('env','OS_REGION_NAME')  }}"
+openstack_tenant_id: "{{ lookup('env','OS_TENANT_ID')  }}"
diff --git a/roles/kubernetes/preinstall/tasks/main.yml b/roles/kubernetes/preinstall/tasks/main.yml
index be9515a2d..c81cf47f1 100644
--- a/roles/kubernetes/preinstall/tasks/main.yml
+++ b/roles/kubernetes/preinstall/tasks/main.yml
@@ -48,8 +48,11 @@
 
 - name: check cloud_provider value
   fail:
-    msg: "If set the 'cloud_provider' var must be set eithe to 'gce' or 'aws'"
-  when: cloud_provider is defined and cloud_provider not in ['gce', 'aws']
+    msg: "If set the 'cloud_provider' var must be set either to 'gce', 'aws' or 'openstack'"
+  when: cloud_provider is defined and cloud_provider not in ['gce', 'aws', 'openstack']
+
+- include: openstack-credential-check.yml
+  when: cloud_provider is defined and cloud_provider == 'openstack'
 
 - name: Create cni directories
   file:
@@ -105,4 +108,12 @@
   when: ansible_os_family == "RedHat"
   changed_when: False
 
+- name: Write openstack cloud-config
+  template:
+    src: openstack-cloud-config.j2
+    dest: "{{ kube_config_dir }}/cloud_config"
+    group: "{{ kube_cert_group }}"
+    mode: 0640
+  when: cloud_provider is defined and cloud_provider == "openstack"
+
 - include: etchosts.yml
diff --git a/roles/kubernetes/preinstall/tasks/openstack-credential-check.yml b/roles/kubernetes/preinstall/tasks/openstack-credential-check.yml
new file mode 100644
index 000000000..db544066e
--- /dev/null
+++ b/roles/kubernetes/preinstall/tasks/openstack-credential-check.yml
@@ -0,0 +1,25 @@
+---
+- name: check openstack_auth_url value
+  fail:
+    msg: "openstack_auth_url is missing"
+  when: openstack_auth_url is not defined or openstack_auth_url == ""
+
+- name: check openstack_username value
+  fail:
+    msg: "openstack_username is missing"
+  when: openstack_username is not defined or openstack_username == ""
+
+- name: check openstack_password value
+  fail:
+    msg: "openstack_password is missing"
+  when: openstack_password is not defined or openstack_password == ""
+
+- name: check openstack_region value
+  fail:
+    msg: "openstack_region is missing"
+  when: openstack_region is not defined or openstack_region == ""
+
+- name: check tenant_id value
+  fail:
+    msg: "tenant_id is missing"
+  when: openstack_tenant_id is not defined or openstack_tenant_id == ""
diff --git a/roles/kubernetes/preinstall/templates/openstack-cloud-config.j2 b/roles/kubernetes/preinstall/templates/openstack-cloud-config.j2
new file mode 100644
index 000000000..77668f295
--- /dev/null
+++ b/roles/kubernetes/preinstall/templates/openstack-cloud-config.j2
@@ -0,0 +1,6 @@
+[Global]
+auth-url={{ openstack_auth_url }}
+username={{ openstack_username }}
+password={{ openstack_password }}
+region={{ openstack_region }}
+tenant-id={{ openstack_tenant_id }}
\ No newline at end of file
-- 
GitLab