예제 #1
0
 def test_version(self):
     handler = GeneralHandler(factory.make_User(), {}, None)
     self.patch_autospec(
         general,
         "get_running_version").return_value = MAASVersion.from_string(
             "1.2.3~rc1")
     self.assertEqual(handler.version({}), "1.2.3~rc1")
예제 #2
0
 def test_get_maas_version_track_channel(self):
     self.patch(
         version,
         "get_running_version").return_value = MAASVersion.from_string(
             self.version)
     result = version.get_maas_version_track_channel()
     self.assertEqual(result, self.output)
예제 #3
0
 def test_version_extended_info(self):
     handler = GeneralHandler(factory.make_User(), {}, None)
     self.patch_autospec(
         general,
         "get_running_version").return_value = MAASVersion.from_string(
             "1.2.3-456-g.deadbeef")
     self.assertEqual(handler.version({}), "1.2.3 (456-g.deadbeef)")
예제 #4
0
 def test_update_return_earliest_reported(self):
     c1 = factory.make_RackController()
     c2 = factory.make_RackController()
     c3 = factory.make_RackController()
     ControllerInfo.objects.set_versions_info(
         c1,
         DebVersionsInfo(
             current={"version": "2.9.0-001-g.zzz"},
             update={"version": "3.0.0~alpha1-111-g.aaa"},
         ),
     )
     ControllerInfo.objects.set_versions_info(
         c2,
         DebVersionsInfo(
             current={"version": "2.9.0-001-g.zzz"},
             update={"version": "3.0.0-333-g.ccc"},
         ),
     )
     ControllerInfo.objects.set_versions_info(
         c3,
         DebVersionsInfo(
             current={"version": "2.9.0-001-g.zzz"},
             update={"version": "3.0.0-333-g.ccc"},
         ),
     )
     target_version = get_target_version()
     self.assertEqual(
         target_version.version,
         MAASVersion.from_string("3.0.0-333-g.ccc"),
     )
     self.assertEqual(
         target_version.first_reported,
         c2.info.update_first_reported,
     )
예제 #5
0
 def test_parse(self):
     maas_version = MAASVersion.from_string(self.version)
     self.assertEqual(maas_version, self.maas_version)
     self.assertEqual(maas_version.short_version, self.short_version)
     self.assertEqual(maas_version.extended_info, self.extended_info)
     self.assertEqual(maas_version._qualifier_type_order,
                      self.qualifier_type_order)
예제 #6
0
 def test_version_with_highest_count(self):
     c1 = factory.make_RegionRackController()
     ControllerInfo.objects.set_version(c1, "3.0.0")
     c2 = factory.make_RegionRackController()
     ControllerInfo.objects.set_version(c2, "3.0.0")
     c3 = factory.make_RegionRackController()
     ControllerInfo.objects.set_version(c3, "3.1.0")
     self.assertEqual(get_maas_version(), MAASVersion.from_string("3.0.0"))
예제 #7
0
def _process_update_status_notification():
    def set_update_notification(version, completed):
        context = {"version": str(version)}
        if completed:
            message = "MAAS has been updated to version {version}."
            context["status"] = "completed"
        else:
            message = (
                "MAAS {version} is available, controllers will upgrade soon.")
            context["status"] = "inprogress"

        defaults = {
            "category": "success" if completed else "info",
            "admins": True,
            "message": message,
            "context": context,
        }
        return Notification.objects.get_or_create(
            ident=UPGRADE_STATUS_NOTIFICATION_IDENT,
            defaults=defaults,
        )

    target_version = get_target_version()
    state_notification = Notification.objects.filter(
        ident=UPGRADE_STATUS_NOTIFICATION_IDENT).first()
    if target_version and target_version.first_reported:
        # an update is available
        update_version = target_version.version.main_version
        if state_notification:
            notification_version = MAASVersion.from_string(
                state_notification.context["version"])
            if notification_version < update_version:
                # replace old notification with the new one
                state_notification.delete()
        set_update_notification(update_version, completed=False)
    elif state_notification:
        # no update but there's a previous notification
        current_version = get_maas_version().main_version
        notification_version = MAASVersion.from_string(
            state_notification.context["version"])
        if (state_notification.context["status"] == "completed"
                and notification_version == current_version):
            return
        state_notification.delete()
        set_update_notification(current_version, completed=True)
예제 #8
0
 def test_notification_is_old(self):
     self.patch(
         release_notifications.version, "get_running_version"
     ).return_value = MAASVersion.from_string("2.9.0")
     notification_maas_version = "2.8.0"
     self.assertFalse(
         release_notifications.notification_available(
             notification_maas_version
         )
     )
예제 #9
0
 def test_combine_versions_up_to_qualifier(self):
     c1 = factory.make_RegionRackController()
     ControllerInfo.objects.set_version(c1, "3.0.0~beta1-123-g.asdf")
     c2 = factory.make_RegionRackController()
     ControllerInfo.objects.set_version(c2, "3.0.0~beta2-456-g.cafe")
     c2 = factory.make_RegionRackController()
     ControllerInfo.objects.set_version(c2, "3.0.0~beta2-789-g.abcd")
     c3 = factory.make_RegionRackController()
     ControllerInfo.objects.set_version(c3, "3.1.0")
     self.assertEqual(get_maas_version(),
                      MAASVersion.from_string("3.0.0~beta2"))
예제 #10
0
 def test_is_up_to_date_with_different_version(self):
     target_version = TargetVersion(
         version=MAASVersion.from_string("3.0.0-222-g.cafecafe"),
         snap_channel="3.0/stable",
     )
     controller = factory.make_RackController()
     ControllerInfo.objects.set_versions_info(
         controller,
         SnapVersionsInfo(current={
             "revision": "1234",
             "version": "3.0.0~alpha1-111-g.deadbeef",
         }, ),
     )
     self.assertFalse(controller.info.is_up_to_date(target_version))
예제 #11
0
 def get_controller_version_info(self):
     versions = list(
         self.select_related("node").filter(
             node__node_type__in=(
                 NODE_TYPE.RACK_CONTROLLER,
                 NODE_TYPE.REGION_CONTROLLER,
                 NODE_TYPE.REGION_AND_RACK_CONTROLLER,
             ),
             version__isnull=False,
         ).values_list("node__hostname", "node__system_id", "version"))
     for i in range(len(versions)):
         version_info = list(versions[i])
         version_info.append(MAASVersion.from_string(version_info[-1]))
         versions[i] = ControllerVersionInfo(*version_info)
     return sorted(versions, key=lambda version: version[-1], reverse=True)
예제 #12
0
 def test_is_up_to_date(self):
     version = "3.0.0~alpha1-111-g.deadbeef"
     target_version = TargetVersion(
         version=MAASVersion.from_string(version),
         snap_channel="3.0/stable",
     )
     controller = factory.make_RackController()
     ControllerInfo.objects.set_versions_info(
         controller,
         SnapVersionsInfo(current={
             "revision": "1234",
             "version": version,
         }, ),
     )
     self.assertTrue(controller.info.is_up_to_date(target_version))
예제 #13
0
 def dehydrate(self, obj, data, for_list=False):
     obj = obj.as_self()
     data = super().dehydrate(obj, data, for_list=for_list)
     data["version"] = obj.version
     if obj.version:
         version = MAASVersion.from_string(obj.version)
         data["version__short"] = version.short_version
         long_version = version.short_version
         if version.extended_info:
             long_version += f" ({version.extended_info})"
         data["version__long"] = long_version
     data["service_ids"] = [service.id for service in obj.service_set.all()]
     if not for_list:
         data["vlan_ids"] = [
             interface.vlan_id for interface in obj.interface_set.all()
         ]
     return data
예제 #14
0
 def test_update_older_than_installed(self):
     c1 = factory.make_RackController()
     c2 = factory.make_RackController()
     ControllerInfo.objects.set_versions_info(
         c1,
         DebVersionsInfo(current={"version": "3.0.0-111-g.aaa"}, ),
     )
     ControllerInfo.objects.set_versions_info(
         c2,
         DebVersionsInfo(
             current={"version": "2.9.0-001-g.zzz"},
             update={"version": "2.9.1-010-g.bbb"},
         ),
     )
     target_version = get_target_version()
     self.assertEqual(target_version.version,
                      MAASVersion.from_string("3.0.0-111-g.aaa"))
예제 #15
0
def get_maas_version() -> Optional[MAASVersion]:
    """Return the version for the deployment.

    The returned version is the short version (up to the qualifier, if any)
    used by the most controllers.

    """
    version_data = (ControllerInfo.objects.exclude(
        version="").values_list("version").annotate(count=Count("node_id")))
    versions = Counter()
    for version, count in version_data:
        versions[MAASVersion.from_string(version).main_version] += count
    # sort versions by the highest count first, and highest version in case of
    # equal count
    versions = sorted(
        ((count, version) for version, count in versions.items()),
        reverse=True)
    if not versions:
        return None
    return versions[0][1]
예제 #16
0
 def test_return_highest_version(self):
     c1 = factory.make_RackController()
     c2 = factory.make_RackController()
     c3 = factory.make_RackController()
     ControllerInfo.objects.set_versions_info(
         c1,
         DebVersionsInfo(current={"version": "3.0.0~alpha1-111-g.aaa"}),
     )
     ControllerInfo.objects.set_versions_info(
         c2,
         DebVersionsInfo(current={"version": "3.0.0~beta1-222-g.bbb"}),
     )
     ControllerInfo.objects.set_versions_info(
         c3,
         DebVersionsInfo(current={"version": "3.0.0-333-g.ccc"}),
     )
     target_version = get_target_version()
     self.assertEqual(
         target_version.version,
         MAASVersion.from_string("3.0.0-333-g.ccc"),
     )
예제 #17
0
 def test_get_version_issues(self):
     target_version = TargetVersion(
         version=MAASVersion.from_string("3.0.0-222-g.cafecafe"),
         snap_channel="3.0/stable",
     )
     controller = factory.make_RackController()
     ControllerInfo.objects.set_versions_info(
         controller,
         SnapVersionsInfo(
             current={
                 "revision": "1234",
                 "version": "3.0.0~alpha1-111-g.deadbeef",
             },
             channel="3.0/beta",
             cohort="abc",
         ),
     )
     self.assertEqual(
         controller.info.get_version_issues(target_version),
         [
             VERSION_ISSUES.DIFFERENT_CHANNEL.value,
             VERSION_ISSUES.DIFFERENT_COHORT.value,
         ],
     )
예제 #18
0
class TestMAASVersion(MAASTestCase):

    scenarios = (
        (
            "version only",
            {
                "version":
                "1.2.3",
                "maas_version":
                MAASVersion(
                    major=1,
                    minor=2,
                    point=3,
                    qualifier_version=0,
                    revno=0,
                    git_rev="",
                    qualifier_type=None,
                ),
                "str_version":
                "1.2.3",
                "short_version":
                "1.2.3",
                "extended_info":
                "",
                "qualifier_type_order":
                0,
            },
        ),
        (
            "version with qualifier",
            {
                "version":
                "11.22.33~rc3",
                "maas_version":
                MAASVersion(
                    major=11,
                    minor=22,
                    point=33,
                    qualifier_version=3,
                    revno=0,
                    git_rev="",
                    qualifier_type="rc",
                ),
                "str_version":
                "11.22.33~rc3",
                "short_version":
                "11.22.33~rc3",
                "extended_info":
                "",
                "qualifier_type_order":
                -1,
            },
        ),
        (
            "full version",
            {
                "version":
                "2.3.0~alpha3-6202-g54f83de-0ubuntu1~16.04.1",
                "maas_version":
                MAASVersion(
                    major=2,
                    minor=3,
                    point=0,
                    qualifier_version=3,
                    revno=6202,
                    git_rev="54f83de",
                    qualifier_type="alpha",
                ),
                "str_version":
                "2.3.0~alpha3-6202-g.54f83de",
                "short_version":
                "2.3.0~alpha3",
                "extended_info":
                "6202-g.54f83de",
                "qualifier_type_order":
                -3,
            },
        ),
        (
            "full version with snap suffix",
            {
                "version":
                "2.3.0~alpha3-6202-g54f83de-0ubuntu1~16.04.1-snap",
                "maas_version":
                MAASVersion(
                    major=2,
                    minor=3,
                    point=0,
                    qualifier_version=3,
                    revno=6202,
                    git_rev="54f83de",
                    qualifier_type="alpha",
                ),
                "str_version":
                "2.3.0~alpha3-6202-g.54f83de",
                "short_version":
                "2.3.0~alpha3",
                "extended_info":
                "6202-g.54f83de",
                "qualifier_type_order":
                -3,
            },
        ),
        (
            "full version with dotted git hash prefix",
            {
                "version":
                "2.3.0~alpha3-6202-g.54f83de-0ubuntu1~16.04.1",
                "maas_version":
                MAASVersion(
                    major=2,
                    minor=3,
                    point=0,
                    qualifier_version=3,
                    revno=6202,
                    git_rev="54f83de",
                    qualifier_type="alpha",
                ),
                "str_version":
                "2.3.0~alpha3-6202-g.54f83de",
                "short_version":
                "2.3.0~alpha3",
                "extended_info":
                "6202-g.54f83de",
                "qualifier_type_order":
                -3,
            },
        ),
        (
            "full version with epoch",
            {
                "version":
                "1:2.3.0~alpha3-6202-g54f83de-0ubuntu1~16.04.1",
                "maas_version":
                MAASVersion(
                    major=2,
                    minor=3,
                    point=0,
                    qualifier_version=3,
                    revno=6202,
                    git_rev="54f83de",
                    qualifier_type="alpha",
                ),
                "str_version":
                "2.3.0~alpha3-6202-g.54f83de",
                "short_version":
                "2.3.0~alpha3",
                "extended_info":
                "6202-g.54f83de",
                "qualifier_type_order":
                -3,
            },
        ),
    )

    def test_parse(self):
        maas_version = MAASVersion.from_string(self.version)
        self.assertEqual(maas_version, self.maas_version)
        self.assertEqual(maas_version.short_version, self.short_version)
        self.assertEqual(maas_version.extended_info, self.extended_info)
        self.assertEqual(maas_version._qualifier_type_order,
                         self.qualifier_type_order)

    def test_string(self):
        self.assertEqual(str(MAASVersion.from_string(self.version)),
                         self.str_version)
