def test_get_desired_state_and_type_2(mocker): instance = {} schedule = InstanceSchedule(name='test-1', periods={}, timezone='UTC', override_status=None, description=None, use_metrics=None, stop_new_instances=None, schedule_dt=None, use_maintenance_window=True, ssm_maintenance_window=True, enforced=False, hibernate=False, retain_running=False) instance['maintenance_window'] = None instance["account"] = 'test' instance["region"] = 'us-east-1' instance["service"] = 'ec2' instance["id"] = 'ut12y21232u' inst = as_namedtuple('ec2' + "Instance", instance, excludes=["tags"]) ec2_service = Ec2Service() scheduler_configuration = {} scheduler = InstanceScheduler(ec2_service, scheduler_configuration) mocker.patch.object(scheduler, '_logger') inst_state, inst_type = scheduler.get_desired_state_and_type( schedule, inst) assert inst_state == 'stopped'
def build_schedule_from_maintenance_window(period_str): """ Builds a Instance running schedule based on an RDS preferred maintenance windows string in format ddd:hh:mm-ddd:hh:mm :param period_str: rds maintenance windows string :return: Instance running schedule with timezone UTC """ # get elements of period start_string, stop_string = period_str.split("-") start_day_string, start_hhmm_string = start_string.split(":", 1) stop_day_string, stop_hhmm_string = stop_string.split(":", 1) # weekday set builder weekdays_builder = WeekdaySetBuilder() start_weekday = weekdays_builder.build(start_day_string) start_time = SchedulerConfigBuilder.get_time_from_string(start_hhmm_string) end_time = SchedulerConfigBuilder.get_time_from_string(stop_hhmm_string) # windows with now day overlap, can do with one period for schedule if start_day_string == stop_day_string: periods = [ { "period": RunningPeriod(name=MAINTENANCE_PERIOD_NAME, begintime=start_time, endtime=end_time, weekdays=start_weekday) }] else: # window with day overlap, need two periods for schedule end_time_day1 = SchedulerConfigBuilder.get_time_from_string("23:59") begin_time_day2 = SchedulerConfigBuilder.get_time_from_string("00:00") stop_weekday = weekdays_builder.build(stop_day_string) periods = [ { "period": RunningPeriod(name=MAINTENANCE_PERIOD_NAME + "-{}".format(start_day_string), begintime=start_time, endtime=end_time_day1, weekdays=start_weekday), "instancetype": None }, { "period": RunningPeriod(name=MAINTENANCE_PERIOD_NAME + "-{}".format(stop_day_string), begintime=begin_time_day2, endtime=end_time, weekdays=stop_weekday), "instancetype": None }] # create schedule with period(s) and timezone UTC schedule = InstanceSchedule(name=MAINTENANCE_SCHEDULE_NAME, periods=periods, timezone="UTC", enforced=True) return schedule
def _schedule_from_maint_window(self, name, start, hours, interval): start_dt = start.replace(second=0, microsecond=0) start_before_begin = min(interval, 10) begin_dt = start_dt - timedelta(minutes=start_before_begin) end_dt = start_dt + timedelta(hours=hours) if begin_dt.day == end_dt.day: periods = [{ "period": RunningPeriod(name="{}-period".format(name), begintime=begin_dt.time(), endtime=end_dt.time(), monthdays={begin_dt.day}, months={begin_dt.month}), "instancetype": None }] elif end_dt - begin_dt <= timedelta(hours=24): periods = [{ "period": RunningPeriod( name="{}-period-1".format(name), begintime=begin_dt.time(), endtime=SchedulerConfigBuilder.get_time_from_string( "23:59"), monthdays={begin_dt.day}, months={begin_dt.month}), "instancetype": None }, { "period": RunningPeriod( name="{}-period-2".format(name), begintime=SchedulerConfigBuilder.get_time_from_string( "00:00"), endtime=end_dt.time(), monthdays={end_dt.day}, months={end_dt.month}), "instancetype": None }] else: periods = [{ "period": RunningPeriod( name="{}-period-1".format(name), begintime=begin_dt.time(), endtime=SchedulerConfigBuilder.get_time_from_string( "23:59"), monthdays={begin_dt.day}, months={begin_dt.month}), "instancetype": None }, { "period": RunningPeriod(name="{}-period-2".format(name), monthdays={(end_dt - timedelta(days=1)).day}, months={(end_dt - timedelta(days=1)).month}), "instancetype": None }, { "period": RunningPeriod( name="{}-period-3".format(name), begintime=SchedulerConfigBuilder.get_time_from_string( "00:00"), endtime=end_dt.time(), monthdays={end_dt.day}, months={end_dt.month}), "instancetype": None }] schedule = InstanceSchedule( name=name, timezone="UTC", description="{} maintenance window".format(name), enforced=True, periods=periods) self._logger.info(INF_MAINT_WINDOW, name, begin_dt.isoformat(), end_dt.isoformat()) return schedule
def configuration_from_dict(d): """ This method builds a configuration object instance that is passed as a dictionary in the event of a lambda function :param d: :return: """ config_args = {} for attr in [ ATTR_TAGNAME, ATTR_DEFAULT_TIMEZONE, ATTR_TRACE, ATTR_ENABLE_SSM_MAINTENANCE_WINDOWS, ATTR_SCHEDULE_CLUSTERS, ATTR_CREATE_RDS_SNAPSHOT, ATTR_USE_METRICS, ATTR_SCHEDULE_LAMBDA_ACCOUNT, ATTR_STARTED_TAGS, ATTR_STOPPED_TAGS ]: config_args[attr] = d.get(attr, None) for attr in [ ATTR_REGIONS, ATTR_CROSS_ACCOUNT_ROLES, ATTR_SCHEDULED_SERVICES ]: config_args[attr] = set(d.get(attr, [])) periods = {} for period_name in d.get(ATTR_PERIODS, {}): period_data = d[ATTR_PERIODS][period_name] period_args = {ATTR_NAME: period_name} for attr in [ATTR_BEGINTIME, ATTR_ENDTIME]: if attr in period_data: period_args[ attr] = SchedulerConfigBuilder.get_time_from_string( period_data[attr]) for attr in [ATTR_WEEKDAYS, ATTR_MONTHDAYS, ATTR_MONTHS]: if attr in period_data: period_args[attr] = set(period_data.get(attr, None)) period = RunningPeriod(**period_args) periods[period_name] = period config_args[ATTR_SCHEDULES] = {} for schedule_name in d.get(ATTR_SCHEDULES, {}): schedule_args = {} schedule_data = d[ATTR_SCHEDULES][schedule_name] for attr in [ ATTR_NAME, ATTR_TIMEZONE, ATTR_OVERRIDE_STATUS, ATTR_STOP_NEW_INSTANCES, ATTR_USE_METRICS, ATTR_ENFORCED, ATTR_HIBERNATE, ATTR_RETAIN_RUNNING, ATTR_SSM_MAINTENANCE_WINDOW, ATTR_USE_MAINTENANCE_WINDOW ]: schedule_args[attr] = schedule_data.get(attr, None) for attr in [ATTR_SCHEDULE_DT]: if attr in schedule_data: schedule_args[attr] = dateutil.parser.parse( schedule_data[attr]) if schedule_args[ATTR_OVERRIDE_STATUS] is None: schedule_args[ATTR_PERIODS] = [] for period in schedule_data.get(ATTR_PERIODS): temp = period.split(configuration.INSTANCE_TYPE_SEP) if len(temp) > 1: name = temp[0] instance_type = temp[1] else: name = period instance_type = None schedule_args[ATTR_PERIODS].append({ ATTR_PERIOD: periods[name], ATTR_INSTANCE_TYPE: instance_type }) schedule = InstanceSchedule(**schedule_args) config_args[ATTR_SCHEDULES][schedule_name] = schedule config = SchedulerConfig(**config_args) return config
def _build_schedule(self, schedule_config, dflt_tz, scheduler_use_config, dt): # gets the timezone def get_timezone(schedule_configuration): schedule_timezone = schedule_configuration.get( configuration.TIMEZONE) if not schedule_timezone: schedule_timezone = dflt_tz validated = SchedulerConfigBuilder.validated_timezone( schedule_timezone) if validated is None: raise ValueError( MSG_INVALID_SCHEDULE_TIMEZONE.format( schedule_timezone, schedule_configuration)) return validated def get_schedule_name(config): schedule_name = config.get(configuration.NAME, None) if not schedule_name: raise ValueError(MSG_NAME_MISSING_IN_SCHEDULE.format(config)) return schedule_name def get_override_status(config): if configuration.OVERWRITE in config: if configuration.OVERRIDE_STATUS in config: raise ValueError( MSG_OVERWRITE_OVERRIDE_MUTUAL_EXCLUSIVE.format( configuration.OVERWRITE, configuration.OVERRIDE_STATUS)) overwrite = config[configuration.OVERWRITE] return configuration.OVERRIDE_STATUS_RUNNING if overwrite else configuration.OVERRIDE_STATUS_STOPPED status = config.get(configuration.OVERRIDE_STATUS, None) if status is not None and status not in configuration.OVERRIDE_STATUS_VALUES: raise ValueError( MSG_INVALID_OVERRIDE_STATUS.format( status, configuration.OVERRIDE_STATUS, ",".join(configuration.OVERRIDE_STATUS_VALUES))) return status try: timezone = get_timezone(schedule_config) override_status = get_override_status(schedule_config) periods_for_schedule = [] # ignore periods if there is an always on or if override_status option is used if not override_status: # use current date and time for timezone of schedule current_schema_dt = dt.now( SchedulerConfigBuilder._get_timezone(timezone)) periods_for_schedule = self._get_schedule_periods( schedule_config, current_schema_dt) return InstanceSchedule( name=get_schedule_name(schedule_config), periods=periods_for_schedule, timezone=timezone, override_status=override_status, description=schedule_config.get(configuration.DESCRIPTION, ""), use_metrics=schedule_config.get(configuration.METRICS, scheduler_use_config), stop_new_instances=schedule_config.get( configuration.STOP_NEW_INSTANCES, True), use_maintenance_window=schedule_config.get( configuration.USE_MAINTENANCE_WINDOW, False), ssm_maintenance_window=schedule_config.get( configuration.SSM_MAINTENANCE_WINDOW, None), enforced=schedule_config.get(configuration.ENFORCED, False), hibernate=schedule_config.get(configuration.HIBERNATE, False), retain_running=schedule_config.get( configuration.RETAINED_RUNNING)) except ValueError as ex: if self._logger is not None: self._logger.error(str(ex)) return None