diff --git a/src/azure-cli/azure/cli/command_modules/acs/_help.py b/src/azure-cli/azure/cli/command_modules/acs/_help.py index 1042a738ceb..7bfc634ab0b 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/_help.py +++ b/src/azure-cli/azure/cli/command_modules/acs/_help.py @@ -1487,16 +1487,16 @@ parameters: - name: --weekday type: string - short-summary: A day in week on which maintenance is allowed. E.g. Monday. Applicable to default maintenance configuration only. + short-summary: A day in week on which maintenance is allowed. E.g. Monday. Applicable to default maintenance configuration only, using the legacy timeInWeek format. Use --schedule-type Weekly with --day-of-week, --start-time, and --duration instead for the maintenanceWindow format, which also supports --utc-offset and --start-date. - name: --start-hour type: string - short-summary: The start time of 1 hour window which maintenance is allowd. E.g. 1 means it's allowd between 1:00 am and 2:00 am. Applicable to default maintenance configuration only. + short-summary: The start of a 1-hour maintenance window. E.g. 1 means maintenance is allowed between 1:00am and 2:00am. Applicable to default maintenance configuration only, using the legacy timeInWeek format. Use --schedule-type Weekly with --start-time and --duration instead for the maintenanceWindow format, which also supports --utc-offset and --start-date. - name: --schedule-type type: string - short-summary: Choose either 'Daily', 'Weekly', 'AbsoluteMonthly' or 'RelativeMonthly' for your maintenance schedule. Only applicable to 'aksManagedAutoUpgradeSchedule' and 'aksManagedNodeOSUpgradeSchedule' maintenance configuration. + short-summary: Choose either 'Daily', 'Weekly', 'AbsoluteMonthly' or 'RelativeMonthly' for your maintenance schedule. For default maintenance configuration, only 'Weekly' is supported. - name: --start-date type: string - short-summary: The date the maintenance configuration activates. If not specified, the maintenance window will be active right away." + short-summary: The date the maintenance configuration activates. If not specified, the maintenance window will be active right away. Supported for all configuration types, including default." - name: --start-time type: string short-summary: The start time of the maintenance window. Accepted values are from '00:00' to '23:59'. '--utc-offset' applies to this field. For example, '02:00' with '--utc-offset +02:00' means UTC time '00:00'. @@ -1505,25 +1505,25 @@ short-summary: The length of maintenance window range from 4 to 24 hours. - name: --utc-offset type: string - short-summary: The UTC offset in format +/-HH:mm. For example, '+05:30' for IST and '-07:00' for PST. If not specified, the default is '+00:00'. + short-summary: The UTC offset in format +/-HH:mm. For example, '+05:30' for IST and '-07:00' for PST. If not specified, the default is '+00:00'. Supported for all configuration types, including default. - name: --interval-days type: int - short-summary: The number of days between each set of occurrences for daily schedule type. + short-summary: The number of days between each set of occurrences for daily schedule type. Not applicable to default maintenance configuration. - name: --interval-weeks type: int - short-summary: The number of weeks between each set of occurrences. Applicable to weekly schedule types only. + short-summary: The number of weeks between each set of occurrences. Applicable to weekly schedule types only. Cannot be specified for default maintenance configuration (the interval is always 1 week). - name: --interval-months type: int - short-summary: The number of months between each set of occurrences. Applicable to absolute and relative monthly schedule types. + short-summary: The number of months between each set of occurrences. Applicable to absolute and relative monthly schedule types. Not applicable to default maintenance configuration. - name: --day-of-week type: string short-summary: Specify on which day of the week the maintenance occurs. E.g. "Monday". Applicable to weekly and relative monthly schedule types. - name: --day-of-month type: int - short-summary: Specify on which day of the month the maintenance occurs. E.g. 1 indicates the 1st of the month. Applicable to absolute monthly schedule type only. + short-summary: Specify on which day of the month the maintenance occurs. E.g. 1 indicates the 1st of the month. Applicable to absolute monthly schedule type only. Not applicable to default maintenance configuration. - name: --week-index type: string - short-summary: Specify on which instance of the allowed days specified in '--day-of-week' the maintenance occurs. Applicable to relative monthly schedule type only. + short-summary: Specify on which instance of the allowed days specified in '--day-of-week' the maintenance occurs. Applicable to relative monthly schedule type only. Not applicable to default maintenance configuration. - name: --config-file type: string short-summary: The maintenance configuration json file. @@ -1569,6 +1569,10 @@ } ] } + - name: Add default maintenance configuration with weekly maintenanceWindow schedule. + text: | + az aks maintenanceconfiguration add -g MyResourceGroup --cluster-name test1 -n default --schedule-type Weekly --day-of-week Monday --duration 4 --start-time 09:00 + The maintenance is allowed on Monday from 09:00 to 13:00 (UTC) every week. Use --utc-offset to adjust the timezone and --start-date to set an activation date. - name: Add aksManagedNodeOSUpgradeSchedule maintenance configuration with daily schedule. text: | az aks maintenanceconfiguration add -g MyResourceGroup --cluster-name test1 -n aksManagedNodeOSUpgradeSchedule --schedule-type Daily --interval-days 2 --duration 12 --utc-offset=-08:00 --start-date 2023-01-16 --start-time 00:00 @@ -1621,16 +1625,16 @@ parameters: - name: --weekday type: string - short-summary: A day in week on which maintenance is allowed. E.g. Monday. Applicable to default maintenance configuration only. + short-summary: A day in week on which maintenance is allowed. E.g. Monday. Applicable to default maintenance configuration only, using the legacy timeInWeek format. Use --schedule-type Weekly with --day-of-week, --start-time, and --duration instead for the maintenanceWindow format, which also supports --utc-offset and --start-date. - name: --start-hour type: string - short-summary: The start time of 1 hour window which maintenance is allowd. E.g. 1 means it's allowd between 1:00 am and 2:00 am. Applicable to default maintenance configuration only. + short-summary: The start of a 1-hour maintenance window. E.g. 1 means maintenance is allowed between 1:00am and 2:00am. Applicable to default maintenance configuration only, using the legacy timeInWeek format. Use --schedule-type Weekly with --start-time and --duration instead for the maintenanceWindow format, which also supports --utc-offset and --start-date. - name: --schedule-type type: string - short-summary: Choose either 'Daily', 'Weekly', 'AbsoluteMonthly' or 'RelativeMonthly' for your maintenance schedule. Only applicable to 'aksManagedAutoUpgradeSchedule' and 'aksManagedNodeOSUpgradeSchedule' maintenance configuration. + short-summary: Choose either 'Daily', 'Weekly', 'AbsoluteMonthly' or 'RelativeMonthly' for your maintenance schedule. For default maintenance configuration, only 'Weekly' is supported. - name: --start-date type: string - short-summary: The date the maintenance configuration activates. If not specified, the maintenance window will be active right away." + short-summary: The date the maintenance configuration activates. If not specified, the maintenance window will be active right away. Supported for all configuration types, including default." - name: --start-time type: string short-summary: The start time of the maintenance window. Accepted values are from '00:00' to '23:59'. '--utc-offset' applies to this field. For example, '02:00' with '--utc-offset +02:00' means UTC time '00:00'. @@ -1639,25 +1643,25 @@ short-summary: The length of maintenance window range from 4 to 24 hours. - name: --utc-offset type: string - short-summary: The UTC offset in format +/-HH:mm. For example, '+05:30' for IST and '-07:00' for PST. If not specified, the default is '+00:00'. + short-summary: The UTC offset in format +/-HH:mm. For example, '+05:30' for IST and '-07:00' for PST. If not specified, the default is '+00:00'. Supported for all configuration types, including default. - name: --interval-days type: int - short-summary: The number of days between each set of occurrences for daily schedule type. + short-summary: The number of days between each set of occurrences for daily schedule type. Not applicable to default maintenance configuration. - name: --interval-weeks type: int - short-summary: The number of weeks between each set of occurrences. Applicable to weekly schedule types only. + short-summary: The number of weeks between each set of occurrences. Applicable to weekly schedule types only. Cannot be specified for default maintenance configuration (the interval is always 1 week). - name: --interval-months type: int - short-summary: The number of months between each set of occurrences. Applicable to absolute and relative monthly schedule types. + short-summary: The number of months between each set of occurrences. Applicable to absolute and relative monthly schedule types. Not applicable to default maintenance configuration. - name: --day-of-week type: string short-summary: Specify on which day of the week the maintenance occurs. E.g. "Monday". Applicable to weekly and relative monthly schedule types. - name: --day-of-month type: int - short-summary: Specify on which day of the month the maintenance occurs. E.g. 1 indicates the 1st of the month. Applicable to absolute monthly schedule type only. + short-summary: Specify on which day of the month the maintenance occurs. E.g. 1 indicates the 1st of the month. Applicable to absolute monthly schedule type only. Not applicable to default maintenance configuration. - name: --week-index type: string - short-summary: Specify on which instance of the allowed days specified in '--day-of-week' the maintenance occurs. Applicable to relative monthly schedule type only. + short-summary: Specify on which instance of the allowed days specified in '--day-of-week' the maintenance occurs. Applicable to relative monthly schedule type only. Not applicable to default maintenance configuration. - name: --config-file type: string short-summary: The maintenance configuration json file. @@ -1703,6 +1707,10 @@ } ] } + - name: Update default maintenance configuration with weekly maintenanceWindow schedule. + text: | + az aks maintenanceconfiguration update -g MyResourceGroup --cluster-name test1 -n default --schedule-type Weekly --day-of-week Monday --duration 4 --start-time 09:00 + The maintenance is allowed on Monday from 09:00 to 13:00 (UTC) every week. Use --utc-offset to adjust the timezone and --start-date to set an activation date. - name: Update aksManagedNodeOSUpgradeSchedule maintenance configuration with daily schedule. text: | az aks maintenanceconfiguration update -g MyResourceGroup --cluster-name test1 -n aksManagedNodeOSUpgradeSchedule --schedule-type Daily --interval-days 2 --duration 12 --utc-offset=-08:00 --start-date 2023-01-16 --start-time 00:00 diff --git a/src/azure-cli/azure/cli/command_modules/acs/_params.py b/src/azure-cli/azure/cli/command_modules/acs/_params.py index 9c757034c50..e77fe290cfd 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/_params.py +++ b/src/azure-cli/azure/cli/command_modules/acs/_params.py @@ -1049,7 +1049,7 @@ def load_arguments(self, _): c.argument('weekday', help='Weekday on which maintenance can happen. e.g. Monday') c.argument('start_hour', type=int, help='Maintenance start hour of 1 hour window on the weekday. e.g. 1 means 1:00am - 2:00am') c.argument('schedule_type', arg_type=get_enum_type(schedule_types), - help='Schedule type for non-default maintenance configuration.') + help='Schedule type for maintenance configuration. For default configuration, only Weekly is supported.') c.argument('interval_days', type=int, help='The number of days between each set of occurrences for Daily schedule.') c.argument('interval_weeks', type=int, help='The number of weeks between each set of occurrences for Weekly schedule.') c.argument('interval_months', type=int, help='The number of months between each set of occurrences for AbsoluteMonthly or RelativeMonthly schedule.') diff --git a/src/azure-cli/azure/cli/command_modules/acs/maintenanceconfiguration.py b/src/azure-cli/azure/cli/command_modules/acs/maintenanceconfiguration.py index e032bb4ce71..0a3180c4537 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/maintenanceconfiguration.py +++ b/src/azure-cli/azure/cli/command_modules/acs/maintenanceconfiguration.py @@ -59,10 +59,30 @@ def constructDefaultMaintenanceConfiguration(cmd, raw_parameters): start_hour = raw_parameters.get("start_hour") schedule_type = raw_parameters.get("schedule_type") - if weekday is None or start_hour is None: - raise RequiredArgumentMissingError('Please specify --weekday and --start-hour for default maintenance configuration, or use --config-file instead.') + # If schedule_type is provided, use maintenanceWindow format for the default config if schedule_type is not None: - raise MutuallyExclusiveArgumentError('--schedule-type is not supported for default maintenance configuration.') + if weekday is not None or start_hour is not None: + raise MutuallyExclusiveArgumentError('--weekday and --start-hour cannot be used together with --schedule-type for default maintenance configuration.') + if schedule_type != CONST_WEEKLY_MAINTENANCE_SCHEDULE: + raise InvalidArgumentValueError('--schedule-type for default maintenance configuration must be Weekly.') + if raw_parameters.get("interval_weeks") is not None: + raise InvalidArgumentValueError('--interval-weeks cannot be specified for default maintenance configuration; the interval is always 1 week.') + if any(raw_parameters.get(p) is not None for p in ("interval_days", "interval_months", "day_of_month", "week_index")): + raise MutuallyExclusiveArgumentError('--interval-days, --interval-months, --day-of-month and --week-index cannot be used for default maintenance configuration.') + raw_parameters["interval_weeks"] = 1 + maintenance_configuration_models = AKSManagedClusterModels(cmd, ResourceType.MGMT_CONTAINERSERVICE).maintenance_configuration_models + MaintenanceConfiguration = ( + maintenance_configuration_models.MaintenanceConfiguration + ) + maintenanceConfiguration = MaintenanceConfiguration() + # utc_offset and start_date are intentionally not validated here: the RP accepts the full + # MaintenanceWindow schema (including these optional fields) for all maintenance config types. + maintenanceConfiguration.maintenance_window = constructMaintenanceWindow(cmd, raw_parameters) + return maintenanceConfiguration + + # Legacy timeInWeek format + if weekday is None or start_hour is None: + raise RequiredArgumentMissingError('Please specify --weekday and --start-hour, or --schedule-type Weekly with --day-of-week, --start-time, and --duration for default maintenance configuration, or use --config-file instead.') maintenance_configuration_models = AKSManagedClusterModels(cmd, ResourceType.MGMT_CONTAINERSERVICE).maintenance_configuration_models TimeInWeek = ( @@ -73,13 +93,13 @@ def constructDefaultMaintenanceConfiguration(cmd, raw_parameters): timeInWeek_dict["day"] = weekday timeInWeek_dict["hour_slots"] = [start_hour] timeInWeek = TimeInWeek(**timeInWeek_dict) - Result = ( + MaintenanceConfiguration = ( maintenance_configuration_models.MaintenanceConfiguration ) - result = Result() - result.time_in_week = [timeInWeek] - result.not_allowed_time = [] - return result + maintenanceConfiguration = MaintenanceConfiguration() + maintenanceConfiguration.time_in_week = [timeInWeek] + maintenanceConfiguration.not_allowed_time = [] + return maintenanceConfiguration def constructDedicatedMaintenanceConfiguration(cmd, raw_parameters): @@ -89,12 +109,12 @@ def constructDedicatedMaintenanceConfiguration(cmd, raw_parameters): raise MutuallyExclusiveArgumentError('--weekday and --start-hour are only applicable to default maintenance configuration.') maintenance_configuration_models = AKSManagedClusterModels(cmd, ResourceType.MGMT_CONTAINERSERVICE).maintenance_configuration_models - Result = ( + MaintenanceConfiguration = ( maintenance_configuration_models.MaintenanceConfiguration ) - result = Result() - result.maintenance_window = constructMaintenanceWindow(cmd, raw_parameters) - return result + maintenanceConfiguration = MaintenanceConfiguration() + maintenanceConfiguration.maintenance_window = constructMaintenanceWindow(cmd, raw_parameters) + return maintenanceConfiguration def constructMaintenanceWindow(cmd, raw_parameters): diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_maintenanceconfiguration.py b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_maintenanceconfiguration.py index 6cbf146c8c5..67fa9396bcd 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_maintenanceconfiguration.py +++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_maintenanceconfiguration.py @@ -34,7 +34,7 @@ def test_add_maintenance_configuration_with_invalid_name(self): aks_maintenanceconfiguration_update_internal(cmd, None, raw_parameters) self.assertEqual(str(cm.exception), err) - def test_add_default_maintenance_configuration_with_schedule_type(self): + def test_add_default_maintenance_configuration_with_schedule_type_and_weekday(self): cmd = SimpleNamespace() raw_parameters = { "resource_group_name": "test_rg", @@ -45,11 +45,103 @@ def test_add_default_maintenance_configuration_with_schedule_type(self): "schedule_type": "Weekly", } - err = ("--schedule-type is not supported for default maintenance configuration.") + err = ("--weekday and --start-hour cannot be used together with --schedule-type for default maintenance configuration.") with self.assertRaises(MutuallyExclusiveArgumentError) as cm: aks_maintenanceconfiguration_update_internal(cmd, None, raw_parameters) self.assertEqual(str(cm.exception), err) - + + def test_add_default_maintenance_configuration_with_invalid_schedule_type(self): + cmd = MockCmd(self.cli_ctx) + raw_parameters = { + "resource_group_name": "test_rg", + "cluster_name": "test_cluster", + "config_name": "default", + "weekday": None, + "start_hour": None, + "schedule_type": "Daily", + "interval_days": 3, + "interval_weeks": None, + "interval_months": None, + "day_of_week": None, + "day_of_month": None, + "week_index": None, + } + + err = ("--schedule-type for default maintenance configuration must be Weekly.") + with self.assertRaises(InvalidArgumentValueError) as cm: + aks_maintenanceconfiguration_update_internal(cmd, None, raw_parameters) + self.assertEqual(str(cm.exception), err) + + def test_add_default_maintenance_configuration_rejects_interval_weeks(self): + cmd = MockCmd(self.cli_ctx) + raw_parameters = { + "resource_group_name": "test_rg", + "cluster_name": "test_cluster", + "config_name": "default", + "weekday": None, + "start_hour": None, + "schedule_type": "Weekly", + "interval_days": None, + "interval_weeks": 3, + "interval_months": None, + "day_of_week": "Monday", + "day_of_month": None, + "week_index": None, + } + + err = ("--interval-weeks cannot be specified for default maintenance configuration; the interval is always 1 week.") + with self.assertRaises(InvalidArgumentValueError) as cm: + aks_maintenanceconfiguration_update_internal(cmd, None, raw_parameters) + self.assertEqual(str(cm.exception), err) + + def test_add_default_maintenance_configuration_rejects_interval_weeks_even_if_1(self): + """interval_weeks=1 is also rejected; users must simply omit --interval-weeks.""" + cmd = MockCmd(self.cli_ctx) + raw_parameters = { + "resource_group_name": "test_rg", + "cluster_name": "test_cluster", + "config_name": "default", + "weekday": None, + "start_hour": None, + "schedule_type": "Weekly", + "interval_days": None, + "interval_weeks": 1, + "interval_months": None, + "day_of_week": "Monday", + "day_of_month": None, + "week_index": None, + } + + err = ("--interval-weeks cannot be specified for default maintenance configuration; the interval is always 1 week.") + with self.assertRaises(InvalidArgumentValueError) as cm: + aks_maintenanceconfiguration_update_internal(cmd, None, raw_parameters) + self.assertEqual(str(cm.exception), err) + + def test_add_default_maintenance_configuration_rejects_inapplicable_schedule_params(self): + """interval_days, interval_months, day_of_month, week_index are rejected for default config.""" + err = ("--interval-days, --interval-months, --day-of-month and --week-index cannot be used for default maintenance configuration.") + for param in ("interval_days", "interval_months", "day_of_month", "week_index"): + with self.subTest(param=param): + cmd = MockCmd(self.cli_ctx) + raw_parameters = { + "resource_group_name": "test_rg", + "cluster_name": "test_cluster", + "config_name": "default", + "weekday": None, + "start_hour": None, + "schedule_type": "Weekly", + "interval_days": None, + "interval_weeks": None, + "interval_months": None, + "day_of_week": "Monday", + "day_of_month": None, + "week_index": None, + } + raw_parameters[param] = 1 + with self.assertRaises(MutuallyExclusiveArgumentError) as cm: + aks_maintenanceconfiguration_update_internal(cmd, None, raw_parameters) + self.assertEqual(str(cm.exception), err) + def test_add_non_default_schedule_with_weekday(self): cmd = SimpleNamespace() raw_parameters = { @@ -177,4 +269,73 @@ def test_add_dedicated_schedule_with_missing_options(self): with self.assertRaises(RequiredArgumentMissingError) as cm: aks_maintenanceconfiguration_update_internal(cmd, None, raw_parameters) self.assertEqual(str(cm.exception), err) - \ No newline at end of file + + def test_add_default_maintenance_configuration_with_weekly_schedule_type(self): + cmd = MockCmd(self.cli_ctx) + + class MockMaintenanceConfigClient: + def create_or_update(self, **kwargs): + return kwargs.get('parameters') + + raw_parameters = { + "resource_group_name": "test_rg", + "cluster_name": "test_cluster", + "config_name": "default", + "weekday": None, + "start_hour": None, + "schedule_type": "Weekly", + "interval_days": None, + "interval_weeks": None, + "interval_months": None, + "day_of_week": "Monday", + "day_of_month": None, + "week_index": None, + "start_time": "09:00", + "duration_hours": 4, + "utc_offset": None, + "start_date": None, + } + + result = aks_maintenanceconfiguration_update_internal(cmd, MockMaintenanceConfigClient(), raw_parameters) + + self.assertIsNotNone(result.maintenance_window) + self.assertEqual(result.maintenance_window.start_time, "09:00") + self.assertEqual(result.maintenance_window.duration_hours, 4) + self.assertIsNotNone(result.maintenance_window.schedule) + self.assertIsNotNone(result.maintenance_window.schedule.weekly) + self.assertIsNone(getattr(result, 'time_in_week', None)) + + def test_add_default_maintenance_configuration_with_weekly_schedule_type_omits_interval_weeks(self): + """interval_weeks should default to 1 when omitted for the default config.""" + cmd = MockCmd(self.cli_ctx) + + class MockMaintenanceConfigClient: + def create_or_update(self, **kwargs): + return kwargs.get('parameters') + + raw_parameters = { + "resource_group_name": "test_rg", + "cluster_name": "test_cluster", + "config_name": "default", + "weekday": None, + "start_hour": None, + "schedule_type": "Weekly", + "interval_days": None, + "interval_weeks": None, + "interval_months": None, + "day_of_week": "Monday", + "day_of_month": None, + "week_index": None, + "start_time": "09:00", + "duration_hours": 4, + "utc_offset": None, + "start_date": None, + } + + result = aks_maintenanceconfiguration_update_internal(cmd, MockMaintenanceConfigClient(), raw_parameters) + + self.assertIsNotNone(result.maintenance_window) + self.assertIsNotNone(result.maintenance_window.schedule) + self.assertIsNotNone(result.maintenance_window.schedule.weekly) + self.assertEqual(result.maintenance_window.schedule.weekly.interval_weeks, 1) + self.assertIsNone(getattr(result, 'time_in_week', None))