dockersetup: support update/reinstall mode

Make it easier to do updates and also reinstall from scratch; if the
application is already installed, we force the user be explicit about
which one they want to do so that there is less chance of data loss.

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
This commit is contained in:
Paul Eggleton 2019-01-04 14:48:27 +13:00
parent 4370564b91
commit 99a86d7e0a

View File

@ -30,6 +30,8 @@ import tempfile
def get_args(): def get_args():
parser = argparse.ArgumentParser(description='Script sets up the Layer Index tool with Docker Containers.') parser = argparse.ArgumentParser(description='Script sets up the Layer Index tool with Docker Containers.')
parser.add_argument('-u', '--update', action="store_true", default=False, help='Update existing installation instead of installing')
parser.add_argument('-r', '--reinstall', action="store_true", default=False, help='Reinstall over existing installation (wipes database!)')
parser.add_argument('-o', '--hostname', type=str, help='Hostname of your machine. Defaults to localhost if not set.', required=False, default = "localhost") parser.add_argument('-o', '--hostname', type=str, help='Hostname of your machine. Defaults to localhost if not set.', required=False, default = "localhost")
parser.add_argument('-p', '--http-proxy', type=str, help='http proxy in the format http://<myproxy:port>', required=False) parser.add_argument('-p', '--http-proxy', type=str, help='http proxy in the format http://<myproxy:port>', required=False)
parser.add_argument('-s', '--https-proxy', type=str, help='https proxy in the format http://<myproxy:port>', required=False) parser.add_argument('-s', '--https-proxy', type=str, help='https proxy in the format http://<myproxy:port>', required=False)
@ -42,6 +44,12 @@ def get_args():
args = parser.parse_args() args = parser.parse_args()
if args.update:
if args.http_proxy or args.https_proxy or args.databasefile or args.no_https or args.cert or args.cert_key or args.letsencrypt:
raise argparse.ArgumentTypeError("The -u/--update option will not update configuration or database content, and thus none of the other configuration options can be used in conjunction with it")
if args.reinstall:
raise argparse.ArgumentTypeError("The -u/--update and -r/--reinstall options are mutually exclusive")
port = proxymod = "" port = proxymod = ""
try: try:
if args.http_proxy: if args.http_proxy:
@ -73,7 +81,7 @@ def get_args():
if not os.path.exists(cert_key): if not os.path.exists(cert_key):
raise argparse.ArgumentTypeError("Could not find certificate key, please use --cert-key to specify it") raise argparse.ArgumentTypeError("Could not find certificate key, please use --cert-key to specify it")
return args.hostname, args.http_proxy, args.https_proxy, args.databasefile, port, proxymod, args.portmapping, args.no_https, args.cert, cert_key, args.letsencrypt return args.update, args.reinstall, args.hostname, args.http_proxy, args.https_proxy, args.databasefile, port, proxymod, args.portmapping, args.no_https, args.cert, cert_key, args.letsencrypt
# Edit http_proxy and https_proxy in Dockerfile # Edit http_proxy and https_proxy in Dockerfile
def edit_dockerfile(http_proxy, https_proxy): def edit_dockerfile(http_proxy, https_proxy):
@ -375,21 +383,44 @@ dbpassword = generatepasswords(10)
rmqpassword = generatepasswords(10) rmqpassword = generatepasswords(10)
## Get user arguments and modify config files ## Get user arguments and modify config files
hostname, http_proxy, https_proxy, dbfile, port, proxymod, portmapping, no_https, cert, cert_key, letsencrypt = get_args() updatemode, reinstmode, hostname, http_proxy, https_proxy, dbfile, port, proxymod, portmapping, no_https, cert, cert_key, letsencrypt = get_args()
https_port = None https_port = None
http_port = None http_port = None
for portmap in portmapping.split(','): if not updatemode:
outport, inport = portmap.split(':', 1) for portmap in portmapping.split(','):
if inport == '443': outport, inport = portmap.split(':', 1)
https_port = outport if inport == '443':
elif inport == '80': https_port = outport
http_port = outport elif inport == '80':
if (not https_port) and (not no_https): http_port = outport
print("No HTTPS port mapping (to port 443 inside the container) was specified and --no-https was not specified") if (not https_port) and (not no_https):
sys.exit(1) print("No HTTPS port mapping (to port 443 inside the container) was specified and --no-https was not specified")
if not http_port: sys.exit(1)
print("Port mapping must include a mapping to port 80 inside the container") if not http_port:
print("Port mapping must include a mapping to port 80 inside the container")
sys.exit(1)
## Check if it's installed
installed = False
return_code = subprocess.call("docker ps -a | grep -q layersapp", shell=True)
if return_code == 0:
installed = True
if updatemode:
if not installed:
print("Application container not found - update mode can only be used on an existing installation")
sys.exit(1)
with open('docker-compose.yml', 'r') as f:
for line in f:
if 'DATABASE_PASSWORD=' in line:
pw = line.split('=')[1].rstrip().rstrip('"')
if pw == 'testingpw':
print("Update mode can only be used when previous configuration is still present in docker-compose.yml and other files")
sys.exit(1)
break
elif installed and not reinstmode:
print('Application already installed. Please use -u/--update to update or -r/--reinstall to reinstall')
sys.exit(1) sys.exit(1)
print(""" print("""
@ -406,26 +437,41 @@ again with the --help argument.
Note that this script does have interactive prompts, so be prepared to Note that this script does have interactive prompts, so be prepared to
provide information as needed. provide information as needed.
""") """)
if reinstmode:
print(""" WARNING: continuing will wipe out any existing data in the database and set
up the application from scratch! Press Ctrl+C now if this is not what you
want.
""")
try: try:
input('Press Enter to begin setup (or Ctrl+C to exit)...') if updatemode:
promptstr = 'Press Enter to begin update (or Ctrl+C to exit)...'
else:
promptstr = 'Press Enter to begin setup (or Ctrl+C to exit)...'
input(promptstr)
except KeyboardInterrupt: except KeyboardInterrupt:
print('') print('')
sys.exit(2) sys.exit(2)
if http_proxy: if reinstmode:
edit_gitproxy(proxymod, port) return_code = subprocess.call("docker-compose down -v", shell=True)
if http_proxy or https_proxy:
edit_dockerfile(http_proxy, https_proxy)
edit_dockercompose(hostname, dbpassword, secretkey, rmqpassword, portmapping, letsencrypt) if not updatemode:
if http_proxy:
edit_gitproxy(proxymod, port)
if http_proxy or https_proxy:
edit_dockerfile(http_proxy, https_proxy)
edit_dockerfile_web(hostname, no_https) edit_dockercompose(hostname, dbpassword, secretkey, rmqpassword, portmapping, letsencrypt)
if not no_https: edit_dockerfile_web(hostname, no_https)
setup_https(hostname, http_port, https_port, letsencrypt, cert, cert_key)
if not no_https:
setup_https(hostname, http_port, https_port, letsencrypt, cert, cert_key)
## Start up containers ## Start up containers
return_code = subprocess.call("docker-compose up -d", shell=True) return_code = subprocess.call("docker-compose up -d --build", shell=True)
if return_code != 0: if return_code != 0:
print("docker-compose up failed") print("docker-compose up failed")
sys.exit(1) sys.exit(1)
@ -440,26 +486,27 @@ while True:
else: else:
print("Database server may not be ready; will try again.") print("Database server may not be ready; will try again.")
# Import the user's supplied data if not updatemode:
if dbfile: # Import the user's supplied data
return_code = subprocess.call("docker exec -i layersdb mysql -uroot -p" + dbpassword + " layersdb " + " < " + dbfile, shell=True) if dbfile:
return_code = subprocess.call("docker exec -i layersdb mysql -uroot -p" + dbpassword + " layersdb " + " < " + dbfile, shell=True)
if return_code != 0:
print("Database import failed")
sys.exit(1)
## For a fresh database, create an admin account
print("Creating database superuser. Input user name, email, and password when prompted.")
return_code = subprocess.call("docker-compose run --rm layersapp /opt/layerindex/manage.py createsuperuser", shell=True)
if return_code != 0: if return_code != 0:
print("Database import failed") print("Creating superuser failed")
sys.exit(1) sys.exit(1)
## For a fresh database, create an admin account ## Set the volume permissions using debian:stretch since we recently fetched it
print("Creating database superuser. Input user name, email, and password when prompted.") return_code = subprocess.call("docker run --rm -v layerindexweb_layersmeta:/opt/workdir debian:stretch chown 500 /opt/workdir && \
return_code = subprocess.call("docker-compose run --rm layersapp /opt/layerindex/manage.py createsuperuser", shell=True) docker run --rm -v layerindexweb_layersstatic:/usr/share/nginx/html debian:stretch chown 500 /usr/share/nginx/html", shell=True)
if return_code != 0: if return_code != 0:
print("Creating superuser failed") print("Setting volume permissions failed")
sys.exit(1) sys.exit(1)
## Set the volume permissions using debian:stretch since we recently fetched it
return_code = subprocess.call("docker run --rm -v layerindexweb_layersmeta:/opt/workdir debian:stretch chown 500 /opt/workdir && \
docker run --rm -v layerindexweb_layersstatic:/usr/share/nginx/html debian:stretch chown 500 /usr/share/nginx/html", shell=True)
if return_code != 0:
print("Setting volume permissions failed")
sys.exit(1)
## Generate static assets. Run this command again to regenerate at any time (when static assets in the code are updated) ## Generate static assets. Run this command again to regenerate at any time (when static assets in the code are updated)
return_code = subprocess.call("docker-compose run --rm -e STATIC_ROOT=/usr/share/nginx/html -v layerindexweb_layersstatic:/usr/share/nginx/html layersapp /opt/layerindex/manage.py collectstatic --noinput", shell = True) return_code = subprocess.call("docker-compose run --rm -e STATIC_ROOT=/usr/share/nginx/html -v layerindexweb_layersstatic:/usr/share/nginx/html layersapp /opt/layerindex/manage.py collectstatic --noinput", shell = True)
@ -467,11 +514,14 @@ if return_code != 0:
print("Collecting static files failed") print("Collecting static files failed")
sys.exit(1) sys.exit(1)
print("") if updatemode:
if https_port and not no_https: print("Update complete")
protocol = 'https'
port = https_port
else: else:
protocol = 'http' print("")
port = http_port if https_port and not no_https:
print("The application should now be accessible at %s://%s:%s" % (protocol, hostname, port)) protocol = 'https'
port = https_port
else:
protocol = 'http'
port = http_port
print("The application should now be accessible at %s://%s:%s" % (protocol, hostname, port))