blob: aa20a6800420bf1d909f5fd5c2628b51119866fb [file] [log] [blame]
#!/usr/bin/python3
# *****************************************************************************
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# ******************************************************************************
import argparse
import json
import os
import sys
import time
from datalab.ssn_lib import *
from fabric import *
parser = argparse.ArgumentParser()
parser.add_argument('--hostname', type=str, default='')
parser.add_argument('--keyfile', type=str, default='')
parser.add_argument('--additional_config', type=str, default='{"empty":"string"}')
parser.add_argument('--os_family', type=str, default='')
parser.add_argument('--os_user', type=str, default='')
parser.add_argument('--datalab_path', type=str, default='')
parser.add_argument('--cloud_provider', type=str, default='')
parser.add_argument('--resource', type=str, default='')
parser.add_argument('--region', type=str, default='')
parser.add_argument('--odahu_image', type=str, default='')
parser.add_argument('--gcr_creds', type=str, default='')
args = parser.parse_args()
def modify_conf_file(args):
if os.environ['conf_duo_vpc_enable'] == 'true':
os.environ['conf_vpc2_cidr'] = get_cidr_by_vpc(os.environ['aws_vpc2_id'])
variables_list = {}
host_string = '{}@{}'.format(args.os_user, args.hostname)
for os_var in os.environ:
if "'" not in os.environ[os_var] and os_var != 'aws_access_key' and os_var != 'aws_secret_access_key':
variables_list[os_var] = os.environ[os_var]
conn.local('scp -r -i {} /project_tree/* {}:{}sources/'.format(args.keyfile, host_string, args.datalab_path))
conn.local('scp -i {} /root/scripts/configure_conf_file.py {}:/tmp/configure_conf_file.py'.format(args.keyfile,
host_string))
conn.sudo("python3 /tmp/configure_conf_file.py --datalab_dir {} --variables_list '{}'".format(
args.datalab_path, json.dumps(variables_list)))
def download_toree():
toree_path = '/opt/datalab/sources/infrastructure-provisioning/src/general/files/os/'
tarball_link = 'https://dist.apache.org/repos/dist/dev/incubator/toree/0.5.0-incubating-rc1/toree/toree-0.5.0-incubating-bin.tar.gz'
try:
conn.run('wget {}'.format(tarball_link))
conn.run('tar -xzf toree-0.5.0-incubating-bin.tar.gz')
conn.run('mv toree-0.5.0-incubating-bin.tar.gz {}toree_kernel.tar.gz'.format(toree_path))
conn.run('mv ./toree-0.5.0-incubating/lib/toree-assembly-0.5.0-incubating.jar {}toree-assembly-0.5.0.jar'.format(toree_path))
except Exception as err:
traceback.print_exc()
print('Failed to download toree: ', str(err))
sys.exit(1)
def add_china_repository(datalab_path):
conn.sudo('''bash -c 'cd {1}sources/infrastructure-provisioning/src/base/ && sed -i "/pip install/s/$/ -i https\:\/\/{0}\/simple --trusted-host {0} --timeout 60000/g" Dockerfile' '''.format(os.environ['conf_pypi_mirror'], datalab_path))
conn.sudo('''bash -c 'cd {}sources/infrastructure-provisioning/src/base/ && sed -i "/pip install/s/jupyter/ipython==5.0.0 jupyter==1.0.0/g" Dockerfile' '''.format(datalab_path))
conn.sudo('''bash -c 'cd {}sources/infrastructure-provisioning/src/base/ && sed -i "22i COPY general/files/os/debian/sources.list /etc/apt/sources.list" Dockerfile' '''.format(datalab_path))
def login_in_gcr(os_user, gcr_creds, odahu_image, datalab_path, cloud_provider):
if gcr_creds != '':
try:
if os.environ['conf_cloud_provider'] != 'gcp':
try:
conn.sudo('echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt '
'cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list')
conn.sudo('apt-get -y install apt-transport-https ca-certificates gnupg')
conn.sudo('curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -')
conn.sudo('apt-get update')
conn.sudo('apt-get -y install google-cloud-sdk')
except Exception as err:
traceback.print_exc()
print('Failed to install gcloud: ', str(err))
sys.exit(1)
try:
host_string = '{}@{}'.format(args.os_user, args.hostname)
with open('/tmp/config', 'w') as f:
f.write(base64.b64decode(gcr_creds))
conn.local('scp -i {} /tmp/config {}:/tmp/config'.format(args.keyfile, host_string, os_user))
conn.sudo('mkdir /home/{}/.docker'.format(os_user))
conn.sudo('cp /tmp/config /home/{}/.docker/config.json'.format(os_user))
conn.sudo('sed -i "s|ODAHU_IMAGE|{}|" {}sources/infrastructure-provisioning/src/general/files/{}/odahu_Dockerfile'
.format(odahu_image, datalab_path, cloud_provider))
except Exception as err:
traceback.print_exc()
print('Failed to prepare odahu image: ', str(err))
sys.exit(1)
except Exception as err:
traceback.print_exc()
print('Failed to prepare odahu image: ', str(err))
sys.exit(1)
def build_docker_images(image_list, region, datalab_path):
try:
host_string = '{}@{}'.format(args.os_user, args.hostname)
if os.environ['conf_cloud_provider'] == 'azure':
conn.local('scp -i {} /root/azure_auth.json {}:{}sources/infrastructure-provisioning/src/base/'
'azure_auth.json'.format(args.keyfile, host_string, args.datalab_path))
conn.sudo('cp {0}sources/infrastructure-provisioning/src/base/azure_auth.json '
'/home/{1}/keys/azure_auth.json'.format(args.datalab_path, args.os_user))
if region == 'cn-north-1':
add_china_repository(datalab_path)
for image in image_list:
name = image['name']
tag = image['tag']
conn.sudo('cp {0}sources/infrastructure-provisioning/src/general/files/{1}/{2}_description.json '
'{0}sources/infrastructure-provisioning/src/{2}/description.json'.format(args.datalab_path, args.cloud_provider, name))
if name == 'base':
conn.sudo("bash -c 'cd {4}sources/infrastructure-provisioning/src/; docker build --build-arg OS={2} "
"--build-arg SRC_PATH=\"\" --file general/files/{3}/{0}_Dockerfile -t docker.datalab-{0}:{1} "
".'".format(name, tag, args.os_family, args.cloud_provider, args.datalab_path))
else:
conn.sudo("bash -c 'cd {4}sources/infrastructure-provisioning/src/; docker build --build-arg OS={2} "
"--file general/files/{3}/{0}_Dockerfile -t docker.datalab-{0}:{1} .'".format(name, tag, args.os_family, args.cloud_provider, args.datalab_path))
conn.sudo('rm -f {}sources/infrastructure-provisioning/src/base/azure_auth.json'.format(args.datalab_path))
return True
except:
return False
def configure_guacamole():
try:
mysql_pass = id_generator()
conn.sudo('docker run --name guacd --restart unless-stopped -d -p 4822:4822 guacamole/guacd')
conn.sudo('docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > initdb.sql')
conn.sudo('mkdir /tmp/scripts')
conn.sudo('cp initdb.sql /tmp/scripts')
conn.sudo('mkdir /opt/mysql')
conn.sudo('docker run --name guac-mysql --restart unless-stopped -v /tmp/scripts:/tmp/scripts '\
' -v /opt/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD={} -d mysql:latest'.format(mysql_pass))
time.sleep(180)
conn.sudo('touch /opt/mysql/dock-query.sql')
conn.sudo('''bash -c "echo \\"CREATE DATABASE guacamole; CREATE USER 'guacamole' IDENTIFIED BY '{}';''' \
''' GRANT SELECT,INSERT,UPDATE,DELETE ON guacamole.* TO 'guacamole';\\" > /opt/mysql/dock-query.sql"''' \
.format(mysql_pass))
conn.sudo('docker exec -i guac-mysql /bin/bash -c "mysql -u root -p{} < /var/lib/mysql/dock-query.sql"' \
.format(mysql_pass))
conn.sudo('docker exec -i guac-mysql /bin/bash -c "cat /tmp/scripts/initdb.sql | mysql -u root -p{} guacamole"' \
.format(mysql_pass))
conn.sudo("docker run --name guacamole --restart unless-stopped --link guacd:guacd --link guac-mysql:mysql" \
" -e MYSQL_DATABASE='guacamole' -e MYSQL_USER='guacamole' -e MYSQL_PASSWORD='{}'" \
" -d -p 8080:8080 guacamole/guacamole".format(mysql_pass))
# create cronjob for run containers on reboot
conn.sudo('mkdir /opt/datalab/cron')
conn.sudo('touch /opt/datalab/cron/mysql.sh')
conn.sudo('chmod 755 /opt/datalab/cron/mysql.sh')
conn.sudo('bash -c "echo \"docker start guacd\" >> /opt/datalab/cron/mysql.sh"')
conn.sudo('bash -c "echo \"docker start guac-mysql\" >> /opt/datalab/cron/mysql.sh"')
conn.sudo('bash -c "echo \"docker rm guacamole\" >> /opt/datalab/cron/mysql.sh"')
conn.sudo('''bash -c "echo \\"docker run --name guacamole --restart unless-stopped --link guacd:guacd --link ''' \
'''guac-mysql:mysql -e MYSQL_DATABASE='guacamole' -e MYSQL_USER='guacamole' -e MYSQL_PASSWORD='{}' '''\
'''-d -p 8080:8080 guacamole/guacamole\\" >> /opt/datalab/cron/mysql.sh"'''.format(mysql_pass))
conn.sudo("bash -c '(crontab -l 2>/dev/null; echo \"@reboot sh /opt/datalab/cron/mysql.sh\") | crontab -'")
return True
except Exception as err:
traceback.print_exc()
print('Failed to configure guacamole: ', str(err))
return False
def status_container_removal_cron():
try:
conn.sudo('bash -c \'echo "*/15 * * * * datalab-user docker container prune -f --filter until=50m --filter label=edge_status" >> /etc/crontab\'')
except Exception as err:
traceback.print_exc()
print('Failed to create admin status container removal cron: ', str(err))
sys.exit(1)
##############
# Run script #
##############
if __name__ == "__main__":
print("Configure connections")
try:
global conn
conn = datalab.fab.init_datalab_connection(args.hostname, args.os_user, args.keyfile)
deeper_config = json.loads(args.additional_config)
except:
sys.exit(2)
print('Modifying configuration files')
try:
modify_conf_file(args)
except Exception as err:
print('Error:', str(err))
sys.exit(1)
print("Downloading Apache Toree")
download_toree()
print("Installing docker daemon")
if not ensure_docker_daemon(args.datalab_path, args.os_user, args.region):
sys.exit(1)
print("Login in Google Container Registry")
login_in_gcr(args.os_user, args.gcr_creds, args.odahu_image, args.datalab_path, args.cloud_provider)
print("Building Datalab images")
count = 0
while not build_docker_images(deeper_config, args.region, args.datalab_path) and count < 5:
count += 1
time.sleep(5)
print("Configuring guacamole")
if not configure_guacamole():
sys.exit(1)
print("Adding cron to remove edge status containers")
status_container_removal_cron()
conn.close()
sys.exit(0)