Skip to content

Commit

Permalink
Merge 96eea46 into 5998257
Browse files Browse the repository at this point in the history
  • Loading branch information
mohierf committed Apr 18, 2018
2 parents 5998257 + 96eea46 commit 27870e8
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 70 deletions.
96 changes: 44 additions & 52 deletions alignak_backend/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,14 @@ def get_inherited_fields(item, fields, tpl_type='host'):
if field_name not in fields:
continue
if isinstance(field_value, dict):
fields[field_name].update(field_value)
# Update a dictionary makes it take the value of the 'oldest' template.
# We do not want this, we want to get the 'youngest' value... so iterate
# the dictionary keys to update only if it does not still exist
# saved = deepcopy(field_value)
for key in field_value:
if key not in fields[field_name]:
fields[field_name][key] = field_value[key]
# fields[field_name].update(field_value)
elif isinstance(field_value, list):
fields[field_name][:0] = field_value

Expand Down Expand Up @@ -433,11 +440,7 @@ def fill_template_host(item): # pylint: disable=too-many-locals
not_updated_fields.append(field_name)
item['_template_fields'] = []

# Whether host is a template or not...
is_a_template = False
if '_is_template' in item:
is_a_template = item['_is_template']

# If has some templates...
if '_templates' in item and item['_templates']:
for host_template in item['_templates']:
if not ObjectId.is_valid(host_template):
Expand All @@ -454,18 +457,17 @@ def fill_template_host(item): # pylint: disable=too-many-locals
item[field_name] = field_value
item['_template_fields'].append(field_name)

# Cumulate fields only if item is not a template
if not is_a_template:
Template.get_inherited_fields(item, cumulated_fields, tpl_type='host')
for (field_name, field_value) in iteritems(cumulated_fields):
if isinstance(field_value, dict):
item[field_name] = field_value
elif isinstance(field_value, list):
seen = set()
seen_add = seen.add
item[field_name] = [x for x in field_value
if not (x in seen or seen_add(x))]
item['_template_fields'].append(field_name)
# Cumulate fields from inherited templates
Template.get_inherited_fields(item, cumulated_fields, tpl_type='host')
for (field_name, field_value) in iteritems(cumulated_fields):
if isinstance(field_value, dict):
item[field_name] = field_value
elif isinstance(field_value, list):
seen = set()
seen_add = seen.add
item[field_name] = [x for x in field_value
if not (x in seen or seen_add(x))]
item['_template_fields'].append(field_name)

schema = host_schema()
for key in schema['schema']:
Expand Down Expand Up @@ -527,11 +529,7 @@ def fill_template_service(item): # pylint: disable=too-many-locals
not_updated_fields.append(field_name)
item['_template_fields'] = []

# Whether service is a template or not...
is_a_template = False
if '_is_template' in item:
is_a_template = item['_is_template']

# If has some templates...
if '_templates' in item and item['_templates'] != []:
for service_template in item['_templates']:
if not ObjectId.is_valid(service_template):
Expand All @@ -547,18 +545,17 @@ def fill_template_service(item): # pylint: disable=too-many-locals
item[field_name] = field_value
item['_template_fields'].append(field_name)

# Cumulate fields only if item is not a template
if not is_a_template:
Template.get_inherited_fields(item, cumulated_fields, tpl_type='service')
for (field_name, field_value) in iteritems(cumulated_fields):
if isinstance(field_value, dict):
item[field_name] = field_value
elif isinstance(field_value, list):
seen = set()
seen_add = seen.add
item[field_name] = [x for x in field_value
if not (x in seen or seen_add(x))]
item['_template_fields'].append(field_name)
# Cumulate fields from inherited templates
Template.get_inherited_fields(item, cumulated_fields, tpl_type='service')
for (field_name, field_value) in iteritems(cumulated_fields):
if isinstance(field_value, dict):
item[field_name] = field_value
elif isinstance(field_value, list):
seen = set()
seen_add = seen.add
item[field_name] = [x for x in field_value
if not (x in seen or seen_add(x))]
item['_template_fields'].append(field_name)

