Пример #1
0
    def test_load_from_cache_caches_each_file_separately(self):
        log1, log2 = self.make_file(), self.make_file()
        config1 = self.make_file(contents=yaml.safe_dump({'logfile': log1}))
        config2 = self.make_file(contents=yaml.safe_dump({'logfile': log2}))

        self.assertEqual(log1, Config.load_from_cache(config1)['logfile'])
        self.assertEqual(log2, Config.load_from_cache(config2)['logfile'])
Пример #2
0
    def test_save_and_load_interoperate(self):
        logfile = self.make_file(name='test.log')
        saved_file = self.make_file()

        Config.save({'logfile': logfile}, saved_file)
        loaded_config = Config.load(saved_file)
        self.assertEqual(logfile, loaded_config['logfile'])
Пример #3
0
 def test_load_from_cache_reloads_from_cache_not_from_file(self):
     # A config loaded by Config.load_from_cache() is never reloaded.
     filename = self.make_file(name="config.yaml", contents='')
     config_before = Config.load_from_cache(filename)
     os.unlink(filename)
     config_after = Config.load_from_cache(filename)
     self.assertEqual(config_before, config_after)
Пример #4
0
    def test_save_defaults_to_default_filename(self):
        logfile = self.make_file(name='test.log')
        filename = self.make_file(name="config.yaml")
        self.patch(Config, 'DEFAULT_FILENAME', filename)

        Config.save({'logfile': logfile})

        self.assertEqual(logfile, Config.load(filename)['logfile'])
Пример #5
0
    def test_save_saves_yaml_file(self):
        config = {'logfile': self.make_file()}
        saved_file = self.make_file()

        Config.save(config, saved_file)

        with open(saved_file, 'rb') as written_file:
            loaded_config = yaml.load(written_file)
        self.assertEqual(config, loaded_config)
Пример #6
0
    def test_create_backup_creates_backup(self):
        logfile = self.make_file(name='test.log')
        filename = self.make_file(name="config.yaml")
        config = {'logfile': logfile}
        yaml_config = yaml.safe_dump(config)
        self.patch(Config, 'DEFAULT_FILENAME', filename)
        Config.save(config)

        Config.create_backup('test')

        backup_name = "%s.%s.bak" % (filename, 'test')
        self.assertThat(backup_name, FileContains(yaml_config))
Пример #7
0
def make_arg_parser(doc):
    """Create an `argparse.ArgumentParser` for this script.

    :param doc: Description of the script, for help output.
    """
    try:
        config = Config.load_from_cache()
    except IOError as e:
        if e.errno != errno.ENOENT:
            raise
        # Plod on with defaults.  There may be a legacy shell-script config.
        config = Config.get_defaults()
    # Merge legacy settings into our copy of the config.
    merge_legacy_ephemerals_config(config)

    filters = []
    arches = config['boot'].get('architectures')
    if arches is not None:
        filters.append(compose_filter('arch', arches))
    releases = config['boot']['ephemeral'].get('releases')
    if releases is not None:
        filters.append(compose_filter('release', releases))
    images_directory = config['boot']['ephemeral'].get('images_directory')

    parser = ArgumentParser(description=doc)
    parser.add_argument(
        '--path', action="store", default="streams/v1/index.sjson",
        help="Path to simplestreams index file, relative to mirror URL")
    parser.add_argument(
        '--url', action='store', default=RELEASES_URL,
        help="Simplestreams mirror URL (may use 'file://' for local mirror)")
    parser.add_argument(
        '--output', action='store', default=images_directory,
        help="Directory where boot images should be stored")
    parser.add_argument(
        '--max', action='store', default=1,
        help="Store downloads for only the MAX most recent images.")
    parser.add_argument(
        '--keyring', action='store', default=DEFAULT_KEYRING,
        help="gpg keyring for verifying boot image metadata")
    parser.add_argument(
        '--delete', action='store_true', default=False,
        help="Delete local copies of images when no longer available")
    parser.add_argument(
        '--products', action='store', default=PRODUCTS_REGEX,
        help="Regular expression matching products to import, "
             "e.g. com.ubuntu.maas.daily:ephemerals:.* for daily")
    parser.add_argument(
        'filters', nargs='*', default=filters,
        help="Simplestreams filters for image metadata to download, "
             "e.g. arch=i386 release=precise")
    return parser
