def test_get_not_in_snap(self): config_manager = MAASConfiguration(environ={}) # use mocked dir instead of /etc/maas config_manager.DEFAULT_CONFIG_DIR = self.config_dir config = { factory.make_name('key'): factory.make_name('value'), factory.make_name('key'): factory.make_name('value') } self.write_config(config, 'regiond.conf') self.assertEqual(config_manager.get(), config)
def handle(self, options): if os.getuid() != 0: raise SystemExit("The 'init' command must be run by root.") mode = options.run_mode current_mode = get_current_mode() if current_mode != "none": if not options.force: init_text = "initialize again" if mode == "none": init_text = "de-initialize" else: print_msg("Controller has already been initialized.") initialize = prompt_for_choices( "Are you sure you want to %s " "(yes/no) [default=no]? " % init_text, ["yes", "no"], default="no", ) if initialize == "no": sys.exit(0) rpc_secret = None if mode in ("region", "region+rack"): try: database_settings = get_database_settings(options) except DatabaseSettingsError as error: raise CommandError(str(error)) else: database_settings = {} maas_url = options.maas_url if mode != "none" and not maas_url: maas_url = required_prompt( "MAAS URL", default=get_default_url(), help_text=ARGUMENTS["maas-url"]["help"], ) if mode == "rack": rpc_secret = options.secret if not rpc_secret: rpc_secret = required_prompt( "Secret", help_text=ARGUMENTS["secret"]["help"]) if current_mode != "none": def stop_services(): render_supervisord("none") sighup_supervisord() perform_work("Stopping services", stop_services) # Configure the settings. settings = {"maas_url": maas_url} settings.update(database_settings) MAASConfiguration().update(settings) set_rpc_secret(rpc_secret) # Finalize the Initialization. self._finalize_init(mode, options)
def init_db(): """Initialize the database.""" config_data = MAASConfiguration().get() base_db_dir = get_base_db_dir() db_path = os.path.join(base_db_dir, 'data') if not os.path.exists(base_db_dir): os.mkdir(base_db_dir) # allow both root and non-root user to create/delete directories under # this one shutil.chown(base_db_dir, group=NON_ROOT_USER) os.chmod(base_db_dir, 0o770) if os.path.exists(db_path): run_with_drop_privileges(shutil.rmtree, db_path) os.mkdir(db_path) shutil.chown(db_path, user=NON_ROOT_USER, group=NON_ROOT_USER) log_path = os.path.join( os.environ['SNAP_COMMON'], 'log', 'postgresql-init.log') if not os.path.exists(log_path): open(log_path, 'a').close() shutil.chown(log_path, user=NON_ROOT_USER, group=NON_ROOT_USER) socket_path = os.path.join(get_base_db_dir(), 'sockets') if not os.path.exists(socket_path): os.mkdir(socket_path) os.chmod(socket_path, 0o775) shutil.chown(socket_path, user=NON_ROOT_USER) # keep root as group def _init_db(): subprocess.check_output([ os.path.join(os.environ['SNAP'], 'bin', 'initdb'), '-D', os.path.join(get_base_db_dir(), 'data'), '-U', 'postgres', '-E', 'UTF8', '--locale=C'], stderr=subprocess.STDOUT) with with_postgresql(): create_db(config_data) run_with_drop_privileges(_init_db)
def print_config(parsable=False, show_database_password=False, show_secret=False): """Print the config output.""" current_mode = get_current_mode() config = MAASConfiguration().get() if parsable: print_msg('mode=%s' % current_mode) else: print_msg('Mode: %s' % current_mode) if current_mode != 'none': if not parsable: print_msg('Settings:') print_config_value(config, 'maas_url') if current_mode in ['region+rack', 'region']: print_config_value(config, 'database_host') print_config_value(config, 'database_port') print_config_value(config, 'database_name') print_config_value(config, 'database_user') print_config_value(config, 'database_pass', hidden=(not show_database_password)) if current_mode == 'rack': secret = "(hidden)" if show_secret: secret = get_rpc_secret() print_msg('secret=%s' % secret) if current_mode != 'rack': if 'num_workers' in config: print_config_value(config, 'num_workers') if 'debug' in config: print_config_value(config, 'debug') if 'debug_queries' in config: print_config_value(config, 'debug_queries')
def print_config(parsable=False, show_database_password=False, show_secret=False): """Print the config output.""" current_mode = get_current_mode() config = MAASConfiguration().get() if parsable: print_msg("mode=%s" % current_mode) else: print_msg("Mode: %s" % current_mode) if current_mode != "none": if not parsable: print_msg("Settings:") print_config_value(config, "maas_url") if current_mode in ["region+rack", "region"]: print_config_value(config, "database_host") print_config_value(config, "database_port") print_config_value(config, "database_name") print_config_value(config, "database_user") print_config_value(config, "database_pass", hidden=(not show_database_password)) if current_mode == "rack": secret = "(hidden)" if show_secret: secret = get_rpc_secret() print_msg("secret=%s" % secret) if current_mode != "rack": if "num_workers" in config: print_config_value(config, "num_workers") if "debug" in config: print_config_value(config, "debug") if "debug_queries" in config: print_config_value(config, "debug_queries")
def init_maas(options): print_msg("Configuring authentication") configure_authentication(options) if not options.skip_admin: auth_config = get_current_auth_config() if auth_config["external_auth_url"]: maas_config = MAASConfiguration().get() create_account_external_auth(auth_config, maas_config) else: create_admin_account(options)
def init_maas(options): if options.enable_candid: print_msg('Configuring authentication') configure_authentication(options) if not options.skip_admin: auth_config = get_current_auth_config() if auth_config['external_auth_url']: maas_config = MAASConfiguration().get() create_account_external_auth(auth_config, maas_config) else: create_admin_account(options)
def init_db(): """Initialize the database.""" config_data = MAASConfiguration().get() base_db_dir = get_base_db_dir() db_path = os.path.join(base_db_dir, "data") if not os.path.exists(base_db_dir): os.mkdir(base_db_dir) # allow both root and non-root user to create/delete directories under # this one shutil.chown(base_db_dir, group=NON_ROOT_USER) os.chmod(base_db_dir, 0o770) if os.path.exists(db_path): run_with_drop_privileges(shutil.rmtree, db_path) os.mkdir(db_path) shutil.chown(db_path, user=NON_ROOT_USER, group=NON_ROOT_USER) log_path = os.path.join(os.environ["SNAP_COMMON"], "log", "postgresql-init.log") if not os.path.exists(log_path): open(log_path, "a").close() shutil.chown(log_path, user=NON_ROOT_USER, group=NON_ROOT_USER) socket_path = os.path.join(get_base_db_dir(), "sockets") if not os.path.exists(socket_path): os.mkdir(socket_path) os.chmod(socket_path, 0o775) shutil.chown(socket_path, user=NON_ROOT_USER) # keep root as group def _init_db(): subprocess.check_output( [ os.path.join(os.environ["SNAP"], "bin", "initdb"), "-D", os.path.join(get_base_db_dir(), "data"), "-U", "postgres", "-E", "UTF8", "--locale=C", ], stderr=subprocess.STDOUT, ) with with_postgresql(): create_db(config_data) run_with_drop_privileges(_init_db)
def init_db(): """Initialize the database.""" config_data = MAASConfiguration().get() db_path = os.path.join(os.environ['SNAP_COMMON'], 'db') if os.path.exists(db_path): shutil.rmtree(db_path) os.mkdir(db_path) shutil.chown(db_path, user='******', group='nogroup') log_path = os.path.join(os.environ['SNAP_COMMON'], 'log', 'postgresql.log') if not os.path.exists(log_path): open(log_path, 'a').close() shutil.chown(log_path, user='******', group='nogroup') def _init_db(): subprocess.check_output([ os.path.join(os.environ['SNAP'], 'bin', 'initdb'), '-D', os.path.join(os.environ['SNAP_COMMON'], 'db'), '-U', 'postgres', '-E', 'UTF8', '--locale=C'], stderr=subprocess.STDOUT) with with_postgresql(): create_db(config_data) run_with_drop_privileges(_init_db)
def handle(self, options): if os.getuid() != 0: raise SystemExit("The 'config' command must be run by root.") config_manager = MAASConfiguration() # Hidden option only called by the run-supervisord script. Renders # the initial supervisord.conf based on the current mode. if options.render: render_supervisord(get_current_mode()) return # In config mode if --show is passed or none of the following flags # have been passed. in_config_mode = options.show if not in_config_mode: in_config_mode = not any( (getattr(options, flag) is not None and getattr(options, flag) is not False) for flag in (('mode', 'secret') + self.setting_flags + tuple(self.optional_flags.keys()))) # Config mode returns the current config of the snap. if in_config_mode: return print_config(options.parsable, options.show_database_password, options.show_secret) else: restart_required = False changed_to_all = False current_mode = get_current_mode() running_mode = current_mode if options.mode is not None: running_mode = options.mode # Validate the mode and flags. self._validate_mode(options) self._validate_flags(options, running_mode) # Changing the mode to from all requires --force. if options.mode is not None: if current_mode == 'all' and options.mode != 'all': if not options.force: print_msg( "Changing mode from 'all' to '%s' will " "disconnect the database and all data will " "be lost. Use '--force' if your sure you want " "to do this." % options.mode) sys.exit(1) elif current_mode != 'all' and options.mode == 'all': # Changing mode to all requires services to be stopped and # a new database to be initialized. changed_to_all = True def stop_services(): render_supervisord('none') sighup_supervisord() perform_work('Stopping services', stop_services) # Configure the new database settings. options.database_host = os.path.join( get_base_db_dir(), 'sockets') options.database_name = 'maasdb' options.database_user = '******' options.database_pass = ''.join( random.choice(string.ascii_uppercase + string.digits) for _ in range(10)) MAASConfiguration().write_to_file( { 'maas_url': options.maas_url, 'database_host': options.database_host, 'database_name': options.database_name, 'database_user': options.database_user, 'database_pass': options.database_pass }, 'regiond.conf') # Initialize the database before starting the services. perform_work('Initializing database', init_db) if options.mode != current_mode: render_supervisord(options.mode) set_current_mode(options.mode) restart_required = True current_config = config_manager.get() if current_mode != running_mode: # Update all the settings since the mode changed. for flag in self.setting_flags: flag_value = getattr(options, flag) if current_config.get(flag) != flag_value: config_manager.update({flag: flag_value}) restart_required = True set_rpc_secret(options.secret) else: # Only update the passed settings. for flag in self.setting_flags: flag_value = getattr(options, flag) should_update = (flag_value is not None and current_config.get(flag) != flag_value) if should_update: config_manager.update({flag: flag_value}) restart_required = True if options.secret is not None: set_rpc_secret(options.secret) # fetch config again, as it might have changed current_config = config_manager.get() # Update any optional settings. for flag, flag_info in self.optional_flags.items(): flag_value = getattr(options, flag) if flag_info['type'] != 'store_true': flag_key = flag_info['config'] should_update = ( flag_value is not None and current_config.get(flag_key) != flag_value) if should_update: config_manager.update({flag_key: flag_value}) restart_required = True elif flag_value: flag_key = flag_info['config'] flag_value = flag_info['set_value'] if current_config.get(flag_key) != flag_value: config_manager.update({flag_key: flag_value}) restart_required = True # Restart the supervisor as its required. if restart_required: perform_work( 'Restarting services' if running_mode != 'none' else 'Stopping services', sighup_supervisord) clear_line() # Perform migrations when switching to all. if changed_to_all: perform_work('Waiting for postgresql', wait_for_postgresql) perform_work("Performing database migrations", migrate_db, capture=sys.stdout.isatty()) clear_line()
def handle(self, options): if os.getuid() != 0: raise SystemExit("The 'init' command must be run by root.") mode = options.mode current_mode = get_current_mode() if current_mode != 'none': if not options.force: init_text = 'initialize again' if mode == 'none': init_text = 'de-initialize' else: print_msg('Controller has already been initialized.') initialize = prompt_for_choices('Are you sure you want to %s ' '(yes/no) [default=no]? ' % init_text, ['yes', 'no'], default='no') if initialize == 'no': sys.exit(0) if not mode: mode = prompt_for_choices( "Mode ({choices}) [default={default}]? ".format( choices='/'.join(ARGUMENTS['mode']['choices']), default=DEFAULT_OPERATION_MODE), ARGUMENTS['mode']['choices'], default=DEFAULT_OPERATION_MODE, help_text=OPERATION_MODES) if current_mode == 'all' and mode != 'all' and not options.force: print_msg( 'This will disconnect your MAAS from the running database.') disconnect = prompt_for_choices( 'Are you sure you want to disconnect the database ' '(yes/no) [default=no]? ', ['yes', 'no'], default='no') if disconnect == 'no': return 0 elif current_mode == 'all' and mode == 'all' and not options.force: print_msg('This will re-initialize your entire database and all ' 'current data will be lost.') reinit_db = prompt_for_choices( 'Are you sure you want to re-initialize the database ' '(yes/no) [default=no]? ', ['yes', 'no'], default='no') if reinit_db == 'no': return 0 maas_url = options.maas_url if mode != 'none' and not maas_url: maas_url = prompt_for_maas_url() database_host = database_name = None database_user = database_pass = None rpc_secret = None if mode == 'all': database_host = os.path.join(get_base_db_dir(), 'sockets') database_name = 'maasdb' database_user = '******' database_pass = ''.join( random.choice(string.ascii_uppercase + string.digits) for _ in range(10)) if mode in ['region', 'region+rack']: database_host = options.database_host if not database_host: database_host = required_prompt( "Database host: ", help_text=ARGUMENTS['database-host']['help']) database_name = options.database_name if not database_name: database_name = required_prompt( "Database name: ", help_text=ARGUMENTS['database-name']['help']) database_user = options.database_user if not database_user: database_user = required_prompt( "Database user: "******"Database password: "******"Secret: ", help_text=ARGUMENTS['secret']['help']) # Stop all services if in another mode. if current_mode != 'none': def stop_services(): render_supervisord('none') sighup_supervisord() perform_work('Stopping services', stop_services) # Configure the settings. settings = { 'maas_url': maas_url, 'database_host': database_host, 'database_name': database_name, 'database_user': database_user, 'database_pass': database_pass } # Add the port to the configuration if exists. By default # MAAS handles picking the port automatically in the backend # if none provided. if options.database_port: settings['database_port'] = options.database_port MAASConfiguration().update(settings) set_rpc_secret(rpc_secret) # Finalize the Initialization. self._finalize_init(mode, options)
def handle(self, options): if os.getuid() != 0: raise SystemExit("The 'init' command must be run by root.") mode = options.mode current_mode = get_current_mode() if current_mode != "none": if not options.force: init_text = "initialize again" if mode == "none": init_text = "de-initialize" else: print_msg("Controller has already been initialized.") initialize = prompt_for_choices( "Are you sure you want to %s " "(yes/no) [default=no]? " % init_text, ["yes", "no"], default="no", ) if initialize == "no": sys.exit(0) if not mode: print_msg( dedent(""" Select the mode the snap should operate in. When installing region or rack+region modes, MAAS needs a PostgreSQL database to connect to. If you want to set up PostgreSQL on this machine, and configure it for use with MAAS, you can run the following command: /snap/maas/current/helpers/maas-database-setup """)) mode = prompt_for_choices( "Mode ({choices}) [default={default}]? ".format( choices="/".join(ARGUMENTS["mode"]["choices"]), default=DEFAULT_OPERATION_MODE, ), ARGUMENTS["mode"]["choices"], default=DEFAULT_OPERATION_MODE, help_text=OPERATION_MODES, ) if current_mode == "all" and not options.force: print_msg( "This will disconnect your MAAS from the running database.") disconnect = prompt_for_choices( "Are you sure you want to disconnect the database " "(yes/no) [default=no]? ", ["yes", "no"], default="no", ) if disconnect == "no": return 0 maas_url = options.maas_url if mode != "none" and not maas_url: maas_url = prompt_for_maas_url() database_host = database_name = None database_user = database_pass = None rpc_secret = None if mode in ["region", "region+rack"]: database_host = options.database_host if not database_host: database_host = required_prompt( "Database host: ", help_text=ARGUMENTS["database-host"]["help"], ) database_name = options.database_name if not database_name: database_name = required_prompt( "Database name: ", help_text=ARGUMENTS["database-name"]["help"], ) database_user = options.database_user if not database_user: database_user = required_prompt( "Database user: "******"database-user"]["help"], ) database_pass = options.database_pass if not database_pass: database_pass = required_prompt( "Database password: "******"database-pass"]["help"], ) if mode == "rack": rpc_secret = options.secret if not rpc_secret: rpc_secret = required_prompt( "Secret: ", help_text=ARGUMENTS["secret"]["help"]) # Stop all services if in another mode. if current_mode != "none": def stop_services(): render_supervisord("none") sighup_supervisord() perform_work("Stopping services", stop_services) # Configure the settings. settings = { "maas_url": maas_url, "database_host": database_host, "database_name": database_name, "database_user": database_user, "database_pass": database_pass, } # Add the port to the configuration if exists. By default # MAAS handles picking the port automatically in the backend # if none provided. if options.database_port: settings["database_port"] = options.database_port MAASConfiguration().update(settings) set_rpc_secret(rpc_secret) # Finalize the Initialization. self._finalize_init(mode, options)
def handle(self, options): if os.getuid() != 0: raise SystemExit("The 'config' command must be run by root.") config_manager = MAASConfiguration() # Hidden option only called by the run-supervisord script. Renders # the initial supervisord.conf based on the current mode. if options.render: render_supervisord(get_current_mode()) return # In config mode if --show is passed or none of the following flags # have been passed. in_config_mode = options.show if not in_config_mode: in_config_mode = not any( (getattr(options, flag) is not None and getattr(options, flag) is not False) for flag in (("mode", "secret") + self.setting_flags + tuple(self.optional_flags.keys()))) # Config mode returns the current config of the snap. if in_config_mode: return print_config( options.parsable, options.show_database_password, options.show_secret, ) else: restart_required = False current_mode = get_current_mode() running_mode = current_mode if options.mode is not None: running_mode = options.mode # Validate the mode and flags. self._validate_mode(options) self._validate_flags(options, running_mode) # Changing the mode from all requires --force. if options.mode is not None: if current_mode == "all": if not options.force: print_msg( "Changing mode from 'all' to '%s' will " "disconnect the database and all data will " "be lost. Use '--force' if your sure you want " "to do this." % options.mode) sys.exit(1) if options.mode != current_mode: render_supervisord(options.mode) set_current_mode(options.mode) restart_required = True current_config = config_manager.get() if current_mode != running_mode: # Update all the settings since the mode changed. for flag in self.setting_flags: flag_value = getattr(options, flag) if current_config.get(flag) != flag_value: config_manager.update({flag: flag_value}) restart_required = True set_rpc_secret(options.secret) else: # Only update the passed settings. for flag in self.setting_flags: flag_value = getattr(options, flag) should_update = (flag_value is not None and current_config.get(flag) != flag_value) if should_update: config_manager.update({flag: flag_value}) restart_required = True if options.secret is not None: set_rpc_secret(options.secret) # fetch config again, as it might have changed current_config = config_manager.get() # Update any optional settings. for flag, flag_info in self.optional_flags.items(): flag_value = getattr(options, flag) if flag_info["type"] != "store_true": flag_key = flag_info["config"] should_update = ( flag_value is not None and current_config.get(flag_key) != flag_value) if should_update: config_manager.update({flag_key: flag_value}) restart_required = True elif flag_value: flag_key = flag_info["config"] flag_value = flag_info["set_value"] if current_config.get(flag_key) != flag_value: config_manager.update({flag_key: flag_value}) restart_required = True # Restart the supervisor as its required. if restart_required: perform_work( "Restarting services" if running_mode != "none" else "Stopping services", sighup_supervisord, ) clear_line()
def handle(self, options): if os.getuid() != 0: raise SystemExit("The 'config' command must be run by root.") config_manager = MAASConfiguration() # Hidden option only called by the run-supervisord script. Renders # the initial supervisord.conf based on the current mode. if options.render: render_supervisord(get_current_mode()) return # In config mode if --show is passed or none of the following flags # have been passed. in_config_mode = options.show if not in_config_mode: in_config_mode = not any( (getattr(options, flag) is not None and getattr(options, flag) is not False) for flag in (("secret", ) + self.setting_flags + tuple(self.optional_flags.keys()))) # Config mode returns the current config of the snap. if in_config_mode: return print_config( options.parsable, options.show_database_password, options.show_secret, ) else: restart_required = False running_mode = get_current_mode() # Validate the mode and flags. self._validate_flags(options, running_mode) current_config = config_manager.get() # Only update the passed settings. for flag in self.setting_flags: flag_value = getattr(options, flag) should_update = (flag_value is not None and current_config.get(flag) != flag_value) if should_update: config_manager.update({flag: flag_value}) restart_required = True if options.secret is not None: set_rpc_secret(options.secret) # fetch config again, as it might have changed current_config = config_manager.get() # Update any optional settings. for flag, flag_info in self.optional_flags.items(): flag_value = getattr(options, flag) if flag_info["type"] != "store_true": flag_key = flag_info["config"] should_update = ( flag_value is not None and current_config.get(flag_key) != flag_value) if should_update: config_manager.update({flag_key: flag_value}) restart_required = True elif flag_value: flag_key = flag_info["config"] flag_value = flag_info["set_value"] if current_config.get(flag_key) != flag_value: config_manager.update({flag_key: flag_value}) restart_required = True # Restart the supervisor as its required. if restart_required: perform_work( "Restarting services" if running_mode != "none" else "Stopping services", sighup_supervisord, )
class TestMAASConfiguration(MAASTestCase): def setUp(self): super().setUp() self.config_dir = Path(self.make_dir()) self.environ = {"SNAP_DATA": self.config_dir} self.config_manager = MAASConfiguration(environ=self.environ) def write_config(self, config, filename): config_file = self.config_dir / filename config_file.write_text(yaml.safe_dump(config)) def read_config(self, filename): config_file = self.config_dir / filename if not config_file.exists(): return None return yaml.safe_load(config_file.read_text()) def test_get_not_in_snap(self): config_manager = MAASConfiguration(environ={}) # use mocked dir instead of /etc/maas config_manager.DEFAULT_CONFIG_DIR = self.config_dir config = { factory.make_name("key"): factory.make_name("value"), factory.make_name("key"): factory.make_name("value"), } self.write_config(config, "regiond.conf") self.assertEqual(config_manager.get(), config) def test_get(self): config = { factory.make_name("key"): factory.make_name("value"), factory.make_name("key"): factory.make_name("value"), } self.write_config(config, "regiond.conf") self.assertEqual(self.config_manager.get(), config) def test_get_empty(self): self.assertEqual(self.config_manager.get(), {}) def test_write_to_file(self): config = { factory.make_name("key"): factory.make_name("value"), factory.make_name("key"): factory.make_name("value"), } filename = factory.make_name("file") self.config_manager.write_to_file(config, filename) self.assertEqual(self.read_config(filename), config) def test_update_updates(self): config1 = {"foo": "bar"} config2 = {"foo": "baz"} self.config_manager.update(config1) self.config_manager.update(config2) self.assertEqual(self.read_config("regiond.conf"), config2) def test_update_from_empty_file(self): config = {factory.make_name("key"): factory.make_name("value")} (self.config_dir / "regiond.conf").touch() self.config_manager.update(config) self.assertEqual(self.read_config("regiond.conf"), config) def test_update_sets(self): config = { factory.make_name("key"): factory.make_name("value"), factory.make_name("key"): factory.make_name("value"), } self.config_manager.update(config) self.assertEqual(self.read_config("regiond.conf"), config) # no rackd config is written self.assertIsNone(self.read_config("rackd.conf")) def test_update_extends(self): config1 = {"foo": "bar"} config2 = {"baz": "bza"} self.config_manager.update(config1) self.config_manager.update(config2) full_config = {} full_config.update(config1) full_config.update(config2) self.assertEqual(self.read_config("regiond.conf"), full_config) def test_update_removes_empty(self): config = {"foo": "bar", "baz": "bza"} self.config_manager.update(config) self.config_manager.update({"foo": None}) self.assertEqual(self.read_config("regiond.conf"), {"baz": "bza"}) def test_update_with_maas_url(self): url = factory.make_name("url") self.config_manager.update({"maas_url": url}) expected = {"maas_url": url} self.assertEqual(self.read_config("regiond.conf"), expected) # MAAS url is set in rackd config as well self.assertEqual(self.read_config("rackd.conf"), expected) def test_unset_maas_url(self): config = {"maas_url": factory.make_name("url")} self.write_config(config, "regiond.conf") self.write_config(config, "rackd.conf") self.config_manager.update({"maas_url": None}) self.assertEqual(self.read_config("regiond.conf"), {}) self.assertEqual(self.read_config("rackd.conf"), {})
def handle(self, options): if os.getuid() != 0: raise SystemExit("The 'init' command must be run by root.") mode = options.run_mode if options.deprecated_mode: mode = options.deprecated_mode current_mode = get_current_mode() if current_mode != "none": if not options.force: init_text = "initialize again" if mode == "none": init_text = "de-initialize" else: print_msg("Controller has already been initialized.") initialize = prompt_for_choices( "Are you sure you want to %s " "(yes/no) [default=no]? " % init_text, ["yes", "no"], default="no", ) if initialize == "no": sys.exit(0) if current_mode == "all" and mode != "all" and not options.force: print_msg( "This will disconnect your MAAS from the running database.") disconnect = prompt_for_choices( "Are you sure you want to disconnect the database " "(yes/no) [default=no]? ", ["yes", "no"], default="no", ) if disconnect == "no": return 0 elif current_mode == "all" and mode == "all" and not options.force: print_msg("This will re-initialize your entire database and all " "current data will be lost.") reinit_db = prompt_for_choices( "Are you sure you want to re-initialize the database " "(yes/no) [default=no]? ", ["yes", "no"], default="no", ) if reinit_db == "no": return 0 rpc_secret = None if mode == "all": database_settings = { "database_host": os.path.join(get_base_db_dir(), "sockets"), "database_name": "maasdb", "database_user": "******", "database_pass": "".join( random.choice(string.ascii_uppercase + string.digits) for _ in range(10)), } elif mode in ["region", "region+rack"]: try: database_settings = get_database_settings(options) except DatabaseSettingsError as error: raise CommandError(str(error)) else: database_settings = {} maas_url = options.maas_url if mode != "none" and not maas_url: maas_url = required_prompt( "MAAS URL", default=get_default_url(), help_text=ARGUMENTS["maas-url"]["help"], ) if mode == "rack": rpc_secret = options.secret if not rpc_secret: rpc_secret = required_prompt( "Secret", help_text=ARGUMENTS["secret"]["help"]) # Stop all services if in another mode. if current_mode != "none": def stop_services(): render_supervisord("none") sighup_supervisord() perform_work("Stopping services", stop_services) # Configure the settings. settings = {"maas_url": maas_url} settings.update(database_settings) MAASConfiguration().update(settings) set_rpc_secret(rpc_secret) # Finalize the Initialization. self._finalize_init(mode, options)
def setUp(self): super().setUp() self.config_dir = Path(self.make_dir()) self.environ = {'SNAP_DATA': self.config_dir} self.config_manager = MAASConfiguration(environ=self.environ)
class TestMAASConfiguration(MAASTestCase): def setUp(self): super().setUp() self.config_dir = Path(self.make_dir()) self.environ = {'SNAP_DATA': self.config_dir} self.config_manager = MAASConfiguration(environ=self.environ) def write_config(self, config, filename): config_file = self.config_dir / filename config_file.write_text(yaml.safe_dump(config)) def read_config(self, filename): config_file = self.config_dir / filename if not config_file.exists(): return None return yaml.safe_load(config_file.read_text()) def test_get_not_in_snap(self): config_manager = MAASConfiguration(environ={}) # use mocked dir instead of /etc/maas config_manager.DEFAULT_CONFIG_DIR = self.config_dir config = { factory.make_name('key'): factory.make_name('value'), factory.make_name('key'): factory.make_name('value') } self.write_config(config, 'regiond.conf') self.assertEqual(config_manager.get(), config) def test_get(self): config = { factory.make_name('key'): factory.make_name('value'), factory.make_name('key'): factory.make_name('value') } self.write_config(config, 'regiond.conf') self.assertEqual(self.config_manager.get(), config) def test_get_empty(self): self.assertEqual(self.config_manager.get(), {}) def test_write_to_file(self): config = { factory.make_name('key'): factory.make_name('value'), factory.make_name('key'): factory.make_name('value') } filename = factory.make_name('file') self.config_manager.write_to_file(config, filename) self.assertEqual(self.read_config(filename), config) def test_update_updates(self): config1 = {'foo': 'bar'} config2 = {'foo': 'baz'} self.config_manager.update(config1) self.config_manager.update(config2) self.assertEqual(self.read_config('regiond.conf'), config2) def test_update_from_empty_file(self): config = {factory.make_name('key'): factory.make_name('value')} (self.config_dir / 'regiond.conf').touch() self.config_manager.update(config) self.assertEqual(self.read_config('regiond.conf'), config) def test_update_sets(self): config = { factory.make_name('key'): factory.make_name('value'), factory.make_name('key'): factory.make_name('value') } self.config_manager.update(config) self.assertEqual(self.read_config('regiond.conf'), config) # no rackd config is written self.assertIsNone(self.read_config('rackd.conf')) def test_update_extends(self): config1 = {'foo': 'bar'} config2 = {'baz': 'bza'} self.config_manager.update(config1) self.config_manager.update(config2) full_config = {} full_config.update(config1) full_config.update(config2) self.assertEqual(self.read_config('regiond.conf'), full_config) def test_update_removes_empty(self): config = {'foo': 'bar', 'baz': 'bza'} self.config_manager.update(config) self.config_manager.update({'foo': None}) self.assertEqual(self.read_config('regiond.conf'), {'baz': 'bza'}) def test_update_with_maas_url(self): url = factory.make_name('url') self.config_manager.update({'maas_url': url}) expected = {'maas_url': url} self.assertEqual(self.read_config('regiond.conf'), expected) # MAAS url is set in rackd config as well self.assertEqual(self.read_config('rackd.conf'), expected) def test_unset_maas_url(self): config = {'maas_url': factory.make_name('url')} self.write_config(config, 'regiond.conf') self.write_config(config, 'rackd.conf') self.config_manager.update({'maas_url': None}) self.assertEqual(self.read_config('regiond.conf'), {}) self.assertEqual(self.read_config('rackd.conf'), {})
def handle(self, options): if os.getuid() != 0: raise SystemExit("The 'init' command must be run by root.") mode = options.mode current_mode = get_current_mode() if current_mode != "none": if not options.force: init_text = "initialize again" if mode == "none": init_text = "de-initialize" else: print_msg("Controller has already been initialized.") initialize = prompt_for_choices( "Are you sure you want to %s " "(yes/no) [default=no]? " % init_text, ["yes", "no"], default="no", ) if initialize == "no": sys.exit(0) if not mode: mode = prompt_for_choices( "Mode ({choices}) [default={default}]? ".format( choices="/".join(ARGUMENTS["mode"]["choices"]), default=DEFAULT_OPERATION_MODE, ), ARGUMENTS["mode"]["choices"], default=DEFAULT_OPERATION_MODE, help_text=OPERATION_MODES, ) if current_mode == "all" and mode != "all" and not options.force: print_msg( "This will disconnect your MAAS from the running database.") disconnect = prompt_for_choices( "Are you sure you want to disconnect the database " "(yes/no) [default=no]? ", ["yes", "no"], default="no", ) if disconnect == "no": return 0 elif current_mode == "all" and mode == "all" and not options.force: print_msg("This will re-initialize your entire database and all " "current data will be lost.") reinit_db = prompt_for_choices( "Are you sure you want to re-initialize the database " "(yes/no) [default=no]? ", ["yes", "no"], default="no", ) if reinit_db == "no": return 0 maas_url = options.maas_url if mode != "none" and not maas_url: maas_url = prompt_for_maas_url() database_host = database_name = None database_user = database_pass = None rpc_secret = None if mode == "all": database_host = os.path.join(get_base_db_dir(), "sockets") database_name = "maasdb" database_user = "******" database_pass = "".join( random.choice(string.ascii_uppercase + string.digits) for _ in range(10)) if mode in ["region", "region+rack"]: database_host = options.database_host if not database_host: database_host = required_prompt( "Database host: ", help_text=ARGUMENTS["database-host"]["help"], ) database_name = options.database_name if not database_name: database_name = required_prompt( "Database name: ", help_text=ARGUMENTS["database-name"]["help"], ) database_user = options.database_user if not database_user: database_user = required_prompt( "Database user: "******"database-user"]["help"], ) database_pass = options.database_pass if not database_pass: database_pass = required_prompt( "Database password: "******"database-pass"]["help"], ) if mode == "rack": rpc_secret = options.secret if not rpc_secret: rpc_secret = required_prompt( "Secret: ", help_text=ARGUMENTS["secret"]["help"]) # Stop all services if in another mode. if current_mode != "none": def stop_services(): render_supervisord("none") sighup_supervisord() perform_work("Stopping services", stop_services) # Configure the settings. settings = { "maas_url": maas_url, "database_host": database_host, "database_name": database_name, "database_user": database_user, "database_pass": database_pass, } # Add the port to the configuration if exists. By default # MAAS handles picking the port automatically in the backend # if none provided. if options.database_port: settings["database_port"] = options.database_port MAASConfiguration().update(settings) set_rpc_secret(rpc_secret) # Finalize the Initialization. self._finalize_init(mode, options)