schema = service_schema()
for key in schema['schema']:
Expand Down Expand Up @@ -661,11 +658,7 @@ def fill_template_user(item): # pylint: disable=too-many-locals
not_updated_fields.append(field_name)
item['_template_fields'] = []

# Whether user is a template or not...
is_a_template = False
if '_is_template' in item:
is_a_template = item['_is_template']

# If has some templates...
if '_templates' in item and item['_templates']:
for user_template in item['_templates']:
if not ObjectId.is_valid(user_template):
Expand All @@ -680,18 +673,17 @@ def fill_template_user(item): # pylint: disable=too-many-locals
item[field_name] = field_value
item['_template_fields'].append(field_name)

# Cumulate fields only if item is not a template
if not is_a_template:
Template.get_inherited_fields(item, cumulated_fields, tpl_type='user')
for (field_name, field_value) in iteritems(cumulated_fields):
if isinstance(field_value, dict):
item[field_name] = field_value
elif isinstance(field_value, list):
seen = set()
seen_add = seen.add
item[field_name] = [x for x in field_value
if not (x in seen or seen_add(x))]
item['_template_fields'].append(field_name)
# Cumulate fields from inherited templates
Template.get_inherited_fields(item, cumulated_fields, tpl_type='user')
for (field_name, field_value) in iteritems(cumulated_fields):
if isinstance(field_value, dict):
item[field_name] = field_value
elif isinstance(field_value, list):
seen = set()
seen_add = seen.add
item[field_name] = [x for x in field_value
if not (x in seen or seen_add(x))]
item['_template_fields'].append(field_name)

schema = user_schema()
for key in schema['schema']:
Expand Down
172 changes: 154 additions & 18 deletions test/test_hook_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def setUpClass(cls):
cls.p = subprocess.Popen(['uwsgi', '--plugin', 'python', '-w', 'alignak_backend.app:app',
'--socket', '0.0.0.0:5000',
'--protocol=http', '--enable-threads', '--pidfile',
'/tmp/uwsgi.pid'])
'/tmp/uwsgi.pid', '--logto', '/tmp/alignak-backend.log'])
time.sleep(3)

