Add support for properties that span across all action of a job

Added support for action_defaults

Change-Id: Iccc6faf6472cce12c69d4bcbe7fe05cffa902df1
This commit is contained in:
Pierre-Arthur MATHIEU 2015-11-23 14:03:38 +00:00
parent f86560268e
commit bdb743aef6
4 changed files with 114 additions and 10 deletions

View File

@ -566,6 +566,71 @@ Finished job with result::
}
8.2 Actions default value
-------------------------
It is possible to define properties that span accross multiple actions
This allow not to rewrite values that might be the same in multiple actions.
If properties are specificaly set in one action, then the specified value is the one used.
Example::
"job": {
"action_defaults": {
"log_file": "/tmp/freezer_tmp_log",
"container": "my_backup_container"
},
"job_actions":
[
{"freezer_action":{
"action" : "backup",
"mode" : "fs",
"src_file" : "/home/user1/file",
"backup_name" : "user1_backup"}},
{"freezer_action":{
"action" : "backup",
"mode" : "fs",
"src_file" : "/home/user2/file",
"backup_name" : "user2_backup"}},
{"freezer_action":{
"action" : "backup",
"mode" : "fs",
"src_file" : "/home/user3/file",
"backup_name" : "user2_backup",
"log_file" : "/home/user3/specific_log_file" }}
]
"description": "scheduled one shot"
}
Is Equivalent to::
"job": {
"job_actions":
[
{"freezer_action":{
"action" : "backup",
"mode" : "fs",
"src_file" : "/home/user1/file",
"backup_name" : "user1_backup",
"log_file": "/tmp/freezer_tmp_log",
"container": "my_backup_container"}},
{"freezer_action":{
"action" : "backup",
"mode" : "fs",
"src_file" : "/home/user2/file",
"backup_name" : "user2_backup",
"log_file": "/tmp/freezer_tmp_log",
"container": "my_backup_container"}},
{"freezer_action":{
"action" : "backup",
"mode" : "fs",
"src_file" : "/home/user3/file",
"backup_name" : "user2_backup",
"log_file" : "/home/user3/specific_log_file",
"container": "my_backup_container"}},
]
"description": "scheduled one shot"
}
9 Actions
=========

View File

@ -79,14 +79,14 @@ class JobsCollectionResource(JobsBaseResource):
def on_post(self, req, resp):
# POST /v1/jobs Creates job entry
try:
doc = self.json_body(req)
job = Job(self.json_body(req))
except KeyError:
raise freezer_api_exc.BadDataFormat(
message='Missing request body')
user_id = req.get_header('X-User-ID')
self.update_actions_in_job(user_id, doc)
job_id = self.db.add_job(user_id=user_id, doc=doc)
self.update_actions_in_job(user_id, job.doc)
job_id = self.db.add_job(user_id=user_id, doc=job.doc)
resp.status = falcon.HTTP_201
resp.body = {'job_id': job_id}
@ -116,21 +116,21 @@ class JobsResource(JobsBaseResource):
def on_patch(self, req, resp, job_id):
# PATCH /v1/jobs/{job_id} updates the specified job
user_id = req.get_header('X-User-ID') or ''
doc = self.json_body(req)
self.update_actions_in_job(user_id, doc)
job = Job(self.json_body(req))
self.update_actions_in_job(user_id, job.doc)
new_version = self.db.update_job(user_id=user_id,
job_id=job_id,
patch_doc=doc)
patch_doc=job.doc)
resp.body = {'job_id': job_id, 'version': new_version}
def on_post(self, req, resp, job_id):
# PUT /v1/jobs/{job_id} creates/replaces the specified job
user_id = req.get_header('X-User-ID') or ''
doc = self.json_body(req)
self.update_actions_in_job(user_id, doc)
job = Job(self.json_body(req))
self.update_actions_in_job(user_id, job.doc)
new_version = self.db.replace_job(user_id=user_id,
job_id=job_id,
doc=doc)
doc=job.doc)
resp.status = falcon.HTTP_201
resp.body = {'job_id': job_id, 'version': new_version}
@ -215,6 +215,8 @@ class Job(object):
"""
def __init__(self, doc):
self.doc = doc
if self.doc.get("action_defaults") is not None:
self.expand_default_properties()
self.event_result = ''
self.need_update = False
if 'job_schedule' not in doc:
@ -282,3 +284,14 @@ class Job(object):
"""
for action_doc in self.doc.get('job_actions', []):
yield Action(action_doc)
def expand_default_properties(self):
action_defaults = self.doc.pop("action_defaults")
if isinstance(action_defaults, dict):
for key, val in action_defaults.items():
for action in self.doc.get("job_actions"):
if action["freezer_action"].get(key) is None:
action["freezer_action"][key] = val
else:
raise freezer_api_exc.BadDataForma(message="action_defaults should"
"be a dictionary")

View File

@ -215,6 +215,9 @@ job_schema = {
"_version": {
"id": "_version",
"type": "integer"
},
"action_defaults": {
"$ref": "#/definitions/freezer_action"
}
},
"additionalProperties": False,
@ -304,6 +307,9 @@ job_patch_schema = {
"_version": {
"id": "_version",
"type": "integer"
},
"action_defaults": {
"$ref": "#/definitions/freezer_action"
}
},
"additionalProperties": False

View File

@ -204,7 +204,8 @@ class TestJobsResource(unittest.TestCase):
new_version = random.randint(0, 99)
self.mock_db.update_job.return_value = new_version
patch_doc = {'some_field': 'some_value',
'because': 'size_matters'}
'because': 'size_matters',
'job_schedule': {}}
self.mock_req.stream.read.return_value = json.dumps(patch_doc)
expected_result = {'job_id': fake_job_0_job_id,
'version': new_version}
@ -472,3 +473,22 @@ class TestJobs(unittest.TestCase):
def test_execute_raises_BadDataFormat_when_event_not_implemented(self):
job = v1_jobs.Job({})
self.assertRaises(BadDataFormat, job.execute_event, 'smile', 'my_params')
def test_expand_action_defaults(self):
job_doc = {
'action_defaults': {'that_field': 'that_value'},
'job_actions': [
{'freezer_action': {'not_that_field': 'some_value'}},
{'freezer_action': {'that_field': 'another_value'}}
]
}
expected_job_doc = {
'job_actions': [
{'freezer_action': {'not_that_field': 'some_value',
'that_field': 'that_value'}},
{'freezer_action': {'that_field': 'another_value'}}
],
'job_schedule': {}
}
job = v1_jobs.Job(job_doc)
self.assertEqual(job.doc, expected_job_doc)