Пример #1
0
def list_schedules(owner):
    schedules = Schedule.objects(owner=owner, deleted=None).order_by('-_id')
    schedule_objects = []
    for schedule in schedules:
        schedule_object = schedule.as_dict()
        schedule_object["tags"] = get_tags_for_resource(owner, schedule)
        schedule_objects.append(schedule_object)
    return schedule_objects
Пример #2
0
def list_schedules(owner):
    schedules = Schedule.objects(owner=owner, deleted=None).order_by('-_id')
    schedule_objects = []
    for schedule in schedules:
        schedule_object = schedule.as_dict()
        schedule_object["tags"] = get_tags_for_resource(owner, schedule)
        # no need to for remnder schedules to be visible
        if schedule.schedule_type.type != 'reminder':
            schedule_objects.append(schedule_object)
    return schedule_objects
Пример #3
0
def add_schedule_entry(request):
    """
    Tags: schedules
    ---
    Adds an entry to user schedules.
    Add permission required on schedule.
    RUN_SCRIPT permission required on machine.
    RUN permission required on script.
    ---
    script_id:
      type: string
    action:
      type: string
    machines_uuids:
      required: true
      type: array
      description: list of machines_uuids
    machines_tags:
      required: true
      type: array
      description: list of machines_tags
    name:
      required: true
      type: string
      description: schedule name
    task_enabled:
      type: boolean
      description: schedule is ready to run
    run_immediately:
      type: boolean
      description: run immediately only  the first time
    expires:
      type: string
      description: expiration date
    description:
      type: string
      description: describe schedule
    schedule_type:
      required: true
      type: string
      description: three different types, interval, crontab, one_off
    schedule_entry:
      type: object
      description: period of time
    params:
      type: string
    """
    params = params_from_request(request)

    # SEC
    auth_context = auth_context_from_request(request)
    # SEC require ADD permission on schedule
    schedule_tags, _ = auth_context.check_perm("schedule", "add", None)

    name = params.pop('name')

    schedule = Schedule.add(auth_context, name, **params)

    if schedule_tags:
        resolve_id_and_set_tags(auth_context.owner, 'schedule', schedule.id,
                                list(schedule_tags.items()))
    trigger_session_update(auth_context.owner, ['schedules'])
    return schedule.as_dict()
Пример #4
0
    def update(self, auth_context, params={}):
        if params.get('expiration'):
            """
            FIXME: we're recreating instead of updating existing expiration
                   schedules because updating them doesn't seem to affect the
                   actual expiration datetime.
            """
            from mist.api.schedules.models import Schedule
            exp_date = params['expiration']['date']
            exp_reminder = int(params['expiration'].get('notify', 0) or 0)
            exp_action = params['expiration'].get('action', 'stop')
            assert exp_action in ['stop', 'destroy'], 'Invalid action'
            if self.machine.expiration:  # Existing expiration schedule
                # Delete after removing db ref
                sched = self.machine.expiration
                self.machine.expiration = None
                self.machine.save()
                sched.delete()

            if exp_date:  # Create new expiration schedule
                params = {
                    'description': 'Scheduled to run when machine expires',
                    'task_enabled': True,
                    'schedule_type': 'one_off',
                    'schedule_entry': exp_date,
                    'action': exp_action,
                    'selectors': [{
                        'type': 'machines',
                        'ids': [self.machine.id]
                    }],
                    'notify': exp_reminder
                }
                name = self.machine.name + '-expiration-' + str(
                    randrange(1000))
                self.machine.expiration = Schedule.add(auth_context, name,
                                                       **params)
                self.machine.save()

            # Prepare exp date JSON patch to update the UI
            if not self.machine.expiration:
                patch = [{
                    'op':
                    'remove',
                    'path':
                    '/%s-%s/expiration' %
                    (self.machine.id, self.machine.machine_id)
                }]
            else:
                patch = [{
                    'op':
                    'replace',
                    'path':
                    '/%s-%s/expiration' %
                    (self.machine.id, self.machine.machine_id),
                    'value':
                    not self.machine.expiration and None or {
                        'id':
                        self.machine.expiration.id,
                        'date':
                        self.machine.expiration.schedule_type.entry,
                        'action':
                        self.machine.expiration.task_type.action,
                        'notify':
                        self.machine.expiration.reminder and int(
                            (self.machine.expiration.schedule_type.entry -
                             self.machine.expiration.reminder.schedule_type.
                             entry).total_seconds()) or 0
                    }
                }]
            # Publish patches to rabbitmq.
            amqp_publish_user(self.machine.cloud.owner.id,
                              routing_key='patch_machines',
                              data={
                                  'cloud_id': self.machine.cloud.id,
                                  'patch': patch
                              })

        return self.machine