Пример #8
0
 def test_load(self):
     # Configuration can be loaded and parsed from a file.
     config = dedent("""
         logfile: "/some/where.log"
         """)
     filename = self.make_file(name="config.yaml", contents=config)
     observed = Config.load(filename)
     self.assertEqual("/some/where.log", observed["logfile"])
Пример #9
0
    def test_load_defaults_to_default_filename(self):
        logfile = self.make_file(name='test.log')
        config = yaml.safe_dump({'logfile': logfile})
        filename = self.make_file(name="config.yaml", contents=config)
        self.patch(Config, 'DEFAULT_FILENAME', filename)

        observed = Config.load()

        self.assertEqual(logfile, observed['logfile'])
Пример #10
0
    def get_bcd_load_options(self, params):
        client = self.clients[params['remote']]
        data = client['data']

        loadoptions = '%s;%s;%s' % \
            (Config.load_from_cache()['windows']['remote_path'],
             "%s\\source" % data['release'],
             data['preseed_url'].replace('/', '\\'))
        return (loadoptions, params)
Пример #11
0
    def test_does_not_modify_config(self):
        self.useFixture(ConfigFixture({
            'boot': {
                'architectures': [factory.make_name('arch')],
                'ephemeral': {
                    'images_directory': self.make_dir(),
                    'releases': [factory.make_name('release')],
                },
            },
        }))
        original_boot_config = deepcopy(Config.load_from_cache()['boot'])
        install_legacy_config(self, make_legacy_config())

        make_arg_parser(factory.getRandomString())

        self.assertEqual(
            original_boot_config,
            Config.load_from_cache()['boot'])
Пример #12
0
    def test_does_not_modify_config(self):
        self.useFixture(
            ConfigFixture({
                'boot': {
                    'architectures': [factory.make_name('arch')],
                    'ephemeral': {
                        'images_directory': self.make_dir(),
                        'releases': [factory.make_name('release')],
                    },
                },
            }))
        original_boot_config = deepcopy(Config.load_from_cache()['boot'])
        install_legacy_config(self, make_legacy_config())

        make_arg_parser(factory.getRandomString())

        self.assertEqual(original_boot_config,
                         Config.load_from_cache()['boot'])
Пример #13
0
    def test_load_from_cache_caches_immutable_copy(self):
        logfile = self.make_file()
        filename = self.make_file(
            name="config.yaml", contents=yaml.safe_dump({'logfile': logfile}))

        first_load = Config.load_from_cache(filename)
        second_load = Config.load_from_cache(filename)

        self.assertEqual(first_load, second_load)
        self.assertIsNot(first_load, second_load)
        first_load['logfile'] = factory.make_name('otherlog')
        self.assertNotEqual(first_load['logfile'], second_load['logfile'])
        self.assertEqual(logfile, second_load['logfile'])
        self.assertIsNot(first_load['boot'], second_load['boot'])
        first_load['boot']['architectures'] = [factory.make_name('otherarch')]
        self.assertNotEqual(
            first_load['boot']['architectures'],
            second_load['boot']['architectures'])
Пример #14
0
def report_to_server():
    """For master worker only: report available netboot images."""
    maas_url, api_credentials = get_cached_knowledge()
    if not all([maas_url, api_credentials]):
        return

    images = tftppath.list_boot_images(
        Config.load_from_cache()['tftp']['root'])

    submit(maas_url, api_credentials, images)
Пример #15
0
def run(args):
    """Install a PXE pre-boot loader into the TFTP directory structure.

    This won't overwrite an existing loader if its contents are unchanged.
    """
    config = Config.load(args.config_file)
    tftproot = config["tftp"]["root"]
    destination_path = make_destination(tftproot)
    destination = os.path.join(destination_path, os.path.basename(args.loader))
    install_bootloader(args.loader, destination)
Пример #16
0
def report_to_server():
    """For master worker only: report available netboot images."""
    maas_url, api_credentials = get_cached_knowledge()
    if not all([maas_url, api_credentials]):
        return

    images = tftppath.list_boot_images(
        Config.load_from_cache()['tftp']['root'])

    submit(maas_url, api_credentials, images)
