Merge "Setup repository with backports"
[fuel.git] / mcp / scripts / lib_jump_common.sh
1 #!/bin/bash -e
2 ##############################################################################
3 # Copyright (c) 2018 Mirantis Inc., Enea AB and others.
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9 #
10 # Library of shell functions used by build / deploy scripts on jumpserver:
11 # - distro package requirements installation (e.g. DEB, RPM);
12 # - other package requirements from custom sources (e.g. docker);
13 # - jumpserver prerequisites validation (e.g. network bridges);
14 # - distro configuration (e.g. udev, sysctl);
15 # etc.
16
17 ##############################################################################
18 # private helper functions
19 ##############################################################################
20
21 function __parse_yaml {
22   local prefix=$2
23   local s
24   local w
25   local fs
26   s='[[:space:]]*'
27   w='[a-zA-Z0-9_]*'
28   fs="$(echo @|tr @ '\034')"
29   sed -e 's|---||g' -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
30       -e "s|^\($s\)\($w\)$s[:-]$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$1" |
31   awk -F"$fs" '{
32   indent = length($1)/2;
33   vname[indent] = $2;
34   for (i in vname) {if (i > indent) {delete vname[i]}}
35       if (length($3) > 0) {
36           vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
37           printf("%s%s%s=(\"%s\")\n", "'"$prefix"'",vn, $2, $3);
38       }
39   }' | sed 's/_=/+=/g'
40 }
41
42 ##############################################################################
43 # public functions
44 ##############################################################################
45
46 function jumpserver_pkg_install {
47   local req_type=$1
48   if [ -n "$(command -v apt-get)" ]; then
49     pkg_type='deb'; pkg_cmd='sudo apt-get install -y'
50   else
51     pkg_type='rpm'; pkg_cmd='sudo yum install -y --skip-broken'
52   fi
53   eval "$(__parse_yaml "./requirements_${pkg_type}.yaml")"
54   for section in 'common' "$(uname -i)"; do
55     section_var="${req_type}_${section}[*]"
56     pkg_list+=" ${!section_var}"
57   done
58   # shellcheck disable=SC2086
59   ${pkg_cmd} ${pkg_list}
60 }
61
62 function jumpserver_check_requirements {
63   # shellcheck disable=SC2178
64   local states=$1; shift
65   # shellcheck disable=SC2178
66   local vnodes=$1; shift
67   local br=("$@")
68   local err_br_not_found='Linux bridge not found!'
69   local err_br_virsh_net='is a virtual network, Linux bridge expected!'
70   local warn_br_endpoint="Endpoints might be inaccessible from external hosts!"
71   # MaaS requires a Linux bridge for PXE/admin
72   if [[ "${states}" =~ maas ]]; then
73     if ! brctl showmacs "${br[0]}" >/dev/null 2>&1; then
74       notify_e "[ERROR] PXE/admin (${br[0]}) ${err_br_not_found}"
75     fi
76     # Assume virsh network name matches bridge name (true if created by us)
77     if ${VIRSH} net-info "${br[0]}" >/dev/null 2>&1; then
78       notify_e "[ERROR] ${br[0]} ${err_br_virsh_net}"
79     fi
80   fi
81   # If virtual nodes are present, public should be a Linux bridge
82   if [ -n "${vnodes}" ]; then
83     if ! brctl showmacs "${br[3]}" >/dev/null 2>&1; then
84       if [[ "${states}" =~ maas ]]; then
85         # Baremetal nodes *require* a proper public network
86         notify_e "[ERROR] Public (${br[3]}) ${err_br_not_found}"
87       else
88         notify_n "[WARN] Public (${br[3]}) ${err_br_not_found}" 3
89         notify_n "[WARN] ${warn_br_endpoint}" 3
90       fi
91     fi
92     if ${VIRSH} net-info "${br[3]}" >/dev/null 2>&1; then
93       if [[ "${states}" =~ maas ]]; then
94         notify_e "[ERROR] ${br[3]} ${err_br_virsh_net}"
95       else
96         notify_n "[WARN] ${br[3]} ${err_br_virsh_net}" 3
97         notify_n "[WARN] ${warn_br_endpoint}" 3
98       fi
99     fi
100     # https://bugs.launchpad.net/ubuntu/+source/qemu/+bug/1797332
101     if lsb_release -d | grep -q -e 'Ubuntu 16.04'; then
102       if uname -r | grep -q -e '^4\.4\.'; then
103         notify_n "[WARN] Host kernel too old; nested virtualization issues!" 3
104         notify_n "[WARN] apt install linux-generic-hwe-16.04 && reboot" 3
105         notify_e "[ERROR] Please upgrade the kernel and reboot!"
106       fi
107     fi
108   fi
109 }
110
111 function docker_install {
112   local image_dir=$1
113   # Mininum effort attempt at installing Docker if missing
114   if ! docker --version; then
115     curl -fsSL https://get.docker.com -o get-docker.sh
116     sudo sh get-docker.sh
117     rm get-docker.sh
118     # On RHEL distros, the Docker service should be explicitly started
119     sudo systemctl start docker
120   else
121     DOCKER_VER=$(docker version --format '{{.Server.Version}}')
122     if [ "${DOCKER_VER%%.*}" -lt 2 ]; then
123       notify_e "[ERROR] Docker version ${DOCKER_VER} is too old, please upgrade it."
124     fi
125   fi
126   # Distro-provided docker-compose might be simply broken (Ubuntu 16.04, CentOS 7)
127   if ! docker-compose --version > /dev/null 2>&1 || \
128       [ "$(docker-compose version --short | tr -d '.')" -lt 1220 ] && \
129       [ "$(uname -m)" = 'x86_64' ]; then
130     COMPOSE_BIN="${image_dir}/docker-compose"
131     COMPOSE_VERSION='1.22.0'
132     notify_n "[WARN] Using docker-compose ${COMPOSE_VERSION} in ${COMPOSE_BIN}" 3
133     if [ ! -e "${COMPOSE_BIN}" ]; then
134       COMPOSE_URL="https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}"
135       sudo curl -L "${COMPOSE_URL}/docker-compose-$(uname -s)-$(uname -m)" -o "${COMPOSE_BIN}"
136       sudo chmod +x "${COMPOSE_BIN}"
137     fi
138   fi
139 }
140
141 function virtinst_install {
142   local image_dir=$1
143   VIRT_VER=$(virt-install --version 2>&1)
144   if [ "${VIRT_VER//./}" -lt 140 ]; then
145     VIRT_TGZ="${image_dir}/virt-manager.tar.gz"
146     VIRT_VER='1.4.3'
147     VIRT_URL="https://github.com/virt-manager/virt-manager/archive/v${VIRT_VER}.tar.gz"
148     notify_n "[WARN] Using virt-install ${VIRT_VER} from ${VIRT_TGZ}" 3
149     if [ ! -e "${VIRT_TGZ}" ]; then
150       curl -L "${VIRT_URL}" -o "${VIRT_TGZ}"
151       mkdir -p "${image_dir}/virt-manager"
152       tar xzf "${VIRT_TGZ}" -C "${image_dir}/virt-manager" --strip-components=1
153     fi
154   fi
155 }
156
157 function do_udev_cfg {
158   local _conf='/etc/udev/rules.d/99-opnfv-fuel-vnet-mtu.rules'
159   # http://linuxaleph.blogspot.com/2013/01/how-to-network-jumbo-frames-to-kvm-guest.html
160   echo 'SUBSYSTEM=="net", ACTION=="add|change", KERNEL=="vnet*", RUN+="/bin/sh -c '"'/bin/sleep 1; /sbin/ip link set %k mtu 9000'\"" |& sudo tee "${_conf}"
161   echo 'SUBSYSTEM=="net", ACTION=="add|change", KERNEL=="*-nic", RUN+="/bin/sh -c '"'/bin/sleep 1; /sbin/ip link set %k mtu 9000'\"" |& sudo tee -a "${_conf}"
162   sudo udevadm control --reload
163   sudo udevadm trigger
164 }
165
166 function do_sysctl_cfg {
167   local _conf='/etc/sysctl.d/99-opnfv-fuel-bridge.conf'
168   # https://wiki.libvirt.org/page/Net.bridge.bridge-nf-call_and_sysctl.conf
169   if modprobe br_netfilter bridge; then
170     echo 'net.bridge.bridge-nf-call-arptables = 0' |& sudo tee "${_conf}"
171     echo 'net.bridge.bridge-nf-call-iptables = 0'  |& sudo tee -a "${_conf}"
172     echo 'net.bridge.bridge-nf-call-ip6tables = 0' |& sudo tee -a "${_conf}"
173     # Some distros / sysadmins explicitly blacklist br_netfilter
174     sudo sysctl -q -p "${_conf}" || true
175   fi
176 }
177
178 function generate_ssh_key {
179   # shellcheck disable=SC2155
180   local mcp_ssh_key=$(basename "${SSH_KEY}")
181   local user=${USER}
182   if [ -n "${SUDO_USER}" ] && [ "${SUDO_USER}" != 'root' ]; then
183     user=${SUDO_USER}
184   fi
185
186   if [ -f "${SSH_KEY}" ]; then
187     cp "${SSH_KEY}" .
188     ssh-keygen -f "${mcp_ssh_key}" -y > "${mcp_ssh_key}.pub"
189   fi
190
191   [ -f "${mcp_ssh_key}" ] || ssh-keygen -f "${mcp_ssh_key}" -N ''
192   sudo install -D -o "${user}" -m 0600 "${mcp_ssh_key}" "${SSH_KEY}"
193 }