Support image and kernel selection
- Image selection based of Ubuntu series name (e.g. 'xenial') - Kernel selection based on MAAS kernel names of 'ga-16.04' or 'hwe-16.04' - Validation that defined images and kernels are valid in the current node driver - Unit test for the validation Change-Id: I6256a2e00a4594af38a2d862c738e03efb7ddb29
This commit is contained in:
parent
1804203ea1
commit
4a1367a39a
3
.gitignore
vendored
3
.gitignore
vendored
@ -101,3 +101,6 @@ ENV/
|
||||
|
||||
# IDEA IDE
|
||||
.idea/
|
||||
|
||||
# VIM
|
||||
.*.swp
|
||||
|
@ -57,3 +57,17 @@ class NodeDriver(ProviderDriver):
|
||||
else:
|
||||
raise errors.DriverError("Unsupported action %s for driver %s" %
|
||||
(task_action, self.driver_desc))
|
||||
|
||||
def get_available_images(self):
|
||||
"""Return images that can be deployed to nodes by this driver."""
|
||||
|
||||
return []
|
||||
|
||||
def get_available_kernels(self, image):
|
||||
"""Return a list of kernels that can be specified for deployment.
|
||||
|
||||
:param image: str specifying what image the kernel will be activated
|
||||
within
|
||||
"""
|
||||
|
||||
return []
|
||||
|
@ -1801,10 +1801,11 @@ class DeployNode(BaseMaasAction):
|
||||
"Error setting boot action id key tag for %s." % n.name,
|
||||
exc_info=ex)
|
||||
|
||||
self.logger.info("Deploying node %s" % (n.name))
|
||||
self.logger.info("Deploying node %s: image=%s, kernel=%s" %
|
||||
(n.name, n.image, n.kernel))
|
||||
|
||||
try:
|
||||
machine.deploy()
|
||||
machine.deploy(platform=n.image, kernel=n.kernel)
|
||||
except errors.DriverError:
|
||||
msg = "Error deploying node %s, skipping" % n.name
|
||||
self.logger.warning(msg)
|
||||
|
@ -176,6 +176,7 @@ class MaasRequestFactory(object):
|
||||
self.logger.debug(
|
||||
"Received error response - URL: %s %s - RESPONSE: %s" %
|
||||
(prepared_req.method, prepared_req.url, resp.status_code))
|
||||
self.logger.debug("Response content: %s" % resp.text)
|
||||
raise errors.DriverError("MAAS Error: %s - %s" % (resp.status_code,
|
||||
resp.text))
|
||||
return resp
|
||||
|
@ -24,6 +24,7 @@ import drydock_provisioner.config as config
|
||||
|
||||
from drydock_provisioner.drivers.node.driver import NodeDriver
|
||||
from drydock_provisioner.drivers.node.maasdriver.api_client import MaasRequestFactory
|
||||
from drydock_provisioner.drivers.node.maasdriver.models.boot_resource import BootResources
|
||||
|
||||
from .actions.node import ValidateNodeServices
|
||||
from .actions.node import CreateStorageTemplate
|
||||
@ -207,6 +208,31 @@ class MaasNodeDriver(NodeDriver):
|
||||
|
||||
return
|
||||
|
||||
def get_available_images(self):
|
||||
"""Return images available in MAAS."""
|
||||
maas_client = MaasRequestFactory(
|
||||
config.config_mgr.conf.maasdriver.maas_api_url,
|
||||
config.config_mgr.conf.maasdriver.maas_api_key)
|
||||
|
||||
br = BootResources(maas_client)
|
||||
br.refresh()
|
||||
|
||||
return br.get_available_images()
|
||||
|
||||
def get_available_kernels(self, image_name):
|
||||
"""Return kernels available for ``image_name``.
|
||||
|
||||
:param image_name: str image name (e.g. 'xenial')
|
||||
"""
|
||||
maas_client = MaasRequestFactory(
|
||||
config.config_mgr.conf.maasdriver.maas_api_url,
|
||||
config.config_mgr.conf.maasdriver.maas_api_key)
|
||||
|
||||
br = BootResources(maas_client)
|
||||
br.refresh()
|
||||
|
||||
return br.get_available_kernels(image_name)
|
||||
|
||||
|
||||
def list_opts():
|
||||
return {MaasNodeDriver.driver_key: MaasNodeDriver.maasdriver_options}
|
||||
|
@ -37,6 +37,28 @@ class BootResource(model_base.ResourceBase):
|
||||
def __init__(self, api_client, **kwargs):
|
||||
super().__init__(api_client, **kwargs)
|
||||
|
||||
def get_image_name(self):
|
||||
"""Return the name that would be specified in a deployment.
|
||||
|
||||
Return None if this is not an ubuntu image, otherwise
|
||||
the distro series name
|
||||
"""
|
||||
(os, release) = self.name.split('/')
|
||||
|
||||
# Only supply image names for ubuntu-based images
|
||||
if os == 'ubuntu':
|
||||
return release
|
||||
else:
|
||||
# Non-ubuntu images such as the uefi bootloader
|
||||
# should never be selectable
|
||||
return None
|
||||
|
||||
def get_kernel_name(self):
|
||||
"""Return the kernel name that would be specified in a deployment."""
|
||||
(_, kernel) = self.architecture.split('/')
|
||||
|
||||
return kernel
|
||||
|
||||
|
||||
class BootResources(model_base.ResourceCollectionBase):
|
||||
|
||||
@ -62,3 +84,26 @@ class BootResources(model_base.ResourceCollectionBase):
|
||||
resp.status_code, resp.text)
|
||||
self.logger.error(msg)
|
||||
raise errors.DriverError(msg)
|
||||
|
||||
def get_available_images(self):
|
||||
"""Get list of available deployable images."""
|
||||
image_options = list()
|
||||
for k, v in self.resources.items():
|
||||
if v.get_image_name() not in image_options:
|
||||
image_options.append(v.get_image_name())
|
||||
return image_options
|
||||
|
||||
def get_available_kernels(self, image_name):
|
||||
"""Get kernels available for image_name
|
||||
|
||||
Return list of kernel names available for
|
||||
``image_name``.
|
||||
|
||||
:param image_name: str image_name (e.g. 'xenial')
|
||||
"""
|
||||
kernel_options = list()
|
||||
for k, v in self.resources.items():
|
||||
if (v.get_image_name() == image_name
|
||||
and v.get_kernel_name() not in kernel_options):
|
||||
kernel_options.append(v.get_kernel_name())
|
||||
return kernel_options
|
||||
|
@ -457,8 +457,7 @@ class Machines(model_base.ResourceCollectionBase):
|
||||
if k.startswith('power_params.'):
|
||||
field = k[13:]
|
||||
result = [
|
||||
i for i in result
|
||||
if str(
|
||||
i for i in result if str(
|
||||
getattr(i, 'power_parameters', {}).get(field, None)) ==
|
||||
str(v)
|
||||
]
|
||||
|
@ -939,8 +939,7 @@ class BootactionReport(BaseAction):
|
||||
bas = self.state_manager.get_boot_actions_for_node(n)
|
||||
running_bas = {
|
||||
k: v
|
||||
for (k, v) in bas.items()
|
||||
if v.get('action_status') ==
|
||||
for (k, v) in bas.items() if v.get('action_status') ==
|
||||
hd_fields.ActionResult.Incomplete
|
||||
}
|
||||
if len(running_bas) > 0:
|
||||
|
@ -281,7 +281,7 @@ class Orchestrator(object):
|
||||
"""
|
||||
status = None
|
||||
site_design = None
|
||||
val = Validator()
|
||||
val = Validator(self)
|
||||
try:
|
||||
status, site_design = self.get_described_site(design_ref)
|
||||
if status.status == hd_fields.ActionResult.Success:
|
||||
|
@ -22,6 +22,13 @@ from drydock_provisioner.objects.task import TaskStatus, TaskStatusMessage
|
||||
|
||||
|
||||
class Validator():
|
||||
def __init__(self, orchestrator):
|
||||
"""Create a validator with a reference to the orchestrator.
|
||||
|
||||
:param orchestrator: instance of Orchestrator
|
||||
"""
|
||||
self.orchestrator = orchestrator
|
||||
|
||||
def validate_design(self, site_design, result_status=None):
|
||||
"""Validate the design in site_design passes all validation rules.
|
||||
|
||||
@ -32,13 +39,12 @@ class Validator():
|
||||
:param site_design: instance of objects.SiteDesign
|
||||
:param result_status: instance of objects.TaskStatus
|
||||
"""
|
||||
|
||||
if result_status is None:
|
||||
result_status = TaskStatus()
|
||||
|
||||
validation_error = False
|
||||
for rule in rule_set:
|
||||
output = rule(site_design)
|
||||
output = rule(site_design, orchestrator=self.orchestrator)
|
||||
result_status.message_list.extend(output)
|
||||
error_msg = [m for m in output if m.error]
|
||||
result_status.error_count = result_status.error_count + len(
|
||||
@ -54,7 +60,66 @@ class Validator():
|
||||
return result_status
|
||||
|
||||
@classmethod
|
||||
def rational_network_bond(cls, site_design):
|
||||
def valid_platform_selection(cls, site_design, orchestrator=None):
|
||||
"""Validate that the platform selection for all nodes is valid.
|
||||
|
||||
Each node specifies an ``image`` and a ``kernel`` to use for
|
||||
deployment. Check that these are valid for the image repoistory
|
||||
configured in MAAS.
|
||||
"""
|
||||
message_list = list()
|
||||
|
||||
try:
|
||||
node_driver = orchestrator.enabled_drivers['node']
|
||||
except KeyError:
|
||||
message_list.append(
|
||||
TaskStatusMessage(
|
||||
msg="Platform Validation: No enabled node driver, image"
|
||||
"and kernel selections not validated.",
|
||||
error=False,
|
||||
ctx_type='NA',
|
||||
ctx='NA'))
|
||||
return message_list
|
||||
|
||||
valid_images = node_driver.get_available_images()
|
||||
|
||||
valid_kernels = dict()
|
||||
|
||||
for i in valid_images:
|
||||
valid_kernels[i] = node_driver.get_available_kernels(i)
|
||||
|
||||
for n in site_design.baremetal_nodes:
|
||||
if n.image in valid_images:
|
||||
if n.kernel in valid_kernels[n.image]:
|
||||
continue
|
||||
message_list.append(
|
||||
TaskStatusMessage(
|
||||
msg="Platform Validation: invalid kernel %s for node %s."
|
||||
% (n.kernel, n.name),
|
||||
error=True,
|
||||
ctx_type='NA',
|
||||
ctx='NA'))
|
||||
continue
|
||||
message_list.append(
|
||||
TaskStatusMessage(
|
||||
msg="Platform Validation: invalid image %s for node %s." %
|
||||
(n.image, n.name),
|
||||
error=True,
|
||||
ctx_type='NA',
|
||||
ctx='NA'))
|
||||
if not message_list:
|
||||
message_list.append(
|
||||
TaskStatusMessage(
|
||||
msg="Platform Validation: all nodes have valid "
|
||||
"image and kernel selections.",
|
||||
error=False,
|
||||
ctx_type='NA',
|
||||
ctx='NA'))
|
||||
|
||||
return message_list
|
||||
|
||||
@classmethod
|
||||
def rational_network_bond(cls, site_design, orchestrator=None):
|
||||
"""
|
||||
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.
|
||||
@ -74,8 +139,7 @@ class Validator():
|
||||
if bonding_mode == 'disabled':
|
||||
# check to make sure nothing else is specified
|
||||
if any([
|
||||
network_link.get(x)
|
||||
for x in [
|
||||
network_link.get(x) for x in [
|
||||
'bonding_peer_rate', 'bonding_xmit_hash',
|
||||
'bonding_mon_rate', 'bonding_up_delay',
|
||||
'bonding_down_delay'
|
||||
@ -144,7 +208,7 @@ class Validator():
|
||||
return message_list
|
||||
|
||||
@classmethod
|
||||
def network_trunking_rational(cls, site_design):
|
||||
def network_trunking_rational(cls, site_design, orchestrator=None):
|
||||
"""
|
||||
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.
|
||||
@ -194,7 +258,7 @@ class Validator():
|
||||
return message_list
|
||||
|
||||
@classmethod
|
||||
def storage_partitioning(cls, site_design):
|
||||
def storage_partitioning(cls, site_design, orchestrator=None):
|
||||
"""
|
||||
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.
|
||||
@ -276,7 +340,7 @@ class Validator():
|
||||
return message_list
|
||||
|
||||
@classmethod
|
||||
def unique_network_check(cls, site_design):
|
||||
def unique_network_check(cls, site_design, orchestrator=None):
|
||||
"""
|
||||
Ensures that each network name appears at most once between all NetworkLink
|
||||
allowed networks
|
||||
@ -327,7 +391,7 @@ class Validator():
|
||||
return message_list
|
||||
|
||||
@classmethod
|
||||
def mtu_rational(cls, site_design):
|
||||
def mtu_rational(cls, site_design, orchestrator=None):
|
||||
"""
|
||||
Ensure that the MTU for each network is equal or less than the MTU defined
|
||||
for the parent NetworkLink for that network.
|
||||
@ -385,7 +449,7 @@ class Validator():
|
||||
return message_list
|
||||
|
||||
@classmethod
|
||||
def storage_sizing(cls, site_design):
|
||||
def storage_sizing(cls, site_design, orchestrator=None):
|
||||
"""
|
||||
Ensures that for a partitioned physical device or logical volumes
|
||||
in a volume group, if sizing is a percentage then those percentages
|
||||
@ -469,7 +533,7 @@ class Validator():
|
||||
return message_list
|
||||
|
||||
@classmethod
|
||||
def no_duplicate_IPs_check(cls, site_design):
|
||||
def no_duplicate_IPs_check(cls, site_design, orchestrator=None):
|
||||
"""
|
||||
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
|
||||
@ -483,7 +547,9 @@ class Validator():
|
||||
|
||||
if not baremetal_nodes_list:
|
||||
msg = 'No BaremetalNodes Found.'
|
||||
message_list.append(TaskStatusMessage(msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||
message_list.append(
|
||||
TaskStatusMessage(
|
||||
msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||
else:
|
||||
for node in baremetal_nodes_list:
|
||||
addressing_list = node.get('addressing', [])
|
||||
@ -504,12 +570,14 @@ class Validator():
|
||||
|
||||
if not message_list:
|
||||
msg = 'No Duplicate IP Addresses.'
|
||||
message_list.append(TaskStatusMessage(msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||
message_list.append(
|
||||
TaskStatusMessage(
|
||||
msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||
|
||||
return message_list
|
||||
|
||||
@classmethod
|
||||
def boot_storage_rational(cls, site_design):
|
||||
def boot_storage_rational(cls, site_design, orchestrator=None):
|
||||
"""
|
||||
Ensures that root volume is defined and is at least 20GB and that boot volume is at least 1 GB
|
||||
"""
|
||||
@ -599,7 +667,7 @@ class Validator():
|
||||
return message_list
|
||||
|
||||
@classmethod
|
||||
def ip_locality_check(cls, site_design):
|
||||
def ip_locality_check(cls, site_design, orchestrator=None):
|
||||
"""
|
||||
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.
|
||||
@ -613,7 +681,9 @@ class Validator():
|
||||
|
||||
if not network_list:
|
||||
msg = 'No networks found.'
|
||||
message_list.append(TaskStatusMessage(msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||
message_list.append(
|
||||
TaskStatusMessage(
|
||||
msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||
else:
|
||||
for net in network_list:
|
||||
name = net.get('name')
|
||||
@ -650,7 +720,9 @@ class Validator():
|
||||
ctx='NA'))
|
||||
if not baremetal_nodes_list:
|
||||
msg = 'No baremetal_nodes found.'
|
||||
message_list.append(TaskStatusMessage(msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||
message_list.append(
|
||||
TaskStatusMessage(
|
||||
msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||
else:
|
||||
for node in baremetal_nodes_list:
|
||||
addressing_list = node.get('addressing', [])
|
||||
@ -687,7 +759,9 @@ class Validator():
|
||||
ctx='NA'))
|
||||
if not message_list:
|
||||
msg = 'IP Locality Success'
|
||||
message_list.append(TaskStatusMessage(msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||
message_list.append(
|
||||
TaskStatusMessage(
|
||||
msg=msg, error=False, ctx_type='NA', ctx='NA'))
|
||||
return message_list
|
||||
|
||||
|
||||
@ -701,4 +775,5 @@ rule_set = [
|
||||
Validator.ip_locality_check,
|
||||
Validator.no_duplicate_IPs_check,
|
||||
Validator.boot_storage_rational,
|
||||
Validator.valid_platform_selection,
|
||||
]
|
||||
|
@ -90,6 +90,11 @@ def setup(setup_logging):
|
||||
config.config_mgr.register_options(enable_keystone=False)
|
||||
|
||||
config.config_mgr.conf([])
|
||||
config.config_mgr.conf.set_override(
|
||||
name="node_driver",
|
||||
group="plugins",
|
||||
override=
|
||||
"drydock_provisioner.drivers.node.maasdriver.driver.MaasNodeDriver")
|
||||
config.config_mgr.conf.set_override(
|
||||
name="database_connect_string",
|
||||
group="database",
|
||||
|
@ -19,8 +19,15 @@ from drydock_provisioner.orchestrator.actions.orchestrator import PrepareNodes
|
||||
|
||||
|
||||
class TestActionPrepareNodes(object):
|
||||
def test_preparenodes(self, input_files, deckhand_ingester, setup,
|
||||
def test_preparenodes(self, mocker, input_files, deckhand_ingester, setup,
|
||||
drydock_state):
|
||||
mock_images = mocker.patch("drydock_provisioner.drivers.node.driver.NodeDriver"
|
||||
".get_available_images")
|
||||
mock_images.return_value = ['xenial']
|
||||
mock_kernels = mocker.patch("drydock_provisioner.drivers.node.driver.NodeDriver"
|
||||
".get_available_kernels")
|
||||
mock_kernels.return_value = ['ga-16.04', 'hwe-16.04']
|
||||
|
||||
input_file = input_files.join("deckhand_fullsite.yaml")
|
||||
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
|
@ -30,7 +30,7 @@ class TestDesignValidator(object):
|
||||
|
||||
status, site_design = Orchestrator.get_effective_site(orch, design_ref)
|
||||
|
||||
val = Validator()
|
||||
val = Validator(orch)
|
||||
response = val.validate_design(site_design)
|
||||
|
||||
for msg in response.message_list:
|
||||
|
85
tests/unit/test_validation_rule_valid_platform.py
Normal file
85
tests/unit/test_validation_rule_valid_platform.py
Normal file
@ -0,0 +1,85 @@
|
||||
# Copyright 2017 AT&T Intellectual Property. All other rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Test Validation Rule Rational Boot Storage"""
|
||||
|
||||
import drydock_provisioner.config as config
|
||||
|
||||
from drydock_provisioner.orchestrator.orchestrator import Orchestrator
|
||||
from drydock_provisioner.orchestrator.validations.validator import Validator
|
||||
|
||||
|
||||
class TestValidPlatform(object):
|
||||
def test_valid_platform(self, mocker, deckhand_ingester, drydock_state,
|
||||
input_files):
|
||||
mock_images = mocker.patch(
|
||||
"drydock_provisioner.drivers.node.maasdriver.driver."
|
||||
"MaasNodeDriver.get_available_images")
|
||||
mock_images.return_value = ['xenial']
|
||||
mock_kernels = mocker.patch(
|
||||
"drydock_provisioner.drivers.node.maasdriver.driver."
|
||||
"MaasNodeDriver.get_available_kernels")
|
||||
mock_kernels.return_value = ['ga-16.04', 'hwe-16.04']
|
||||
|
||||
input_file = input_files.join("validation.yaml")
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
|
||||
orch = Orchestrator(
|
||||
state_manager=drydock_state,
|
||||
ingester=deckhand_ingester,
|
||||
enabled_drivers=config.config_mgr.conf.plugins)
|
||||
|
||||
status, site_design = Orchestrator.get_effective_site(orch, design_ref)
|
||||
|
||||
message_list = Validator.valid_platform_selection(
|
||||
site_design, orchestrator=orch)
|
||||
for m in message_list:
|
||||
print(m.to_dict())
|
||||
|
||||
msg = message_list[0].to_dict()
|
||||
|
||||
assert 'all nodes have valid' in msg.get('message')
|
||||
assert msg.get('error') is False
|
||||
assert len(message_list) == 1
|
||||
|
||||
def test_invalid_platform(self, mocker, deckhand_ingester, drydock_state,
|
||||
input_files):
|
||||
mock_images = mocker.patch(
|
||||
"drydock_provisioner.drivers.node.maasdriver.driver."
|
||||
"MaasNodeDriver.get_available_images")
|
||||
mock_images.return_value = ['xenial']
|
||||
mock_kernels = mocker.patch(
|
||||
"drydock_provisioner.drivers.node.maasdriver.driver."
|
||||
"MaasNodeDriver.get_available_kernels")
|
||||
mock_kernels.return_value = ['ga-16.04', 'hwe-16.04']
|
||||
|
||||
input_file = input_files.join("invalid_kernel.yaml")
|
||||
design_ref = "file://%s" % str(input_file)
|
||||
|
||||
orch = Orchestrator(
|
||||
state_manager=drydock_state,
|
||||
ingester=deckhand_ingester,
|
||||
enabled_drivers=config.config_mgr.conf.plugins)
|
||||
|
||||
status, site_design = Orchestrator.get_effective_site(orch, design_ref)
|
||||
|
||||
message_list = Validator.valid_platform_selection(
|
||||
site_design, orchestrator=orch)
|
||||
|
||||
for m in message_list:
|
||||
print(m.to_dict())
|
||||
|
||||
msg = message_list[0].to_dict()
|
||||
assert 'invalid kernel lts' in msg.get('message')
|
||||
assert msg.get('error')
|
||||
assert len(message_list) == 1
|
@ -264,8 +264,8 @@ data:
|
||||
fstype: 'xfs'
|
||||
mount_options: 'defaults'
|
||||
platform:
|
||||
image: ubuntu_16.04
|
||||
kernel: generic
|
||||
image: 'xenial'
|
||||
kernel: 'ga-16.04'
|
||||
kernel_params:
|
||||
quiet: true
|
||||
console: ttyS2
|
||||
|
329
tests/yaml_samples/invalid_kernel.yaml
Normal file
329
tests/yaml_samples/invalid_kernel.yaml
Normal file
@ -0,0 +1,329 @@
|
||||
#Copyright 2017 AT&T Intellectual Property. All other rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
####################
|
||||
#
|
||||
# bootstrap_seed.yaml - Site server design definition for physical layer
|
||||
#
|
||||
####################
|
||||
# version the schema in this file so consumers can rationally parse it
|
||||
---
|
||||
schema: 'drydock/Region/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: 'sitename'
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
tag_definitions:
|
||||
- tag: 'test'
|
||||
definition_type: 'lshw_xpath'
|
||||
definition: "//node[@id=\"display\"]/'clock units=\"Hz\"' > 1000000000"
|
||||
authorized_keys:
|
||||
- |
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDENeyO5hLPbLLQRZ0oafTYWs1ieo5Q+XgyZQs51Ju
|
||||
jDGc8lKlWsg1/6yei2JewKMgcwG2Buu1eqU92Xn1SvMZLyt9GZURuBkyjcfVc/8GiU5QP1Of8B7CV0c
|
||||
kfUpHWYJ17olTzT61Hgz10ioicBF6cjgQrLNcyn05xoaJHD2Vpf8Unxzi0YzA2e77yRqBo9jJVRaX2q
|
||||
wUJuZrzb62x3zw8Knz6GGSZBn8xRKLaw1SKFpd1hwvL62GfqX5ZBAT1AYTZP1j8GcAoK8AFVn193SEU
|
||||
vjSdUFa+RNWuJhkjBRfylJczIjTIFb5ls0jpbA3bMA9DE7lFKVQl6vVwFmiIVBI1 samplekey
|
||||
---
|
||||
schema: 'drydock/NetworkLink/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: oob
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
bonding:
|
||||
mode: disabled
|
||||
mtu: 1500
|
||||
linkspeed: 100full
|
||||
trunking:
|
||||
mode: disabled
|
||||
default_network: oob
|
||||
allowed_networks:
|
||||
- oob
|
||||
---
|
||||
schema: 'drydock/NetworkLink/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: pxe
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
bonding:
|
||||
mode: disabled
|
||||
mtu: 1500
|
||||
linkspeed: auto
|
||||
trunking:
|
||||
mode: disabled
|
||||
default_network: pxe
|
||||
allowed_networks:
|
||||
- pxe
|
||||
---
|
||||
schema: 'drydock/NetworkLink/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: gp
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
bonding:
|
||||
mode: 802.3ad
|
||||
hash: layer3+4
|
||||
peer_rate: slow
|
||||
mtu: 9000
|
||||
linkspeed: auto
|
||||
trunking:
|
||||
mode: 802.1q
|
||||
default_network: mgmt
|
||||
allowed_networks:
|
||||
- public
|
||||
- mgmt
|
||||
---
|
||||
schema: 'drydock/Rack/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: rack1
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
tor_switches:
|
||||
switch01name:
|
||||
mgmt_ip: 1.1.1.1
|
||||
sdn_api_uri: polo+https://polo-api.web.att.com/switchmgmt?switch=switch01name
|
||||
switch02name:
|
||||
mgmt_ip: 1.1.1.2
|
||||
sdn_api_uri: polo+https://polo-api.web.att.com/switchmgmt?switch=switch02name
|
||||
location:
|
||||
clli: HSTNTXMOCG0
|
||||
grid: EG12
|
||||
local_networks:
|
||||
- pxe-rack1
|
||||
---
|
||||
schema: 'drydock/Network/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: oob
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
cidr: 172.16.100.0/24
|
||||
ranges:
|
||||
- type: static
|
||||
start: 172.16.100.15
|
||||
end: 172.16.100.254
|
||||
dns:
|
||||
domain: ilo.sitename.att.com
|
||||
servers: 172.16.100.10
|
||||
---
|
||||
schema: 'drydock/Network/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: pxe
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
dhcp_relay:
|
||||
self_ip: 172.16.0.4
|
||||
upstream_target: 172.16.5.5
|
||||
mtu: 1500
|
||||
cidr: 172.16.0.0/24
|
||||
ranges:
|
||||
- type: dhcp
|
||||
start: 172.16.0.5
|
||||
end: 172.16.0.254
|
||||
dns:
|
||||
domain: admin.sitename.att.com
|
||||
servers: 172.16.0.10
|
||||
---
|
||||
schema: 'drydock/Network/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: mgmt
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
vlan: '100'
|
||||
mtu: 1500
|
||||
cidr: 172.16.1.0/24
|
||||
ranges:
|
||||
- type: static
|
||||
start: 172.16.1.15
|
||||
end: 172.16.1.254
|
||||
routes:
|
||||
- subnet: 0.0.0.0/0
|
||||
gateway: 172.16.1.1
|
||||
metric: 10
|
||||
dns:
|
||||
domain: mgmt.sitename.example.com
|
||||
servers: 172.16.1.9,172.16.1.10
|
||||
---
|
||||
schema: 'drydock/Network/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: private
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
vlan: '101'
|
||||
mtu: 9000
|
||||
cidr: 172.16.2.0/24
|
||||
ranges:
|
||||
- type: static
|
||||
start: 172.16.2.15
|
||||
end: 172.16.2.254
|
||||
dns:
|
||||
domain: priv.sitename.example.com
|
||||
servers: 172.16.2.9,172.16.2.10
|
||||
---
|
||||
schema: 'drydock/Network/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: public
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
vlan: '102'
|
||||
mtu: 1500
|
||||
cidr: 172.16.3.0/24
|
||||
ranges:
|
||||
- type: static
|
||||
start: 172.16.3.15
|
||||
end: 172.16.3.254
|
||||
routes:
|
||||
- subnet: 0.0.0.0/0
|
||||
gateway: 172.16.3.1
|
||||
metric: 10
|
||||
dns:
|
||||
domain: sitename.example.com
|
||||
servers: 8.8.8.8
|
||||
---
|
||||
schema: 'drydock/HostProfile/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: defaults
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
hardware_profile: HPGen9v3
|
||||
oob:
|
||||
type: ipmi
|
||||
network: oob
|
||||
account: admin
|
||||
credential: admin
|
||||
storage:
|
||||
physical_devices:
|
||||
sda:
|
||||
labels:
|
||||
role: rootdisk
|
||||
partitions:
|
||||
- name: root
|
||||
size: 39%
|
||||
bootable: true
|
||||
filesystem:
|
||||
mountpoint: '/'
|
||||
fstype: 'ext4'
|
||||
mount_options: 'defaults'
|
||||
- name: boot
|
||||
size: 42%
|
||||
bootable: false
|
||||
filesystem:
|
||||
mountpoint: '/boot'
|
||||
fstype: 'ext4'
|
||||
mount_options: 'defaults'
|
||||
sdb:
|
||||
volume_group: 'log_vg'
|
||||
volume_groups:
|
||||
log_vg:
|
||||
logical_volumes:
|
||||
- name: 'log_lv'
|
||||
size: '25%'
|
||||
filesystem:
|
||||
mountpoint: '/var/log'
|
||||
fstype: 'xfs'
|
||||
mount_options: 'defaults'
|
||||
platform:
|
||||
image: xenial
|
||||
kernel: lts
|
||||
kernel_params:
|
||||
quiet: true
|
||||
console: ttyS2
|
||||
metadata:
|
||||
owner_data:
|
||||
foo: bar
|
||||
---
|
||||
schema: 'drydock/BaremetalNode/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: controller01
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
host_profile: defaults
|
||||
interfaces:
|
||||
bond0:
|
||||
networks:
|
||||
- '!private'
|
||||
addressing:
|
||||
- network: pxe
|
||||
address: dhcp
|
||||
- network: mgmt
|
||||
address: 172.16.1.20
|
||||
- network: public
|
||||
address: 172.16.3.20
|
||||
- network: oob
|
||||
address: 172.16.100.20
|
||||
metadata:
|
||||
rack: rack1
|
||||
---
|
||||
schema: 'drydock/HardwareProfile/v1'
|
||||
metadata:
|
||||
schema: 'metadata/Document/v1'
|
||||
name: HPGen9v3
|
||||
storagePolicy: 'cleartext'
|
||||
labels:
|
||||
application: 'drydock'
|
||||
data:
|
||||
vendor: HP
|
||||
generation: '8'
|
||||
hw_version: '3'
|
||||
bios_version: '2.2.3'
|
||||
boot_mode: bios
|
||||
bootstrap_protocol: pxe
|
||||
pxe_interface: 0
|
||||
device_aliases:
|
||||
prim_nic01:
|
||||
address: '0000:00:03.0'
|
||||
dev_type: '82540EM Gigabit Ethernet Controller'
|
||||
bus_type: 'pci'
|
||||
prim_nic02:
|
||||
address: '0000:00:04.0'
|
||||
dev_type: '82540EM Gigabit Ethernet Controller'
|
||||
bus_type: 'pci'
|
||||
primary_boot:
|
||||
address: '2:0.0.0'
|
||||
dev_type: 'VBOX HARDDISK'
|
||||
bus_type: 'scsi'
|
@ -264,8 +264,8 @@ data:
|
||||
fstype: 'xfs'
|
||||
mount_options: 'defaults'
|
||||
platform:
|
||||
image: ubuntu_16.04
|
||||
kernel: generic
|
||||
image: 'xenial'
|
||||
kernel: 'ga-16.04'
|
||||
kernel_params:
|
||||
quiet: true
|
||||
console: ttyS2
|
||||
|
Loading…
x
Reference in New Issue
Block a user