Documentation for Drydock Validate Design API
Change-Id: I10aa8ee6fca98168ac0a652e763d38322cd3220c
This commit is contained in:
parent
01549432b6
commit
d9b3a678ec
|
@ -73,3 +73,9 @@ object in details can be extended with additional fields as needed.
|
||||||
|
|
||||||
Once a POST containing the ``status`` field is made to a bootaction-id, that bootaction-id can no
|
Once a POST containing the ``status`` field is made to a bootaction-id, that bootaction-id can no
|
||||||
longer be updated with status changes nor additional detailed status messages.
|
longer be updated with status changes nor additional detailed status messages.
|
||||||
|
|
||||||
|
validatedesign API
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The Validatedesign API is used for validating documents before they will be used by Drydock. See
|
||||||
|
:ref:`validatedesign` for more details on validating documents.
|
||||||
|
|
|
@ -44,6 +44,7 @@ API Documentation
|
||||||
API
|
API
|
||||||
task
|
task
|
||||||
bootaction
|
bootaction
|
||||||
|
validatedesign
|
||||||
|
|
||||||
Client Documentation
|
Client Documentation
|
||||||
--------------------
|
--------------------
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
.. _validatedesign:
|
||||||
|
|
||||||
|
Validate Design
|
||||||
|
===============
|
||||||
|
|
||||||
|
The DryDock Validation API is a set of logic checks that must be passed before any information from the YAMLs will be
|
||||||
|
processed by Drydock. These checks are performed synchronously and will return a message list with a success or
|
||||||
|
failures for each check.
|
||||||
|
|
||||||
|
Formatting
|
||||||
|
----------
|
||||||
|
|
||||||
|
This document can be POSTed to the Drydock validatedesign to validate a set of documents that have been
|
||||||
|
processed by Deckhand::
|
||||||
|
|
||||||
|
{
|
||||||
|
rel : "design",
|
||||||
|
href: "deckhand+https://{{deckhand_url}}/revisions/{{revision_id}}/rendered-documents",
|
||||||
|
type: "application/x-yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
v1.0
|
||||||
|
----
|
||||||
|
|
||||||
|
Validation Checks
|
||||||
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
These checks are meant to check the business logic of documents sent to the validatedesign API.
|
||||||
|
|
||||||
|
.. autoclass:: drydock_provisioner.orchestrator.validations.validator.Validator
|
||||||
|
:members:
|
|
@ -56,7 +56,12 @@ class Validator():
|
||||||
@classmethod
|
@classmethod
|
||||||
def rational_network_bond(cls, site_design):
|
def rational_network_bond(cls, site_design):
|
||||||
"""
|
"""
|
||||||
Ensures that NetworkLink 'bonding' is rational
|
This check ensures that each NetworkLink has a rational bonding setup.
|
||||||
|
If the bonding mode is set to 'disabled' then it ensures that no other options are specified.
|
||||||
|
If the bonding mode it set to '802.3ad' then it ensures that the bonding up delay and the bonding down delay
|
||||||
|
are both greater then or equal to the mon rate.
|
||||||
|
If the bonding mode is set to active-backup or balanced-rr then it ensures that the bonding hash and the
|
||||||
|
bonding peer rate are both NOT defined.
|
||||||
"""
|
"""
|
||||||
message_list = []
|
message_list = []
|
||||||
site_design = site_design.obj_to_simple()
|
site_design = site_design.obj_to_simple()
|
||||||
|
@ -141,7 +146,8 @@ class Validator():
|
||||||
@classmethod
|
@classmethod
|
||||||
def network_trunking_rational(cls, site_design):
|
def network_trunking_rational(cls, site_design):
|
||||||
"""
|
"""
|
||||||
Ensures that Network Trunking is Rational
|
This check ensures that for each NetworkLink if the allowed networks are greater then 1 trunking mode is
|
||||||
|
enabled. It also makes sure that if trunking mode is disabled then a default network is defined.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
message_list = []
|
message_list = []
|
||||||
|
@ -190,7 +196,8 @@ class Validator():
|
||||||
@classmethod
|
@classmethod
|
||||||
def storage_partitioning(cls, site_design):
|
def storage_partitioning(cls, site_design):
|
||||||
"""
|
"""
|
||||||
Checks storage partitioning
|
This checks that for each storage device a partition list OR volume group is defined. Also for each partition
|
||||||
|
list it ensures that a file system and partition volume group are not defined in the same partition.
|
||||||
"""
|
"""
|
||||||
message_list = []
|
message_list = []
|
||||||
site_design = site_design.obj_to_simple()
|
site_design = site_design.obj_to_simple()
|
||||||
|
@ -249,8 +256,8 @@ class Validator():
|
||||||
if volume_group.get('name') not in volume_group_check_list:
|
if volume_group.get('name') not in volume_group_check_list:
|
||||||
|
|
||||||
msg = ('Storage Partitioning Error: A volume group must be assigned to a storage device or '
|
msg = ('Storage Partitioning Error: A volume group must be assigned to a storage device or '
|
||||||
'partition; volume group %s on BaremetalNode %s' %
|
'partition; volume group %s on BaremetalNode %s' % (volume_group.get('name'),
|
||||||
(volume_group.get('name'), baremetal_node.get('name')))
|
baremetal_node.get('name')))
|
||||||
|
|
||||||
message_list.append(
|
message_list.append(
|
||||||
TaskStatusMessage(
|
TaskStatusMessage(
|
||||||
|
@ -420,7 +427,9 @@ class Validator():
|
||||||
@classmethod
|
@classmethod
|
||||||
def no_duplicate_IPs_check(cls, site_design):
|
def no_duplicate_IPs_check(cls, site_design):
|
||||||
"""
|
"""
|
||||||
Ensures that the same IP is not assigned to multiple baremetal nodes.
|
Ensures that the same IP is not assigned to multiple baremetal node definitions by checking each new IP against
|
||||||
|
the list of known IPs. If the IP is unique no error is thrown and the new IP will be added to the list to be
|
||||||
|
checked against in the future.
|
||||||
"""
|
"""
|
||||||
found_ips = {} # Dictionary Format - IP address: BaremetalNode name
|
found_ips = {} # Dictionary Format - IP address: BaremetalNode name
|
||||||
message_list = []
|
message_list = []
|
||||||
|
@ -430,9 +439,7 @@ class Validator():
|
||||||
|
|
||||||
if not baremetal_nodes_list:
|
if not baremetal_nodes_list:
|
||||||
msg = 'No BaremetalNodes Found.'
|
msg = 'No BaremetalNodes Found.'
|
||||||
message_list.append(
|
message_list.append(TaskStatusMessage(msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||||
TaskStatusMessage(
|
|
||||||
msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
|
||||||
else:
|
else:
|
||||||
for node in baremetal_nodes_list:
|
for node in baremetal_nodes_list:
|
||||||
addressing_list = node.get('addressing', [])
|
addressing_list = node.get('addressing', [])
|
||||||
|
@ -443,19 +450,14 @@ class Validator():
|
||||||
|
|
||||||
if address in found_ips and address is not None:
|
if address in found_ips and address is not None:
|
||||||
msg = ('Error! Duplicate IP Address Found: %s '
|
msg = ('Error! Duplicate IP Address Found: %s '
|
||||||
'is in use by both %s and %s.'
|
'is in use by both %s and %s.' % (address, found_ips[address], node_name))
|
||||||
% (address, found_ips[address], node_name))
|
message_list.append(TaskStatusMessage(msg=msg, error=True, ctx_type='NA', ctx='NA'))
|
||||||
message_list.append(
|
|
||||||
TaskStatusMessage(
|
|
||||||
msg=msg, error=True, ctx_type='NA', ctx='NA'))
|
|
||||||
elif address is not None:
|
elif address is not None:
|
||||||
found_ips[address] = node_name
|
found_ips[address] = node_name
|
||||||
|
|
||||||
if not message_list:
|
if not message_list:
|
||||||
msg = 'No Duplicate IP Addresses.'
|
msg = 'No Duplicate IP Addresses.'
|
||||||
message_list.append(
|
message_list.append(TaskStatusMessage(msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||||
TaskStatusMessage(
|
|
||||||
msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
|
||||||
|
|
||||||
return message_list
|
return message_list
|
||||||
|
|
||||||
|
@ -523,7 +525,8 @@ class Validator():
|
||||||
@classmethod
|
@classmethod
|
||||||
def ip_locality_check(cls, site_design):
|
def ip_locality_check(cls, site_design):
|
||||||
"""
|
"""
|
||||||
Ensures that IP addresses are within defined CIDR ranges.
|
Ensures that each IP addresses assigned to a baremetal node is within the defined CIDR for the network. Also
|
||||||
|
verifies that the gateway IP for each static route of a network is within that network's CIDR.
|
||||||
"""
|
"""
|
||||||
network_dict = {} # Dictionary Format - network name: cidr
|
network_dict = {} # Dictionary Format - network name: cidr
|
||||||
message_list = []
|
message_list = []
|
||||||
|
@ -534,9 +537,7 @@ class Validator():
|
||||||
|
|
||||||
if not network_list:
|
if not network_list:
|
||||||
msg = 'No networks found.'
|
msg = 'No networks found.'
|
||||||
message_list.append(
|
message_list.append(TaskStatusMessage(msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||||
TaskStatusMessage(
|
|
||||||
msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
|
||||||
else:
|
else:
|
||||||
for net in network_list:
|
for net in network_list:
|
||||||
name = net.get('name')
|
name = net.get('name')
|
||||||
|
@ -552,23 +553,16 @@ class Validator():
|
||||||
|
|
||||||
if not gateway:
|
if not gateway:
|
||||||
msg = 'No gateway found for route %s.' % routes
|
msg = 'No gateway found for route %s.' % routes
|
||||||
message_list.append(
|
message_list.append(TaskStatusMessage(msg=msg, error=True, ctx_type='NA', ctx='NA'))
|
||||||
TaskStatusMessage(
|
|
||||||
msg=msg, error=True, ctx_type='NA', ctx='NA'))
|
|
||||||
else:
|
else:
|
||||||
ip = IPAddress(gateway)
|
ip = IPAddress(gateway)
|
||||||
if ip not in cidr_range:
|
if ip not in cidr_range:
|
||||||
msg = ('IP Locality Error: The gateway IP Address %s '
|
msg = ('IP Locality Error: The gateway IP Address %s '
|
||||||
'is not within the defined CIDR: %s of %s.'
|
'is not within the defined CIDR: %s of %s.' % (gateway, cidr, name))
|
||||||
% (gateway, cidr, name))
|
message_list.append(TaskStatusMessage(msg=msg, error=True, ctx_type='NA', ctx='NA'))
|
||||||
message_list.append(
|
|
||||||
TaskStatusMessage(
|
|
||||||
msg=msg, error=True, ctx_type='NA', ctx='NA'))
|
|
||||||
if not baremetal_nodes_list:
|
if not baremetal_nodes_list:
|
||||||
msg = 'No baremetal_nodes found.'
|
msg = 'No baremetal_nodes found.'
|
||||||
message_list.append(
|
message_list.append(TaskStatusMessage(msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||||
TaskStatusMessage(
|
|
||||||
msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
|
||||||
else:
|
else:
|
||||||
for node in baremetal_nodes_list:
|
for node in baremetal_nodes_list:
|
||||||
addressing_list = node.get('addressing', [])
|
addressing_list = node.get('addressing', [])
|
||||||
|
@ -582,23 +576,16 @@ class Validator():
|
||||||
if ip_address_network_name not in network_dict:
|
if ip_address_network_name not in network_dict:
|
||||||
msg = 'IP Locality Error: %s is not a valid network.' \
|
msg = 'IP Locality Error: %s is not a valid network.' \
|
||||||
% (ip_address_network_name)
|
% (ip_address_network_name)
|
||||||
message_list.append(
|
message_list.append(TaskStatusMessage(msg=msg, error=True, ctx_type='NA', ctx='NA'))
|
||||||
TaskStatusMessage(
|
|
||||||
msg=msg, error=True, ctx_type='NA', ctx='NA'))
|
|
||||||
else:
|
else:
|
||||||
if IPAddress(address) not in IPNetwork(network_dict[ip_address_network_name]):
|
if IPAddress(address) not in IPNetwork(network_dict[ip_address_network_name]):
|
||||||
msg = ('IP Locality Error: The IP Address %s '
|
msg = ('IP Locality Error: The IP Address %s '
|
||||||
'is not within the defined CIDR: %s of %s .'
|
'is not within the defined CIDR: %s of %s .' %
|
||||||
% (address, network_dict[ip_address_network_name],
|
(address, network_dict[ip_address_network_name], ip_address_network_name))
|
||||||
ip_address_network_name))
|
message_list.append(TaskStatusMessage(msg=msg, error=True, ctx_type='NA', ctx='NA'))
|
||||||
message_list.append(
|
|
||||||
TaskStatusMessage(
|
|
||||||
msg=msg, error=True, ctx_type='NA', ctx='NA'))
|
|
||||||
if not message_list:
|
if not message_list:
|
||||||
msg = 'IP Locality Success'
|
msg = 'IP Locality Success'
|
||||||
message_list.append(
|
message_list.append(TaskStatusMessage(msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||||
TaskStatusMessage(
|
|
||||||
msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
|
||||||
return message_list
|
return message_list
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue