Skip to content

Instantly share code, notes, and snippets.

@ChrisMacNaughton
Created March 5, 2018 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChrisMacNaughton/631bafd62b2762b3bf972cb8804f2e80 to your computer and use it in GitHub Desktop.
Save ChrisMacNaughton/631bafd62b2762b3bf972cb8804f2e80 to your computer and use it in GitHub Desktop.
#!/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