def test_set_and_get_tftp_port(self): config = ClusterConfiguration({}) example_port = factory.pick_port() config.tftp_port = example_port self.assertEqual(example_port, config.tftp_port) # It's also stored in the configuration database. self.assertEqual({"tftp_port": example_port}, config.store)
def test_set_and_get_cluster_uuid(self): example_uuid = uuid4() config = ClusterConfiguration({}) config.cluster_uuid = example_uuid self.assertEqual(str(example_uuid), config.cluster_uuid) # It's also stored in the configuration database. self.assertEqual({"cluster_uuid": str(example_uuid)}, config.store)
def test_set_maas_url_accepts_very_short_hostnames(self): config = ClusterConfiguration({}) example_url = factory.make_simple_http_url(netloc=factory.make_string( size=1)) config.maas_url = example_url self.assertEqual(example_url, config.maas_url) self.assertEqual({"maas_url": example_url}, config.store)
def test_set_maas_url_accepts_ipv6_addresses_with_brackets(self): config = ClusterConfiguration({}) example_url = factory.make_simple_http_url(netloc="[%s]" % factory.make_ipv6_address()) config.maas_url = example_url self.assertEqual(example_url, config.maas_url) self.assertEqual({"maas_url": example_url}, config.store)
def test_set_maas_url_rejects_bare_ipv6_addresses(self): config = ClusterConfiguration({}) example_url = factory.make_simple_http_url( netloc=factory.make_ipv6_address() ) with ExpectedException(formencode.api.Invalid): config.maas_url = example_url
def test_set_and_get_maas_url(self): config = ClusterConfiguration({}) example_url = factory.make_simple_http_url() config.maas_url = example_url self.assertEqual(example_url, config.maas_url) # It's also stored in the configuration database. self.assertEqual({"maas_url": example_url}, config.store)
def test_config_set_maas_url_without_setting_does_nothing(self): with ClusterConfiguration.open() as config: expected = config.maas_url cluster_config_command.run(self.make_args(region_url=None)) with ClusterConfiguration.open() as config: observed = config.maas_url self.assertEqual(expected, observed)
def test_config_set_tftp_root_without_setting_does_nothing(self): with ClusterConfiguration.open() as config: expected = config.tftp_root cluster_config_command.run(self.make_args(tftp_root=None)) with ClusterConfiguration.open() as config: observed = config.tftp_root self.assertEqual(expected, observed)
def test_config_set_debug_without_setting_does_nothing(self): with ClusterConfiguration.open() as config: expected = config.debug cluster_config_command.run(self.make_args(debug=None)) with ClusterConfiguration.open() as config: observed = config.debug self.assertEqual(expected, observed)
def test_set_and_get_tftp_root(self): config = ClusterConfiguration({}) example_dir = self.make_dir() config.tftp_root = example_dir self.assertEqual(example_dir, config.tftp_root) # It's also stored in the configuration database. self.assertEqual({"tftp_root": example_dir}, config.store)
def test_config_init_when_already_configured_does_nothing(self): expected_previous_value = str(uuid.uuid4()) with ClusterConfiguration.open_for_update() as config: config.cluster_uuid = expected_previous_value with ClusterConfiguration.open() as config: observed_previous_value = config.cluster_uuid self.assertEqual(expected_previous_value, observed_previous_value) cluster_config_command.run(self.make_args(init=True)) parsed_observed, observed = self.get_parsed_uuid_from_config() self.assertEqual(parsed_observed, observed) self.assertEqual(parsed_observed, expected_previous_value)
def get_xinstall_parameters(self, arch, subarch, release, label): """Returns the xinstall image name and type for given image.""" filetypes = { "root-tgz": "tgz", "root-dd.tar": "dd-tar", "root-dd.raw": "dd-raw", "root-dd.tar.bz2": "dd-tbz", "root-dd": "dd-tgz", "root-dd.tar.xz": "dd-txz", "root-dd.bz2": "dd-bz2", "root-dd.gz": "dd-gz", "root-dd.xz": "dd-xz" } with ClusterConfiguration.open() as config: dd_path = os.path.join(config.tftp_root, 'ubuntu-core', arch, subarch, release, label) filename, filetype = "", "" try: for fname in os.listdir(dd_path): if fname in filetypes.keys(): filename, filetype = fname, filetypes[fname] break except FileNotFoundError: # In case the path does not exist pass return filename, filetype
def test_calls_hooks(self): upgrade_hook = Mock() upgrade_hook.__name__ = "upgrade_hook" self.patch_upgrade_hooks([upgrade_hook]) self.run_command() with ClusterConfiguration.open() as config: self.assertThat(upgrade_hook, MockCalledOnceWith(config.tftp_root))
def get_local_cluster_UUID(): """Return the UUID of the local cluster (or None if it cannot be found).""" with ClusterConfiguration.open() as config: if config.cluster_uuid == UUID_NOT_SET: return None else: return config.cluster_uuid
def make_maas_own_boot_resources(): """Upgrade hook: make the `maas` user the owner of the boot resources.""" # This reduces the privileges required for importing and managing images. with ClusterConfiguration.open() as config: boot_resources_storage = config.tftp_root if os.path.isdir(boot_resources_storage): check_call(['chown', '-R', 'maas', boot_resources_storage])
def makeService(self, options, clock=reactor): """Construct the MAAS Cluster service.""" register_sigusr1_toggle_cprofile('rackd') register_sigusr2_thread_dump_handler() clean_prometheus_dir() add_patches_to_txtftp() add_patches_to_twisted() self._loadSettings() self._configureCrochet() if settings.DEBUG: # Always log at debug level in debug mode. self._configureLogging(3) else: self._configureLogging(options["verbosity"]) with ClusterConfiguration.open() as config: tftp_root = config.tftp_root tftp_port = config.tftp_port from provisioningserver import services for service in self._makeServices(tftp_root, tftp_port, clock=clock): service.setServiceParent(services) return services
def reload_boot_images(): """Update the cached boot images so `list_boot_images` returns the most up-to-date boot images list.""" global CACHED_BOOT_IMAGES with ClusterConfiguration.open() as config: tftp_root = config.tftp_root CACHED_BOOT_IMAGES = tftppath.list_boot_images(tftp_root)
def _loadSettings(self): # Load the settings from rackd.conf. with ClusterConfiguration.open() as config: settings.DEBUG = config.debug # Debug mode is always on in the development environment. if is_dev_environment(): settings.DEBUG = True
def get_resource_path(self, kernel_params, path): """Gets the resource path from the kernel param.""" with ClusterConfiguration.open() as config: resources = config.tftp_root return os.path.join(resources, 'windows', kernel_params.arch, kernel_params.subarch, kernel_params.release, kernel_params.label, path)
def update_maas_cluster_conf(urls=None, uuid=None, init=None, tftp_port=None, tftp_root=None, debug=None): """This function handles the logic behind using the parameters passed to run and setting / initializing values in the config backend. :param urls: The MAAS URLs to set. Does nothing if None. :param tftp_port: The tftp port number to set. Does nothing if None. :param tftp_root: The tftp root file path to set. Does nothing if None. :param uuid: The UUID to use for this cluster. Does nothing if None. :param init: Initializes the config backend with a new UUID if the backend does not currently have a value configured. NOTE: that the argument parser will not let uuid and init be passed at the same time, as these are mutually exclusive parameters. :param debug: Enables or disables debug mode. """ with ClusterConfiguration.open_for_update() as config: if urls is not None: config.maas_url = urls if uuid is not None: config.cluster_uuid = uuid if init: cur_uuid = config.cluster_uuid if cur_uuid == UUID_NOT_SET: config.cluster_uuid = str(uuid4()) if tftp_port is not None: config.tftp_port = tftp_port if tftp_root is not None: config.tftp_root = tftp_root if debug is not None: config.debug = debug
def test____sets_url(self): secret = factory.make_bytes() expected_url = factory.make_simple_http_url() register_command.run( self.make_args(url=expected_url, secret=to_hex(secret))) with ClusterConfiguration.open() as config: observed = config.maas_url self.assertEqual([expected_url], observed)
def test_default_tftp_root(self): # The default tftp_root is calculated relative to MAAS_ROOT at module # import time, so we need to recreate that value. maas_root = os.path.join(maastesting.root, ".run") config = ClusterConfiguration({}) self.assertEqual( os.path.join(maas_root, "var/lib/maas/boot-resources/current"), config.tftp_root)
def run(args): """Register the rack controller with a region controller.""" # If stdin supplied to program URL must be passed as argument. if not stdin.isatty() and args.url is None: print( "MAAS region controller URL must be given when supplying the " "shared secret via stdin with a non-interactive shell." ) raise SystemExit(1) try: call_and_check(["systemctl", "stop", "maas-rackd"]) except ExternalProcessError as e: print("Unable to stop maas-rackd service.", file=stderr) print("Failed with error: %s." % e.output_as_unicode, file=stderr) raise SystemExit(1) # maas_id could be stale so remove it set_maas_id(None) if args.url is not None: with ClusterConfiguration.open_for_update() as config: config.maas_url = args.url else: try: url = input("MAAS region controller URL: ") except EOFError: print() # So that the shell prompt appears on the next line. raise SystemExit(1) except KeyboardInterrupt: print() # So that the shell prompt appears on the next line. raise with ClusterConfiguration.open_for_update() as config: config.maas_url = url print("MAAS region controller URL saved as %s." % url) if args.secret is not None: set_shared_secret_on_filesystem(to_bin(args.secret)) else: InstallSharedSecretScript.run(args) try: call_and_check(["systemctl", "enable", "maas-rackd"]) call_and_check(["systemctl", "start", "maas-rackd"]) except ExternalProcessError as e: print( "Unable to enable and start the maas-rackd service.", file=stderr ) print("Failed with error: %s." % e.output_as_unicode, file=stderr) raise SystemExit(1)
def filter_out_directories_with_extra_levels(paths): """Remove paths that contain directories with more levels. We don't want to move other operating systems under the ubuntu directory.""" with ClusterConfiguration.open() as config: tftp_root = config.tftp_root for arch, subarch, release, label in paths: path = os.path.join(tftp_root, arch, subarch, release, label) if len(list_subdirs(path)) == 0: yield (arch, subarch, release, label)
def test_config_init_creates_initial_cluster_id(self): with ClusterConfiguration.open() as config: observed_default = config.cluster_uuid self.assertEqual(UUID_NOT_SET, observed_default) cluster_config_command.run(self.make_args(init=True)) expected, observed = self.get_parsed_uuid_from_config() self.assertEqual(expected, observed)
def get_parsed_uuid_from_config(self): with ClusterConfiguration.open() as config: observed = config.cluster_uuid try: parsed_observed = str(uuid.UUID(observed)) except: parsed_observed = None return (parsed_observed, observed)
def run(args): """Install a GRUB2 pre-boot loader config into the TFTP directory structure. """ with ClusterConfiguration.open() as config: if not os.path.exists(config.grub_root): os.makedirs(config.grub_root) destination_file = os.path.join(config.grub_root, "grub.cfg") write_text_file(destination_file, CONFIG_FILE)
def run(args): """Perform any data migrations needed for upgrading this cluster.""" with ClusterConfiguration.open() as config: tftp_root = config.tftp_root for hook in UPGRADE_HOOKS: maaslog.info("Rack controller upgrade hook '%s' started." % hook.__name__) hook(tftp_root) maaslog.info("Rack controller upgrade hook '%s' finished." % hook.__name__)
def get_cluster_configuration(): config_dict = {} try: with ClusterConfiguration.open() as configuration: for var in vars(ClusterConfiguration): if not var.startswith("_"): config_dict[var] = getattr(configuration, var) except Exception: print("Warning: Could not load cluster configuration.") print("(some data may not be accurate)") print() return config_dict
def _find_image( self, arch, subarch, release, label, squashfs=False, tgz=False, dd=False, default_fname=None, ): filetypes = {} if squashfs: filetypes.update({"squashfs": "squashfs"}) if tgz: filetypes.update( {"root-tgz": "tgz", "root-txz": "txz", "root-tbz": "tbz"} ) if dd: filetypes.update( { # root-dd maps to dd-tgz for backwards compatibility. "root-dd": "dd-tgz", "root-dd.tar": "dd-tar", "root-dd.raw": "dd-raw", "root-dd.bz2": "dd-bz2", "root-dd.gz": "dd-gz", "root-dd.xz": "dd-xz", "root-dd.tar.bz2": "dd-tbz", "root-dd.tar.xz": "dd-txz", } ) with ClusterConfiguration.open() as config: base_path = os.path.join( config.tftp_root, self.name, arch, subarch, release, label ) try: for fname in os.listdir(base_path): if fname in filetypes.keys(): return fname, filetypes[fname] except FileNotFoundError: # In case the path does not exist pass assert squashfs or tgz or dd, "One type must be selected" # If none is found return the default for messaging. if default_fname and default_fname in filetypes: return default_fname, filetypes[default_fname] else: return list(filetypes.items())[0]