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, )
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)")
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)
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_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")
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"))
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)
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 ) )
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"))
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))
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))
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)
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
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"))
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]
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"), )
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, ], )
def test_string(self): self.assertEqual(str(MAASVersion.from_string(self.version)), self.str_version)
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
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)
def test_short_version(self): maas_version = MAASVersion.from_string(self.version) self.assertEqual(maas_version.main_version, self.main_version)
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, )