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
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
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()
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
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()