From 0d057d8e10fd5e29156516196ffec60ecb115087 Mon Sep 17 00:00:00 2001 From: hu xinhui Date: Wed, 30 Aug 2017 15:36:13 +0800 Subject: Add k8s support JIRA: - Add a new k8s scenario for compass Change-Id: Ic5f58a6152315333684e4f2752aaa0d5d870d9ee Signed-off-by: hu xinhui --- .../ansible/kubernetes/ansible-kubernetes.yml | 32 ++ .../roles/install-k8s-dependence/tasks/main.yml | 17 + .../roles/install-k8s-dependence/vars/Debian.yml | 20 + .../roles/install-k8s-dependence/vars/RedHat.yml | 19 + .../roles/install-k8s-dependence/vars/main.yml | 14 + .../roles/kargo/files/generate_inventories.py | 57 +++ .../kubernetes/roles/kargo/files/mirrors.repo | 32 ++ .../ansible/kubernetes/roles/kargo/tasks/main.yml | 84 ++++ .../roles/pre-k8s/files/centos_base.repo | 31 ++ .../ansible/kubernetes/roles/pre-k8s/files/modules | 7 + .../kubernetes/roles/pre-k8s/tasks/RedHat.yml | 55 +++ .../kubernetes/roles/pre-k8s/tasks/Ubuntu.yml | 71 +++ .../kubernetes/roles/pre-k8s/tasks/main.yml | 14 + .../kubernetes/roles/pre-k8s/templates/hosts | 9 + .../ansible/kubernetes/roles/pre-k8s/vars/main.yml | 21 + .../files/setup_networks/check_network.py | 70 +++ .../setup-k8s-network/files/setup_networks/log.py | 52 ++ .../files/setup_networks/net_init | 24 + .../files/setup_networks/setup_networks.py | 93 ++++ .../roles/setup-k8s-network/tasks/main.yml | 66 +++ .../roles/setup-k8s-network/templates/ifcfg-eth.j2 | 11 + .../setup-k8s-network/templates/my_configs.debian | 14 + .../roles/setup-k8s-network/templates/network.cfg | 5 + .../compass_conf/adapter/ansible_kubernetes.conf | 7 + .../distributed_system/kubernetes.conf | 3 + deploy/compass_conf/flavor/kubernetes.conf | 11 + deploy/compass_conf/flavor_mapping/kubernetes.conf | 28 ++ .../flavor_metadata/ansible-kubernetes.conf | 19 + .../package_installer/ansible-kubernetes.conf | 15 + .../compass_conf/package_metadata/kubernetes.conf | 536 +++++++++++++++++++++ deploy/compass_conf/role/kubernetes_ansible.conf | 115 +++++ .../kubernetes/ansible_cfg/ansible-kubernetes.tmpl | 11 + .../kubernetes/hosts/ansible-kubernetes.tmpl | 31 ++ .../kubernetes/inventories/ansible-kubernetes.tmpl | 75 +++ .../kubernetes/vars/ansible-kubernetes.tmpl | 198 ++++++++ deploy/conf/cluster.conf | 6 + deploy/conf/compass.conf | 5 + 37 files changed, 1878 insertions(+) create mode 100644 deploy/adapters/ansible/kubernetes/ansible-kubernetes.yml create mode 100644 deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/tasks/main.yml create mode 100644 deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/Debian.yml create mode 100644 deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/RedHat.yml create mode 100644 deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/main.yml create mode 100644 deploy/adapters/ansible/kubernetes/roles/kargo/files/generate_inventories.py create mode 100644 deploy/adapters/ansible/kubernetes/roles/kargo/files/mirrors.repo create mode 100644 deploy/adapters/ansible/kubernetes/roles/kargo/tasks/main.yml create mode 100644 deploy/adapters/ansible/kubernetes/roles/pre-k8s/files/centos_base.repo create mode 100644 deploy/adapters/ansible/kubernetes/roles/pre-k8s/files/modules create mode 100644 deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/RedHat.yml create mode 100644 deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/Ubuntu.yml create mode 100644 deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/main.yml create mode 100644 deploy/adapters/ansible/kubernetes/roles/pre-k8s/templates/hosts create mode 100644 deploy/adapters/ansible/kubernetes/roles/pre-k8s/vars/main.yml create mode 100644 deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/check_network.py create mode 100644 deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/log.py create mode 100644 deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/net_init create mode 100644 deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/setup_networks.py create mode 100644 deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/tasks/main.yml create mode 100644 deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/ifcfg-eth.j2 create mode 100644 deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/my_configs.debian create mode 100644 deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/network.cfg create mode 100644 deploy/compass_conf/adapter/ansible_kubernetes.conf create mode 100644 deploy/compass_conf/distributed_system/kubernetes.conf create mode 100644 deploy/compass_conf/flavor/kubernetes.conf create mode 100644 deploy/compass_conf/flavor_mapping/kubernetes.conf create mode 100644 deploy/compass_conf/flavor_metadata/ansible-kubernetes.conf create mode 100644 deploy/compass_conf/package_installer/ansible-kubernetes.conf create mode 100755 deploy/compass_conf/package_metadata/kubernetes.conf create mode 100644 deploy/compass_conf/role/kubernetes_ansible.conf create mode 100644 deploy/compass_conf/templates/ansible_installer/kubernetes/ansible_cfg/ansible-kubernetes.tmpl create mode 100644 deploy/compass_conf/templates/ansible_installer/kubernetes/hosts/ansible-kubernetes.tmpl create mode 100644 deploy/compass_conf/templates/ansible_installer/kubernetes/inventories/ansible-kubernetes.tmpl create mode 100644 deploy/compass_conf/templates/ansible_installer/kubernetes/vars/ansible-kubernetes.tmpl (limited to 'deploy') diff --git a/deploy/adapters/ansible/kubernetes/ansible-kubernetes.yml b/deploy/adapters/ansible/kubernetes/ansible-kubernetes.yml new file mode 100644 index 00000000..9f20cdbc --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/ansible-kubernetes.yml @@ -0,0 +1,32 @@ +############################################################################## +# Copyright (c) 2016 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +--- +- hosts: all + remote_user: root + max_fail_percentage: 0 + roles: + - pre-k8s + +- hosts: all + remote_user: root + max_fail_percentage: 0 + roles: + - setup-k8s-network + +- hosts: all + remote_user: root + max_fail_percentage: 0 + roles: + - install-k8s-dependence + +- hosts: localhost + remote_user: root + max_fail_percentage: 0 + roles: + - kargo diff --git a/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/tasks/main.yml b/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/tasks/main.yml new file mode 100644 index 00000000..ae70427d --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/tasks/main.yml @@ -0,0 +1,17 @@ +############################################################################## +# Copyright (c) 2016 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +--- +- include_vars: "{{ ansible_os_family }}.yml" + +- name: Install yum packages + yum: + pkg: "{{ item }}" + state: "present" + with_items: "{{ packages }}" + when: ansible_os_family == 'RedHat' and ansible_distribution_major_version == '7' diff --git a/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/Debian.yml b/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/Debian.yml new file mode 100644 index 00000000..e016b855 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/Debian.yml @@ -0,0 +1,20 @@ +--- +packages: + - ubuntu-cloud-keyring + - python-dev + - openvswitch-switch + - openvswitch-switch-dpdk + - python-memcache + - python-iniparse + - python-lxml + - python-crypto + +pip_packages: + - crudini + - python-keyczar + - yang2tosca + +pip_conf: pip.conf + +services: + - ntp diff --git a/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/RedHat.yml b/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/RedHat.yml new file mode 100644 index 00000000..3ec18e7f --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/RedHat.yml @@ -0,0 +1,19 @@ +--- +packages: + - python-devel + - gcc + - redhat-lsb-core + - python-crypto + - wget + - yum-plugin-priorities + - vim + - lsof + - strace + - net-tools + + +pip_packages: + - crudini + - python-keyczar + +pip_conf: pip.conf diff --git a/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/main.yml b/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/main.yml new file mode 100644 index 00000000..713b6b5f --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/install-k8s-dependence/vars/main.yml @@ -0,0 +1,14 @@ +############################################################################## +# Copyright (c) 2016 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +--- +packages_noarch: + - python-pip + - ntp + +services_noarch: [] diff --git a/deploy/adapters/ansible/kubernetes/roles/kargo/files/generate_inventories.py b/deploy/adapters/ansible/kubernetes/roles/kargo/files/generate_inventories.py new file mode 100644 index 00000000..62f29d84 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/kargo/files/generate_inventories.py @@ -0,0 +1,57 @@ +import yaml +import sys +from jinja2 import Environment + +INVENTORY_TEMPLATE = """ +[all] +{% for host, ip in hosts.iteritems() %} +{{ host }} ansible_ssh_host={{ ip }} ansible_ssh_pass=root ansible_user=root +{% endfor %} +[kube-master] +host1 +host2 + +[etcd] +host1 +host2 +host3 + +[kube-node] +host2 +host3 +host4 +host5 + +[k8s-cluster:children] +kube-node +kube-master + +[calico-rr] +[vault] +""" + + +def create_inventory_file(inventories_path, hosts): + content = Environment().from_string(INVENTORY_TEMPLATE).render(hosts=hosts) + with open(inventories_path, 'w+') as f: + f.write(content) + + +def fetch_all_sorted_external_ip(ip_cfg): + hosts = {} + for host, settings in ip_cfg.iteritems(): + external = settings["external"]["ip"] + hosts[host] = external + return hosts + + +def main(inventories_path, ip_cfg): + hosts = fetch_all_sorted_external_ip(ip_cfg) + create_inventory_file(inventories_path, hosts) + + +if __name__ == "__main__": + path = yaml.load(sys.argv[1]) + ipv_cfg = yaml.load(sys.argv[2]) + + main(path, ipv_cfg) diff --git a/deploy/adapters/ansible/kubernetes/roles/kargo/files/mirrors.repo b/deploy/adapters/ansible/kubernetes/roles/kargo/files/mirrors.repo new file mode 100644 index 00000000..4900db69 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/kargo/files/mirrors.repo @@ -0,0 +1,32 @@ +[base] +name=CentOS-$releasever - Base +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +#released updates +[updates] +name=CentOS-$releasever - Updates +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +#additional packages that may be useful +[extras] +name=CentOS-$releasever - Extras +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +#additional packages that extend functionality of existing packages +[centosplus] +name=CentOS-$releasever - Plus +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + diff --git a/deploy/adapters/ansible/kubernetes/roles/kargo/tasks/main.yml b/deploy/adapters/ansible/kubernetes/roles/kargo/tasks/main.yml new file mode 100644 index 00000000..4e902606 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/kargo/tasks/main.yml @@ -0,0 +1,84 @@ +############################################################################## +# Copyright (c) 2016 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +--- +- name: clean local repo conf + file: + path: /etc/yum.repos.d + state: absent + run_once: "True" + +- name: create local repo conf dir + file: + path: /etc/yum.repos.d + state: directory + run_once: "True" + +- name: configure local mirror repo + copy: + src: mirrors.repo + dest: /etc/yum.repos.d/mirrors.repo + run_once: "True" + +- name: clean local pip conf to use official pip repo + file: + path: /root/.pip/pip.conf + state: absent + run_once: "True" + +- name: install dependency for ansible update + yum: + name: "{{ item }}" + state: latest + with_items: + - git + - libffi-devel + - openssl-devel + - python-devel + run_once: "True" + +- name: update python packages + pip: + name: "{{ item }}" + state: latest + with_items: + - netaddr + - jinja2 + + +- name: copy inventories generate script + copy: + src: generate_inventories.py + dest: /tmp/generate_inventories.py + tags: + - ansible + +- name: generate kargo inventories + shell: > + python /tmp/generate_inventories.py \ + "/opt/kargo_k8s/inventory/inventory.cfg" \ + "{{ ip_settings | to_json }}" + tags: + - ansible + +- name: configure target hosts + shell: | + cd /opt/kargo_k8s + ansible -i inventory/inventory.cfg -m ping all + ansible -i inventory/inventory.cfg all -m shell -a "rm /etc/yum.repos.d/*" + ansible -i inventory/inventory.cfg all -m copy -a \ + "src=/etc/yum.repos.d/mirrors.repo dest=/etc/yum.repos.d" + tags: + - ansible + +- name: run kargo playbook + shell: | + cd /opt/kargo_k8s + ansible-playbook -i inventory/inventory.cfg cluster.yml -b -v 2>&1 | tee kargo.log + tags: + - ansible diff --git a/deploy/adapters/ansible/kubernetes/roles/pre-k8s/files/centos_base.repo b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/files/centos_base.repo new file mode 100644 index 00000000..914b0a8b --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/files/centos_base.repo @@ -0,0 +1,31 @@ +[base] +name=CentOS-$releasever - Base +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +#released updates +[updates] +name=CentOS-$releasever - Updates +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +#additional packages that may be useful +[extras] +name=CentOS-$releasever - Extras +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/ +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +#additional packages that extend functionality of existing packages +[centosplus] +name=CentOS-$releasever - Plus +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 diff --git a/deploy/adapters/ansible/kubernetes/roles/pre-k8s/files/modules b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/files/modules new file mode 100644 index 00000000..7a479351 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/files/modules @@ -0,0 +1,7 @@ +# /etc/modules: kernel modules to load at boot time. +# This file contains the names of kernel modules that should be loaded +# at boot time, one per line. Lines beginning with "#" are ignored. +# Parameters can be specified after the module name. + +bonding +8021q diff --git a/deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/RedHat.yml b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/RedHat.yml new file mode 100644 index 00000000..58af0f7b --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/RedHat.yml @@ -0,0 +1,55 @@ +############################################################################ +# Copyright (c) 2016 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################ +--- +- name: make sure ssh dir exist + file: + path: '{{ item.path }}' + owner: '{{ item.owner }}' + group: '{{ item.group }}' + state: directory + mode: 0755 + with_items: + - path: /root/.ssh + owner: root + group: root + +- name: write ssh config + copy: + content: "UserKnownHostsFile /dev/null\nStrictHostKeyChecking no" + dest: '{{ item.dest }}' + owner: '{{ item.owner }}' + group: '{{ item.group }}' + mode: 0600 + with_items: + - dest: /root/.ssh/config + owner: root + group: root + +- name: generate ssh keys + shell: if [ ! -f ~/.ssh/id_rsa.pub ]; \ + then ssh-keygen -q -t rsa -f ~/.ssh/id_rsa -N ""; \ + else echo "already gen ssh key!"; fi; + +- name: fetch ssh keys + fetch: + src: /root/.ssh/id_rsa.pub + dest: /tmp/ssh-keys-{{ ansible_hostname }} + flat: "yes" + +- authorized_key: + user: root + key: "{{ lookup('file', item) }}" + with_fileglob: + - /tmp/ssh-keys-* + - /root/.ssh/id_rsa.pub + +- name: change sources(yum) list + copy: + src: centos_base.repo + dest: /etc/yum.repos.d/centos_base.repo diff --git a/deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/Ubuntu.yml b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/Ubuntu.yml new file mode 100644 index 00000000..5bb77485 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/Ubuntu.yml @@ -0,0 +1,71 @@ +############################################################################## +# Copyright (c) 2016 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +--- +- name: make sure ssh dir exist + file: + path: '{{ item.path }}' + owner: '{{ item.owner }}' + group: '{{ item.group }}' + state: directory + mode: 0755 + with_items: + - path: /root/.ssh + owner: root + group: root + +- name: write ssh config + copy: + content: "UserKnownHostsFile /dev/null\nStrictHostKeyChecking no" + dest: '{{ item.dest }}' + owner: '{{ item.owner }}' + group: '{{ item.group }}' + mode: 0600 + with_items: + - dest: /root/.ssh/config + owner: root + group: root + +- name: generate ssh keys + shell: if [ ! -f ~/.ssh/id_rsa.pub ]; \ + then ssh-keygen -q -t rsa -f ~/.ssh/id_rsa -N ""; \ + else echo "already gen ssh key!"; fi; + +- name: fetch ssh keys + fetch: + src: /root/.ssh/id_rsa.pub + dest: /tmp/ssh-keys-{{ ansible_hostname }} + flat: "yes" + +- authorized_key: + user: root + key: "{{ lookup('file', item) }}" + with_fileglob: + - /tmp/ssh-keys-* + - /root/.ssh/id_rsa.pub + +- name: rm apt.conf + file: + path: /etc/apt/apt.conf + state: absent + +- name: restart ntp service + shell: "service ntp restart" + +- name: add the appropriate kernel modules + copy: + src: modules + dest: /etc/modules + +- name: change the MaxSessions + lineinfile: + dest: /etc/ssh/sshd_config + line: "MaxSessions 500" + +- name: restart ssh service + shell: service ssh restart diff --git a/deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/main.yml b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/main.yml new file mode 100644 index 00000000..76203440 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/tasks/main.yml @@ -0,0 +1,14 @@ +############################################################################## +# Copyright (c) 2016 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +--- +- include: "{{ ansible_distribution }}.yml" + when: ansible_distribution == 'Ubuntu' + +- include: "{{ ansible_os_family }}.yml" + when: ansible_os_family == 'RedHat' and ansible_distribution_major_version == '7' diff --git a/deploy/adapters/ansible/kubernetes/roles/pre-k8s/templates/hosts b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/templates/hosts new file mode 100644 index 00000000..847c193e --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/templates/hosts @@ -0,0 +1,9 @@ +# localhost +127.0.0.1 localhost +# controller +10.1.0.50 host1 +10.1.0.51 host2 +10.1.0.52 host3 +# compute +10.1.0.53 host4 +10.1.0.54 host5 diff --git a/deploy/adapters/ansible/kubernetes/roles/pre-k8s/vars/main.yml b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/vars/main.yml new file mode 100644 index 00000000..b196bd25 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/pre-k8s/vars/main.yml @@ -0,0 +1,21 @@ +--- +aptpackages: +- bridge-utils +- debootstrap +- ifenslave +- ifenslave-2.6 +- lsof +- lvm2 +- ntp +- ntpdate +- sudo +- vlan +- tcpdump + +yumpackages: +- bridge-utils +- iputils +- lvm2 +- ntp +- tcpdump +- vim diff --git a/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/check_network.py b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/check_network.py new file mode 100644 index 00000000..ffdafcd3 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/check_network.py @@ -0,0 +1,70 @@ +############################################################################## +# Copyright (c) 2016 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +import yaml +import sys +import subprocess + +import log as logging + +LOG = logging.getLogger("net-check") + + +def is_ip_reachable(ip): + cmd = "ping -c 2 %s" % ip + process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=None, + shell=True) + + output = process.communicate()[0] + if " 0% packet loss" in output: + LOG.info("%s is reachable", ip) + elif "100% packet loss" in output: + LOG.error("%s is unreachable" % (ip)) + return False + else: + LOG.warn("%r", output) + + return True + + +def is_host_ips_reachable(settings): + external = settings["external"]["ip"] + external_gw = settings["external"]["gw"] + # storage = settings["storage"]["ip"] + mgmt = settings["mgmt"]["ip"] + + return is_ip_reachable(external) \ + and is_ip_reachable(external_gw) \ + and is_ip_reachable(mgmt) + + +def main(hostname, config): + LOG.info("host is %s", hostname) + + result = True + + for host, settings in config.iteritems(): + LOG.info("check %s network connectivity start", host) + result = result and is_host_ips_reachable(settings) + + if result: + LOG.info("All hosts ips are reachable") + else: + LOG.error("Some hosts ips are unreachable !!!") + sys.exit(-1) + +if __name__ == "__main__": + hostname = yaml.load(sys.argv[1]) + config = yaml.load(sys.argv[2]) + config.pop(hostname, None) + + main(hostname, config) diff --git a/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/log.py b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/log.py new file mode 100644 index 00000000..422931bc --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/log.py @@ -0,0 +1,52 @@ +############################################################################## +# Copyright (c) 2016 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +import logging +import os +loggers = {} +log_dir = "/var/log/setup_network" +try: + os.makedirs(log_dir) +except: + pass + + +def getLogger(name): + if name in loggers: + return loggers[name] + + logger = logging.getLogger(name) + logger.setLevel(logging.DEBUG) + + # create file handler which logs even debug messages + log_file = "%s/%s.log" % (log_dir, name) + try: + os.remove(log_file) + except: + pass + + fh = logging.FileHandler(log_file) + fh.setLevel(logging.DEBUG) + + # create console handler with a higher log level + ch = logging.StreamHandler() + ch.setLevel(logging.ERROR) + + # create formatter and add it to the handlers + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s") + ch.setFormatter(formatter) + fh.setFormatter(formatter) + + # add the handlers to logger + logger.addHandler(ch) + logger.addHandler(fh) + + loggers[name] = logger + return logger diff --git a/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/net_init b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/net_init new file mode 100644 index 00000000..41ccb988 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/net_init @@ -0,0 +1,24 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: anamon.init +# Required-Start: $network +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Starts the cobbler anamon boot notification program +# Description: anamon runs the first time a machine is booted after installation. +### END INIT INFO + + + +# +# anamon.init: Starts the cobbler post-install boot notification program +# +# chkconfig: 35 0 6 +# +# description: anamon runs the first time a machine is booted after +# installation. +# +python /opt/setup_networks/setup_networks.py diff --git a/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/setup_networks.py b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/setup_networks.py new file mode 100644 index 00000000..ab13e088 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/files/setup_networks/setup_networks.py @@ -0,0 +1,93 @@ +############################################################################## +# Copyright (c) 2016 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +import yaml +import netaddr +import os +import log as logging + +LOG = logging.getLogger("net-init") +config_path = os.path.join(os.path.dirname(__file__), "network.cfg") + + +def setup_bondings(bond_mappings): + print bond_mappings + + +def add_vlan_link(interface, ifname, vlan_id): + LOG.info("add_vlan_link enter") + cmd = "ip link add link %s name %s type vlan id %s; " % ( + ifname, interface, vlan_id) + cmd += "ip link set %s up; ip link set %s up" % (interface, ifname) + LOG.info("add_vlan_link: cmd=%s" % cmd) + os.system(cmd) + + +def add_ovs_port(ovs_br, ifname, uplink, vlan_id=None): + LOG.info("add_ovs_port enter") + cmd = "ovs-vsctl --may-exist add-port %s %s" % (ovs_br, ifname) + if vlan_id: + cmd += " tag=%s" % vlan_id + cmd += " -- set Interface %s type=internal;" % ifname + cmd += "ip link set dev %s address \ + `ip link show %s |awk '/link\/ether/{print $2}'`;" % (ifname, uplink) + cmd += "ip link set %s up;" % ifname + LOG.info("add_ovs_port: cmd=%s" % cmd) + os.system(cmd) + + +def setup_intfs(sys_intf_mappings, uplink_map): + LOG.info("setup_intfs enter") + for intf_name, intf_info in sys_intf_mappings.items(): + if intf_info["type"] == "vlan": + add_vlan_link( + intf_name, + intf_info["interface"], + intf_info["vlan_tag"]) + elif intf_info["type"] == "ovs": + add_ovs_port( + intf_info["interface"], + intf_name, + uplink_map[intf_info["interface"]], + vlan_id=intf_info.get("vlan_tag")) + else: + pass + + +def setup_ips(ip_settings, sys_intf_mappings): + LOG.info("setup_ips enter") + for intf_info in ip_settings.values(): + network = netaddr.IPNetwork(intf_info["cidr"]) + if sys_intf_mappings[intf_info["name"]]["type"] == "ovs": + intf_name = intf_info["name"] + else: + intf_name = intf_info["alias"] + cmd = "ip addr add %s/%s brd %s dev %s;" \ + % (intf_info["ip"], intf_info["netmask"], str(network.broadcast), intf_name) # noqa + if "gw" in intf_info: + cmd += "route del default;" + cmd += "ip route add default via %s dev %s" % ( + intf_info["gw"], intf_name) + LOG.info("setup_ips: cmd=%s" % cmd) + os.system(cmd) + + +def main(config): + uplink_map = {} + setup_bondings(config["bond_mappings"]) + for provider_net in config["provider_net_mappings"]: + uplink_map[provider_net['name']] = provider_net['interface'] + + setup_intfs(config["sys_intf_mappings"], uplink_map) + setup_ips(config["ip_settings"], config["sys_intf_mappings"]) + +if __name__ == "__main__": + os.system("service openvswitch-switch status|| service openvswitch-switch start") # noqa + config = yaml.load(open(config_path)) + main(config) diff --git a/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/tasks/main.yml b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/tasks/main.yml new file mode 100644 index 00000000..c59fdfc5 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/tasks/main.yml @@ -0,0 +1,66 @@ +############################################################################## +# Copyright (c) 2016 HUAWEI TECHNOLOGIES CO.,LTD and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +--- +- name: disable NetworkManager + service: name=NetworkManager state=stopped enabled=no + when: ansible_os_family == 'RedHat' + +- name: enable network service + service: name=network state=started enabled=yes + when: ansible_os_family == 'RedHat' + +- name: ensure script dir exist + shell: mkdir -p /opt/setup_networks + +- name: copy scripts + copy: src={{ item }} dest=/opt/setup_networks + with_items: + - setup_networks/log.py + - setup_networks/setup_networks.py + - setup_networks/check_network.py + tags: + - network_check + + +- name: copy config files + template: src=network.cfg dest=/opt/setup_networks + +- name: config external nic + template: + src: ifcfg-eth.j2 + dest: /etc/sysconfig/network-scripts/ifcfg-{{sys_intf_mappings["external"]["interface"]}} + +- name: remove defualt gw + lineinfile: + dest: /etc/sysconfig/network + regexp: "^GATEWAY=*" + state: absent + +- name: restart the network + shell: systemctl restart network + +- name: make sure python lib exist + action: "{{ ansible_pkg_mgr }} name={{ item }} state=present" + with_items: + - python-yaml + - python-netaddr + +- name: check basic network connectivity + shell: > + python /opt/setup_networks/check_network.py \ + "{{ inventory_hostname }}" \ + "{{ ip_settings | to_json }}" + register: result + until: result.stderr.find('unreachable')==-1 + retries: 3 + delay: 2 + tags: + - network_check + +- meta: flush_handlers diff --git a/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/ifcfg-eth.j2 b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/ifcfg-eth.j2 new file mode 100644 index 00000000..78afa052 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/ifcfg-eth.j2 @@ -0,0 +1,11 @@ +DEVICE={{ sys_intf_mappings["external"]["interface"]}} +TYPE=Ethernet +IPADDR={{ ip_settings[inventory_hostname]["external"]["ip"] }} +PREFIX={{ ip_settings[inventory_hostname]["external"]["netmask"] }} +GATEWAY={{ ip_settings[inventory_hostname]["external"]["gw"] }} +BOOTPROTO=none +ONBOOT=yes +DELAY=0 +DEFROUTE="yes" +DNS1=8.8.8.8 +DNS2=8.8.4.4 diff --git a/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/my_configs.debian b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/my_configs.debian new file mode 100644 index 00000000..5ab1519b --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/my_configs.debian @@ -0,0 +1,14 @@ +{%- for alias, intf in host_ip_settings.items() %} + +auto {{ alias }} +iface {{ alias }} inet static + address {{ intf["ip"] }} + netmask {{ intf["netmask"] }} +{% if "gw" in intf %} + gateway {{ intf["gw"] }} +{% endif %} +{% if intf["name"] == alias %} + pre-up ip link set {{ sys_intf_mappings[alias]["interface"] }} up + pre-up ip link add link {{ sys_intf_mappings[alias]["interface"] }} name {{ alias }} type vlan id {{ sys_intf_mappings[alias]["vlan_tag"] }} +{% endif %} +{% endfor %} diff --git a/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/network.cfg b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/network.cfg new file mode 100644 index 00000000..cf271ad6 --- /dev/null +++ b/deploy/adapters/ansible/kubernetes/roles/setup-k8s-network/templates/network.cfg @@ -0,0 +1,5 @@ +bond_mappings: {{ network_cfg["bond_mappings"] | to_json }} +ip_settings: {{ ip_settings[inventory_hostname] | to_json }} +sys_intf_mappings: {{ sys_intf_mappings | to_json }} +provider_net_mappings: {{ network_cfg["provider_net_mappings"] | to_json }} + diff --git a/deploy/compass_conf/adapter/ansible_kubernetes.conf b/deploy/compass_conf/adapter/ansible_kubernetes.conf new file mode 100644 index 00000000..7b8023c2 --- /dev/null +++ b/deploy/compass_conf/adapter/ansible_kubernetes.conf @@ -0,0 +1,7 @@ +NAME = 'kubernetes' +DISPLAY_NAME = 'Kubernetes' +PARENT = 'general' +PACKAGE_INSTALLER = 'ansible_installer_kubernetes' +OS_INSTALLER = 'cobbler' +SUPPORTED_OS_PATTERNS = ['(?i)ubuntu-16\.04', '(?i)CentOS-7.*16.*'] +DEPLOYABLE = True diff --git a/deploy/compass_conf/distributed_system/kubernetes.conf b/deploy/compass_conf/distributed_system/kubernetes.conf new file mode 100644 index 00000000..8050ec18 --- /dev/null +++ b/deploy/compass_conf/distributed_system/kubernetes.conf @@ -0,0 +1,3 @@ +NAME ='kubernetes' +PARENT = 'general' +DEPLOYABLE = True diff --git a/deploy/compass_conf/flavor/kubernetes.conf b/deploy/compass_conf/flavor/kubernetes.conf new file mode 100644 index 00000000..96b5f95f --- /dev/null +++ b/deploy/compass_conf/flavor/kubernetes.conf @@ -0,0 +1,11 @@ +ADAPTER_NAME = 'kubernetes' +FLAVORS = [{ + 'flavor': 'ansible-kubernetes', + 'display_name': 'ansible-kubernetes', + 'template': 'ansible-kubernetes.tmpl', + 'roles': [ + 'controller', 'compute', 'ha', 'odl', 'onos', 'opencontrail', 'ceph', 'ceph-adm', 'ceph-mon', 'ceph-osd', 'sec-patch', 'ceph-osd-node' + ], +}] + + diff --git a/deploy/compass_conf/flavor_mapping/kubernetes.conf b/deploy/compass_conf/flavor_mapping/kubernetes.conf new file mode 100644 index 00000000..e569ea46 --- /dev/null +++ b/deploy/compass_conf/flavor_mapping/kubernetes.conf @@ -0,0 +1,28 @@ +ADAPTER = 'kubernetes' +FLAVOR = 'ansible-kubernetes' +CONFIG_MAPPING = { + "mapped_name": "flavor_config", + "mapped_children": [{ + "security": { + "accordion_heading": "Kubernetes Database and Queue Credentials", + "category": "service_credentials", + "data_structure": "table", + "action": "true", + "modifiable_data": ["username", "password"], + "table_display_header": ["Service", "UserName", "Password", "Action"], + "config": { + } + } + },{ + "security": { + "accordion_heading": "Kubernetes User Credentials", + "category": "console_credentials", + "data_structure": "table", + "action": "true", + "modifiable_data": ["username", "password"], + "table_display_header": ["Service", "UserName", "Password", "Action"], + "config":{ + } + } + }] +} diff --git a/deploy/compass_conf/flavor_metadata/ansible-kubernetes.conf b/deploy/compass_conf/flavor_metadata/ansible-kubernetes.conf new file mode 100644 index 00000000..f878d58c --- /dev/null +++ b/deploy/compass_conf/flavor_metadata/ansible-kubernetes.conf @@ -0,0 +1,19 @@ +ADAPTER = 'kubernetes' +FLAVOR = 'ansible-kubernetes' +METADATA = { + 'ha_proxy': { + '_self': { + }, + 'vip': { + '_self': { + 'is_required': True, + 'field': 'general', + 'mapping_to': 'ha_vip' + } + }, + 'test': { + '_self': { + }, + } + } +} diff --git a/deploy/compass_conf/package_installer/ansible-kubernetes.conf b/deploy/compass_conf/package_installer/ansible-kubernetes.conf new file mode 100644 index 00000000..c706ccb2 --- /dev/null +++ b/deploy/compass_conf/package_installer/ansible-kubernetes.conf @@ -0,0 +1,15 @@ +NAME = 'ansible_installer' +INSTANCE_NAME = 'ansible_installer_kubernetes' +SETTINGS = { + 'ansible_dir': '/var/ansible', + 'ansible_run_dir': '/var/ansible/run', + 'ansible_config': 'ansible.cfg', + 'playbook_file': 'site.yml', + 'inventory_file': 'inventory.py', + 'inventory_json_file': 'inventory.json', + 'inventory_group': ['controller', 'compute', 'ha', 'odl', 'onos', 'opencontrail', 'ceph_adm', 'ceph_mon', 'ceph_osd', 'moon'], + 'group_variable': 'all', + 'etc_hosts_path': 'roles/pre-k8s/templates/hosts', + 'runner_dirs': ['roles','kubernetes/roles'] +} + diff --git a/deploy/compass_conf/package_metadata/kubernetes.conf b/deploy/compass_conf/package_metadata/kubernetes.conf new file mode 100755 index 00000000..d5e9a50f --- /dev/null +++ b/deploy/compass_conf/package_metadata/kubernetes.conf @@ -0,0 +1,536 @@ +ADAPTER = 'kubernetes' +METADATA = { + 'security': { + '_self': { + 'required_in_whole_config': True, + }, + 'service_credentials': { + '_self': { + 'required_in_whole_config': True, + 'key_extensions': { + '$service': ['image', 'compute', 'dashboard', 'identity', 'metering', 'network', 'rabbitmq', 'volume', 'mysql', 'heat', 'alarming', 'policy'] + }, + 'mapping_to': 'service_credentials' + }, + '$service': { + '_self': { + 'required_in_whole_config': True, + 'mapping_to': '$service' + }, + 'username': { + '_self': { + 'is_required': True, + 'field': 'username', + 'mapping_to': 'username' + } + }, + 'password': { + '_self': { + 'is_required': True, + 'field': 'password', + 'mapping_to': 'password' + } + } + } + }, + 'console_credentials': { + '_self': { + 'required_in_whole_config': True, + 'key_extensions': { + '$console': ['admin', 'demo', 'compute', 'dashboard', 'image', 'identity', 'metering', 'network', 'object-store', 'volume', 'heat', 'alarming', 'policy'] + }, + 'mapping_to': 'console_credentials' + }, + '$console': { + '_self': { + 'required_in_whole_config': True, + 'mapping_to': '$console' + }, + 'username': { + '_self': { + 'is_required': True, + 'field': 'username', + 'mapping_to': 'username' + } + }, + 'password': { + '_self': { + 'is_required': True, + 'field': 'password', + 'mapping_to': 'password' + } + } + } + } + }, + + 'compass_ip': { + '_self': { + 'mapping_to': 'compass_ip', + 'field': 'anytype', + 'is_required':False, + 'default_value': '10.1.0.1' + } + }, + + 'enable_secgroup': { + '_self': { + 'mapping_to': 'enable_secgroup', + 'field': 'anytype', + 'is_required':False, + 'default_value': True + } + }, + 'enable_fwaas': { + '_self': { + 'mapping_to': 'enable_fwaas', + 'field': 'anytype', + 'is_required':False, + 'default_value': True + } + }, + 'enable_vpnaas': { + '_self': { + 'mapping_to': 'enable_vpnaas', + 'field': 'anytype', + 'is_required':False, + 'default_value': True + } + }, + 'odl_l3_agent': { + '_self': { + 'mapping_to': 'odl_l3_agent', + 'field': 'anytype', + 'is_required':False, + 'default_value': 'Disable' + } + }, + 'onos_sfc': { + '_self': { + 'mapping_to': 'onos_sfc', + 'field': 'anytype', + 'is_required':False, + 'default_value': 'Disable' + } + }, + 'odl_sfc': { + '_self': { + 'mapping_to': 'odl_sfc', + 'field': 'anytype', + 'is_required':False, + 'default_value': 'Disable' + } + }, + 'plugins': { + '_self': { + 'mapping_to': 'plugins', + 'field': 'general_list', + 'is_required':False, + 'default_value': '[]' + } + }, + 'ha_network': { + '_self': { + 'mapping_to': 'ha_network', + 'field': 'anytype', + 'is_required':False, + 'default_value': 'Disable' + } + }, + 'offline_repo_port': { + '_self': { + 'mapping_to': 'offline_repo_port', + 'field': 'anytype', + 'is_required':False, + 'default_value': '5151' + } + }, + 'offline_deployment': { + '_self': { + 'mapping_to': 'offline_deployment', + 'field': 'anytype', + 'is_required':False, + 'default_value': 'Disable' + } + }, + 'network_cfg': { + '_self': { + 'mapping_to': 'network_cfg' + }, + + 'nic_mappings': { + '_self': { + 'mapping_to': 'nic_mappings', + 'field': 'general_list' + } + }, + + 'bond_mappings': { + '_self': { + 'mapping_to': 'bond_mappings', + 'field': 'general_list' + } + }, + + 'sys_intf_mappings': { + '_self': { + 'mapping_to': 'sys_intf_mappings', + 'field': 'general_list' + } + }, + + 'ip_settings': { + '_self': { + 'mapping_to': 'ip_settings', + 'field': 'general_list' + } + }, + + 'provider_net_mappings': { + '_self': { + 'mapping_to': 'provider_net_mappings', + 'field': 'general_list' + } + }, + + 'ceph_disk': { + '_self': { + 'mapping_to': 'ceph_disk', + 'field': 'general', + 'is_required':False + } + }, + + 'public_vip': { + '_self': { + 'mapping_to': 'public_vip', + 'is_required': False + }, + + 'ip': { + '_self': { + 'mapping_to': 'ip', + 'is_required': True, + 'field': 'general', + } + }, + 'netmask': { + '_self': { + 'mapping_to': 'netmask', + 'is_required': True, + 'field': 'general', + } + }, + 'interface': { + '_self': { + 'mapping_to': 'interface', + 'is_required': True, + 'field': 'general', + } + } + }, + + 'internal_vip': { + '_self': { + 'mapping_to': 'internal_vip', + 'is_required': False + }, + + 'ip': { + '_self': { + 'mapping_to': 'ip', + 'is_required': True, + 'field': 'general', + } + }, + 'netmask': { + '_self': { + 'mapping_to': 'netmask', + 'is_required': True, + 'field': 'general', + } + }, + 'interface': { + '_self': { + 'mapping_to': 'interface', + 'is_required': True, + 'field': 'general', + } + } + }, + + 'onos_nic': { + '_self': { + 'mapping_to': 'onos_nic', + 'is_required': False, + 'field': 'general', + 'default_value': 'eth2' + } + }, + + 'tenant_net_info': { + '_self': { + 'mapping_to': 'tenant_net_info', + 'is_required': True + }, + + 'type': { + '_self': { + 'mapping_to': 'type', + 'is_required': True, + 'field': 'general', + 'options': ['vxlan', 'vlan'], + } + }, + 'range': { + '_self': { + 'mapping_to': 'range', + 'is_required': True, + 'field': 'general', + } + }, + 'provider_network': { + '_self': { + 'mapping_to': 'provider_network', + 'is_required': True, + 'field': 'general', + } + } + }, + + 'public_net_info': { + '_self': { + 'mapping_to': 'public_net_info' + }, + + 'enable': { + '_self': { + 'mapping_to': 'enable', + 'is_required': False, + 'field': 'anytype', + 'default_value': True + } + }, + + 'network': { + '_self': { + 'mapping_to': 'network', + 'is_required': True, + 'field': 'general', + 'default_value': 'ext-net' + } + }, + + 'type': { + '_self': { + 'mapping_to': 'type', + 'is_required': True, + 'field': 'general', + 'options': ['flat', 'vlan'], + 'default_value': 'vlan' + } + }, + + 'segment_id': { + '_self': { + 'mapping_to': 'segment_id', + 'is_required': False, + 'field': 'anytype' + } + }, + + 'subnet': { + '_self': { + 'mapping_to': 'subnet', + 'is_required': True, + 'field': 'general', + 'default_value': 'ext-subnet' + } + }, + + 'provider_network': { + '_self': { + 'mapping_to': 'provider_network', + 'is_required': True, + 'field': 'general', + 'default_value': 'physnet' + } + }, + + 'router': { + '_self': { + 'mapping_to': 'router', + 'is_required': True, + 'field': 'general', + 'default_value': 'ext-router' + } + }, + + 'enable_dhcp': { + '_self': { + 'mapping_to': 'enable_dhcp', + 'is_required': True, + 'field': 'anytype' + } + }, + + 'no_gateway': { + '_self': { + 'mapping_to': 'no_gateway', + 'is_required': True, + 'field': 'anytype' + } + }, + + 'external_gw': { + '_self': { + 'mapping_to': 'external_gw', + 'is_required': False, + 'field': 'general' + } + }, + + 'floating_ip_cidr': { + '_self': { + 'mapping_to': 'floating_ip_cidr', + 'is_required': True, + 'field': 'general' + } + }, + + 'floating_ip_start': { + '_self': { + 'mapping_to': 'floating_ip_start', + 'is_required': True, + 'field': 'general' + } + }, + + 'floating_ip_end': { + '_self': { + 'mapping_to': 'floating_ip_end', + 'is_required': True, + 'field': 'general' + } + } + }, + }, + 'neutron_config': { + '_self': { + 'mapping_to': 'neutron_config' + }, + 'openvswitch': { + '_self': { + 'mapping_to': 'openvswitch', + 'required_in_whole_config': True + }, + 'tenant_network_type': { + '_self': { + 'mapping_to': 'tenant_network_type', + 'is_required': True, + 'field': 'general', + 'options': ['gre', 'vlan'], + 'default_value': 'gre' + } + }, + 'network_vlan_ranges': { + '_self': { + 'mapping_to': 'vlan_ranges', + 'is_required': False, + 'field': 'general_list', + 'default_value': ['physnet1:2700:2999'] + } + }, + 'bridge_mappings': { + '_self': { + 'mapping_to': 'bridge_mappings', + 'is_required': False, + 'field': 'general_list', + 'default_value': ['physnet1:br-eth1'] + } + }, + 'tunnel_id_ranges': { + '_self': { + 'mapping_to': 'tunnel_id_ranges', + 'is_required': False, + 'field': 'general_list', + 'default_value': ['1:1000'] + } + } + } + }, + 'network_mapping': { + '_self': { + 'required_in_whole_config': True, + 'key_extensions': { + '$interface_type': ['install'] + } + }, + '$interface_type': { + '_self': { + 'required_in_whole_config': True, + 'field': 'anytype', + 'autofill_callback': autofill_network_mapping, + 'mapping_to': '$interface_type' + }, + 'interface': { + '_self': { + 'is_required': True, + 'field': 'general', + } + }, + 'subnet': { + '_self': { + 'is_required': False, + 'field': 'general' + } + } + } + }, + 'moon_cfg': { + '_self': { + 'required_in_whole_config': False, + 'mapping_to': 'moon_cfg' + }, + 'master': { + '_self': { + 'required_in_whole_config': False, + 'mapping_to': 'master' + }, + 'flag': { + '_self': { + 'is_required': False, + 'field': 'general', + 'mapping_to': 'flag' + } + }, + }, + 'slave': { + '_self': { + 'required_in_whole_config': False, + 'mapping_to': 'slave' + }, + 'flag': { + '_self': { + 'is_required': False, + 'field': 'general', + 'mapping_to': 'flag' + } + }, + 'name': { + '_self': { + 'is_required': False, + 'field': 'general', + 'mapping_to': 'name' + } + }, + 'master_ip': { + '_self': { + 'is_required': False, + 'field': 'general', + 'mapping_to': 'master_ip' + } + }, + } + } +} diff --git a/deploy/compass_conf/role/kubernetes_ansible.conf b/deploy/compass_conf/role/kubernetes_ansible.conf new file mode 100644 index 00000000..89c03d94 --- /dev/null +++ b/deploy/compass_conf/role/kubernetes_ansible.conf @@ -0,0 +1,115 @@ +ADAPTER_NAME = 'kubernetes' +ROLES = [{ + 'role': 'allinone-compute', + 'display_name': 'all in one', + 'description': 'All in One' +}, { + 'role': 'controller', + 'display_name': 'controller node', + 'description': 'Controller Node' +}, { + 'role': 'compute', + 'display_name': 'compute node', + 'description': 'Compute Node' +}, { + 'role': 'storage', + 'display_name': 'storage node', + 'description': 'Storage Node' +}, { + 'role': 'network', + 'display_name': 'network node', + 'description': 'Network Node' +}, { + 'role': 'compute-worker', + 'display_name': 'Compute worker node', + 'description': 'Compute worker node' +}, { + 'role': 'compute-controller', + 'display_name': 'Compute controller node', + 'description': 'Compute controller node' +}, { + 'role': 'network-server', + 'display_name': 'Network server node', + 'description': 'Network server node' +}, { + 'role': 'database', + 'display_name': 'Database node', + 'description': 'Database node' +}, { + 'role': 'messaging', + 'display_name': 'Messaging queue node', + 'description': 'Messaging queue node' +}, { + 'role': 'image', + 'display': 'Image node', + 'description': 'Image node' +}, { + 'role': 'dashboard', + 'display': 'Dashboard node', + 'description': 'Dashboard node' +}, { + 'role': 'identity', + 'display': 'Identity node', + 'description': 'Identity node' +}, { + 'role': 'storage-controller', + 'display': 'Storage controller node', + 'description': 'Storage controller node' +}, { + 'role': 'storage-volume', + 'display': 'Storage volume node', + 'description': 'Storage volume node' +}, { + 'role': 'network-worker', + 'display': 'Network worker node', + 'description': 'Network worker node' +}, { + 'role': 'odl', + 'display': 'open day light', + 'description': 'odl node', + 'optional': True +}, { + 'role': 'onos', + 'display': 'open network operating system', + 'description': 'onos node', + 'optional': True +}, { + 'role': 'opencontrail', + 'display': 'open contrail', + 'description': 'opencontrail node', + 'optional': True +}, { + 'role': 'ha', + 'display': 'Cluster with HA', + 'description': 'Cluster with HA node' +}, { + 'role': 'ceph-adm', + 'display': 'Ceph Admin Node', + 'description': 'Ceph Admin Node', + 'optional': True +}, { + 'role': 'ceph-mon', + 'display': 'Ceph Monitor Node', + 'description': 'Ceph Monitor Node', + 'optional': True +}, { + 'role': 'ceph-osd', + 'display': 'Ceph Storage Node', + 'description': 'Ceph Storage Node', + 'optional': True +}, { + 'role': 'ceph-osd-node', + 'display': 'Ceph osd install from node', + 'description': '', + 'optional': True +}, { + 'role': 'ceph', + 'display': 'ceph node', + 'description': 'ceph node', + 'optional': True +}, { + 'role': 'sec-patch', + 'display': 'sec-patch node', + 'description': 'Security Patch Node', + 'optional': True +}] diff --git a/deploy/compass_conf/templates/ansible_installer/kubernetes/ansible_cfg/ansible-kubernetes.tmpl b/deploy/compass_conf/templates/ansible_installer/kubernetes/ansible_cfg/ansible-kubernetes.tmpl new file mode 100644 index 00000000..f09fa9c8 --- /dev/null +++ b/deploy/compass_conf/templates/ansible_installer/kubernetes/ansible_cfg/ansible-kubernetes.tmpl @@ -0,0 +1,11 @@ +#set cluster_name = $getVar('name', '') +[defaults] +log_path = /var/ansible/run/kubernetes-$cluster_name/ansible.log +host_key_checking = False +callback_whitelist = playbook_done, status_callback +callback_plugins = /opt/ansible_callbacks +forks=100 + +[ssh_connection] +pipelining=True +retries = 5 diff --git a/deploy/compass_conf/templates/ansible_installer/kubernetes/hosts/ansible-kubernetes.tmpl b/deploy/compass_conf/templates/ansible_installer/kubernetes/hosts/ansible-kubernetes.tmpl new file mode 100644 index 00000000..9d628b5e --- /dev/null +++ b/deploy/compass_conf/templates/ansible_installer/kubernetes/hosts/ansible-kubernetes.tmpl @@ -0,0 +1,31 @@ +#set ip_settings={} +#for k,v in $getVar('ip_settings', {}).items() +#set host_ip_settings={} +#for intf in v +#set $host_ip_settings[$intf["alias"]]=intf +#end for +#set $ip_settings[$k]=$host_ip_settings +#end for + +# localhost +127.0.0.1 localhost +#set controllers = $getVar('controller', []) +#set computes = $getVar('compute', []) +#if not $isinstance($controllers, list) + #set controllers = [$controllers] +#end if +#if not $isinstance($compute, list) + #set computes = [$computes] +#end if +# controller +#for worker in $controllers + #set worker_hostname = $worker.hostname + #set worker_ip = $ip_settings[$worker_hostname].mgmt.ip +$worker_ip $worker_hostname +#end for +# compute +#for worker in $computes + #set worker_hostname = $worker.hostname + #set worker_ip = $ip_settings[$worker_hostname].mgmt.ip +$worker_ip $worker_hostname +#end for diff --git a/deploy/compass_conf/templates/ansible_installer/kubernetes/inventories/ansible-kubernetes.tmpl b/deploy/compass_conf/templates/ansible_installer/kubernetes/inventories/ansible-kubernetes.tmpl new file mode 100644 index 00000000..4c363a61 --- /dev/null +++ b/deploy/compass_conf/templates/ansible_installer/kubernetes/inventories/ansible-kubernetes.tmpl @@ -0,0 +1,75 @@ +#set inventory_json = $getVar('inventory_json', []) +#!/usr/bin/env python + +import os +import sys +import copy +import argparse + +try: + import json +except ImportError: + import simplejson as json + +local_inventory='$inventory_json' + +def _byteify(data, ignore_dicts = False): + if isinstance(data, unicode): + return data.encode('utf-8') + if isinstance(data, list): + return [ _byteify(item, ignore_dicts=True) for item in data ] + if isinstance(data, dict) and not ignore_dicts: + return { + _byteify(key, ignore_dicts=True): _byteify(value, ignore_dicts=True) + for key, value in data.iteritems() + } + return data + +def merge_dict(ldict, rdict, overwrite=True): + if not (ldict and rdict): + return + + if not isinstance(ldict, dict): + raise TypeError('ldict type is %s not dict' % type(ldict)) + + if not isinstance(rdict, dict): + raise TypeError('rdict type is %s not dict' % type(rdict)) + + for key, value in rdict.items(): + if isinstance(value, dict) and key in ldict and isinstance(ldict[key], + dict): + merge_dict(ldict[key], value, overwrite) + else: + if overwrite or key not in ldict: + ldict[key] = copy.deepcopy(value) + +def load_inventory(inventory): + if not os.path.exists(inventory): + raise RuntimeError('file: %s not exist' % inventory) + with open(inventory, 'r') as fd: + return json.load(fd, object_hook=_byteify) + +def dump_inventory(inventory, data): + with open(inventory, 'w') as fd: + json.dump(data, fd, indent=4) + +def merge_inventory(linv, rinv): + ldata = load_inventory(linv) + rdata = load_inventory(rinv) + merge_dict(ldata, rdata, overwrite=True) + dump_inventory(linv, ldata) + +def read_cli_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--list', action = 'store_true') + parser.add_argument('--merge', action = 'store') + return parser.parse_args() + +if __name__ == '__main__': + get_args = read_cli_args() + new_inventory = get_args.merge + if get_args.list: + print load_inventory(local_inventory) + elif new_inventory: + merge_inventory(local_inventory, new_inventory) + diff --git a/deploy/compass_conf/templates/ansible_installer/kubernetes/vars/ansible-kubernetes.tmpl b/deploy/compass_conf/templates/ansible_installer/kubernetes/vars/ansible-kubernetes.tmpl new file mode 100644 index 00000000..27211e06 --- /dev/null +++ b/deploy/compass_conf/templates/ansible_installer/kubernetes/vars/ansible-kubernetes.tmpl @@ -0,0 +1,198 @@ +#from random import randint +#set cluster_name = $getVar('name', '') +#set network_cfg = $getVar('network_cfg', {}) +#set ntp_server = $getVar('ntp_server', "") +#set ceph_disk = $getVar('ceph_disk',"") +#set $sys_intf_mappings= {} +#for $intf_info in $network_cfg.sys_intf_mappings +#set $sys_intf_mappings[$intf_info["name"]] = $intf_info +#end for + +#set ip_settings={} +#for k,v in $getVar('ip_settings', {}).items() +#set host_ip_settings={} +#for intf in v +#set $host_ip_settings[$intf["alias"]]=intf +#end for +#set $ip_settings[$k]=$host_ip_settings +#end for + +#set has = $getVar('ha', []) +#set ha_vip = $getVar('ha_vip', []) + +#set controllers = $getVar('controller', []) +#set computers = $getVar('compute', []) + +enable_secgroup: $getVar('enable_secgroup', True) +enable_fwaas: $getVar('enable_fwaas', True) +enable_vpnaas: $getVar('enable_vpnaas', True) +odl_l3_agent: $getVar('odl_l3_agent', 'Disable') +moon: $getVar('moon', 'Disable') +ha_network: $getVar('ha_network', 'Disable') +onos_nic: $getVar('onos_nic', 'eth2') +ip_settings: $ip_settings +network_cfg: $network_cfg +sys_intf_mappings: $sys_intf_mappings +deploy_type: $getVar('deploy_type', 'virtual') + +public_cidr: $computers[0]['install']['subnet'] +storage_cidr: "{{ ip_settings[inventory_hostname]['storage']['cidr'] }}" +mgmt_cidr: "{{ ip_settings[inventory_hostname]['mgmt']['cidr'] }}" + +public_net_info: "{{ network_cfg.public_net_info }}" +host_ip_settings: "{{ ip_settings[inventory_hostname] }}" + +ntp_server: $ntp_server +internal_vip: + ip: $network_cfg["internal_vip"]["ip"] + netmask: $network_cfg["internal_vip"]["netmask"] +#if "vlan_tag" in $sys_intf_mappings[$network_cfg["internal_vip"]["interface"]] + interface: $sys_intf_mappings[$network_cfg["internal_vip"]["interface"]]["name"] +#else + interface: $sys_intf_mappings[$network_cfg["internal_vip"]["interface"]]["interface"] +#end if + +public_vip: + ip: $network_cfg["public_vip"]["ip"] + netmask: $network_cfg["public_vip"]["netmask"] +#if "vlan_tag" in $sys_intf_mappings[$network_cfg["public_vip"]["interface"]] + interface: $sys_intf_mappings[$network_cfg["public_vip"]["interface"]]["name"] +#else + interface: $sys_intf_mappings[$network_cfg["public_vip"]["interface"]]["interface"] +#end if + +db_host: "{{ internal_vip.ip }}" +rabbit_host: "{{ internal_vip.ip }}" + +internal_ip: "{{ ip_settings[inventory_hostname]['mgmt']['ip'] }}" +internal_nic: mgmt + +#set random_id = randint(1, 255) +vrouter_id_internal: $random_id +vrouter_id_public: $random_id + +identity_host: "{{ internal_ip }}" +controllers_host: "{{ internal_ip }}" +storage_controller_host: "{{ internal_ip }}" +compute_controller_host: "{{ internal_ip }}" +image_host: "{{ internal_ip }}" +network_server_host: "{{ internal_ip }}" +dashboard_host: "{{ internal_ip }}" + +haproxy_hosts: +#for $item in $has +#set $hostname=$item["hostname"] + $hostname: $ip_settings[$hostname]["mgmt"]["ip"] +#end for + +host_index: +#for $index, $item in enumerate($has) + $item["hostname"]: $index +#end for + +ERLANG_TOKEN: YOWSJSJIGGAUFZTIBRAD +#set credentials = $getVar('service_credentials', {}) +#set console_credentials = $getVar('console_credentials', {}) +#set rabbit_username = $credentials.rabbitmq.username +#set rabbit_password = $credentials.rabbitmq.password +#set keystone_dbpass = $credentials.identity.password +#set keystone_pass = $console_credentials.identity.password +#set glance_dbpass = $credentials.image.password +#set glance_pass = $console_credentials.image.password +#set nova_dbpass = $credentials.compute.password +#set nova_pass = $console_credentials.compute.password +#set dash_dbpass = $credentials.dashboard.password +#set cinder_dbpass = $credentials.volume.password +#set cinder_pass = $console_credentials.volume.password +#set heat_dbpass = $credentials.heat.password +#set heat_pass = $console_credentials.heat.password +#set neutron_dbpass = $credentials.network.password +#set neutron_pass = $console_credentials.network.password +#set ceilometer_dbpass = $credentials.metering.password +#set ceilometer_pass = $console_credentials.metering.password +#set aodh_dbpass = $credentials.alarming.password +#set aodh_pass = $console_credentials.alarming.password +#set congress_dbpass = $credentials.policy.password +#set congress_pass = $console_credentials.policy.password +#set admin_pass = $console_credentials.admin.password +#set demo_pass = $console_credentials.demo.password + +cluster_name: $cluster_name + +odl_controller: 11.1.0.15 + +DEBUG: true +VERBOSE: true +NTP_SERVER_LOCAL: "{{ controllers_host }}" +DB_HOST: "{{ db_host }}" +MQ_BROKER: rabbitmq + +OPENSTACK_REPO: cloudarchive-newton.list +newton_cloud_archive: deb http://ubuntu-cloud.archive.canonical.com/ubuntu xenial-updates/newton main +ADMIN_TOKEN: admin +CEILOMETER_TOKEN: c095d479023a0fd58a54 +erlang.cookie: DJJVECFMCJPVYQTJTDWG + +RABBIT_USER: $rabbit_username +RABBIT_PASS: $rabbit_password +KEYSTONE_DBPASS: $keystone_dbpass +KEYSTONE_PASS: $keystone_pass +CEILOMETER_DBPASS: $ceilometer_dbpass +CEILOMETER_PASS: $ceilometer_pass +AODH_DBPASS: $aodh_dbpass +AODH_PASS: $aodh_pass +GLANCE_DBPASS: $glance_dbpass +GLANCE_PASS: $glance_pass +NOVA_DBPASS: $nova_dbpass +NOVA_PASS: $nova_pass +DASH_DBPASS: $dash_dbpass +CINDER_DBPASS: $cinder_dbpass +CINDER_PASS: $cinder_pass +NEUTRON_DBPASS: $neutron_dbpass +NEUTRON_PASS: $neutron_pass +HEAT_DBPASS: $heat_dbpass +HEAT_PASS: $heat_pass +CONGRESS_DBPASS: $congress_dbpass +CONGRESS_PASS: $congress_pass +DEMO_PASS: $demo_pass +ADMIN_PASS: $admin_pass + +#set neutron_service_plugins=['router'] + +#if $getVar('enable_fwaas', True) +#neutron_service_plugins.append('firewall') +#end if + +#if $getVar('enable_vpnaas', True) +#neutron_service_plugins.append('vpnaas') +#end if + +NEUTRON_SERVICE_PLUGINS: $neutron_service_plugins +NEUTRON_TYPE_DRIVERS: ['flat', 'gre', 'vxlan', 'vlan'] + +#NEUTRON_MECHANISM_DRIVERS: ['opendaylight'] +NEUTRON_MECHANISM_DRIVERS: ['openvswitch'] +NEUTRON_TUNNEL_TYPES: ['vxlan'] +METADATA_SECRET: metadata_secret +WSREP_SST_USER: wsrep_sst +WSREP_SST_PASS: wsrep_sst_sercet + +INSTANCE_TUNNELS_INTERFACE_IP_ADDRESS: "{{ internal_ip }}" + +#build_in_image: http://download.cirros-cloud.net/0.3.3/cirros-0.3.3-x86_64-disk.img +build_in_image: http://192.168.121.12:9999/img/cirros-0.3.3-x86_64-disk.img +build_in_image_name: cirros-0.3.3-x86_64-disk.img + +physical_device: /dev/sdb + +odl_username: admin +odl_password: admin +odl_api_port: 8080 + +odl_pkg_url: https://nexus.opendaylight.org/content/groups/public/org/opendaylight/integration/distribution-karaf/0.2.2-Helium-SR2/distribution-karaf-0.2.2-Helium-SR2.tar.gz +odl_pkg_name: karaf.tar.gz +odl_home: "/opt/opendaylight-0.2.2/" +odl_base_features: ['config', 'standard', 'region', 'package', 'kar', 'ssh', 'management', 'http', 'odl-base-all','odl-aaa-authn','odl-restconf','odl-nsf-all','odl-adsal-northbound','odl-mdsal-apidocs', 'odl-openflowplugin-all'] +odl_extra_features: ['odl-l2switch-switch', 'odl-ovsdb-plugin', 'odl-ovsdb-openstack', 'odl-ovsdb-northbound','odl-dlux-core', 'odl-restconf-all', 'odl-mdsal-clustering', 'odl-openflowplugin-flow-services', 'odl-netconf-connector', 'odl-netconf-connector-ssh', 'jolokia-osgi'] +odl_features: "{{ odl_base_features + odl_extra_features }}" +odl_api_port: 8080 diff --git a/deploy/conf/cluster.conf b/deploy/conf/cluster.conf index e0c5655b..ddcbb6c3 100644 --- a/deploy/conf/cluster.conf +++ b/deploy/conf/cluster.conf @@ -23,5 +23,11 @@ fi export ADAPTER_NAME="openstack_$OPENSTACK_VERSION" export ADAPTER_FLAVOR_PATTERN="HA-ansible-multinodes-$OPENSTACK_VERSION" +if [[ "x"$KUBERNETES_VERSION != "x" ]]; then + export ADAPTER_NAME=kubernetes + export ADAPTER_FLAVOR_PATTERN=ansible-kubernetes + export ADAPTER_TARGET_SYSTEM_PATTERN='^kubernetes$' +fi + export DEFAULT_ROLES="" export VIP="10.1.0.222" diff --git a/deploy/conf/compass.conf b/deploy/conf/compass.conf index c3ea85c0..ba9d8a7d 100644 --- a/deploy/conf/compass.conf +++ b/deploy/conf/compass.conf @@ -19,6 +19,11 @@ export COMPASS_REPO_PORT="5151" export COMPASS_DECK="compass4nfv/compass-deck" export COMPASS_TASKS="compass4nfv/compass-tasks-osa" + +if [[ "x"$KUBERNETES_VERSION != "x" ]]; then + export COMPASS_TASKS="compass4nfv/compass-tasks-k8s" +fi + export COMPASS_COBBLER="compass4nfv/compass-cobbler" export COMPASS_DB="compass4nfv/compass-db" export COMPASS_MQ="compass4nfv/compass-mq" -- cgit 1.2.3-korg