Warn if there are not enough node IPs in pools
Enhance the network-validation with an additional check which ensures sufficient number of IPs for assigned nodes. Static IP pools are defined in the environments/ips-from-pool-all.yaml file in THT, and assigned nodes are saved in plan-environment.yaml. This change adds a check which compares the above values to ensure there are enough IPs allocated in each pool for every role. Change-Id: I63298a1bdd8ae793ec37070559537497e81b8ca4
This commit is contained in:
parent
bc3b90c2a8
commit
b870fd52bc
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Enhanced the network environment validation to validate the node IP pool
|
||||
size. Warnings are issued if there are not enough IPs in any pools for all
|
||||
assigned nodes.
|
|
@ -819,3 +819,119 @@ class TestDuplicateStaticIps(base.TestCase):
|
|||
}
|
||||
errors = validation.duplicate_static_ips(static_ips)
|
||||
self.assertEqual([], errors)
|
||||
|
||||
|
||||
class TestNodePoolSize(base.TestCase):
|
||||
def test_pool_size_ok(self):
|
||||
|
||||
plan_env_path = 'plan-environment.yaml'
|
||||
ip_pools_path = 'environments/ips-from-pool-all.yaml'
|
||||
plan_env_content = """parameter_defaults:
|
||||
BlockStorageCount: 0
|
||||
CephStorageCount: 0
|
||||
ComputeCount: 1
|
||||
ControllerCount: 1
|
||||
ObjectStorageCount: 0"""
|
||||
ip_pools_content = """parameter_defaults:
|
||||
ControllerIPs:
|
||||
external:
|
||||
- 10.0.0.251
|
||||
internal_api:
|
||||
- 172.16.2.251
|
||||
storage:
|
||||
- 172.16.1.251
|
||||
storage_mgmt:
|
||||
- 172.16.3.251
|
||||
tenant:
|
||||
- 172.16.0.251
|
||||
ComputeIPs:
|
||||
internal_api:
|
||||
- 172.16.2.252
|
||||
storage:
|
||||
- 172.16.1.252
|
||||
tenant:
|
||||
- 172.16.0.252"""
|
||||
template_files = {
|
||||
plan_env_path: plan_env_content,
|
||||
ip_pools_path: ip_pools_content
|
||||
}
|
||||
warnings = validation.validate_node_pool_size(
|
||||
plan_env_path, ip_pools_path, template_files)
|
||||
self.assertEqual(len(warnings), 0)
|
||||
|
||||
def test_pool_size_pool_too_small(self):
|
||||
plan_env_path = 'plan-environment.yaml'
|
||||
ip_pools_path = 'environments/ips-from-pool-all.yaml'
|
||||
plan_env_content = """parameter_defaults:
|
||||
BlockStorageCount: 0
|
||||
CephStorageCount: 0
|
||||
ComputeCount: 2
|
||||
ControllerCount: 1
|
||||
ObjectStorageCount: 0"""
|
||||
ip_pools_content = """parameter_defaults:
|
||||
ControllerIPs:
|
||||
external:
|
||||
- 10.0.0.251
|
||||
internal_api:
|
||||
- 172.16.2.251
|
||||
storage:
|
||||
- 172.16.1.251
|
||||
storage_mgmt:
|
||||
- 172.16.3.251
|
||||
tenant:
|
||||
- 172.16.0.251
|
||||
ComputeIPs:
|
||||
internal_api:
|
||||
- 172.16.2.252
|
||||
storage:
|
||||
- 172.16.1.252
|
||||
tenant:
|
||||
- 172.16.0.252"""
|
||||
template_files = {
|
||||
plan_env_path: plan_env_content,
|
||||
ip_pools_path: ip_pools_content
|
||||
}
|
||||
warnings = validation.validate_node_pool_size(
|
||||
plan_env_path, ip_pools_path, template_files)
|
||||
self.assertEqual(len(warnings), 3)
|
||||
self.assertEqual(set(warnings), {
|
||||
"Insufficient number of IPs in 'internal_api' pool for 'Compute' "
|
||||
"role: 1 IP(s) found in pool, but 2 nodes assigned to role.",
|
||||
"Insufficient number of IPs in 'storage' pool for 'Compute' "
|
||||
"role: 1 IP(s) found in pool, but 2 nodes assigned to role.",
|
||||
"Insufficient number of IPs in 'tenant' pool for 'Compute' "
|
||||
"role: 1 IP(s) found in pool, but 2 nodes assigned to role."
|
||||
})
|
||||
|
||||
def test_pool_size_pool_missing(self):
|
||||
plan_env_path = 'plan-environment.yaml'
|
||||
ip_pools_path = 'environments/ips-from-pool-all.yaml'
|
||||
plan_env_content = """parameter_defaults:
|
||||
BlockStorageCount: 0
|
||||
CephStorageCount: 0
|
||||
ComputeCount: 1
|
||||
ControllerCount: 1
|
||||
ObjectStorageCount: 0"""
|
||||
ip_pools_content = """parameter_defaults:
|
||||
ControllerIPs:
|
||||
external:
|
||||
- 10.0.0.251
|
||||
internal_api:
|
||||
- 172.16.2.251
|
||||
storage:
|
||||
- 172.16.1.251
|
||||
storage_mgmt:
|
||||
- 172.16.3.251
|
||||
tenant:
|
||||
- 172.16.0.251"""
|
||||
template_files = {
|
||||
plan_env_path: plan_env_content,
|
||||
ip_pools_path: ip_pools_content
|
||||
}
|
||||
warnings = validation.validate_node_pool_size(
|
||||
plan_env_path, ip_pools_path, template_files)
|
||||
self.assertEqual(len(warnings), 1)
|
||||
self.assertEqual(warnings, [
|
||||
"Found 1 node(s) assigned to 'Compute' role, but no static IP "
|
||||
"pools defined."
|
||||
])
|
||||
|
|
|
@ -33,11 +33,21 @@ short_description: Validate networking templates
|
|||
description:
|
||||
- Performs networking-related checks on a set of TripleO templates
|
||||
options:
|
||||
path:
|
||||
netenv_path:
|
||||
required: true
|
||||
description:
|
||||
- The path of the base network environment file
|
||||
type: str
|
||||
plan_env_path:
|
||||
required: true
|
||||
description:
|
||||
- The path of the plan environment file
|
||||
type: str
|
||||
ip_pools_path:
|
||||
required: true
|
||||
description:
|
||||
- The path of the IP pools network environment file
|
||||
type: str
|
||||
template_files:
|
||||
required: true
|
||||
description:
|
||||
|
@ -51,8 +61,10 @@ EXAMPLES = '''
|
|||
tasks:
|
||||
- name: Check the Network environment
|
||||
network_environment:
|
||||
path: environments/network-environment.yaml
|
||||
netenv_path: environments/network-environment.yaml
|
||||
template_files: "{{ lookup('tht') }}"
|
||||
plan_env_path: plan-environment.yaml
|
||||
ip_pools_path: environments/ips-from-pool-all.yaml
|
||||
'''
|
||||
|
||||
|
||||
|
@ -446,23 +458,82 @@ def duplicate_static_ips(static_ips):
|
|||
return errors
|
||||
|
||||
|
||||
def validate_node_pool_size(plan_env_path, ip_pools_path, template_files):
|
||||
warnings = []
|
||||
plan_env = yaml.load(template_files[plan_env_path])
|
||||
ip_pools = yaml.load(template_files[ip_pools_path])
|
||||
|
||||
param_defaults = plan_env.get('parameter_defaults')
|
||||
node_counts = {
|
||||
param.replace('Count', ''): count
|
||||
for param, count in six.iteritems(param_defaults)
|
||||
if param.endswith('Count') and count > 0
|
||||
}
|
||||
|
||||
# TODO(akrivoka): There are a lot of inconsistency issues with parameter
|
||||
# naming in THT :( Once those issues are fixed, this block should be
|
||||
# removed.
|
||||
if 'ObjectStorage' in node_counts:
|
||||
node_counts['SwiftStorage'] = node_counts['ObjectStorage']
|
||||
del node_counts['ObjectStorage']
|
||||
|
||||
param_defaults = ip_pools.get('parameter_defaults')
|
||||
role_pools = {
|
||||
param.replace('IPs', ''): pool
|
||||
for param, pool in six.iteritems(param_defaults)
|
||||
if param.endswith('IPs') and param.replace('IPs', '') in node_counts
|
||||
}
|
||||
|
||||
for role, node_count in six.iteritems(node_counts):
|
||||
try:
|
||||
pools = role_pools[role]
|
||||
except KeyError:
|
||||
warnings.append(
|
||||
"Found {} node(s) assigned to '{}' role, but no static IP "
|
||||
"pools defined.".format(node_count, role)
|
||||
)
|
||||
continue
|
||||
for pool_name, pool_ips in six.iteritems(pools):
|
||||
if len(pool_ips) < node_count:
|
||||
warnings.append(
|
||||
"Insufficient number of IPs in '{}' pool for '{}' role: "
|
||||
"{} IP(s) found in pool, but {} nodes assigned to role."
|
||||
.format(pool_name, role, len(pool_ips), node_count)
|
||||
)
|
||||
|
||||
return warnings
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(argument_spec=dict(
|
||||
path=dict(required=True, type='str'),
|
||||
netenv_path=dict(required=True, type='str'),
|
||||
plan_env_path=dict(required=True, type='str'),
|
||||
ip_pools_path=dict(required=True, type='str'),
|
||||
template_files=dict(required=True, type='list')
|
||||
))
|
||||
|
||||
netenv_path = module.params.get('path')
|
||||
netenv_path = module.params.get('netenv_path')
|
||||
plan_env_path = module.params.get('plan_env_path')
|
||||
ip_pools_path = module.params.get('ip_pools_path')
|
||||
template_files = {name: content[1] for (name, content) in
|
||||
module.params.get('template_files')}
|
||||
|
||||
errors = validate(netenv_path, template_files)
|
||||
warnings = []
|
||||
|
||||
try:
|
||||
warnings = validate_node_pool_size(plan_env_path, ip_pools_path,
|
||||
template_files)
|
||||
except Exception as e:
|
||||
errors.append("{}".format(e))
|
||||
|
||||
if errors:
|
||||
module.fail_json(msg="\n".join(errors))
|
||||
else:
|
||||
module.exit_json(msg="No errors found for the '{}' file.".format(
|
||||
netenv_path))
|
||||
module.exit_json(
|
||||
msg="No errors found for the '{}' file.".format(netenv_path),
|
||||
warnings=warnings,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -15,8 +15,12 @@
|
|||
groups:
|
||||
- pre-deployment
|
||||
network_environment_path: environments/network-environment.yaml
|
||||
plan_env_path: plan-environment.yaml
|
||||
ip_pools_path: environments/ips-from-pool-all.yaml
|
||||
tasks:
|
||||
- name: Validate the network environment files
|
||||
network_environment:
|
||||
path: "{{ network_environment_path }}"
|
||||
netenv_path: "{{ network_environment_path }}"
|
||||
plan_env_path: "{{ plan_env_path }}"
|
||||
ip_pools_path: "{{ ip_pools_path }}"
|
||||
template_files: "{{ lookup('tht') }}"
|
||||
|
|
Loading…
Reference in New Issue