예제 #19
0
 def test_string(self):
     self.assertEqual(str(MAASVersion.from_string(self.version)),
                      self.str_version)
예제 #20
0
def notification_available(notification_version):
    current_version = get_maas_version()
    notification_version = MAASVersion.from_string(notification_version)
    log.debug(f"Current MAAS version: {current_version}")
    log.debug(f"Notification version: {notification_version}")
    return notification_version > current_version
예제 #21
0
 def is_up_to_date(self, target_version: TargetVersion) -> bool:
     """Return whether the controller is up-to-date with the target version."""
     return (not self.update_version and MAASVersion.from_string(
         self.version) == target_version.version)
예제 #22
0
 def test_short_version(self):
     maas_version = MAASVersion.from_string(self.version)
     self.assertEqual(maas_version.main_version, self.main_version)
예제 #23
0
def get_target_version() -> Optional[TargetVersion]:
    """Get the target version for the deployment."""
    highest_version = None
    highest_update = None
    update_first_reported = None
    for info in ControllerInfo.objects.exclude(version=""):
        version = MAASVersion.from_string(info.version)
        highest_version = (max(
            (highest_version, version)) if highest_version else version)

        if not info.update_version:
            continue

        update = MAASVersion.from_string(info.update_version)
        if not highest_update:
            highest_update = update
            update_first_reported = info.update_first_reported
        elif update < highest_update:
            continue
        elif update > highest_update:
            highest_update = update
            update_first_reported = info.update_first_reported
        else:  # same version
            update_first_reported = min(
                (update_first_reported, info.update_first_reported))

    if highest_update and highest_update > highest_version:
        version = highest_update
    else:
        # don't report any update
        version = highest_version
        update_first_reported = None

    if version is None:
        return None

    def field_for_snap_controllers(field, version):
        version = str(version)
        return list(
            ControllerInfo.objects.filter(
                Q(version=version) | Q(update_version=version),
                install_type=CONTROLLER_INSTALL_TYPE.SNAP,
            ).exclude(**{
                field: ""
            }).values_list(field, flat=True).distinct())

    channels = field_for_snap_controllers("update_origin", version)
    snap_channel = None
    if channels:
        # report the minimum (with lowest risk) channel that sees the target
        # version
        for channel in channels:
            channel = SnapChannel.from_string(channel)
            if not channel.is_release_branch():
                # only point to a branch if it's a release one, as other branches
                # are in general intended as a temporary change for testing
                channel.branch = ""
            snap_channel = (min(channel, snap_channel)
                            if snap_channel else channel)
    else:
        # compose the channel from the target version
        risk_map = {"alpha": "edge", "beta": "beta", "rc": "candidate"}
        risk = risk_map.get(version.qualifier_type, "stable")
        snap_channel = SnapChannel(
            track=f"{version.major}.{version.minor}",
            risk=risk,
        )

    # report a cohort only if all controllers with the target version are on
    # the same cohort (or have no cohort)
    cohorts = field_for_snap_controllers("snap_cohort", version)
    snap_cohort = cohorts[0] if len(cohorts) == 1 else ""

    return TargetVersion(
        version,
        snap_channel,
        snap_cohort=snap_cohort,
        first_reported=update_first_reported,
    )