in source/lambda/schedulers/instance_scheduler.py [0:0]
def _process_account(self, account):
# processes instances for a service in an account
started_instances = {}
stopped_instances = {}
resized_instances = {}
self._logger.info(INF_PROCESSING_ACCOUNT,
self._service.service_name.upper(), account.name,
" using role " + account.role if account.role else "",
", ".join(self._configuration.regions))
for region in self._regions:
state_loaded = False
instances = []
self._scheduler_start_list = []
self._scheduler_stop_list = []
self._schedule_resize_list = []
for instance in self._scheduled_instances_in_region(account, region):
# delay loading instance state until first instance is returned
if not state_loaded:
self._instance_states.load(account.name, region)
state_loaded = True
instances.append(instance)
# handle terminated instances
if instance.is_terminated:
self._logger.debug(DEBUG_SKIPPING_TERMINATED_INSTANCE, instance.instance_str, region,
instance.account)
self._instance_states.delete_instance_state(instance.id)
continue
# get the schedule for this instance
instance_schedule = self._configuration.get_schedule(instance.schedule_name)
if not instance_schedule:
self._logger.warning(WARN_SKIPPING_UNKNOWN_SCHEDULE, instance.instance_str, region,
instance.account,
instance.schedule_name)
continue
self._logger.debug(DEBUG_INSTANCE_HEADER, instance.instance_str)
self._logger.debug(DEBUG_CURRENT_INSTANCE_STATE, instance.current_state, instance.instancetype,
instance_schedule.name)
# based on the schedule get the desired state and instance type for this instance
desired_state, desired_type = self.get_desired_state_and_type(instance_schedule, instance)
# get the previous desired instance state
last_desired_state = self._instance_states.get_instance_state(instance.id)
self._logger.debug(DEBUG_CURRENT_AND_DESIRED_STATE, instance_schedule.name, desired_state,
last_desired_state,
instance.current_state,
INF_DESIRED_TYPE.format(desired_type) if desired_type else "")
# last desired state None means this is the first time the instance is seen by the scheduler
if last_desired_state is InstanceSchedule.STATE_UNKNOWN:
# new instances that are running are optionally not stopped to allow them to finish possible initialization
if instance.is_running and desired_state == InstanceSchedule.STATE_STOPPED:
if not instance_schedule.stop_new_instances:
self._instance_states.set_instance_state(instance.id, InstanceSchedule.STATE_STOPPED)
self._logger.debug(DEBUG_NEW_INSTANCE, instance.instance_str)
continue
self._process_new_desired_state(account, region, instance, desired_state, desired_type,
last_desired_state,
instance_schedule.retain_running)
else:
self._process_new_desired_state(account, region, instance, desired_state, desired_type,
last_desired_state,
instance_schedule.retain_running)
# existing instance
# if enforced check the actual state with the desired state enforcing the schedule state
elif instance_schedule.enforced:
if (instance.is_running and desired_state == InstanceSchedule.STATE_STOPPED) or (
not instance.is_running and desired_state == InstanceSchedule.STATE_RUNNING):
self._logger.debug(DEBUG_ENFORCED_STATE, instance.instance_str,
InstanceSchedule.STATE_RUNNING
if instance.is_running
else InstanceSchedule.STATE_STOPPED,
desired_state)
self._process_new_desired_state(account, region, instance, desired_state, desired_type,
last_desired_state,
instance_schedule.retain_running)
# if not enforced then compare the schedule state with the actual state so state of manually started/stopped
# instance it will honor that state
elif last_desired_state != desired_state:
self._process_new_desired_state(account, region, instance, desired_state, desired_type,
last_desired_state,
instance_schedule.retain_running)
self._schedule_metrics.add_schedule_metrics(self._service.service_name, instance_schedule, instance)
# process lists of instances that must be started or stopped
self._start_and_stop_instances(account, region=region)
# cleanup desired instance states and save
self._instance_states.cleanup([i.id for i in instances])
self._instance_states.save()
# build output structure, hold started, stopped and resized instances per region
if len(self._scheduler_start_list) > 0:
started_instances[region] = [{i.id: {"schedule": i.schedule_name}} for i in self._scheduler_start_list]
if len(self._scheduler_stop_list):
stopped_instances[region] = [{i.id: {"schedule": i.schedule_name}} for i in self._scheduler_stop_list]
if len(self._schedule_resize_list) > 0:
resized_instances[region] = [
{i[0].id: {"schedule": i[0].schedule_name, "old": i[0].instancetype, "new": i[1]}} for
i in self._schedule_resize_list]
if allow_send_metrics():
self._collect_usage_metrics()
# put cloudwatch metrics
if self._configuration.use_metrics:
self._schedule_metrics.put_schedule_metrics()
# output data
result = {"started": started_instances, "stopped": stopped_instances}
if self._service.allow_resize:
result["resized"] = resized_instances
return result