예제 #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
파일: tftp.py 프로젝트: cloudbase/maas
    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
파일: plugin.py 프로젝트: cloudbase/maas
    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
파일: tftp.py 프로젝트: cloudbase/maas
 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'])