Created
March 5, 2018 14:05
-
-
Save ChrisMacNaughton/631bafd62b2762b3bf972cb8804f2e80 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import sys | |
import os | |
import subprocess | |
import logging | |
SYSTEMD_JUJU_SCRIPT = """#!/usr/bin/env bash | |
# Set up logging. | |
touch '/var/log/juju/machine-{machine_id}.log' | |
chown syslog:syslog '/var/log/juju/machine-{machine_id}.log' | |
chmod 0600 '/var/log/juju/machine-{machine_id}.log' | |
exec >> '/var/log/juju/machine-{machine_id}.log' | |
exec 2>&1 | |
# Run the script. | |
'/var/lib/juju/tools/machine-{machine_id}/jujud' machine --data-dir '/var/lib/juju' --machine-id {machine_id} --debug | |
""" | |
SYSTEMD_JUJU_INIT_FILE = """[Unit] | |
Description=juju agent for machine-{machine_id} | |
After=syslog.target | |
After=network.target | |
After=systemd-user-sessions.service | |
[Service] | |
Environment="" | |
LimitNOFILE=20000 | |
ExecStart=/var/lib/juju/init/jujud-machine-{machine_id}/exec-start.sh | |
Restart=on-failure | |
TimeoutSec=300 | |
[Install] | |
WantedBy=multi-user.target | |
""" | |
def do_release_upgrade(unit): | |
"""Runs do-release-upgrade noninteractive""" | |
logging.info('Upgrading ' + unit) | |
subprocess.call(['juju', 'run', '--unit', unit, 'status-set', | |
'maintenance', 'Doing release upgrade']) | |
cmd = ['juju', 'ssh', unit, 'sudo', | |
'do-release-upgrade', '-f', 'DistUpgradeViewNonInteractive'] | |
try: | |
subprocess.check_call(cmd) | |
except subprocess.CalledProcessError as e: | |
logging.warn("Failed do-release-upgrade for {}".format(name)) | |
logging.warn(e) | |
return False | |
finally: | |
subprocess.call(['juju', 'run', '--unit', unit, 'status-set', | |
'active']) | |
return True | |
def reboot(unit): | |
"""Reboot machine""" | |
cmd = ['juju', 'ssh', unit, 'sudo', 'reboot', '&&', 'exit'] | |
try: | |
subprocess.check_call(cmd) | |
except subprocess.CalledProcessError as e: | |
logging.info(e) | |
pass | |
def upgrade_unit(app_name, unit, machine, machine_num): | |
"""Run the upgrade process for a single machine""" | |
cmd = ['juju', 'run', '--unit', unit, 'status-set', | |
'maintenance', 'Upgrading series'] | |
subprocess.call(cmd) | |
if not do_release_upgrade(unit): | |
return False | |
if machine["series"] == "trusty": | |
upstart_to_systemd(machine_num) | |
cmd = ['juju', 'run', '--unit', unit, 'status-set', | |
'active'] | |
subprocess.call(cmd) | |
logging.debug("Rebooting") | |
reboot(unit) | |
cmd = ['juju', "ssh", unit, "exit"] | |
while(True): | |
try: | |
subprocess.check_call(cmd) | |
break | |
except subprocess.CalledProcessError: | |
logging.debug("Waiting 2 more seconds") | |
sleep(2) | |
update_machine_series(app_name, machine_num) | |
return True | |
def update_machine_series(app_name, machine_num): | |
cmd = ['juju', 'ssh', machine_num, 'lsb_release', '-c', '-s'] | |
codename = subprocess.check_output(cmd) | |
if six.PY3: | |
codename = codename.decode('utf-8') | |
codename = codename.strip() | |
logging.debug("Telling juju that {} series is {}".format( | |
machine_num, codename)) | |
cmd = ['juju', 'update-series', str(machine_num), codename] | |
subprocess.call(cmd) | |
cmd = ['juju', 'update-series', app_name, codename] | |
subprocess.call(cmd) | |
def upstart_to_systemd(machine_number): | |
"""Upgrade upstart scripts to Systemd after upgrade from Trusty""" | |
base_command = ['juju', 'run', '--machine', str(machine_number), '--'] | |
commands = [ | |
base_command + [ | |
"sudo", "mkdir", "-p", | |
"/var/lib/juju/init/jujud-machine-{}".format(machine_number)], | |
base_command + [ | |
'echo', SYSTEMD_JUJU_SCRIPT.format( | |
machine_id=machine_number), '|', 'sudo', 'tee', '/var/lib/juju/init/jujud-machine-{machine_id}/exec-start.sh'.format(machine_id=machine_number)], | |
base_command + [ | |
'echo', SYSTEMD_JUJU_INIT_FILE.format( | |
machine_id=machine_number), '|', 'sudo', 'tee', '/var/lib/juju/init/jujud-machine-{machine_id}/jujud-machine-{machine_id}.service'.format(machine_id=machine_number)], | |
base_command + [ | |
'sudo', 'chmod', '755', '/var/lib/juju/init/jujud-machine-{machine_id}/exec-start.sh'.format(machine_id=machine_number)], | |
base_command + [ | |
'sudo', 'ln', '-s', '/var/lib/juju/init/jujud-machine-{machine_id}/jujud-machine-{machine_id}.service'.format(machine_id=machine_number), '/etc/systemd/system/'], | |
base_command + [ | |
'sudo', 'ln', '-s', '/var/lib/juju/init/jujud-machine-{machine_id}/jujud-machine-{machine_id}.service'.format( | |
machine_id=machine_number), '/etc/systemd/system/multi-user.target.wants/jujud-machine-{machine_id}.service'.format(machine_id=machine_number) | |
] | |
] | |
for cmd in commands: | |
try: | |
subprocess.check_call(cmd) | |
except subprocess.CalledProcessError as e: | |
logging.warn(e) | |
return False | |
def upgrade_all_units(juju_status=None): | |
if not juju_status: | |
juju_status = get_juju_status() | |
# Upgrade the rest | |
# print("Juju status: {}".format(juju_status)) | |
for (app_name, details) in juju_status['applications'].items(): | |
# print("name: {}".format(name)) | |
# print("details: {}".format(details)) | |
# print("Units: {}".format(details["units"])) | |
for name, unit_details in details['units'].items(): | |
# print("About to upgrade {}".format(unit)) | |
print("Details for {}: {}".format(name, unit_details)) | |
machine_id = unit_details["machine"] | |
if not upgrade_unit(app_name, name, juju_status["machines"][machine_id], machine_id): | |
logging.warn("No series upgrade found for {}".format(name)) | |
# time.sleep(30) | |
def main(argv): | |
upgrade_all_units() | |
if __name__ == "__main__": | |
sys.exit(main(sys.argv)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment