Ejemplo n.º 1
0
    def _create_sample_schemas(self):

        try:
            admin = ConfigAdmin(logger=self._logger, context=self.context)

            admin.create_period(**demo_data.PERIOD_WORKING_DAYS)
            admin.create_period(**demo_data.PERIOD_WEEKENDS)
            admin.create_period(**demo_data.PERIOD_OFFICE_HOURS)
            admin.create_period(**demo_data.PERIOD_FIRST_MONDAY_IN_QUARTER)

            admin.create_schedule(**demo_data.SCHEDULE_SEATTLE_OFFICE_HOURS)
            admin.create_schedule(**demo_data.SCHEDULE_UK_OFFICE_HOURS)
            admin.create_schedule(**demo_data.SCHEDULE_STOPPED)
            admin.create_schedule(**demo_data.SCHEDULE_RUNNING)
            admin.create_schedule(**demo_data.SCHEDULE_SCALING)

        except Exception as ex:
            self._logger.error("Error creating sample schedules and periods {}".format(ex))
class ScheduleResourceHandler(CustomResource):
    """
    Implements custom resource handler for CFN support for schedules/periods
    """

    def __init__(self, event, context):
        """
        Initializes instance
        :param event: CFN event
        :param context: Lambda context
        """
        CustomResource.__init__(self, event, context)
        self.number_of_periods = 0

        classname = self.__class__.__name__
        dt = datetime.utcnow()
        logstream = LOG_STREAM.format(classname, dt.year, dt.month, dt.day)
        self._logger = Logger(logstream=logstream, buffersize=20, context=context)

        self._admin = ConfigAdmin(logger=self._logger, context=context)

    @staticmethod
    def is_handling_request(event):
        """
        Tests if this handler handles the event
        :param event: Tested event
        :return: True if this is custom resource event for configuring schedule/periods
        """
        return event.get("StackId") is not None and event.get("ResourceType") == "Custom::ServiceInstanceSchedule"

    @classmethod
    def _set_if_specified(cls, source, source_name, dest, dest_name=None, default=None):
        val = source.get(source_name, default)
        if val is not None:
            dest[dest_name if dest_name is not None else source_name] = val

    @property
    def _schedule_resource_name(self):
        name = self.resource_properties.get(PROP_NAME,None)
        if name is None:
            name = self.logical_resource_id
        if str(self.resource_properties.get(PROP_NO_STACK_PREFIX, "False")).lower() == "true":
            return name
        return "{}-{}".format(self.stack_name, name)

    def _create_period(self, period):

        self.number_of_periods += 1

        period_name = PERIOD_NAME.format(self._schedule_resource_name, self.number_of_periods)
        self._logger.info(INF_PERIOD_NAME, period_name)

        for p in period:
            if p not in VALID_PERIOD_PROPERTIES:
                raise ValueError(ERR_INVALID_PERIOD_PROPERTY.format(p, ", ".join(VALID_PERIOD_PROPERTIES)))

        create_period_args = {

            configuration.NAME: period_name
        }

        self._set_if_specified(period, PROP_BEGIN_TIME, create_period_args, configuration.BEGINTIME)
        self._set_if_specified(period, PROP_END_TIME, create_period_args, configuration.ENDTIME)
        self._set_if_specified(period, PROP_MONTH_DAYS, create_period_args, configuration.MONTHDAYS)
        self._set_if_specified(period, PROP_MONTHS, create_period_args, configuration.MONTHS)
        self._set_if_specified(period, PROP_WEEKDAYS, create_period_args, configuration.WEEKDAYS)

        create_period_args[configuration.DESCRIPTION] = PERIOD_DESCRIPTION.format(self._schedule_resource_name,
                                                                                  self.number_of_periods)
        description_config = period.get(PROP_DESCRIPTION, None)
        if description_config is not None:
            create_period_args[configuration.DESCRIPTION] = "{}, {}".format(description_config,
                                                                            create_period_args[configuration.DESCRIPTION])

        period = self._admin.create_period(**create_period_args)

        self._logger.info(INF_PERIOD_CREATED, safe_json(period, 3))

        return period_name, period.get(PROP_INSTANCE_TYPE, None)

    def _delete_periods(self):
        i = 0
        while True:
            i += 1
            name = PERIOD_NAME.format(self._schedule_resource_name, i)
            period = self._admin.delete_period(name, exception_if_not_exists=False)
            if period is None:
                break
            else:
                self._logger.info(INF_DELETED_PERIOD, name)

    def _create_schedule(self):

        self._logger.info(INF_SCHEDULE_NAME, self._schedule_resource_name)

        create_schedule_args = {
            configuration.NAME: self._schedule_resource_name
        }

        ps = self.resource_properties

        for pr in ps:

            # fix for typo in older release, fix parameter if old version with typo is used for compatibility
            if pr == "UseMaintenaceWindow":
                pr = PROP_USE_MAINTENANCE_WINDOW

            if pr not in VALID_SCHEDULE_PROPERTIES:
                raise ValueError(ERR_INVALID_SCHEDULE_PROPERTY.format(pr, ", ".join(VALID_SCHEDULE_PROPERTIES)))

        self._set_if_specified(ps, PROP_METRICS, create_schedule_args, dest_name=configuration.METRICS)
        self._set_if_specified(ps, PROP_OVERWRITE, create_schedule_args, dest_name=configuration.OVERWRITE)
        self._set_if_specified(ps, PROP_OVERRIDE_STATUS, create_schedule_args, dest_name=configuration.OVERRIDE_STATUS)
        self._set_if_specified(ps, PROP_USE_MAINTENANCE_WINDOW, create_schedule_args,
                               dest_name=configuration.USE_MAINTENANCE_WINDOW)
        self._set_if_specified(ps, PROP_ENFORCED, create_schedule_args, dest_name=configuration.ENFORCED, default=False)
        self._set_if_specified(ps, PROP_HIBERNATE, create_schedule_args, dest_name=configuration.HIBERNATE, default=False)
        self._set_if_specified(ps, PROP_RETAIN_RUNNING, create_schedule_args, dest_name=configuration.RETAINED_RUNNING,
                               default=False)
        self._set_if_specified(ps, PROP_STOP_NEW, create_schedule_args, dest_name=configuration.STOP_NEW_INSTANCES, default=True)
        self._set_if_specified(ps, PROP_TIMEZONE, create_schedule_args, dest_name=configuration.TIMEZONE, default="UTC")
        self._set_if_specified(ps, PROP_DESCRIPTION, create_schedule_args, dest_name=configuration.DESCRIPTION)
        self._set_if_specified(ps, PROP_SSM_MAINTENANCE_WINDOW, create_schedule_args, dest_name=configuration.SSM_MAINTENANCE_WINDOW)

        create_schedule_args[configuration.SCHEDULE_CONFIG_STACK] = self.stack_id

        periods = []
        try:
            self.number_of_periods = 0
            for period in ps.get(PROP_PERIODS, []):
                period_name, instance_type = self._create_period(period)
                if instance_type is not None:
                    period_name = "{}{}{}".format(period_name, configuration.INSTANCE_TYPE_SEP, instance_type)
                periods.append(period_name)

            create_schedule_args[configuration.PERIODS] = periods
            schedule = self._admin.create_schedule(**create_schedule_args)
            self.physical_resource_id = self._schedule_resource_name

            self._logger.info(INF_SCHEDULE_CREATED, safe_json(schedule, 3))
        except Exception as ex:
            self._delete_periods()
            raise ex

    def _delete_schedule(self):
        schedule = self._admin.delete_schedule(name=self._schedule_resource_name, exception_if_not_exists=False)
        if schedule is not None:
            self._delete_periods()
            self._logger.info(INF_DELETE_SCHEDULE, self._schedule_resource_name)

    def _update_schedule(self):
        self._delete_schedule()
        self._create_schedule()

    def _create_request(self):
        try:
            self._create_schedule()
            return True
        except Exception as ex:
            self._logger.error(ex)
            return False
        finally:
            self._logger.flush()

    def _update_request(self):
        try:
            self._update_schedule()
            return True
        except Exception as ex:
            self._logger.error(ex)
            return False
        finally:
            self._logger.flush()

            # handles Delete request from CloudFormation

    def _delete_request(self):
        try:
            self._delete_schedule()
            return True
        except Exception as ex:
            self._logger.error(ex)
            return False
        finally:
            self._logger.flush()