Esempio n. 1
0
def get_maas_user_agent():
    from maasserver.models import Config
    user_agent = get_maas_version_user_agent()
    uuid = Config.objects.get_config('uuid')
    if uuid:
        user_agent = "%s/%s" % (user_agent, uuid)
    return user_agent
Esempio n. 2
0
 def test__returns_unknown_if_version_is_empty_and_not_bzr_branch(self):
     mock_version = self.patch(version, "get_version_from_apt")
     mock_version.return_value = ""
     mock_branch_version = self.patch(version, "get_maas_branch_version")
     mock_branch_version.return_value = None
     self.assertEqual("maas/%s/unknown" % old_version,
                      version.get_maas_version_user_agent())
Esempio n. 3
0
 def test_returns_package_version(self):
     mock_apt = self.patch(version, "get_version_from_apt")
     mock_apt.return_value = "1.8.0~alpha4+bzr356-0ubuntu1"
     self.assertEqual(
         "maas/1.8.0~alpha4/bzr356-0ubuntu1",
         version.get_maas_version_user_agent(),
     )
Esempio n. 4
0
 def test__returns_from_source_and_revno_from_branch(self):
     mock_version = self.patch(version, "get_version_from_apt")
     mock_version.return_value = ""
     revno = random.randint(1, 5000)
     mock_branch_version = self.patch(version, "get_maas_branch_version")
     mock_branch_version.return_value = revno
     self.assertEqual("maas/%s from source/bzr%d" % (old_version, revno),
                      version.get_maas_version_user_agent())
Esempio n. 5
0
 def test_get_maas_user_agent_with_uuid(self):
     region = factory.make_RegionController()
     self.useFixture(MAASIDFixture(region.system_id))
     RegionController.objects.get_or_create_uuid()
     user_agent = get_maas_user_agent()
     composed_user_agent = "%s/%s" % (get_maas_version_user_agent(),
                                      Config.objects.get_config('uuid'))
     self.assertEquals(user_agent, composed_user_agent)
Esempio n. 6
0
 def test__returns_from_source_and_hashfrom_repo(self):
     mock_version = self.patch(version, "get_version_from_apt")
     mock_version.return_value = ""
     mock_repo_hash = self.patch(version, "get_maas_repo_hash")
     mock_repo_hash.return_value = 'deadbeef'
     self.assertEqual(
         "maas/%s from source/git+%s" % (old_version, 'deadbeef'),
         version.get_maas_version_user_agent())
Esempio n. 7
0
 def test__passes_user_agent_with_maas_version(self):
     mock_download = self.patch(bootsources,
                                'download_all_image_descriptions')
     factory.make_BootSource(keyring_data=b'1234')
     cache_boot_sources()
     self.assertThat(
         mock_download,
         MockCalledOnceWith(ANY, user_agent=get_maas_version_user_agent()))
Esempio n. 8
0
    def fetch(self, params):
        """Fetch the releases and the arches from the provided source."""
        # Must be administrator.
        assert self.user.is_superuser, "Permission denied."
        # Build a source, but its not saved into the database.
        boot_source = self.get_bootsource(params, from_db=False)
        try:
            # Validate the boot source fields without committing it.
            boot_source.clean_fields()
        except ValidationError as error:
            raise HandlerValidationError(error)
        source = boot_source.to_dict_without_selections()

        # FIXME: This modifies the environment of the entire process, which is
        # Not Cool. We should integrate with simplestreams in a more
        # Pythonic manner.
        set_simplestreams_env()
        with tempdir("keyrings") as keyrings_path:
            [source] = write_all_keyrings(keyrings_path, [source])
            try:
                descriptions = download_all_image_descriptions(
                    [source], user_agent=get_maas_version_user_agent())
            except Exception as error:
                raise HandlerError(str(error))
        items = list(descriptions.items())
        err_msg = "Mirror provides no Ubuntu images."
        if len(items) == 0:
            raise HandlerError(err_msg)
        releases = {}
        arches = {}
        for image_spec, product_info in items:
            # Only care about Ubuntu images.
            if image_spec.os != 'ubuntu':
                continue
            releases[image_spec.release] = {
                'name':
                image_spec.release,
                'title':
                product_info.get(
                    'release_title',
                    format_ubuntu_distro_series(image_spec.release)),
                'checked':
                False,
                'deleted':
                False,
            }
            arches[image_spec.arch] = {
                'name': image_spec.arch,
                'title': image_spec.arch,
                'checked': False,
                'deleted': False,
            }
        if len(releases) == 0 or len(arches) == 0:
            raise HandlerError(err_msg)
        return json.dumps({
            'releases': list(releases.values()),
            'arches': list(arches.values()),
        })