Пример #17
0
def run(args):
    """Install a PXE pre-boot loader into the TFTP directory structure.

    This won't overwrite an existing loader if its contents are unchanged.
    """
    config = Config.load(args.config_file)
    tftproot = config["tftp"]["root"]
    destination_path = make_destination(tftproot)
    destination = os.path.join(destination_path, os.path.basename(args.loader))
    install_bootloader(args.loader, destination)
Пример #18
0
    def test_does_not_require_config(self):
        defaults = Config.get_defaults()
        no_file = os.path.join(self.make_dir(), factory.make_name() + '.yaml')
        self.useFixture(
            EnvironmentVariableFixture('MAAS_PROVISIONING_SETTINGS', no_file))

        parser = make_arg_parser(factory.getRandomString())

        args = parser.parse_args('')
        self.assertEqual(defaults['boot']['ephemeral']['images_directory'],
                         args.output)
        self.assertItemsEqual([], args.filters)
Пример #19
0
    def test_does_not_require_config(self):
        defaults = Config.get_defaults()
        no_file = os.path.join(self.make_dir(), factory.make_name() + '.yaml')
        self.useFixture(
            EnvironmentVariableFixture('MAAS_PROVISIONING_SETTINGS', no_file))

        parser = make_arg_parser(factory.getRandomString())

        args = parser.parse_args('')
        self.assertEqual(
            defaults['boot']['ephemeral']['images_directory'],
            args.output)
        self.assertItemsEqual([], args.filters)
Пример #20
0
def run(args):
    """Move a netboot image into the TFTP directory structure.

    The image is a directory containing a kernel and an initrd.  If the
    destination location already has an image of the same name and
    containing identical files, the new image is deleted and the old one
    is left untouched.
    """
    config = Config.load(args.config_file)
    tftproot = config["tftp"]["root"]
    destination = make_destination(
        tftproot, args.arch, args.subarch, args.release, args.purpose)
    if not are_identical_dirs(destination, args.image):
        # Image has changed.  Move the new version into place.
        install_dir(args.image, destination)
    rmtree(args.image, ignore_errors=True)
Пример #21
0
def get_ephemeral_name(release, arch):
    """Return the name of the most recent ephemeral image.

    That information is read from the config file named 'info' in the
    ephemeral directory e.g:
    /var/lib/maas/ephemeral/precise/ephemeral/i386/20120424/info
    """
    config = Config.load_from_cache()
    root = os.path.join(config["boot"]["ephemeral"]["images_directory"],
                        release, 'ephemeral', arch)
    try:
        filename = os.path.join(get_last_directory(root), 'info')
    except OSError:
        raise EphemeralImagesDirectoryNotFound(
            "The directory containing the ephemeral images/info is missing "
            "(%r).  Make sure to run the script "
            "'maas-import-pxe-files'." % root)
    name = parse_key_value_file(filename, separator="=")['name']
    return name
Пример #22
0
def get_ephemeral_name(release, arch):
    """Return the name of the most recent ephemeral image.

    That information is read from the config file named 'info' in the
    ephemeral directory e.g:
    /var/lib/maas/ephemeral/precise/ephemeral/i386/20120424/info
    """
    config = Config.load_from_cache()
    root = os.path.join(
        config["boot"]["ephemeral"]["images_directory"],
        release, 'ephemeral', arch)
    try:
        filename = os.path.join(get_last_directory(root), 'info')
    except OSError:
        raise EphemeralImagesDirectoryNotFound(
            "The directory containing the ephemeral images/info is missing "
            "(%r).  Make sure to run the script "
            "'maas-import-pxe-files'." % root)
    name = parse_key_value_file(filename, separator="=")['name']
    return name
Пример #23
0
def install_image(image_dir, arch, subarch, release, purpose, config_file=None,
                  alternate_purpose=None):
    """Install a PXE boot image.

    This is the function-call equivalent to a command-line invocation calling
    `add_arguments` and `run`.
    """
    config = Config.load_from_cache(config_file)
    tftproot = config["tftp"]["root"]
    destination = make_destination(tftproot, arch, subarch, release, purpose)
    if not are_identical_dirs(destination, image_dir):
        # Image has changed.  Move the new version into place.
        install_dir(image_dir, destination)

    if alternate_purpose is not None:
        # Symlink the new image directory under the alternate purpose name.
        alternate_destination = make_destination(
            tftproot, arch, subarch, release, alternate_purpose)
        install_symlink(destination, alternate_destination)

    rmtree(image_dir, ignore_errors=True)
