def setup_lxdbr0_network(): """ This attempts to setup LXD networking if not available """ try: utils.run('lxc network show lxdbr0', shell=True, check=True, stdout=DEVNULL, stderr=DEVNULL) except CalledProcessError: out = utils.run_script('lxc network create lxdbr0 ' 'ipv4.address=10.0.8.1/24 ' 'ipv4.nat=true ' 'ipv6.address=none ' 'ipv6.nat=false') if out.returncode != 0: raise Exception("Failed to create LXD network bridge: {}".format( out.stderr.decode())) out = utils.run_script( "lxc network show lxdbr0 | grep -q 'ipv4\.address:\snone'") if out.returncode == 0: network_set_cmds = [ 'lxc network set lxdbr0 ipv4.address 10.0.8.1/24', 'lxc network set lxdbr0 ipv4.nat true' ] for n in network_set_cmds: out = utils.run_script(n) if out.returncode != 0: raise Exception("Problem with {}: {}".format( n, out.stderr.decode()))
def setup_bridge_network(self, iface): """ Sets up our main network bridge to be used with Localhost deployments """ out = utils.run_script('conjure-up.lxc network show conjureup1') if out.returncode == 0: return # already configured self.kill_dnsmasq('conjureup1') out = utils.run_script('conjure-up.lxc network create conjureup1 ' 'ipv4.address=auto ' 'ipv4.nat=true ' 'ipv6.address=none ' 'ipv6.nat=false') if out.returncode != 0: raise Exception("Failed to create LXD conjureup1 network bridge: " "{}".format(out.stderr.decode()))
def setup_conjureup0_network(): """ This attempts to setup LXD network bridge for conjureup if not available """ out = utils.run_script('lxc network show conjureup0', stdout=DEVNULL, stderr=DEVNULL) if out.returncode != 0: out = utils.run_script('lxc network create conjureup0 ' 'ipv4.address=10.99.0.1/24 ' 'ipv4.nat=true ' 'ipv6.address=none ' 'ipv6.nat=false') if out.returncode != 0: raise Exception( "Failed to create LXD conjureup0 network bridge: {}".format( out.stderr.decode()))
def set_default_profile(self): """ Sets the default profile with the correct parent network bridges """ profile = textwrap.dedent(""" config: boot.autostart: "true" description: Default LXD profile devices: eth0: name: eth0 nictype: bridged parent: conjureup1 type: nic eth1: name: eth1 nictype: bridged parent: conjureup0 type: nic root: path: / pool: default type: disk name: default """) with NamedTemporaryFile(mode='w', encoding='utf-8', delete=False) as tempf: utils.spew(tempf.name, profile) out = utils.run_script( 'cat {} |conjure-up.lxc profile edit default'.format( tempf.name)) if out.returncode != 0: raise Exception( "Problem setting default profile: {}".format(out))
def set_lxd_storage(self): """ Runs lxc storage creation """ out = utils.run_script("conjure-up.lxc storage create default dir") if out.returncode != 0: if 'already exists' not in out.stderr.decode(): raise Exception("Problem running lxc storage: {}".format( out.stderr.decode()))
def setup_unused_bridge_network(self): """ Sets up an unused bridge that can be used with deployments such as OpenStack on LXD using NovaLXD. """ out = utils.run_script('conjure-up.lxc network show conjureup0') if out.returncode == 0: return # already configured self.kill_dnsmasq('conjureup0') out = utils.run_script('conjure-up.lxc network create conjureup0 ' 'ipv4.address=auto ' 'ipv4.nat=true ' 'ipv6.address=none ' 'ipv6.nat=false') if out.returncode != 0: raise Exception("Failed to create conjureup0 network bridge: " "{}".format(out.stderr.decode()))
def set_lxc_config(self): """ Runs lxc config Assigns an unused port to our LXD daemon, skips if already set. We also want to retry here just incase the daemon isn't ready. """ delay = 2 for attempt in range(5): out = utils.run_script( "conjure-up.lxc config get core.https_address") if out.stdout.decode().strip(): return out = utils.run_script("conjure-up.lxc config set " "core.https_address [::]:{}".format( utils.get_open_port())) if out.returncode == 0: return time.sleep(delay) raise Exception("Problem running lxc config: {}".format( out.stderr.decode()))
def set_lxd_init_auto(self): """ Runs lxd init --auto We want to retry and delay here as LXD daemon may not be fully awake yet. """ delay = 2 for attempt in range(5): out = utils.run_script("conjure-up.lxd init --auto") if out.returncode == 0: return time.sleep(delay) raise Exception("Problem running lxd init: {}".format( out.stderr.decode()))
def wait_for_applications(script, msg_cb): """ Processes a 00_deploy-done to verify if applications are available Arguments: script: script to run (00_deploy-done) msg_cb: message callback """ if os.path.isfile(script) \ and os.access(script, os.X_OK): msg_cb("Waiting for applications to start") try: rerun = True count = 0 while rerun: sh = utils.run_script(script) if sh.returncode != 0: app.log.error("error running {}:\n{}".format( script, sh.stderr)) raise Exception( "Error in waiting for deployment to finish: " "{}".format(sh.stderr.decode())) try: lines = sh.stdout.decode('utf8').splitlines() result = json.loads(lines[-1]) except json.decoder.JSONDecodeError as e: app.log.exception(sh.stdout.decode()) raise Exception(sh) if result['returnCode'] > 0: app.log.error("Failure in deploy done: {}".format( result['message'])) raise Exception(result['message']) if not result['isComplete']: time.sleep(5) if count == 0: msg_cb("{}, please wait".format(result['message'])) count += 1 continue count = 0 rerun = False except CalledProcessError as e: raise e
def wait_for_applications(script, msg_cb): """ Processes a 00_deploy-done to verify if applications are available Arguments: script: script to run (00_deploy-done.sh) msg_cb: message callback """ if os.path.isfile(script) \ and os.access(script, os.X_OK): msg_cb("Waiting for applications to start") try: rerun = True count = 0 while rerun: sh = utils.run_script(script) if sh.returncode != 0: app.log.error("error running {}:\n{}".format(script, sh.stderr)) raise Exception("Error running {}".format(script)) try: lines = sh.stdout.decode('utf8').splitlines() result = json.loads(lines[-1]) except json.decoder.JSONDecodeError as e: app.log.exception(sh.stdout.decode()) raise Exception(sh) if result['returnCode'] > 0: app.log.error( "Failure in deploy done: {}".format(result['message'])) raise Exception(result['message']) if not result['isComplete']: time.sleep(5) if count == 0: msg_cb("{}, please wait".format( result['message'])) count += 1 continue count = 0 rerun = False except CalledProcessError as e: raise e
def do_step(step_model, step_widget, message_cb, gui=False): """ Processes steps in the background Arguments: step: a step to run message_cb: log writer gui: optionally set an UI components if GUI Returns: Step title and results message """ # merge the step_widget input data into our step model if gui: step_widget.clear_button() for i in step_model.additional_input: try: matching_widget = [ x for x in step_widget.additional_input if x['key'] == i['key'] ][0] i['input'] = matching_widget['input'].value except IndexError as e: app.log.error("Tried to pull a value from an " "invalid input: {}/{}".format( e, matching_widget)) try: info = model_info(app.current_model) except: juju.login(force=True) info = model_info(app.current_model) # Set our provider type environment var so that it is # exposed in future processing tasks app.env['JUJU_PROVIDERTYPE'] = info['provider-type'] # Set current juju controller and model app.env['JUJU_CONTROLLER'] = app.current_controller app.env['JUJU_MODEL'] = app.current_model if info['provider-type'] == "maas": app.log.debug("MAAS CONFIG: {}".format(app.maas)) # Expose MAAS endpoints and tokens app.env['MAAS_ENDPOINT'] = app.maas.endpoint app.env['MAAS_APIKEY'] = app.maas.api_key # Set environment variables so they can be accessed from the step scripts set_env(step_model.additional_input) if not os.access(step_model.path, os.X_OK): app.log.error("Step {} not executable".format(step_model.path)) message_cb("Running step: {}".format(step_model.title)) if gui: step_widget.set_icon_state('waiting') app.log.debug("Executing script: {}".format(step_model.path)) with open(step_model.path + ".out", 'w') as outf: with open(step_model.path + ".err", 'w') as errf: utils.run_script(step_model.path, stderr=errf, stdout=outf) try: with open(step_model.path + ".out") as outf: lines = outf.readlines() try: result = json.loads(lines[-1]) except json.decoder.JSONDecodeError as e: raise Exception("Unable to parse json ({}): {}".format( e, lines)) except: raise Exception("Could not read output from step " "{}: {}".format(step_model.path, lines)) if 'returnCode' not in result: raise Exception("Invalid last message from step: {}".format(result)) if result['returnCode'] > 0: app.log.error("Failure in step: {}".format(result['message'])) raise Exception(result['message']) step_model.result = result['message'] message_cb("{} completed.".format(step_model.title)) return (step_model, step_widget)
def do_step(step_model, step_widget, message_cb, gui=False): """ Processes steps in the background Arguments: step: a step to run message_cb: log writer gui: optionally set an UI components if GUI Returns: Step title and results message """ # merge the step_widget input data into our step model if gui: step_widget.clear_button() for i in step_model.additional_input: try: matching_widget = [ x for x in step_widget.additional_input if x['key'] == i['key']][0] i['input'] = matching_widget['input'].value except IndexError as e: app.log.error( "Tried to pull a value from an " "invalid input: {}/{}".format(e, matching_widget)) info = model_info(app.current_model) # Set our provider type environment var so that it is # exposed in future processing tasks app.env['JUJU_PROVIDERTYPE'] = info['provider-type'] if gui: # These environment variables must be set on the CLI or exported # in shell set_env(step_model.additional_input) if not os.access(step_model.path, os.X_OK): app.log.error("Step {} not executable".format(step_model.path)) message_cb("Running step: {}".format(step_model.title)) if gui: step_widget.set_icon_state('waiting') app.log.debug("Executing script: {}".format(step_model.path)) with open(step_model.path + ".out", 'w') as outf: with open(step_model.path + ".err", 'w') as errf: utils.run_script(step_model.path, stderr=errf, stdout=outf) try: with open(step_model.path + ".out") as outf: lines = outf.readlines() result = json.loads(lines[-1]) except: raise Exception("Could not read output from step " "{}".format(step_model.path)) if 'returnCode' not in result: raise Exception("Invalid last message from step: {}".format(result)) if result['returnCode'] > 0: app.log.error( "Failure in step: {}".format(result['message'])) raise Exception(result['message']) step_model.result = result['message'] message_cb("{} done, result:".format(step_model.title, step_model.result)) return (step_model, step_widget)