Пример #5
0
    def update(self, **kwargs):
        """Edit an existing Schedule"""

        if self.auth_context is not None:
            auth_context = self.auth_context
        else:
            raise MistError("You are not authorized to update schedule")

        owner = auth_context.owner

        if kwargs.get('action'):
            if kwargs.get('action') not in ['reboot', 'destroy', 'notify',
                                            'start', 'stop']:
                raise BadRequestError("Action is not correct")

        script_id = kwargs.pop('script_id', '')
        if script_id:
            try:
                Script.objects.get(owner=owner, id=script_id, deleted=None)
            except me.DoesNotExist:
                raise ScriptNotFoundError('Script with id %s does not '
                                          'exist' % script_id)
            # SEC require permission RUN on script
            auth_context.check_perm('script', 'run', script_id)

        # for ui compatibility
        if kwargs.get('expires') == '':
            kwargs['expires'] = None
        if kwargs.get('max_run_count') == '':
            kwargs['max_run_count'] = None
        if kwargs.get('start_after') == '':
            kwargs['start_after'] = None
        # transform string to datetime
        if kwargs.get('expires'):
            try:
                kwargs['expires'] = datetime.datetime.strptime(
                    kwargs['expires'], '%Y-%m-%d %H:%M:%S')
            except ValueError:
                raise BadRequestError('Expiration date value was not valid')

        if kwargs.get('start_after'):
            try:
                kwargs['start_after'] = datetime.datetime.strptime(
                    kwargs['start_after'], '%Y-%m-%d %H:%M:%S')
            except ValueError:
                raise BadRequestError('Start-after date value was not valid')

        now = datetime.datetime.now()
        if self.schedule.expires and self.schedule.expires < now:
            raise BadRequestError('Date of future task is in the past. '
                                  'Please contact Marty McFly')
        if self.schedule.start_after and self.schedule.start_after < now:
            raise BadRequestError('Date of future task is in the past. '
                                  'Please contact Marty McFly')
        try:
            self._update__preparse_machines(auth_context, kwargs)
        except MistError as exc:
            log.error("Error while updating schedule %s: %r",
                      self.schedule.id, exc)
            raise
        except Exception as exc:
            log.exception("Error while preparsing kwargs on update %s",
                          self.schedule.id)
            raise InternalServerError(exc=exc)

        action = kwargs.pop('action', '')
        if action:
            self.schedule.task_type = schedules.ActionTask(action=action)
        elif script_id:
            self.schedule.task_type = schedules.ScriptTask(
                script_id=script_id, params=kwargs.pop('params', ''))

        schedule_type = kwargs.pop('schedule_type', '')

        if (schedule_type == 'crontab' or
                isinstance(self.schedule.schedule_type, schedules.Crontab)):
            schedule_entry = kwargs.pop('schedule_entry', {})

            if schedule_entry:
                for k in schedule_entry:
                    if k not in ['minute', 'hour', 'day_of_week',
                                 'day_of_month', 'month_of_year']:
                        raise BadRequestError("Invalid key given: %s" % k)

                self.schedule.schedule_type = schedules.Crontab(
                    **schedule_entry)

        elif (schedule_type == 'interval' or
                type(self.schedule.schedule_type) == schedules.Interval):
            schedule_entry = kwargs.pop('schedule_entry', {})

            if schedule_entry:
                for k in schedule_entry:
                    if k not in ['period', 'every']:
                        raise BadRequestError("Invalid key given: %s" % k)

                self.schedule.schedule_type = schedules.Interval(
                    **schedule_entry)

        elif (schedule_type in ['one_off', 'reminder'] or
                type(self.schedule.schedule_type) == schedules.OneOff):
            # implements Interval under the hood
            future_date = kwargs.pop('schedule_entry', '')

            if future_date:
                try:
                    future_date = datetime.datetime.strptime(
                        future_date, '%Y-%m-%d %H:%M:%S')
                except ValueError:
                    raise BadRequestError('Date value was not valid')

                if future_date < now:
                    raise BadRequestError(
                        'Date of future task is in the past. '
                        'Please contact Marty McFly')

                delta = future_date - now
                notify_msg = kwargs.get('notify_msg', '')

                if schedule_type == 'reminder':
                    self.schedule.schedule_type = schedules.Reminder(
                        period='seconds',
                        every=delta.seconds,
                        entry=future_date,
                        message=notify_msg)
                else:
                    self.schedule.schedule_type = schedules.OneOff(
                        period='seconds',
                        every=delta.seconds,
                        entry=future_date)
                self.schedule.max_run_count = 1

                notify = kwargs.pop('notify', 0)
                if notify:
                    _delta = datetime.timedelta(0, notify)
                    notify_at = future_date - _delta
                    notify_at = notify_at.strftime('%Y-%m-%d %H:%M:%S')
                    params = {
                        'action': 'notify',
                        'schedule_type': 'reminder',
                        'description': 'Machine expiration reminder',
                        'task_enabled': True,
                        'schedule_entry': notify_at,
                        'conditions': kwargs.get('conditions'),
                        'notify_msg': notify_msg
                    }
                    name = self.schedule.name + '-reminder'
                    if self.schedule.reminder:
                        self.schedule.reminder.delete()
                    from mist.api.schedules.models import Schedule
                    self.schedule.reminder = Schedule.add(
                        auth_context, name, **params)

        # set schedule attributes
        try:
            kwargs.pop('conditions')
        except KeyError:
            pass
        for key, value in kwargs.items():
            if key in self.schedule._fields:
                setattr(self.schedule, key, value)

        try:
            self.schedule.save()
        except me.ValidationError as e:
            log.error("Error updating %s: %s", self.schedule.name,
                      e.to_dict())
            raise BadRequestError({"msg": str(e), "errors": e.to_dict()})
        except me.NotUniqueError as exc:
            log.error("Schedule %s not unique error: %s", self.schedule, exc)
            raise ScheduleNameExistsError()
        except me.OperationError:
            raise ScheduleOperationError()