Add support for multi-stack installation
Cleanup use of sudo for copying files. Apply docker specific
configuration inside user directory.
Utilize multiple juju controllers utilizing the stack name.
Create stack with no exposed host ports via '-nohostports' for creating
multiple instances of osm (useful in CI)
Change-Id: I32e2eab2cbae7fa6939eee2df556f6788d065a92
Signed-off-by: Mike Marchetti <mmarchetti@sandvine.com>
diff --git a/installers/docker/docker-compose.yaml b/installers/docker/docker-compose.yaml
index a1e88bc..fa27900 100644
--- a/installers/docker/docker-compose.yaml
+++ b/installers/docker/docker-compose.yaml
@@ -20,7 +20,7 @@
kafka:
image: wurstmeister/kafka
ports:
- - "9092:9092"
+ - "9092"
networks:
- netOSM
environment:
@@ -49,7 +49,7 @@
OSMNBI_DATABASE_HOST: mongo
OSMNBI_MESSAGE_HOST: kafka
ports:
- - "9999:9999"
+ - "${OSM_NBI_PORTS:-9999:9999}"
#depends_on:
# - kafka
# - mongo
@@ -90,7 +90,7 @@
#depends_on:
# - ro-db
ports:
- - "9090:9090"
+ - "${OSM_RO_PORTS:-9090:9090}"
mon:
image: osm/mon
networks:
@@ -105,7 +105,7 @@
#depends_on:
# - kafka
ports:
- - "8662:8662"
+ - "8662"
pm:
image: osm/pm
networks:
@@ -124,5 +124,4 @@
#depends_on:
# - nbi
ports:
- - "80:80"
-
+ - "${OSM_UI_PORTS:-80:80}"
diff --git a/installers/full_install_osm.sh b/installers/full_install_osm.sh
index a92e1ba..60a99e3 100755
--- a/installers/full_install_osm.sh
+++ b/installers/full_install_osm.sh
@@ -26,6 +26,9 @@
echo -e " -b v2.0 (v2.0 branch)"
echo -e " -b tags/v1.1.0 (a specific tag)"
echo -e " ..."
+ echo -e " -s <stack name> user defined stack name, default is osm"
+ echo -e " -H <VCA host> use specific juju host controller IP"
+ echo -e " -S <VCA secret> use VCA/juju secret key"
echo -e " --vimemu: additionally deploy the VIM emulator as a docker container"
echo -e " --elk_stack: additionally deploy an ELK docker stack for event logging"
echo -e " --pm_stack: additionally deploy a Prometheus+Grafana stack for performance monitoring (PM)"
@@ -34,6 +37,9 @@
echo -e " -D <devops path> use local devops installation path"
echo -e " --nolxd: do not install and configure LXD, allowing unattended installations (assumes LXD is already installed and confifured)"
echo -e " --nodocker: do not install docker, do not initialize a swarm (assumes docker is already installed and a swarm has been initialized)"
+ echo -e " --nojuju: do not juju, assumes already installed"
+ echo -e " --nodockerbuild:do not build docker images (use existing locally cached images)"
+ echo -e " --nohostports: do not expose docker ports to host (useful for creating multiple instances of osm on the same host)"
echo -e " --uninstall: uninstall OSM: remove the containers and delete NAT rules"
echo -e " --source: install OSM from source code using the latest stable tag"
echo -e " --develop: (deprecated, use '-b master') install OSM from source code using the master branch"
@@ -72,6 +78,29 @@
return 0
}
+# takes a juju/accounts.yaml file and returns the password specific
+# for a controller. I wrote this using only bash tools to minimize
+# additions of other packages
+function parse_juju_password {
+ password_file="${HOME}/.local/share/juju/accounts.yaml"
+ local controller_name=$1
+ local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
+ sed -ne "s|^\($s\):|\1|" \
+ -e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p" \
+ -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" $password_file |
+ awk -F$fs -v controller=$controller_name '{
+ indent = length($1)/2;
+ vname[indent] = $2;
+ for (i in vname) {if (i > indent) {delete vname[i]}}
+ if (length($3) > 0) {
+ vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
+ if (match(vn,controller) && match($2,"password")) {
+ printf("%s",$3);
+ }
+ }
+ }'
+}
+
function remove_stack() {
stack=$1
if sg docker -c "docker stack ps ${stack}" ; then
@@ -102,17 +131,17 @@
if [ -n "$INSTALL_ELK" ]; then
echo -e "\nUninstalling OSM ELK stack"
remove_stack osm_elk
- sudo rm -rf /etc/osm/docker/osm_elk
+ rm -rf $OSM_DOCKER_WORK_DIR/osm_elk
fi
if [ -n "$INSTALL_PERFMON" ]; then
echo -e "\nUninstalling OSM Performance Monitoring stack"
remove_stack osm_metrics
sg docker -c "docker image rm osm/kafka-exporter"
- sudo rm -rf /etc/osm/docker/osm_metrics
+ rm -rf $OSM_DOCKER_WORK_DIR/osm_metrics
fi
else
echo -e "\nUninstalling OSM"
- remove_stack osm
+ remove_stack $OSM_STACK_NAME
remove_stack osm_elk
remove_stack osm_metrics
echo "Now osm docker images and volumes will be deleted"
@@ -129,9 +158,8 @@
docker volume rm osm_osm_packages
docker volume rm osm_ro_db
EONG
- echo "Removing /etc/osm and /var/log/osm files"
- sudo rm -rf /etc/osm
- sudo rm -rf /var/log/osm
+ echo "Removing $OSM_DOCKER_WORK_DIR"
+ rm -rf $OSM_DOCKER_WORK_DIR
fi
echo "Some docker images will be kept in case they are used by other docker stacks"
echo "To remove them, just run 'docker image prune' in a terminal"
@@ -579,9 +607,16 @@
echo "Installing juju"
sudo snap install juju --classic
[ -z "$INSTALL_NOLXD" ] && sudo dpkg-reconfigure -p medium lxd
- sg lxd -c "juju bootstrap --bootstrap-series=xenial localhost osm"
- [ $(sg lxd -c "juju status" |grep "osm" |wc -l) -eq 1 ] || FATAL "Juju installation failed"
echo "Finished installation of juju"
+ return 0
+}
+
+function juju_createcontroller() {
+ if ! sg lxd -c "juju show-controller $OSM_STACK_NAME &> /dev/null"; then
+ # Not found created, create the controller
+ sg lxd -c "juju bootstrap --bootstrap-series=xenial localhost $OSM_STACK_NAME"
+ fi
+ [ $(sg lxd -c "juju controllers" |grep "$OSM_STACK_NAME" |wc -l) -eq 1 ] || FATAL "Juju installation failed"
}
function generate_docker_images() {
@@ -633,34 +668,32 @@
file2="$2"
if ! $(cmp "${file1}" "${file2}" >/dev/null 2>&1); then
if [ -f "${file2}" ]; then
- ask_user "The file ${file2} already exists. Overwrite (y/N)? " n && sudo cp -b ${file1} ${file2}
+ ask_user "The file ${file2} already exists. Overwrite (y/N)? " n && cp -b ${file1} ${file2}
else
- sudo cp -b ${file1} ${file2}
+ cp -b ${file1} ${file2}
fi
fi
}
function generate_config_log_folders() {
echo "Generating config and log folders"
- sudo mkdir -p /etc/osm/docker
- sudo cp -b ${OSM_DEVOPS}/installers/docker/docker-compose.yaml /etc/osm/docker/docker-compose.yaml
- sudo mkdir -p /var/log/osm
+ cp -b ${OSM_DEVOPS}/installers/docker/docker-compose.yaml $OSM_DOCKER_WORK_DIR/docker-compose.yaml
echo "Finished generation of config and log folders"
}
function generate_docker_env_files() {
echo "Generating docker env files"
- echo "OSMLCM_VCA_HOST=${OSMLCM_VCA_HOST}" |sudo tee /etc/osm/docker/lcm.env
- echo "OSMLCM_VCA_SECRET=${OSMLCM_VCA_SECRET}" |sudo tee -a /etc/osm/docker/lcm.env
+ echo "OSMLCM_VCA_HOST=${OSMLCM_VCA_HOST}" | tee $OSM_DOCKER_WORK_DIR/lcm.env
+ echo "OSMLCM_VCA_SECRET=${OSMLCM_VCA_SECRET}" | tee -a $OSM_DOCKER_WORK_DIR/lcm.env
+
MYSQL_ROOT_PASSWORD=`date +%s | sha256sum | base64 | head -c 32`
- if [ ! -f /etc/osm/docker/ro-db.env ]; then
- echo "MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}" |sudo tee /etc/osm/docker/ro-db.env
+ if [ ! -f $OSM_DOCKER_WORK_DIR/ro-db.env ]; then
+ echo "MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}" |tee $OSM_DOCKER_WORK_DIR/ro-db.env
fi
- if [ ! -f /etc/osm/docker/ro.env ]; then
- echo "RO_DB_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}" |sudo tee /etc/osm/docker/ro.env
+ if [ ! -f $OSM_DOCKER_WORK_DIR/ro.env ]; then
+ echo "RO_DB_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}" |tee $OSM_DOCKER_WORK_DIR/ro.env
fi
- echo "OS_NOTIFIER_URI=http://${DEFAULT_IP}:8662" |tee /tmp/mon.env
- cmp_overwrite /tmp/mon.env /etc/osm/docker/mon.env
+ echo "OS_NOTIFIER_URI=http://${DEFAULT_IP}:8662" |tee $OSM_DOCKER_WORK_DIR/mon.env
echo "Finished generation of docker env files"
}
@@ -678,9 +711,27 @@
function deploy_lightweight() {
echo "Deploying lightweight build"
[ -n "$INSTALL_NODOCKER" ] || init_docker_swarm
- remove_stack osm
- sg docker -c "docker stack deploy -c /etc/osm/docker/docker-compose.yaml osm"
- #docker-compose -f /etc/osm/docker/docker-compose.yaml up -d
+ remove_stack $OSM_STACK_NAME
+
+ OSM_NBI_PORT=9999
+ OSM_RO_PORT=9090
+ OSM_UI_PORT=80
+
+ if [ -n "$NO_HOST_PORTS" ]; then
+ OSM_PORTS+=(OSM_NBI_PORTS=$OSM_NBI_PORT)
+ OSM_PORTS+=(OSM_RO_PORTS=$OSM_RO_PORT)
+ OSM_PORTS+=(OSM_UI_PORTS=$OSM_UI_PORT)
+ else
+ OSM_PORTS+=(OSM_NBI_PORTS=$OSM_NBI_PORT:$OSM_NBI_PORT)
+ OSM_PORTS+=(OSM_RO_PORTS=$OSM_RO_PORT:$OSM_RO_PORT)
+ OSM_PORTS+=(OSM_UI_PORTS=$OSM_UI_PORT:$OSM_UI_PORT)
+ fi
+ echo "export ${OSM_PORTS[@]}" > $OSM_DOCKER_WORK_DIR/osm_ports.sh
+
+ pushd $OSM_DOCKER_WORK_DIR > /dev/null
+ sg docker -c "source ./osm_ports.sh; docker stack deploy -c $OSM_DOCKER_WORK_DIR/docker-compose.yaml $OSM_STACK_NAME"
+ popd > /dev/null
+
echo "Finished deployment of lightweight build"
}
@@ -690,11 +741,11 @@
sg docker -c "docker pull docker.elastic.co/logstash/logstash-oss:6.2.3" || FATAL "cannot get logstash docker image"
sg docker -c "docker pull docker.elastic.co/kibana/kibana-oss:6.2.3" || FATAL "cannot get kibana docker image"
echo "Finished pulling elk docker images"
- sudo mkdir -p /etc/osm/docker/osm_elk
- sudo cp -b ${OSM_DEVOPS}/installers/docker/osm_elk/* /etc/osm/docker/osm_elk
+ mkdir -p "$OSM_DOCKER_WORK_DIR/osm_elk"
+ cp -b ${OSM_DEVOPS}/installers/docker/osm_elk/* $OSM_DOCKER_WORK_DIR/osm_elk
remove_stack osm_elk
echo "Deploying ELK stack"
- sg docker -c "docker stack deploy -c /etc/osm/docker/osm_elk/docker-compose.yml osm_elk"
+ sg docker -c "docker stack deploy -c $OSM_DOCKER_WORK_DIR/osm_elk/docker-compose.yml osm_elk"
echo "Waiting for ELK stack to be up and running"
time=0
step=5
@@ -740,17 +791,20 @@
echo "Generating osm/kafka-exporter docker image"
sg docker -c "docker build ${OSM_DEVOPS}/installers/docker/osm_metrics/kafka-exporter -f ${OSM_DEVOPS}/installers/docker/osm_metrics/kafka-exporter/Dockerfile -t osm/kafka-exporter --no-cache" || FATAL "cannot build kafka-exporter docker image"
echo "Finished generation of osm/kafka-exporter docker image"
- sudo mkdir -p /etc/osm/docker/osm_metrics
- sudo cp -b ${OSM_DEVOPS}/installers/docker/osm_metrics/*.yml /etc/osm/docker/osm_metrics
- sudo cp -b ${OSM_DEVOPS}/installers/docker/osm_metrics/*.json /etc/osm/docker/osm_metrics
+ mkdir -p $OSM_DOCKER_WORK_DIR/osm_metrics
+ cp -b ${OSM_DEVOPS}/installers/docker/osm_metrics/*.yml $OSM_DOCKER_WORK_DIR/osm_metrics
+ cp -b ${OSM_DEVOPS}/installers/docker/osm_metrics/*.json $OSM_DOCKER_WORK_DIR/osm_metrics
remove_stack osm_metrics
echo "Deploying PM stack (Kafka exporter + Prometheus + Grafana)"
- sg docker -c "docker stack deploy -c /etc/osm/docker/osm_metrics/docker-compose.yml osm_metrics"
+ sg docker -c "docker stack deploy -c $OSM_DOCKER_WORK_DIR/osm_metrics/docker-compose.yml osm_metrics"
echo "Finished deployment of PM stack"
return 0
}
function install_lightweight() {
+ [ -z "$OSM_DOCKER_WORK_DIR" ] && OSM_DOCKER_WORK_DIR="$HOME/.osm/stack/$OSM_STACK_NAME"
+ [ ! -d "$OSM_DOCKER_WORK_DIR" ] && mkdir -p $OSM_DOCKER_WORK_DIR
+
[ "$USER" == "root" ] && FATAL "You are running the installer as root. The installer is prepared to be executed as a normal user with sudo privileges."
[ -z "$ASSUME_YES" ] && ! ask_user "The installation will configure LXD, install juju, install docker CE and init a docker swarm, as pre-requirements. Do you want to proceed (Y/n)? " y && echo "Cancelled!" && exit 1
track proceed
@@ -762,7 +816,9 @@
DEFAULT_IP=`ip -o -4 a |grep ${DEFAULT_IF}|awk '{split($4,a,"/"); print a[1]}'`
[ -z "$DEFAULT_IP" ] && FATAL "Not possible to determine the IP address of the interface with the default route"
DEFAULT_MTU=$(ip addr show ${DEFAULT_IF} | perl -ne 'if (/mtu\s(\d+)/) {print $1;}')
- if [ -z "$INSTALL_NOLXD" ]; then
+
+ # if no host is passed in, we need to install lxd/juju, unless explicilty asked not to
+ if [ -z "$OSMLCM_VCA_HOST" ] && [ -z "$INSTALL_NOLXD" ]; then
need_packages_lw="lxd"
echo -e "Checking required packages: $need_packages_lw"
dpkg -l $need_packages_lw &>/dev/null \
@@ -775,19 +831,26 @@
|| FATAL "failed to install $need_packages_lw"
fi
track prereqok
- install_juju
- OSMLCM_VCA_HOST=`sg lxd -c "juju show-controller"|grep api-endpoints|awk -F\' '{print $2}'|awk -F\: '{print $1}'`
- OSMLCM_VCA_SECRET=`grep password ${HOME}/.local/share/juju/accounts.yaml |awk '{print $2}'`
- [ -z "$OSMLCM_VCA_HOST" ] && FATAL "Cannot obtain juju controller IP address"
- [ -z "$OSMLCM_VCA_SECRET" ] && FATAL "Cannot obtain juju secret"
+ [ -z "$INSTALL_NOJUJU" ] && install_juju
+
+ if [ -z "$OSMLCM_VCA_HOST" ]; then
+ juju_createcontroller
+ OSMLCM_VCA_HOST=`sg lxd -c "juju show-controller $OSM_STACK_NAME"|grep api-endpoints|awk -F\' '{print $2}'|awk -F\: '{print $1}'`
+ [ -z "$OSMLCM_VCA_HOST" ] && FATAL "Cannot obtain juju controller IP address"
+ fi
+ if [ -z "$OSMLCM_VCA_SECRET" ]; then
+ OSMLCM_VCA_SECRET=$(parse_juju_password $OSM_STACK_NAME)
+ [ -z "$OSMLCM_VCA_SECRET" ] && FATAL "Cannot obtain juju secret"
+ fi
+
track juju
[ -n "$INSTALL_NODOCKER" ] || install_docker_ce
track docker_ce
#install_docker_compose
- generate_docker_images
+ [ -z "$DOCKER_NOBUILD" ] && generate_docker_images
track docker_build
- generate_config_log_folders
generate_docker_env_files
+ generate_config_log_folders
deploy_lightweight
track docker_deploy
[ -n "$INSTALL_VIMEMU" ] && install_vimemu && track vimemu
@@ -809,19 +872,20 @@
git clone https://osm.etsi.org/gerrit/osm/vim-emu.git $EMUTEMPDIR
# build vim-emu docker
echo "Building vim-emu Docker container..."
- sudo docker build -t vim-emu-img -f $EMUTEMPDIR/Dockerfile --no-cache $EMUTEMPDIR/ || FATAL "cannot build vim-emu-img docker image"
+
+ sg docker -c "docker build -t vim-emu-img -f $EMUTEMPDIR/Dockerfile --no-cache $EMUTEMPDIR/" || FATAL "cannot build vim-emu-img docker image"
# start vim-emu container as daemon
echo "Starting vim-emu Docker container 'vim-emu' ..."
if [ -n "$INSTALL_LIGHTWEIGHT" ]; then
# in lightweight mode, the emulator needs to be attached to netOSM
- sudo docker run --name vim-emu -t -d --restart always --privileged --pid='host' --network=netOSM -v /var/run/docker.sock:/var/run/docker.sock vim-emu-img python examples/osm_default_daemon_topology_2_pop.py
+ sg docker -c "docker run --name vim-emu -t -d --restart always --privileged --pid='host' --network=netOSM -v /var/run/docker.sock:/var/run/docker.sock vim-emu-img python examples/osm_default_daemon_topology_2_pop.py"
else
# classic build mode
- sudo docker run --name vim-emu -t -d --restart always --privileged --pid='host' -v /var/run/docker.sock:/var/run/docker.sock vim-emu-img python examples/osm_default_daemon_topology_2_pop.py
+ sg docker -c "docker run --name vim-emu -t -d --restart always --privileged --pid='host' -v /var/run/docker.sock:/var/run/docker.sock vim-emu-img python examples/osm_default_daemon_topology_2_pop.py"
fi
echo "Waiting for 'vim-emu' container to start ..."
sleep 5
- export VIMEMU_HOSTNAME=$(sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' vim-emu)
+ export VIMEMU_HOSTNAME=$(sg docker -c "docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' vim-emu")
echo "vim-emu running at ${VIMEMU_HOSTNAME} ..."
# print vim-emu connection info
echo -e "\nYou might be interested in adding the following vim-emu env variables to your .bashrc file:"
@@ -897,12 +961,18 @@
TO_REBUILD=""
INSTALL_NOLXD=""
INSTALL_NODOCKER=""
+INSTALL_NOJUJU=""
NOCONFIGURE=""
RELEASE_DAILY=""
SESSION_ID=`date +%s`
OSM_DEVOPS=
+OSMLCM_VCA_HOST=
+OSMLCM_VCA_SECRET=
+OSM_STACK_NAME=osm
+NO_HOST_PORTS=""
+DOCKER_NOBUILD=""
-while getopts ":hy-:b:r:k:u:R:l:p:D:o:m:" o; do
+while getopts ":hy-:b:r:k:u:R:l:p:D:o:m:H:S:s:" o; do
case "${o}" in
h)
usage && exit 0
@@ -931,6 +1001,15 @@
D)
OSM_DEVOPS="${OPTARG}"
;;
+ s)
+ OSM_STACK_NAME="${OPTARG}"
+ ;;
+ H)
+ OSMLCM_VCA_HOST="${OPTARG}"
+ ;;
+ S)
+ OSMLCM_VCA_SECRET="${OPTARG}"
+ ;;
o)
INSTALL_ONLY="y"
[ "${OPTARG}" == "vimemu" ] && INSTALL_VIMEMU="y" && continue
@@ -968,6 +1047,9 @@
[ "${OPTARG}" == "noconfigure" ] && NOCONFIGURE="y" && continue
[ "${OPTARG}" == "showopts" ] && SHOWOPTS="y" && continue
[ "${OPTARG}" == "daily" ] && RELEASE_DAILY="y" && continue
+ [ "${OPTARG}" == "nohostports" ] && NO_HOST_PORTS="y" && continue
+ [ "${OPTARG}" == "nojuju" ] && INSTALL_NOJUJU="y" && continue
+ [ "${OPTARG}" == "nodockerbuild" ] && DOCKER_NOBUILD="y" && continue
echo -e "Invalid option: '--$OPTARG'\n" >&2
usage && exit 1
;;