Пример #24
0
    def makeService(self, options):
        """Construct a service."""
        services = MultiService()
        config = Config.load(options["config-file"])

        log_service = self._makeLogService(config)
        log_service.setServiceParent(services)

        oops_service = self._makeOopsService(log_service, config["oops"])
        oops_service.setServiceParent(services)

        broker_config = config["broker"]
        # Connecting to RabbitMQ is not yet a required component of a running
        # MAAS installation; skip unless the password has been set explicitly.
        if broker_config["password"] != b"test":
            client_service = self._makeBroker(broker_config)
            client_service.setServiceParent(services)

        tftp_service = self._makeTFTPService(config["tftp"])
        tftp_service.setServiceParent(services)

        return services
Пример #25
0
    def makeService(self, options):
        """Construct a service."""
        services = MultiService()
        config = Config.load(options["config-file"])

        log_service = self._makeLogService(config)
        log_service.setServiceParent(services)

        oops_service = self._makeOopsService(log_service, config["oops"])
        oops_service.setServiceParent(services)

        broker_config = config["broker"]
        # Connecting to RabbitMQ is not yet a required component of a running
        # MAAS installation; skip unless the password has been set explicitly.
        if broker_config["password"] != b"test":
            client_service = self._makeBroker(broker_config)
            client_service.setServiceParent(services)

        tftp_service = self._makeTFTPService(config["tftp"])
        tftp_service.setServiceParent(services)

        return services
Пример #26
0
 def return_binary_path(data):
     r = params['remote']
     self.clients[r] = {}
     self.clients[r]['data'] = data
     self.clients[r]['is_windows'] = False
     log.msg(">>>>>NODE DETAILS%r" % data)
     release = data.get('release')
     if data.get('purpose') == 'local':
         raise FileNotFound("pxelinux.0")
     if release.startswith('win'):
         self.clients[r]['is_windows'] = True
         path = "pxeboot.0"
         self.base = FilePath(
             '/var/lib/maas/tftp/%s/%s/%s/install/' %
             (data['arch'], data['subarch'], data['release']))
         self.clients[r]['base'] = self.base
     else:
         self.is_windows = False
         self.base = FilePath(Config.load_from_cache()['tftp']['root'])
         self.clients[r]['base'] = self.base
         path = "pxelinux.0"
     return path.encode('utf-8')
Пример #27
0
 def test_field(self):
     self.assertIs(Config, Config.field())
     self.assertIs(Config.fields["tftp"], Config.field("tftp"))
     self.assertIs(
         Config.fields["tftp"].fields["root"],
         Config.field("tftp", "root"))
Пример #28
0
 def test_load_from_cache_uses_defaults(self):
     filename = self.make_file(name='config.yaml', contents='')
     self.assertEqual(
         Config.get_defaults(),
         Config.load_from_cache(filename))
Пример #29
0
 def test_load_from_cache_loads_config(self):
     logfile = self.make_file()
     filename = self.make_file(
         name="config.yaml", contents=yaml.safe_dump({'logfile': logfile}))
     loaded_config = Config.load_from_cache(filename)
     self.assertEqual(logfile, loaded_config['logfile'])
Пример #30
0
 def test_load_example(self):
     # The example configuration is designed for development.
     filename = os.path.join(root, "etc", "maas", "pserv.yaml")
     self.assertEqual(
         self.default_development_config,
         Config.load(filename))
Пример #31
0
 def test_defaults(self):
     # The default configuration is production-ready.
     observed = Config.to_python({})
     self.assertEqual(self.default_production_config, observed)
Пример #32
0
 def test_get_defaults_returns_default_config(self):
     # The default configuration is production-ready.
     observed = Config.get_defaults()
     self.assertEqual(self.default_production_config, observed)
Пример #33
0
 def test_parse(self):
     # Configuration can be parsed from a snippet of YAML.
     observed = Config.parse(b'logfile: "/some/where.log"\n')
     self.assertEqual("/some/where.log", observed["logfile"])
Пример #34
0
    def test_get_defaults_ignores_settings(self):
        self.useFixture(ConfigFixture({'logfile': self.make_file()}))

        self.assertEqual(
            self.default_production_config['logfile'],
            Config.get_defaults()['logfile'])