Esempio n. 9
0
 def test_returns_unknown_if_version_is_empty_and_not_git_repo(self):
     mock_version = self.patch(version, "get_version_from_apt")
     mock_version.return_value = ""
     mock_repo_hash = self.patch(version, "get_maas_repo_hash")
     mock_repo_hash.return_value = None
     self.assertEqual(
         "maas/%s/unknown" % old_version,
         version.get_maas_version_user_agent(),
     )
Esempio n. 10
0
def cache_boot_sources():
    """Cache all image information in boot sources.

    Called from *outside* of a transaction this will:

    1. Retrieve information about all boot sources from the database. The
       transaction is committed before proceeding.

    2. The boot sources are consulted (i.e. there's network IO now) and image
       descriptions downloaded.

    3. Update the boot source cache with the fetched information. If the boot
       source has been modified or deleted during #2 then the results are
       discarded.

    This approach does not require an exclusive lock.

    """
    # Nomenclature herein: `bootsource` is an ORM record for BootSource;
    # `source` is one of those converted to a dict. The former ought not to be
    # used outside of a transactional context.

    @transactional
    def get_sources():
        return list(
            bootsource.to_dict_without_selections()
            for bootsource in BootSource.objects.all()
            # TODO: Only where there are no corresponding BootSourceCache
            # records or the BootSource's updated timestamp is later than any
            # of the BootSourceCache records' timestamps.
        )

    @transactional
    def update_cache(source, descriptions):
        try:
            bootsource = BootSource.objects.get(url=source["url"])
        except BootSource.DoesNotExist:
            # The record was deleted while we were fetching the description.
            maaslog.debug(
                "Image descriptions at %s are no longer needed; discarding.",
                source["url"])
        else:
            if bootsource.compare_dict_without_selections(source):
                # Only delete from the cache once we have the descriptions.
                BootSourceCache.objects.filter(boot_source=bootsource).delete()
                if not descriptions.is_empty():
                    for spec, item in descriptions.mapping.items():
                        title = get_product_title(item)
                        if title is None:
                            extra = {}
                        else:
                            extra = {'title': title}
                        BootSourceCache.objects.create(
                            boot_source=bootsource, os=spec.os,
                            arch=spec.arch, subarch=spec.subarch,
                            kflavor=spec.kflavor,
                            release=spec.release, label=spec.label,
                            release_codename=item.get('release_codename'),
                            release_title=item.get('release_title'),
                            support_eol=item.get('support_eol'),
                            bootloader_type=item.get('bootloader-type'),
                            extra=extra,
                            )
                maaslog.debug(
                    "Image descriptions for %s have been updated.",
                    source["url"])
            else:
                maaslog.debug(
                    "Image descriptions for %s are outdated; discarding.",
                    source["url"])

    @transactional
    def check_commissioning_series_selected():
        commissioning_osystem = Config.objects.get_config(
            name='commissioning_osystem')
        commissioning_series = Config.objects.get_config(
            name='commissioning_distro_series')
        qs = BootSourceSelection.objects.filter(
            os=commissioning_osystem, release=commissioning_series)
        if not qs.exists():
            if not Notification.objects.filter(
                    ident='commissioning_series_unselected').exists():
                Notification.objects.create_error_for_users(
                    '%s %s is configured as the commissioning release but it '
                    'is not selected for download!' % (
                        commissioning_osystem, commissioning_series),
                    ident='commissioning_series_unselected')
        qs = BootSourceCache.objects.filter(
            os=commissioning_osystem, release=commissioning_series)
        if not qs.exists():
            if not Notification.objects.filter(
                    ident='commissioning_series_unavailable').exists():
                Notification.objects.create_error_for_users(
                    '%s %s is configured as the commissioning release but it '
                    'is unavailable in the configured streams!' % (
                        commissioning_osystem, commissioning_series),
                    ident='commissioning_series_unavailable')

    # FIXME: This modifies the environment of the entire process, which is Not
    # Cool. We should integrate with simplestreams in a more Pythonic manner.
    yield deferToDatabase(set_simplestreams_env)

    errors = []
    sources = yield deferToDatabase(get_sources)
    for source in sources:
        with tempdir("keyrings") as keyrings_path:
            [source] = write_all_keyrings(keyrings_path, [source])
            try:
                descriptions = download_all_image_descriptions(
                    [source],
                    user_agent=get_maas_version_user_agent())
            except (IOError, ConnectionError) as error:
                errors.append(
                    "Failed to import images from boot source "
                    "%s: %s" % (source["url"], error))
            else:
                yield deferToDatabase(update_cache, source, descriptions)

    yield deferToDatabase(check_commissioning_series_selected)

    maaslog.info("Updated boot sources cache.")

    component = COMPONENT.REGION_IMAGE_IMPORT
    if len(errors) > 0:
        yield deferToDatabase(
            register_persistent_error, component,
            "<br>".join(map(html.escape, errors)))
    else:
        yield deferToDatabase(
            discard_persistent_error, component)