def prep_userdata(self): """ preps userdata file for container install """ render_parts = {"extra_sshkeys": [utils.ssh_readkey()]} if self.config.getopt("upstream_ppa"): render_parts["upstream_ppa"] = self.config.getopt("upstream_ppa") render_parts["seed_command"] = self._proxy_pollinate() for opt in [ "apt_proxy", "apt_https_proxy", "http_proxy", "https_proxy", "no_proxy", "image_metadata_url", "tools_metadata_url", "apt_mirror", ]: val = self.config.getopt(opt) if val: render_parts[opt] = val dst_file = os.path.join(self.config.cfg_path, "userdata.yaml") original_data = utils.load_template("userdata.yaml") log.info("Prepared userdata: {}".format(render_parts)) modified_data = original_data.render(render_parts) utils.spew(dst_file, modified_data)
def save(self): """ Saves configuration """ try: utils.spew(self.cfg_file, yaml.safe_dump(self._config, default_flow_style=False)) except IOError: raise ConfigException("Unable to save configuration.")
def write_lxc_net_config(self): """Finds and configures a new subnet for the host container, to avoid overlapping with IPs used for Neutron. """ lxc_net_template = utils.load_template('lxc-net') lxc_net_container_filename = os.path.join( self.container_abspath, 'rootfs/etc/default/lxc-net') network = netutils.get_unique_lxc_network() self.config.setopt('lxc_network', network) nw = IPv4Network(network) addr = nw[1] netmask = nw.with_netmask.split('/')[-1] net_low, net_high = netutils.ip_range_max(nw, [addr]) dhcp_range = "{},{}".format(net_low, net_high) render_parts = dict(addr=addr, netmask=netmask, network=network, dhcp_range=dhcp_range) lxc_net = lxc_net_template.render(render_parts) name = self.container_name log.info("Writing lxc-net config for {}".format(name)) utils.spew(lxc_net_container_filename, lxc_net) return network
def do_install(self): """ Perform install """ # Set installed placeholder utils.spew(os.path.join( self.config.cfg_path, 'installed'), 'auto-generated') if self.install_type == INSTALL_TYPE_SINGLE[0]: self.ui.status_info_message("Performing a Single Install") self.SingleInstall( self.loop, self.ui, self.config).run() elif self.install_type == INSTALL_TYPE_MULTI[0]: # TODO: Clean this up a bit more I dont like relying on # opts.headless but in a few places if self.config.getopt('headless'): self.ui.status_info_message( "Performing a Multi install with existing MAAS") self.MultiInstallExistingMaas( self.loop, self.ui, self.config).run() else: self.ui.show_maas_input( "Enter MAAS IP and API Key", self._save_maas_creds) elif self.install_type == INSTALL_TYPE_LANDSCAPE[0]: log.info("Performing a OpenStack Autopilot install") self.LandscapeInstall( self.loop, self.ui, self.config).run() else: os.remove(os.path.join(self.config.cfg_path, 'installed')) raise ValueError("Unknown install type: {}".format( self.install_type))
def do_install(self): """ Perform install """ # Set installed placeholder utils.spew(os.path.join(self.config.cfg_path, 'installed'), 'auto-generated') if self.install_type == INSTALL_TYPE_SINGLE[0]: self.ui.status_info_message("Performing a Single Install") self.SingleInstall(self.loop, self.ui, self.config).run() elif self.install_type == INSTALL_TYPE_MULTI[0]: # TODO: Clean this up a bit more I dont like relying on # opts.headless but in a few places if self.config.getopt('headless'): self.ui.status_info_message( "Performing a Multi install with existing MAAS") self.MultiInstallExistingMaas(self.loop, self.ui, self.config).run() else: self.ui.show_maas_input("Enter MAAS IP and API Key", self._save_maas_creds) elif self.install_type == INSTALL_TYPE_LANDSCAPE[0]: log.info("Performing an Autopilot install") self.LandscapeInstall(self.loop, self.ui, self.config).run() else: os.remove(os.path.join(self.config.cfg_path, 'installed')) raise ValueError("Unknown install type: {}".format( self.install_type))
def start_task(self, newtaskname): self.tasks_started_debug.append(newtaskname) if len(self.tasks) <= self.current_task_index: log.error("ran off end of task list, " "can't start {}".format(newtaskname)) return (n, s, e) = self.tasks[self.current_task_index] if s is not None and e is None: self.stop_current_task() if len(self.tasks) <= self.current_task_index: log.error("ran off end of task list") return (expectedname, _, _) = self.tasks[self.current_task_index] if expectedname != newtaskname: log.warning("task name: expected {}, got {}".format(expectedname, newtaskname)) log.info("tasks : {}\n" "tasks_started: {}".format(self.tasks, self.tasks_started_debug)) self.tasks[self.current_task_index] = (expectedname, time.time(), None) self.stopped = False if self.alarm is None: self.update_progress() utils.spew(os.path.join(self.config.cfg_path, 'timings.yaml'), yaml.dump(self.tasks), utils.install_user())
def do_install(self, install_type): """ Callback for install type selector """ if not self.config.getopt('headless'): self.ui.hide_selector_info() # Set installed placeholder utils.spew(os.path.join(self.config.cfg_path, 'installed'), 'auto-generated') if install_type == INSTALL_TYPE_SINGLE[0]: self.ui.status_info_message("Performing a Single Install") self.SingleInstall(self.loop, self.ui, self.config).run() elif install_type == INSTALL_TYPE_MULTI[0]: # TODO: Clean this up a bit more I dont like relying on # opts.headless but in a few places if self.config.getopt('headless'): if self.config.getopt('maascreds'): self.ui.status_info_message( "Performing a Multi install with existing MAAS") self.MultiInstallExistingMaas(self.loop, self.ui, self.config).run() else: self.MultiInstallNewMaas(self.loop, self.ui, self.config).run() else: self.ui.select_maas_type(self._save_maas_creds) elif install_type == INSTALL_TYPE_LANDSCAPE[0]: log.info("Performing a Landscape OpenStack Autopilot install") self.LandscapeInstall(self.loop, self.ui, self.config).run() else: os.remove(os.path.join(self.config.cfg_path, 'installed')) raise ValueError("Unknown install type: {}".format(install_type))
def test_load_machines_single(self): with NamedTemporaryFile(mode='w+', encoding='utf-8') as tempf: utils.spew(tempf.name, yaml.dump(dict())) conf = Config({}, tempf.name) fake_assignments = { 'fake_iid': {'constraints': {}, 'assignments': {'KVM': ['nova-compute']}}, 'fake_iid_2': {'constraints': {'cpu': 8}, 'assignments': {'BareMetal': ['nova-compute']}}} singlepc = PlacementController( None, conf) with TemporaryFile(mode='w+', encoding='utf-8') as tempf: yaml.dump(fake_assignments, tempf) tempf.seek(0) singlepc.load(tempf) self.assertEqual(set([m.instance_id for m in singlepc.machines_pending()]), set(['fake_iid', 'fake_iid_2'])) m2 = next((m for m in singlepc.machines_pending() if m.instance_id == 'fake_iid_2')) self.assertEqual(m2.constraints, {'cpu': 8})
def write_lxc_net_config(self): """Finds and configures a new subnet for the host container, to avoid overlapping with IPs used for Neutron. """ lxc_net_template = utils.load_template('lxc-net') lxc_net_container_filename = os.path.join(self.container_abspath, 'rootfs/etc/default/lxc-net') network = netutils.get_unique_lxc_network() self.config.setopt('lxc_network', network) nw = IPv4Network(network) addr = nw[1] netmask = nw.with_netmask.split('/')[-1] net_low, net_high = netutils.ip_range_max(nw, [addr]) dhcp_range = "{},{}".format(net_low, net_high) render_parts = dict(addr=addr, netmask=netmask, network=network, dhcp_range=dhcp_range) lxc_net = lxc_net_template.render(render_parts) name = self.container_name log.info("Writing lxc-net config for {}".format(name)) utils.spew(lxc_net_container_filename, lxc_net) return network
def prep_userdata(self): """ preps userdata file for container install """ dst_file = os.path.join(self.config.cfg_path, 'userdata.yaml') original_data = utils.load_template('userdata.yaml') modified_data = original_data.render( extra_sshkeys=[utils.ssh_readkey()], extra_pkgs=['juju-local']) utils.spew(dst_file, modified_data)
def write_timings(self): readable_tasks = [] for n, s, e in self.tasks: if e is not None and s is not None: timing = e - s else: timing = None readable_tasks.append((n, s, e, timing)) utils.spew(os.path.join(self.config.cfg_path, 'timings.yaml'), yaml.dump(readable_tasks), utils.install_user())
def prep_juju(self): """ preps juju environments for bootstrap """ # configure juju environment for bootstrap single_env = utils.load_template('juju-env/single.yaml') single_env_modified = single_env.render( openstack_password=self.config.openstack_password) utils.spew(os.path.join(self.config.juju_path, 'environments.yaml'), single_env_modified, owner=utils.install_user())
def save_maas_creds(self, api_host, api_key): """ Saves maas credentials for re-use :param str api_host: ip of maas server :param str api_key: api key of maas admin user """ if api_host.startswith("http://"): raise ConfigException("save_maas_creds expects an ip, not a url") MAAS_CREDS_FILE = os.path.join(self.cfg_path, 'maascreds') utils.spew(MAAS_CREDS_FILE, json.dumps(dict(api_host=api_host, api_key=api_key)))
def setUp(self): self.mock_maas_state = MagicMock() with NamedTemporaryFile(mode='w+', encoding='utf-8') as tempf: utils.spew(tempf.name, yaml.dump(dict())) self.conf = Config({}, tempf.name) self.pc = PlacementController(self.mock_maas_state, self.conf) self.mock_machine = make_fake_machine('machine1') self.mock_machines = [self.mock_machine] self.mock_maas_state.machines.return_value = self.mock_machines
def __init__(self, opts, display_controller): self.config = Config() self.opts = opts self.display_controller = display_controller # Sets install type utils.spew(os.path.join(self.config.cfg_path, 'landscape'), 'auto-generated') self.landscape_tasks = ["Preparing Landscape", "Deploying Landscape", "Registering against Landscape"]
def prep_userdata(self): """ preps userdata file for container install """ render_parts = {'extra_sshkeys': [utils.ssh_readkey()], 'extra_pkgs': ['juju-local']} if self.opts.extra_ppa: render_parts['extra_ppa'] = self.opts.extra_ppa dst_file = os.path.join(self.config.cfg_path, 'userdata.yaml') original_data = utils.load_template('userdata.yaml') log.debug("Userdata options: {}".format(render_parts)) modified_data = original_data.render(render_parts) utils.spew(dst_file, modified_data)
def run(self): utils.spew(os.path.join(self.config.cfg_path, 'new-maas'), 'auto-generated') self.installing_new_maas = True self.tasker.register_tasks([ "Installing MAAS", "Configuring MAAS", "Waiting for MAAS cluster registration", "Searching for existing DHCP servers", "Configuring MAAS networks", "Importing MAAS boot images", "Bootstrapping Juju" ] + self.post_tasks) self.prompt_for_interface()
def __init__(self, opts, display_controller): self.opts = opts super().__init__(display_controller) self.config = Config() self.container_name = 'uoi-bootstrap' self.container_path = '/var/lib/lxc' self.container_abspath = os.path.join(self.container_path, self.container_name) self.userdata = os.path.join( self.config.cfg_path, 'userdata.yaml') # Sets install type utils.spew(os.path.join(self.config.cfg_path, 'single'), 'auto-generated')
def test_charmconfig_custom_overwrite(self, mockspew): """ Verify complex yaml can safely overwrite existing defined keys """ charm_conf = yaml.load(slurp(os.path.join(DATA_DIR, 'charmconf.yaml'))) charm_conf_custom = yaml.load( slurp(os.path.join(DATA_DIR, 'charmconf-deepchainmap-fail.yaml'))) merged_dicts = merge_dicts(charm_conf, charm_conf_custom) with NamedTemporaryFile(mode='w+', encoding='utf-8') as tempf: spew(tempf.name, yaml.safe_dump(merged_dicts, default_flow_style=False)) modified_charm_conf = yaml.load(slurp(tempf.name)) self.assertEqual(modified_charm_conf['mysql']['dataset-size'], '512M') self.assertEqual(modified_charm_conf['swift-storage']['zone'], 1)
def save(self): """ Saves configuration """ try: if self.save_backups and os.path.exists(self.cfg_file): datestr = datetime.datetime.now().strftime("%Y-%m-%d-%H:%M:%S") backup_path = os.path.join(self.cfg_path, "config-backups") backupfilename = "{}/config-{}.yaml".format( backup_path, datestr) os.makedirs(backup_path, exist_ok=True) os.rename(self.cfg_file, backupfilename) utils.spew( self.cfg_file, yaml.safe_dump(dict(self._config), default_flow_style=False)) except IOError as e: raise ConfigException("Unable to save configuration: {}".format(e))
def render_setup_script(self): setup_template = utils.load_template("nova-controller-setup.sh") if self.config.is_single(): lxc_network = self.config.getopt("lxc_network") N = lxc_network.split(".")[2] else: # N is used to define networks for single, so we simply # set a dummy value for multi N = 0 setup_script_path = os.path.join(self.config.cfg_path, "nova-controller-setup.sh") osrel = self.config.getopt("openstack_release") template_args = dict(N=N, openstack_release=osrel) utils.spew(setup_script_path, setup_template.render(template_args)) return setup_script_path
def save(self): """ Saves configuration """ try: if self.save_backups and os.path.exists(self.cfg_file): datestr = datetime.datetime.now().strftime("%Y-%m-%d-%H:%M:%S") backup_path = os.path.join(self.cfg_path, "config-backups") backupfilename = "{}/config-{}.yaml".format(backup_path, datestr) os.makedirs(backup_path, exist_ok=True) os.rename(self.cfg_file, backupfilename) utils.spew(self.cfg_file, yaml.safe_dump(dict(self._config), default_flow_style=False)) except IOError as e: raise ConfigException("Unable to save configuration: {}".format(e))
def __init__(self, opts, display_controller, post_tasks=None): self.opts = opts super().__init__(display_controller) self.config = Config() self.tempdir = TemporaryDirectory(suffix="cloud-install") if post_tasks: self.post_tasks = post_tasks else: self.post_tasks = [] self.installing_new_maas = False # Sets install type if not self.config.is_landscape: utils.spew(os.path.join(self.config.cfg_path, 'multi'), 'auto-generated')
def render_setup_script(self): setup_template = utils.load_template("nova-controller-setup.sh") if self.config.is_single(): lxc_network = self.config.getopt('lxc_network') N = lxc_network.split('.')[2] else: # N is used to define networks for single, so we simply # set a dummy value for multi N = 0 setup_script_path = os.path.join(self.config.cfg_path, "nova-controller-setup.sh") utils.spew(setup_script_path, setup_template.render(dict(N=N))) return setup_script_path
def test_charmconfig_custom_overwrite(self, mockspew): """ Verify complex yaml can safely overwrite existing defined keys """ charm_conf = yaml.load(slurp(os.path.join(DATA_DIR, 'charmconf.yaml'))) charm_conf_custom = yaml.load(slurp( os.path.join(DATA_DIR, 'charmconf-deepchainmap-fail.yaml'))) merged_dicts = merge_dicts(charm_conf, charm_conf_custom) with NamedTemporaryFile(mode='w+', encoding='utf-8') as tempf: spew(tempf.name, yaml.safe_dump( merged_dicts, default_flow_style=False)) modified_charm_conf = yaml.load(slurp(tempf.name)) self.assertEqual(modified_charm_conf['mysql']['dataset-size'], '512M') self.assertEqual(modified_charm_conf['swift-storage']['zone'], 1)
def run(self): utils.spew(os.path.join(self.config.cfg_path, 'new-maas'), 'auto-generated') self.installing_new_maas = True self.register_tasks(["Installing MAAS", "Configuring MAAS", "Waiting for MAAS cluster registration", "Searching for existing DHCP servers", "Configuring MAAS networks", "Importing MAAS boot images", "Bootstrapping Juju"] + self.post_tasks) self.prompt_for_interface()
def setUp(self): self.mock_maas_state = MagicMock() with NamedTemporaryFile(mode='w+', encoding='utf-8') as tempf: utils.spew(tempf.name, yaml.dump(dict())) self.conf = Config({}, tempf.name, save_backups=False) self.pc = PlacementController(self.mock_maas_state, self.conf) self.mock_machine = make_fake_machine('machine1', {'cpu_count': 3}) self.mock_machine2 = make_fake_machine('machine2') self.mock_machine3 = make_fake_machine('machine3') self.mock_machines = [self.mock_machine] self.mock_maas_state.machines.return_value = self.mock_machines self.actions = []
def save_landscape_creds(self, admin_name, admin_email, system_email, maas_server, maas_apikey): """ Saves landscape credentials for re-use :param str admin_name: admin name :param str admin_email: admin email :param str system_email: system_email :param str maas_server: ip of maas server :param str maas_apikey: api key of maas admin user """ LANDSCAPE_CREDS_FILE = os.path.join(self.cfg_path, 'landscapecreds') utils.spew(LANDSCAPE_CREDS_FILE, json.dumps(dict(admin_name=admin_name, admin_email=admin_email, system_email=system_email, maas_server=maas_server, maas_apikey=maas_apikey)))
def do_install(self): self.display_controller.info_message("Building environment") if os.path.exists(self.container_abspath): # Container exists, handle return code in installer raise Exception("Container exists, please uninstall or kill " "existing cloud before proceeding.") utils.ssh_genkey() # Prepare cloud-init file for creation self.prep_userdata() # Start container self.create_container_and_wait() # configure juju environment for bootstrap single_env = utils.load_template('juju-env/single.yaml') single_env_modified = single_env.render( openstack_password=self.config.openstack_password) utils.spew('/tmp/single.yaml', single_env_modified) utils.container_run(self.container_name, 'mkdir -p .juju') utils.container_cp(self.container_name, '/tmp/single.yaml', '.juju/environments.yaml') # Set permissions self.copy_installdata_and_set_perms() # start the party cloud_status_bin = ['openstack-status'] if self.opts.enable_swift: cloud_status_bin.append('--enable-swift') self.display_controller.info_message("Bootstrapping Juju ..") self.start_task("Starting Juju server") utils.container_run(self.container_name, "juju bootstrap") utils.container_run(self.container_name, "juju status") if self.opts.install_only: log.info("Done installing, stopping here per --install-only.") sys.exit(0) self.display_controller.info_message("Starting cloud deployment ..") utils.container_run_status( self.container_name, " ".join(cloud_status_bin))
def setUp(self): self.mock_maas_state = MagicMock() with NamedTemporaryFile(mode='w+', encoding='utf-8') as tempf: utils.spew(tempf.name, yaml.dump(dict())) self.conf = Config({}, tempf.name) self.pc = PlacementController(self.mock_maas_state, self.conf) self.mock_machine = MagicMock(name='machine1') pmid = PropertyMock(return_value='fake-instance-id-1') type(self.mock_machine).instance_id = pmid self.mock_machine_2 = MagicMock(name='machine2') pmid2 = PropertyMock(return_value='fake-instance-id-2') type(self.mock_machine_2).instance_id = pmid2 self.mock_machines = [self.mock_machine, self.mock_machine_2] self.mock_maas_state.machines.return_value = self.mock_machines
def prep_juju(self): """ preps juju environments for bootstrap """ render_parts = {'openstack_password': self.config.getopt('openstack_password')} if self.config.getopt('http_proxy'): render_parts['http_proxy'] = self.config.getopt('http_proxy') if self.config.getopt('https_proxy'): render_parts['https_proxy'] = self.config.getopt('https_proxy') # configure juju environment for bootstrap single_env = utils.load_template('juju-env/single.yaml') single_env_modified = single_env.render(render_parts) utils.spew(os.path.join(self.config.juju_path(), 'environments.yaml'), single_env_modified, owner=utils.install_user())
def run_deployer(self): # Prep deployer template for landscape lscape_password = utils.random_password() lscape_env = utils.load_template('landscape-deployments.yaml') lscape_env_modified = lscape_env.render( landscape_password=lscape_password.strip()) utils.spew(self.lscape_yaml_path, lscape_env_modified) out = utils.get_command_output( "JUJU_HOME={0} juju-deployer -WdvL -w 180 -c {1} " "landscape-dense-maas".format( self.config.cfg_path, self.lscape_yaml_path), timeout=None, user_sudo=True) if out['status']: log.error("Problem deploying Landscape: {}".format(out)) raise Exception("Error deploying Landscape.")
def prep_juju(self): """ preps juju environments for bootstrap """ render_parts = { "openstack_password": self.config.getopt("openstack_password"), "ubuntu_series": self.config.getopt("ubuntu_series"), } for opt in ["apt_proxy", "apt_https_proxy", "http_proxy", "https_proxy"]: val = self.config.getopt(opt) if val: render_parts[opt] = val # configure juju environment for bootstrap single_env = utils.load_template("juju-env/single.yaml") single_env_modified = single_env.render(render_parts) utils.spew( os.path.join(self.config.juju_path(), "environments.yaml"), single_env_modified, owner=utils.install_user() )
def setUp(self): self.mock_maas_state = MagicMock() with NamedTemporaryFile(mode='w+', encoding='utf-8') as tempf: utils.spew(tempf.name, yaml.dump(dict())) self.conf = Config({}, tempf.name) self.conf.setopt('storage_backend', 'none') self.pc = PlacementController(self.mock_maas_state, self.conf) self.mock_machine = make_fake_machine('machine1', {'cpu_count': 3}) self.mock_machine2 = make_fake_machine('machine2') self.mock_machine3 = make_fake_machine('machine3') self.mock_machines = [self.mock_machine] self.mock_maas_state.machines.return_value = self.mock_machines self.actions = [] self.sub_actions = []
def render_setup_script(self): setup_template = utils.load_template("nova-controller-setup.sh") if self.config.is_single(): lxc_network = self.config.getopt('lxc_network') if lxc_network is None: log.error("lxc_network config not found") raise Exception("can't find lxc_network") N = lxc_network.split('.')[2] else: # N is used to define networks for single, so we simply # set a dummy value for multi N = 0 setup_script_path = os.path.join(self.config.cfg_path, "nova-controller-setup.sh") osrel = self.config.getopt('openstack_release') template_args = dict(N=N, openstack_release=osrel) utils.spew(setup_script_path, setup_template.render(template_args)) return setup_script_path
def prep_juju(self): """ preps juju environments for bootstrap """ render_parts = { 'openstack_password': self.config.getopt('openstack_password') } if self.config.getopt('http_proxy'): render_parts['http_proxy'] = self.config.getopt('http_proxy') if self.config.getopt('https_proxy'): render_parts['https_proxy'] = self.config.getopt('https_proxy') # configure juju environment for bootstrap single_env = utils.load_template('juju-env/single.yaml') single_env_modified = single_env.render(render_parts) utils.spew(os.path.join(self.config.juju_path(), 'environments.yaml'), single_env_modified, owner=utils.install_user())
def run_deployer(self): # Prep deployer template for landscape lscape_password = utils.random_password() password_re = re.compile('(change-me)') lscape_env = utils.slurp(self.lscape_yaml_path) lscape_env_re = password_re.sub(lscape_password, str(lscape_env)) lscape_env_modified = { 'landscape-dense-maas': yaml.load(lscape_env_re) } utils.spew(self.lscape_yaml_path, yaml.dump(lscape_env_modified)) out = utils.get_command_output("{0} juju-deployer -WdvL -w 180 -c {1} " "landscape-dense-maas".format( self.config.juju_home(), self.lscape_yaml_path), timeout=None, user_sudo=True) if out['status']: log.error("Problem deploying Landscape: {}".format(out)) raise Exception("Error deploying Landscape.")
def configure_nat(self, network): cmd = ('iptables -t nat -a POSTROUTING ' '-s {} ! -d {} -j MASQUERADE'.format(network, network)) utils.get_command_output(cmd) utils.spew( '/etc/network/iptables.rules', "*nat\n" ":PREROUTING ACCEPT [0:0]\n" ":INPUT ACCEPT [0:0]\n" ":OUTPUT ACCEPT [0:0]\n" ":POSTROUTING ACCEPT [0:0]\n" "-A POSTROUTING -s {} ! -d {} -j MASQUERADE\n" "COMMIT\n".format(network, network)) utils.get_command_output('chmod 0600 /etc/network/iptables.rules') cmd = ("sed -e '/^iface lo inet loopback$/a\ " "pre-up iptables-restore < /etc/network/iptables.rules' " "-i /etc/network/interfaces") res = utils.get_command_output(cmd) if res['status'] != 0: log.debug("error editing /etc/network/interfaces: {}".format(res))
def do_install(self, install_type): """ Callback for install type selector """ self.ui.hide_selector_info() # Set installed placeholder utils.spew(os.path.join( self.config.cfg_path, 'installed'), 'auto-generated') if install_type == INSTALL_TYPE_SINGLE[0]: self.set_openstack_rel("Icehouse (2014.1.3)") self.SingleInstall(self.opts, self).run() elif install_type == INSTALL_TYPE_MULTI[0]: self.set_openstack_rel("Icehouse (2014.1.3)") self.select_maas_type() elif install_type == INSTALL_TYPE_LANDSCAPE[0]: self.set_openstack_rel("") self.LandscapeInstall(self.opts, self).run() else: os.remove(os.path.join(self.config.cfg_path, 'installed')) raise ValueError("Unknown install type: {}".format(install_type))
def configure_nat(self, network): cmd = ('iptables -t nat -a POSTROUTING ' '-s {} ! -d {} -j MASQUERADE'.format(network, network)) utils.get_command_output(cmd) utils.spew('/etc/network/iptables.rules', "*nat\n" ":PREROUTING ACCEPT [0:0]\n" ":INPUT ACCEPT [0:0]\n" ":OUTPUT ACCEPT [0:0]\n" ":POSTROUTING ACCEPT [0:0]\n" "-A POSTROUTING -s {} ! -d {} -j MASQUERADE\n" "COMMIT\n".format(network, network)) utils.get_command_output('chmod 0600 /etc/network/iptables.rules') cmd = ("sed -e '/^iface lo inet loopback$/a\ " "pre-up iptables-restore < /etc/network/iptables.rules' " "-i /etc/network/interfaces") res = utils.get_command_output(cmd) if res['status'] != 0: log.debug("error editing /etc/network/interfaces: {}".format(res))
def prep_juju(self): """ preps juju environments for bootstrap """ render_parts = {'openstack_password': self.config.getopt('openstack_password'), 'ubuntu_series': self.config.getopt('ubuntu_series')} for opt in ['apt_proxy', 'apt_https_proxy', 'http_proxy', 'https_proxy']: val = self.config.getopt(opt) if val: render_parts[opt] = val # configure juju environment for bootstrap single_env = utils.load_template('juju-env/single.yaml') single_env_modified = single_env.render(render_parts) utils.spew(os.path.join(self.config.juju_path(), 'environments.yaml'), single_env_modified, owner=utils.install_user())
def prep_juju(self): """ preps juju environments for bootstrap """ render_parts = { 'openstack_password': self.config.getopt('openstack_password'), 'ubuntu_series': self.config.getopt('ubuntu_series') } for opt in [ 'apt_proxy', 'apt_https_proxy', 'http_proxy', 'https_proxy' ]: val = self.config.getopt(opt) if val: render_parts[opt] = val # configure juju environment for bootstrap single_env = utils.load_template('juju-env/single.yaml') single_env_modified = single_env.render(render_parts) utils.spew(os.path.join(self.config.juju_path(), 'environments.yaml'), single_env_modified, owner=utils.install_user())
def prep_userdata(self): """ preps userdata file for container install """ render_parts = {'extra_sshkeys': [utils.ssh_readkey()]} if self.config.getopt('extra_ppa'): render_parts['extra_ppa'] = self.config.getopt('extra_ppa') render_parts['seed_command'] = self._proxy_pollinate() for opt in [ 'http_proxy', 'https_proxy', 'no_proxy', 'image_metadata_url', 'tools_metadata_url', 'apt_mirror' ]: val = self.config.getopt(opt) if val: render_parts[opt] = val dst_file = os.path.join(self.config.cfg_path, 'userdata.yaml') original_data = utils.load_template('userdata.yaml') log.info("Prepared userdata: {}".format(render_parts)) modified_data = original_data.render(render_parts) utils.spew(dst_file, modified_data)
def test_load_machines_single(self): with NamedTemporaryFile(mode='w+', encoding='utf-8') as tempf: utils.spew(tempf.name, yaml.dump(dict())) conf = Config({}, tempf.name) fake_assignments = { 'fake_iid': { 'constraints': {}, 'assignments': { 'KVM': ['nova-compute'] } }, 'fake_iid_2': { 'constraints': { 'cpu': 8 }, 'assignments': { 'BareMetal': ['nova-compute'] } } } singlepc = PlacementController(None, conf) with TemporaryFile(mode='w+', encoding='utf-8') as tempf: yaml.dump(fake_assignments, tempf) tempf.seek(0) singlepc.load(tempf) self.assertEqual( set([m.instance_id for m in singlepc.machines_pending()]), set(['fake_iid', 'fake_iid_2'])) m2 = next((m for m in singlepc.machines_pending() if m.instance_id == 'fake_iid_2')) self.assertEqual(m2.constraints, {'cpu': 8})
def do_install(self): # Install package deps utils.apt_install('openstack-multi') self.tasker.start_task("Bootstrapping Juju") self.config.setopt('current_state', InstallState.RUNNING.value) maas_creds = self.config.getopt('maascreds') maas_env = utils.load_template('juju-env/maas.yaml') render_parts = { 'openstack_password': self.config.getopt('openstack_password'), 'maas_server': maas_creds['api_host'], 'maas_apikey': maas_creds['api_key'], 'ubuntu_series': self.config.getopt('ubuntu_series') } for opt in [ 'http_proxy', 'https_proxy', 'no_proxy', 'apt_proxy', 'image_metadata_url', 'tools_metadata_url' ]: val = self.config.getopt(opt) if val: render_parts[opt] = val maas_env_modified = maas_env.render(render_parts) check_output(['mkdir', '-p', self.config.juju_path()]) utils.spew(self.config.juju_environments_path, maas_env_modified) utils.render_charm_config(self.config) utils.ssh_genkey() # Set remaining permissions self.set_perms() # Starts the party self.display_controller.status_info_message("Bootstrapping Juju") dbgflags = "" if os.getenv("DEBUG_JUJU_BOOTSTRAP"): dbgflags = "--debug" bsflags = "" bstarget = os.getenv("JUJU_BOOTSTRAP_TO") if bstarget: bsflags += " --to {}".format(bstarget) cons = self.config.getopt('constraints') if cons: bsflags += " --constraints \"{}\"".format(cons) cmd = ("{0} juju {1} bootstrap {2}".format(self.config.juju_home(), dbgflags, bsflags)) log.debug("Bootstrapping Juju: {}".format(cmd)) out = utils.get_command_output(cmd, timeout=None, user_sudo=True) if out['status'] != 0: log.debug("Problem during bootstrap: '{}'".format(out)) raise Exception("Problem with juju bootstrap.") # workaround to avoid connection failure at beginning of # openstack-status out = utils.get_command_output("{0} juju status".format( self.config.juju_home()), timeout=None, user_sudo=True) if out['status'] != 0: log.debug("failure to get initial juju status: '{}'".format(out)) raise Exception("Problem with juju status poke.") self.add_bootstrap_to_no_proxy() self.tasker.stop_current_task() if self.config.getopt('install_only'): log.info("Done installing, stopping here per --install-only.") self.config.setopt('install_only', True) self.loop.exit(0) # Return control back to landscape_install if need be if not self.config.is_landscape(): args = ['openstack-status'] if self.config.getopt('edit_placement'): args.append('--edit-placement') self.drop_privileges() os.execvp('openstack-status', args) else: log.debug("Finished MAAS step, now deploying Landscape.") return LandscapeInstallFinal(self, self.display_controller, self.config, self.loop).run()
def continue_with_interface(self): self.display_controller.hide_widget_on_top() self.tasker.start_task("Installing MAAS") check_output('mkdir -p /etc/openstack', shell=True) check_output([ 'cp', '/etc/network/interfaces', '/etc/openstack/interfaces.cloud.bak' ]) check_output([ 'cp', '-r', '/etc/network/interfaces.d', '/etc/openstack/interfaces.cloud.d.bak' ]) utils.spew('/etc/openstack/interface', self.target_iface) utils.apt_install('openstack-multi') self.tasker.start_task("Configuring MAAS") self.create_superuser() self.apikey = self.get_apikey() self.login_to_maas(self.apikey) try: utils.chown(os.path.join(utils.install_home(), '.maascli.db'), utils.install_user(), utils.install_user()) except: raise MaasInstallError("Unable to set permissions on {}".format( os.path.join(utils.install_home(), '.maascli.db'))) self.tasker.start_task("Waiting for MAAS cluster registration") cluster_uuid = self.wait_for_registration() self.create_maas_bridge(self.target_iface) self.prompt_for_bridge() self.tasker.start_task("Configuring MAAS networks") self.configure_maas_networking(cluster_uuid, 'br0', self.gateway, self.dhcp_range, self.static_range) self.configure_dns() self.config.setopt('maascreds', dict(api_host=self.gateway, api_key=self.apikey)) if "MAAS_HTTP_PROXY" in os.environ: pv = os.environ['MAAS_HTTP_PROXY'] out = utils.get_command_output('maas maas maas set-config ' 'name=http_proxy ' 'value={}'.format(pv)) if out['status'] != 0: log.debug("Error setting maas proxy config: {}".format(out)) raise MaasInstallError("Error setting proxy config") self.display_controller.status_info_message( "Importing MAAS boot images") self.tasker.start_task("Importing MAAS boot images") out = utils.get_command_output('maas maas boot-resources import') if out['status'] != 0: log.debug("Error starting boot images import: {}".format(out)) raise MaasInstallError("Error setting proxy config") def pred(out): return out['output'] != '[]' ok = utils.poll_until_true('maas maas boot-images read ' ' {}'.format(cluster_uuid), pred, 15, timeout=7200) if not ok: log.debug("poll timed out for getting boot images") raise MaasInstallError("Downloading boot images timed out") self.display_controller.status_info_message( "Done importing boot images") self.tasker.stop_current_task() msg = "Waiting for sufficient resources in MAAS" self.display_controller.status_info_message(msg) self.display_controller.current_installer = self self.display_controller.current_state = InstallState.NODE_WAIT