cls.endpoint = 'http://127.0.0.1:5000'
Expand Down Expand Up @@ -215,7 +215,7 @@ def test_host_templates_with_templates(self):
'check_command': rc[2]['_id'],
'_is_template': True,
'tags': ['tag-1'],
'customs': {'key1': 'value1'},
'customs': {'key1': 'value1-A', 'key2': 'value2'},
'_realm': self.realm_all
}
response = requests.post(self.endpoint + '/host', json=data, headers=headers,
Expand All @@ -234,7 +234,7 @@ def test_host_templates_with_templates(self):

# The host template has some specific fields
self.assertEqual(rh[1]['tags'], ['tag-1'])
self.assertEqual(rh[1]['customs'], {'key1': 'value1'})
self.assertEqual(rh[1]['customs'], {'key1': 'value1-A', 'key2': 'value2'})

# Create a service template linked to the newly created host template
data = {
Expand All @@ -251,7 +251,7 @@ def test_host_templates_with_templates(self):
response = requests.get(self.endpoint + '/service', params=sort_id, auth=self.auth)
resp = response.json()
rs = resp['_items']
# Only 1 service in the backend, and it is the newly created service template
# Only 1 service template in the backend, and it is the newly created service template
self.assertEqual(len(rs), 1)
self.assertEqual(rs[0]['name'], "service-tpl-A")
self.assertEqual(rs[0]['_is_template'], True)
Expand All @@ -263,7 +263,7 @@ def test_host_templates_with_templates(self):
'_is_template': True,
'_templates': [host_template_id],
'tags': ['tag-2', 'tag-3'],
'customs': {'key2': 'value2', 'key3': 'value3'},
'customs': {'key1': 'value1-A-1', 'key3': 'value3'},
'_realm': self.realm_all
}
response = requests.post(self.endpoint + '/host', json=data, headers=headers,
Expand All @@ -287,22 +287,32 @@ def test_host_templates_with_templates(self):
template_fields_ref = []
for key in schema['schema']:
if not key.startswith('_') and not key.startswith('ls_'):
template_fields_ref.append(key)
# we remove in reference the fields defined in the host directly
template_fields_ref.append(unicode(key))

# We remove in reference the fields defined in the host directly
if 'name' in template_fields_ref:
template_fields_ref.remove('name')
if 'check_command' in template_fields_ref:
template_fields_ref.remove('check_command')
if 'tags' in template_fields_ref:
template_fields_ref.remove('tags')
if 'customs' in template_fields_ref:
template_fields_ref.remove('customs')
# we compare the _template_fields in the backend and our reference

# Not for customs nor tags because they are cumulative fields inherited from the templates!
# if 'tags' in template_fields_ref:
# template_fields_ref.remove('tags')
# if 'customs' in template_fields_ref:
# template_fields_ref.remove('customs')

# we compare the _template_fields in the backend and our reference:
# host fields should not be in the template_fields
self.assertItemsEqual(rh[2]['_template_fields'], template_fields_ref)

# The host template has some specific fields and cumulated fields are not inherited
self.assertEqual(rh[2]['tags'], ['tag-2', 'tag-3'])
self.assertEqual(rh[2]['customs'], {'key2': 'value2', 'key3': 'value3'})
# - tag-1 inherited from the template A ! And tag-2/tag-3 from itself
self.assertEqual(rh[2]['tags'], ['tag-1', 'tag-2', 'tag-3'])
# - key1 and key3 values from the the template A ! And key2 from itself
# The new template value takes precedence !
self.assertEqual(rh[2]['customs'], {'key1': 'value1-A-1',
'key2': 'value2',
'key3': 'value3'})

host_template_id = rh[2]['_id']

Expand Down Expand Up @@ -333,7 +343,9 @@ def test_host_templates_with_templates(self):
data = {
'name': 'host-1',
'_templates': [host_template_id],
'_realm': self.realm_all
'_realm': self.realm_all,
'tags': ['tag-host', 'tag-host2'],
'customs': {'key1': 'value1-host', 'key4': 'value4'},
}
response = requests.post(self.endpoint + '/host', json=data,
headers=headers, auth=self.auth)
Expand All @@ -358,9 +370,11 @@ def test_host_templates_with_templates(self):
# we compare the _template_fields in the backend and our reference
self.assertItemsEqual(rh[3]['_template_fields'], template_fields_ref)

# The host has some fields that were cumulated from its linked template
self.assertEqual(rh[3]['tags'], ['tag-1', 'tag-2', 'tag-3'])
self.assertEqual(rh[3]['customs'], {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'})
# The host has some fields that were inherited from its linked templates and from itself
self.assertEqual(rh[3]['tags'], ['tag-1', 'tag-2', 'tag-3',
'tag-host', 'tag-host2'])
self.assertEqual(rh[3]['customs'], {'key1': 'value1-host', 'key2': 'value2',
'key3': 'value3', 'key4': 'value4'})
self.assertEqual(rh[3]['check_command'], rc[1]['_id'])

# Check that services got created
Expand All @@ -382,6 +396,128 @@ def test_host_templates_with_templates(self):
self.assertIn(rs[2]['name'], ["service-tpl-A", "service-tpl-B"])
self.assertEqual(rs[3]['_is_template'], False)

def test_host_templates_with_templates_no_check_command(self):
"""Test host templates linked to other templates - one of them do not have a check comand
Test templates ordering for check_command and custom values overriding
:return: None
"""
headers = {'Content-Type': 'application/json'}
sort_id = {'sort': '_id'}
# Add command
data = json.loads(open('cfg/command_ping.json').read())
data['_realm'] = self.realm_all
requests.post(self.endpoint + '/command', json=data, headers=headers, auth=self.auth)
# Check if command right in backend
response = requests.get(self.endpoint + '/command', params=sort_id, auth=self.auth)
resp = response.json()
self.assertEqual(len(resp['_items']), 3)
rc = resp['_items']
self.assertEqual(rc[2]['name'], "ping")

# Create a template
data = {
'name': 'tpl-X',
'check_command': rc[2]['_id'],
'_is_template': True,
'tags': ['tag-1'],
'customs': {'key1': 'value1-x'},
'_realm': self.realm_all
}
response = requests.post(self.endpoint + '/host', json=data, headers=headers,
auth=self.auth)
resp = response.json()
self.assertEqual('OK', resp['_status'], resp)

# Check if host template is in the backend
response = requests.get(self.endpoint + '/host', params=sort_id, auth=self.auth)
resp = response.json()
rh = resp['_items']
host_template_id = rh[1]['_id']

# Create a service template linked to the newly created host template
data = {
'name': 'service-tpl-X',
'host': host_template_id,
'check_command': rc[2]['_id'],
'_is_template': True,
'_realm': self.realm_all
}
ret = requests.post(self.endpoint + '/service', json=data, headers=headers, auth=self.auth)
resp = ret.json()
self.assertEqual(resp['_status'], 'OK')

# Create a second host template NOT templated from the first one - no check_command
data = {
'name': 'tpl-Y',
'check_command': None,
'_is_template': True,
'tags': ['tag-2', 'tag-3'],
'customs': {'key1': 'value1-y', 'key2': 'value2'},
'_realm': self.realm_all
}
response = requests.post(self.endpoint + '/host', json=data, headers=headers,
auth=self.auth)
resp = response.json()
self.assertEqual('OK', resp['_status'], resp)

# Check if host template is in the backend
response = requests.get(self.endpoint + '/host', params=sort_id, auth=self.auth)
resp = response.json()
rh = resp['_items']
host_template_id2 = rh[2]['_id']

# Create an host linked to both templates
data = {
'name': 'host-X-Y',
'_templates': [host_template_id2, host_template_id],
'_realm': self.realm_all
}
response = requests.post(self.endpoint + '/host', json=data,
headers=headers, auth=self.auth)
resp = response.json()
self.assertEqual(resp['_status'], 'OK')

response = requests.get(self.endpoint + '/host', params=sort_id, auth=self.auth)
resp = response.json()
rh = resp['_items']
self.assertEqual(rh[1]['name'], "tpl-X")
self.assertEqual(rh[2]['name'], "tpl-Y")
self.assertEqual(rh[3]['name'], "host-X-Y")

# The host has some fields that were cumulated from its linked template
self.assertEqual(set(rh[3]['tags']), set(['tag-1', 'tag-2', 'tag-3']))
self.assertEqual(rh[3]['customs'], {'key1': 'value1-y', 'key2': 'value2'})
# Inherited check command is the one defined in the last template in the templates list!
# Issue #503!
self.assertEqual(rh[3]['check_command'], rc[2]['_id'])

# Create an host linked to both templates - reverse templates order
data = {
'name': 'host-Y-X',
'_templates': [host_template_id, host_template_id2],
'_realm': self.realm_all
}
response = requests.post(self.endpoint + '/host', json=data,
headers=headers, auth=self.auth)
resp = response.json()
self.assertEqual(resp['_status'], 'OK')

response = requests.get(self.endpoint + '/host', params=sort_id, auth=self.auth)
resp = response.json()
rh = resp['_items']
self.assertEqual(rh[1]['name'], "tpl-X")
self.assertEqual(rh[2]['name'], "tpl-Y")
self.assertEqual(rh[3]['name'], "host-X-Y")
self.assertEqual(rh[4]['name'], "host-Y-X")

# The host has some fields that were cumulated from its linked template
self.assertEqual(set(rh[4]['tags']), set(['tag-1', 'tag-2', 'tag-3']))
self.assertEqual(rh[4]['customs'], {'key1': 'value1-x', 'key2': 'value2'})
# Inherited check command is the one defined in the last template in the templates list!
# Issue #504!
self.assertEqual(rh[4]['check_command'], None)

def test_host_multiple_template_update(self):
"""Test the host have multiple templates and modify field in first or second and
update the field in the host - order of templates list is important
Expand Down

0 comments on commit 27870e8

Please sign in to comment.