def register(anarchy_run, runtime): runner_value = anarchy_run.metadata['labels'].get(runtime.runner_label, None) anarchy_subject_name = anarchy_run.subject_name anarchy_subject = AnarchySubject.get(anarchy_subject_name, runtime) if not anarchy_subject: operator_logger.warn( 'Unable to find AnarchySubject %s for AnarchyRun %s', anarchy_subject_name, anarchy_run.name ) return if not runner_value or runner_value == 'successful': return elif runner_value == 'failed': anarchy_subject.anarchy_run_update(anarchy_run, runtime) last_attempt = anarchy_run.run_post_datetime if last_attempt: if anarchy_run.failures > 9: retry_delay = timedelta(hours=1) else: retry_delay = timedelta(seconds=5 * 2**anarchy_run.failures) next_attempt = last_attempt + retry_delay else: next_attempt = datetime.utcnow() anarchy_subject.retry_after = next_attempt elif runner_value == 'lost': anarchy_subject.anarchy_run_update(anarchy_run, runtime) anarchy_subject.put_in_job_queue(runtime) elif runner_value == 'pending': anarchy_subject.enqueue_anarchy_run(anarchy_run, runtime) else: anarchy_subject.anarchy_run_update(anarchy_run, runtime)
def patch_or_delete_subject(subject_name): anarchy_runner, runner_pod = check_runner_auth( flask.request.headers.get('Authorization', '')) if not anarchy_runner: flask.abort(400) return if subject_name != runner_pod.metadata.labels.get(runtime.subject_label): operator_logger.warning( 'AnarchyRunner %s Pod %s cannot update AnarchySubject %s!', anarchy_runner.name, runner_pod.metadata.name, subject_name) flask.abort(400) return anarchy_subject = AnarchySubject.get(subject_name, runtime) if not anarchy_subject: operator_logger.warning( 'AnarchyRunner %s Pod %s attempted %s on deleted AnarchySubject %s!', anarchy_runner.name, runner_pod.metadata.name, flask.request.method, subject_name) flask.abort(400) return if flask.request.method == 'PATCH': if not 'patch' in flask.request.json: operator_logger.warning('No patch in AnarchySubject %s post', subject_name) flask.abort(400) return result = anarchy_subject.patch(flask.request.json['patch'], runtime) elif flask.request.method == 'DELETE': result = anarchy_subject.delete( flask.request.json.get('remove_finalizers', False), runtime) return flask.jsonify({'success': True, 'result': result})
def run_subject_action_patch(subject_name, action_name): """ Callback from runner to update AnarchyAction associated with AnarchySubject assigned to runner. The only function of this method currently is to pass JSON, `{"successful": true}` or `{"failed": true}` to mark the action as finished. """ anarchy_runner, runner_pod = check_runner_auth( flask.request.headers.get('Authorization', '')) if not anarchy_runner: flask.abort(400) if not runtime.running_all_in_one \ and subject_name != runner_pod.metadata.labels.get(runtime.subject_label): operator_logger.warning( 'AnarchyRunner %s Pod %s cannot update actions for AnarchySubject %s!', anarchy_runner.name, runner_pod.metadata.name, subject_name) flask.abort(400) anarchy_action = AnarchyAction.get(action_name, runtime) if not anarchy_action: operator_logger.warning( 'AnarchyRunner %s Pod %s attempted to update action on deleted AnarchyAction %s!', anarchy_runner.name, runner_pod.metadata.name, action_name) flask.abort(400) anarchy_subject = AnarchySubject.get(subject_name, runtime) if not anarchy_subject: operator_logger.warning( 'AnarchyRunner %s Pod %s attempted to update action on deleted AnarchySubject %s!', anarchy_runner.name, runner_pod.metadata.name, subject_name) flask.abort(400) anarchy_governor = anarchy_subject.get_governor(runtime) if not anarchy_governor: operator_logger.warning( 'AnarchyRunner %s Pod %s cannot post action to AnarchySubject %s, unable to find AnarchyGovernor %s!', anarchy_runner.name, runner_pod, subject_name, anarchy_subject.governor_name) flask.abort(400) finished_state = None if flask.request.json.get('successful', False): finished_state = 'successful' elif flask.request.json.get('failed', False): finished_state = 'failed' if finished_state != None: anarchy_subject.remove_active_action(anarchy_action, runtime) anarchy_action.set_finished(finished_state, runtime) return flask.jsonify({ 'success': True, 'result': anarchy_action.to_dict(runtime) })
def get_subject(self, runtime): return AnarchySubject.get(self.subject_name, runtime)
def post_subject_action(subject_name): anarchy_runner, runner_pod = check_runner_auth( flask.request.headers.get('Authorization', '')) if not anarchy_runner: flask.abort(400) return if subject_name != runner_pod.metadata.labels.get(runtime.subject_label): operator_logger.warning( 'AnarchyRunner %s Pod %s cannot update AnarchySubject %s!', anarchy_runner.name, runner_pod.metadata.name, subject_name) flask.abort(400) return anarchy_subject = AnarchySubject.get(subject_name, runtime) if not anarchy_subject: operator_logger.warning( 'AnarchyRunner %s Pod %s attempted to create action on deleted AnarchySubject %s!', anarchy_runner.name, runner_pod.metadata.name, subject_name) flask.abort(400) return anarchy_governor = anarchy_subject.get_governor(runtime) if not anarchy_governor: operator_logger.warning( 'AnarchyRunner %s Pod %s cannot post action to AnarchySubject %s, unable to find AnarchyGovernor %s!', anarchy_runner.name, runner_pod, subject_name, anarchy_subject.governor_name) flask.abort(400) return action_name = flask.request.json.get('action', None) after_timestamp = flask.request.json.get('after', None) cancel_actions = flask.request.json.get('cancel', None) if not action_name and not cancel_actions: operator_logger.warning( 'No action or cancel given for scheduling action') flask.abort(400) return if after_timestamp and not re.match(r'\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ', after_timestamp): operator_logger.warning( 'Invalide datetime format "%s" given for action after value', after_timestamp) flask.abort(400) return if action_name not in cancel_actions: cancel_actions.append(action_name) for action_resource in runtime.custom_objects_api.list_namespaced_custom_object( runtime.operator_domain, runtime.api_version, runtime.operator_namespace, 'anarchyactions', label_selector='{}/subject={}'.format(runtime.operator_domain, anarchy_subject.name)).get( 'items', []): if action_resource['spec']['action'] in cancel_actions \ and 'status' not in action_resource: runtime.custom_objects_api.delete_namespaced_custom_object( runtime.operator_domain, runtime.api_version, runtime.operator_namespace, 'anarchyactions', action_resource['metadata']['name']) if action_name: result = runtime.custom_objects_api.create_namespaced_custom_object( runtime.operator_domain, runtime.api_version, runtime.operator_namespace, 'anarchyactions', { "apiVersion": runtime.api_group_version, "kind": "AnarchyAction", "metadata": { "generateName": "%s-%s-" % (anarchy_subject.name, action_name), "labels": { runtime.action_label: action_name, runtime.subject_label: anarchy_subject.name, runtime.governor_label: anarchy_governor.name }, "ownerReferences": [{ "apiVersion": runtime.api_group_version, "controller": True, "kind": "AnarchySubject", "name": anarchy_subject.name, "uid": anarchy_subject.uid }] }, "spec": { "action": action_name, "after": after_timestamp, "callbackToken": uuid.uuid4().hex, "governorRef": { "apiVersion": runtime.api_group_version, "kind": "AnarchyGovernor", "name": anarchy_governor.name, "namespace": runtime.operator_namespace, "uid": anarchy_governor.uid }, "subjectRef": { "apiVersion": runtime.api_group_version, "kind": "AnarchySubject", "name": anarchy_subject.name, "namespace": runtime.operator_namespace, "uid": anarchy_subject.uid } } }) else: result = None return flask.jsonify({'success': True, 'result': result})