From 1964d7f9b068fe24c56eff89174e923b313d82d8 Mon Sep 17 00:00:00 2001 From: Scott Hussey Date: Wed, 15 Nov 2017 10:27:50 -0600 Subject: [PATCH] Implement routedomain support Route domains will allow multiple L3 networks to self organize static routes. This allows additions of L3 networks with manually updating previously deployed networks. - Fix a YamlIngester error with labels on NetworkLinks - Update the CLI --block option - Add routedomains attribue to Networks in schema and object model - Add routedomain documentation - Add unit test for routedomain route generation - Add unit test coverage reporting Change-Id: I059d2eae6da84c4f9ad909f0287432e6cf0970d0 --- docs/source/task.rst | 2 +- docs/source/topology.rst | 20 +- drydock_provisioner/cli/const.py | 23 + drydock_provisioner/cli/task/actions.py | 6 +- .../drivers/node/maasdriver/actions/node.py | 3 + .../drivers/node/maasdriver/models/subnet.py | 1 + .../ingester/plugins/deckhand.py | 2 + drydock_provisioner/ingester/plugins/yaml.py | 18 +- drydock_provisioner/objects/network.py | 4 +- .../orchestrator/orchestrator.py | 45 +- drydock_provisioner/schemas/network.yaml | 4 + requirements-test.txt | 1 + tests/unit/test_render_routedomain.py | 53 ++ tests/yaml_samples/deckhand_routedomain.yaml | 77 +++ tests/yaml_samples/hostprof.yaml | 501 ++++++++++++++++++ tox.ini | 12 +- 16 files changed, 744 insertions(+), 28 deletions(-) create mode 100644 drydock_provisioner/cli/const.py create mode 100644 tests/unit/test_render_routedomain.py create mode 100644 tests/yaml_samples/deckhand_routedomain.yaml create mode 100644 tests/yaml_samples/hostprof.yaml diff --git a/docs/source/task.rst b/docs/source/task.rst index 000a3e43..37c50cf4 100644 --- a/docs/source/task.rst +++ b/docs/source/task.rst @@ -11,7 +11,7 @@ the task API for task status and results. Task Document Schema -------------------- -This document can be posted to the Drydock :ref:`task-api` to create a new task.:: +This document can be posted to the Drydock :ref:`tasks-api` to create a new task.:: { "action": "validate_design|verify_site|prepare_site|verify_node|prepare_node|deploy_node|destroy_node", diff --git a/docs/source/topology.rst b/docs/source/topology.rst index ca90fb8a..1d2e30e7 100644 --- a/docs/source/topology.rst +++ b/docs/source/topology.rst @@ -122,6 +122,7 @@ Example YAML schema of the Network spec: vlan: '102' mtu: 1500 cidr: 172.16.3.0/24 + routedomain: storage ranges: - type: static start: 172.16.3.15 @@ -133,6 +134,9 @@ Example YAML schema of the Network spec: - subnet: 0.0.0.0/0 gateway: 172.16.3.1 metric: 10 + - gateawy: 172.16.3.2 + metric: 10 + routedomain: storage dns: domain: sitename.example.com servers: 8.8.8.8 @@ -147,6 +151,11 @@ to the NetworkLink ``mtu``. ``cidr`` is the classless inter-domain routing address for the network. +``routedomain`` is a logical grouping of L3 networks such that a network that +describes a static route for accessing the route domain will yield a list of +static routes for all the networks in the routedomain. See the description +of ``routes`` below for more information. + ``ranges`` defines a sequence of IP addresses within the defined ``cidr``. Ranges cannot overlap. @@ -161,15 +170,18 @@ Ranges cannot overlap. * ``start``: The starting IP of the range, inclusive. * ``end``: The last IP of the range, inclusive -*NOTE: Static routes are not currently implemented beyond specifying a route for -``0.0.0.0/0`` for default route* - ``routes`` defines a list of static routes to be configured on nodes attached to -this network. +this network. The routes can defined in one of two ways: an explicit destination +``subnet`` where the route will be configured exactly as described or a destination +``routedomain`` where Drydock will calculate all the destination L3 subnets for the +routedomain and add routes for each of them using the ``gateway`` and ``metric`` +defined. * ``subnet``: Destination CIDR for the route * ``gateway``: The gateway IP on this Network to use for accessing the destination * ``metric``: The metric or weight for this route +* ``routedomain``: Use this route's gateway and metric for accessing networks in the + defined routedomain. ``dns`` is used for specifying the list of DNS servers to use if this network is the primary network for the node. diff --git a/drydock_provisioner/cli/const.py b/drydock_provisioner/cli/const.py new file mode 100644 index 00000000..c6faa7a2 --- /dev/null +++ b/drydock_provisioner/cli/const.py @@ -0,0 +1,23 @@ +# 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. +"""Constants for the CLI and API client.""" +from enum import Enum + +class TaskStatus(Enum): + Requested = 'requested' + Queued = 'queued' + Running = 'running' + Terminating = 'terminating' + Terminated = 'terminated' + Complete = 'complete' diff --git a/drydock_provisioner/cli/task/actions.py b/drydock_provisioner/cli/task/actions.py index 0a27395b..2afe4ffe 100644 --- a/drydock_provisioner/cli/task/actions.py +++ b/drydock_provisioner/cli/task/actions.py @@ -15,7 +15,7 @@ import time from drydock_provisioner.cli.action import CliAction - +from drydock_provisioner.cli.const import TaskStatus class TaskList(CliAction): # pylint: disable=too-few-public-methods """Action to list tasks.""" @@ -99,7 +99,7 @@ class TaskCreate(CliAction): # pylint: disable=too-few-public-methods while True: time.sleep(self.poll_interval) task = self.api_client.get_task(task_id=task_id) - if task.get('status', '') in ['completed', 'terminated']: + if task.get('status', '') in [TaskStatus.Complete, TaskStatus.Terminated]: return task @@ -134,5 +134,5 @@ class TaskShow(CliAction): # pylint: disable=too-few-public-methods while True: time.sleep(self.poll_interval) task = self.api_client.get_task(task_id=task_id) - if task.status in ['completed', 'terminated']: + if task.status in [TaskStatus.Complete, TaskStatus.Terminated]: return task diff --git a/drydock_provisioner/drivers/node/maasdriver/actions/node.py b/drydock_provisioner/drivers/node/maasdriver/actions/node.py index bcdbf98a..6b2a07d6 100644 --- a/drydock_provisioner/drivers/node/maasdriver/actions/node.py +++ b/drydock_provisioner/drivers/node/maasdriver/actions/node.py @@ -541,6 +541,9 @@ class CreateNetworkTemplate(BaseMaasAction): for n in design_networks: src_subnet = subnet_list.singleton({'cidr': n.cidr}) for r in n.routes: + # care for case of routedomain routes that are logical placeholders + if not r.get('subnet', None): + continue route_net = r.get('subnet') # Skip the default route case if route_net == '0.0.0.0/0': diff --git a/drydock_provisioner/drivers/node/maasdriver/models/subnet.py b/drydock_provisioner/drivers/node/maasdriver/models/subnet.py index de82713e..ae6a1c7b 100644 --- a/drydock_provisioner/drivers/node/maasdriver/models/subnet.py +++ b/drydock_provisioner/drivers/node/maasdriver/models/subnet.py @@ -82,6 +82,7 @@ class Subnet(model_base.ResourceBase): :param metric: weight to assign this gateway """ sr = maas_route.StaticRoutes(self.api_client) + sr.refresh() current_route = sr.singleton({ 'source': self.resource_id, 'destination': dest_subnet diff --git a/drydock_provisioner/ingester/plugins/deckhand.py b/drydock_provisioner/ingester/plugins/deckhand.py index 99774a2c..0e353283 100644 --- a/drydock_provisioner/ingester/plugins/deckhand.py +++ b/drydock_provisioner/ingester/plugins/deckhand.py @@ -286,6 +286,7 @@ class DeckhandIngester(IngesterPlugin): model.cidr = data.get('cidr', None) model.vlan_id = data.get('vlan', None) model.mtu = data.get('mtu', None) + model.routedomain = data.get('routedomain', None) dns = data.get('dns', {}) model.dns_domain = dns.get('domain', 'local') @@ -309,6 +310,7 @@ class DeckhandIngester(IngesterPlugin): 'subnet': r.get('subnet', None), 'gateway': r.get('gateway', None), 'metric': r.get('metric', None), + 'routedomain': r.get('routedomain', None), }) dhcp_relay = data.get('dhcp_relay', None) diff --git a/drydock_provisioner/ingester/plugins/yaml.py b/drydock_provisioner/ingester/plugins/yaml.py index d23ff12e..f3b4bbb5 100644 --- a/drydock_provisioner/ingester/plugins/yaml.py +++ b/drydock_provisioner/ingester/plugins/yaml.py @@ -246,13 +246,7 @@ class YamlIngester(IngesterPlugin): model.source = hd_fields.ModelSource.Designed model.name = name - metalabels = data.get('labels', []) - - for l in metalabels: - if model.metalabels is None: - model.metalabels = [l] - else: - model.metalabels.append(l) + model.metalabels = data.get('labels', {}) bonding = data.get('bonding', {}) @@ -289,17 +283,12 @@ class YamlIngester(IngesterPlugin): model.source = hd_fields.ModelSource.Designed model.name = name - metalabels = data.get('labels', []) - - for l in metalabels: - if model.metalabels is None: - model.metalabels = [l] - else: - model.metalabels.append(l) + model.metalabels = data.get('labels', {}) model.cidr = data.get('cidr', None) model.vlan_id = data.get('vlan', None) model.mtu = data.get('mtu', None) + model.routedomain = data.get('routedomain', None) dns = data.get('dns', {}) model.dns_domain = dns.get('domain', 'local') @@ -323,6 +312,7 @@ class YamlIngester(IngesterPlugin): 'subnet': r.get('subnet', None), 'gateway': r.get('gateway', None), 'metric': r.get('metric', None), + 'routedomain': r.get('routedomain', None), }) dhcp_relay = data.get('dhcp_relay', None) diff --git a/drydock_provisioner/objects/network.py b/drydock_provisioner/objects/network.py index 701536af..69712b67 100644 --- a/drydock_provisioner/objects/network.py +++ b/drydock_provisioner/objects/network.py @@ -88,14 +88,14 @@ class Network(base.DrydockPersistentObject, base.DrydockObject): 'site': ovo_fields.StringField(), 'metalabels': ovo_fields.DictOfNullableStringsField(), 'cidr': ovo_fields.StringField(), - 'allocation_strategy': ovo_fields.StringField(), 'vlan_id': ovo_fields.StringField(nullable=True), + 'routedomain': ovo_fields.StringField(nullable=True), 'mtu': ovo_fields.IntegerField(nullable=True), 'dns_domain': ovo_fields.StringField(nullable=True), 'dns_servers': ovo_fields.StringField(nullable=True), # Keys of ranges are 'type', 'start', 'end' 'ranges': ovo_fields.ListOfDictOfNullableStringsField(), - # Keys of routes are 'subnet', 'gateway', 'metric' + # Keys of routes are 'subnet', 'routedomain', 'gateway', 'metric' 'routes': ovo_fields.ListOfDictOfNullableStringsField(), 'dhcp_relay_self_ip': ovo_fields.StringField(nullable=True), 'dhcp_relay_upstream_target': ovo_fields.StringField(nullable=True), diff --git a/drydock_provisioner/orchestrator/orchestrator.py b/drydock_provisioner/orchestrator/orchestrator.py index 0d10b536..89cbe12f 100644 --- a/drydock_provisioner/orchestrator/orchestrator.py +++ b/drydock_provisioner/orchestrator/orchestrator.py @@ -247,8 +247,12 @@ class Orchestrator(object): Given a fully populated Site model, compute the effecitve design by applying inheritance and references """ - for n in getattr(site_design, 'baremetal_nodes', []): - n.compile_applied_model(site_design) + try: + nodes = site_design.baremetal_nodes + for n in nodes or []: + n.compile_applied_model(site_design) + except AttributeError: + self.logger.debug("Model inheritance skipped, no node definitions in site design.") return @@ -281,7 +285,8 @@ class Orchestrator(object): if status.status == hd_fields.ActionResult.Success: self.compute_model_inheritance(site_design) self.compute_bootaction_targets(site_design) - status = val.validate_design(site_design, result_status=status) + self.render_route_domains(site_design) + status = val.validate_design(site_design, result_status=status) except Exception as ex: if status is not None: status.add_status_msg( @@ -547,3 +552,37 @@ class Orchestrator(object): nodename, task.get_id(), identity_key, action_id, ba.name) return identity_key + + def render_route_domains(self, site_design): + """Update site_design with static routes for route domains. + + site_design will be updated in place with explicit static routes + for all routedomain members + + :param site_design: a populated instance of objects.SiteDesign + """ + self.logger.info("Rendering routes for network route domains.") + if site_design.networks is not None: + routedomains = dict() + for n in site_design.networks: + if n.routedomain is not None: + if n.routedomain not in routedomains: + self.logger.info("Adding routedomain %s to render map." % n.routedomain) + routedomains[n.routedomain] = list() + routedomains[n.routedomain].append(n) + for rd, nl in routedomains.items(): + rd_cidrs = [n.cidr for n in nl] + self.logger.debug("Target CIDRs for routedomain %s: %s" % (rd, ','.join(rd_cidrs))) + for n in site_design.networks: + gw = None + metric = None + for r in n.routes: + if 'routedomain' in r and r.get('routedomain', None) == rd: + gw = r.get('gateway') + metric = r.get('metric') + self.logger.debug("Use gateway %s for routedomain %s on network %s." % + (gw, rd, n.get_name())) + break + if gw is not None and metric is not None: + for cidr in rd_cidrs: + n.routes.append(dict(subnet=cidr, gateway=gw, metric=metric)) diff --git a/drydock_provisioner/schemas/network.yaml b/drydock_provisioner/schemas/network.yaml index 95209420..4eaaf11d 100644 --- a/drydock_provisioner/schemas/network.yaml +++ b/drydock_provisioner/schemas/network.yaml @@ -48,6 +48,8 @@ data: type: 'number' vlan: type: 'string' + routedomain: + type: 'string' routes: type: 'array' items: @@ -60,6 +62,8 @@ data: format: 'ipv4' metric: type: 'number' + routedomain: + type: 'string' additionalProperties: false labels: type: 'object' diff --git a/requirements-test.txt b/requirements-test.txt index 4bdc1ed0..0d6ca35f 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,5 +1,6 @@ pytest-mock pytest +pytest-cov responses mock tox diff --git a/tests/unit/test_render_routedomain.py b/tests/unit/test_render_routedomain.py new file mode 100644 index 00000000..cbe7bcff --- /dev/null +++ b/tests/unit/test_render_routedomain.py @@ -0,0 +1,53 @@ +# 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. + +from drydock_provisioner.objects import fields as hd_fields +from drydock_provisioner.ingester.ingester import Ingester +from drydock_provisioner.statemgmt.state import DrydockState +from drydock_provisioner.orchestrator.orchestrator import Orchestrator + + +class TestRouteDomains(object): + def test_routedomain_render(self, input_files, setup): + input_file = input_files.join("deckhand_routedomain.yaml") + + design_state = DrydockState() + design_ref = "file://%s" % str(input_file) + + ingester = Ingester() + ingester.enable_plugin( + 'drydock_provisioner.ingester.plugins.deckhand.DeckhandIngester') + + orchestrator = Orchestrator( + state_manager=design_state, ingester=ingester) + + design_status, design_data = orchestrator.get_effective_site( + design_ref) + + assert design_status.status == hd_fields.ActionResult.Success + + net_rack3 = design_data.get_network('storage_rack3') + + route_cidrs = list() + for r in net_rack3.routes: + if 'subnet' in r and r.get('subnet') is not None: + route_cidrs.append(r.get('subnet')) + + assert len(route_cidrs) == 3 + + assert '172.16.1.0/24' in route_cidrs + + assert '172.16.2.0/24' in route_cidrs + + assert '172.16.3.0/24' in route_cidrs diff --git a/tests/yaml_samples/deckhand_routedomain.yaml b/tests/yaml_samples/deckhand_routedomain.yaml new file mode 100644 index 00000000..0baeb661 --- /dev/null +++ b/tests/yaml_samples/deckhand_routedomain.yaml @@ -0,0 +1,77 @@ +#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. +--- +schema: 'drydock/Network/v1' +metadata: + schema: 'metadata/Document/v1' + name: storage_rack1 + storagePolicy: 'cleartext' + labels: + application: 'drydock' +data: + vlan: '100' + mtu: 1500 + cidr: 172.16.1.0/24 + routedomain: 'storage' + ranges: + - type: static + start: 172.16.1.15 + end: 172.16.1.254 + routes: + - routedomain: storage + gateway: 172.16.1.1 + metric: 10 +--- +schema: 'drydock/Network/v1' +metadata: + schema: 'metadata/Document/v1' + name: storage_rack2 + storagePolicy: 'cleartext' + labels: + application: 'drydock' +data: + vlan: '100' + mtu: 1500 + cidr: 172.16.2.0/24 + routedomain: storage + ranges: + - type: static + start: 172.16.2.15 + end: 172.16.2.254 + routes: + - routedomain: storage + gateway: 172.16.2.1 + metric: 10 +--- +schema: 'drydock/Network/v1' +metadata: + schema: 'metadata/Document/v1' + name: storage_rack3 + storagePolicy: 'cleartext' + labels: + application: 'drydock' +data: + vlan: '100' + mtu: 1500 + cidr: 172.16.3.0/24 + routedomain: 'storage' + ranges: + - type: static + start: 172.16.3.15 + end: 172.16.3.254 + routes: + - routedomain: storage + gateway: 172.16.3.1 + metric: 10 +... diff --git a/tests/yaml_samples/hostprof.yaml b/tests/yaml_samples/hostprof.yaml new file mode 100644 index 00000000..3db8cc2e --- /dev/null +++ b/tests/yaml_samples/hostprof.yaml @@ -0,0 +1,501 @@ +#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 +--- +apiVersion: 'drydock/v1' +kind: Region +metadata: + name: sitename + date: 17-FEB-2017 + description: Sample site design + author: sh8121@att.com +spec: + 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 +--- +apiVersion: 'drydock/v1' +kind: NetworkLink +metadata: + name: oob + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 1 attributes. Primary key is 'name'. These settings will generally be things the switch and server have to agree on +spec: + bonding: + mode: disabled + mtu: 1500 + linkspeed: 100full + trunking: + mode: disabled + default_network: oob + allowed_networks: + - oob +--- +# pxe is a bit of 'magic' indicating the link config used when PXE booting +# a node. All other links indicate network configs applied when the node +# is deployed. +apiVersion: 'drydock/v1' +kind: NetworkLink +metadata: + name: pxe + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 1 attributes. Primary key is 'name'. These settings will generally be things the switch and server have to agree on +spec: + bonding: + mode: disabled + mtu: 1500 + linkspeed: auto + # Is this link supporting multiple layer 2 networks? + # none is a port-based VLAN identified by default_network + # tagged is is using 802.1q VLAN tagging. Untagged packets will default to default_netwokr + trunking: + mode: disabled + # use name, will translate to VLAN ID + default_network: pxe + allowed_networks: + - pxe +--- +apiVersion: 'drydock/v1' +kind: NetworkLink +metadata: + name: gp + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 1 attributes. These CIs will generally be things the switch and server have to agree on + # pxe is a bit of 'magic' indicating the link config used when PXE booting + # a node. All other links indicate network configs applied when the node + # is deployed. +spec: + # If this link is a bond of physical links, how is it configured + # 802.3ad + # active-backup + # balance-rr + # Can add support for others down the road + bonding: + mode: 802.3ad + # For LACP (802.3ad) xmit hashing policy: layer2, layer2+3, layer3+4, encap3+4 + hash: layer3+4 + # 802.3ad specific options + peer_rate: slow + mtu: 9000 + linkspeed: auto + # Is this link supporting multiple layer 2 networks? + trunking: + mode: 802.1q + default_network: mgmt + allowed_networks: + - public + - mgmt +--- +apiVersion: 'drydock/v1' +kind: Rack +metadata: + name: rack1 + region: sitename + date: 24-AUG-2017 + author: sh8121@att.com + description: A equipment rack +spec: + # List of TOR switches in this rack + 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 + # GIS data for this rack + location: + clli: HSTNTXMOCG0 + grid: EG12 + # Networks wholly contained to this rack + # Nodes in a rack can only connect to local_networks of that rack + local_networks: + - pxe-rack1 +--- +apiVersion: 'drydock/v1' +kind: Network +metadata: + name: oob + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 2/3 attributes. Primarily CIs used for configuring server interfaces +spec: + 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 +--- +apiVersion: 'drydock/v1' +kind: Network +metadata: + name: pxe + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 2/3 attributes. Primarily CIs used for configuring server interfaces +spec: + # Layer 2 VLAN segment id, could support other segmentations. Optional + vlan_id: '99' + # If this network utilizes a dhcp relay, where does it forward DHCPDISCOVER requests to? + dhcp_relay: + # Required if Drydock is configuring a switch with the relay + self_ip: 172.16.0.4 + # Can refer to a unicast IP + upstream_target: 172.16.5.5 + # MTU for this VLAN interface, if not specified it will be inherited from the link + mtu: 1500 + # Network address + cidr: 172.16.0.0/24 + # Desribe IP address ranges + ranges: + - type: dhcp + start: 172.16.0.5 + end: 172.16.0.254 + # DNS settings for this network + dns: + # Domain addresses on this network will be registered under + domain: admin.sitename.att.com + # DNS servers that a server using this network as its default gateway should use + servers: 172.16.0.10 +--- +apiVersion: 'drydock/v1' +kind: Network +metadata: + name: mgmt + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 2/3 attributes. Primarily CIs used for configuring server interfaces +spec: + vlan_id: '100' + # Allow MTU to be inherited from link the network rides on + mtu: 1500 + # Network address + cidr: 172.16.1.0/24 + # Desribe IP address ranges + ranges: + - type: static + start: 172.16.1.15 + end: 172.16.1.254 + # Static routes to be added for this network + routes: + - subnet: 0.0.0.0/0 + # A blank gateway would leave to a static route specifying + # only the interface as a source + gateway: 172.16.1.1 + metric: 10 + # DNS settings for this network + dns: + # Domain addresses on this network will be registered under + domain: mgmt.sitename.example.com + # DNS servers that a server using this network as its default gateway should use + servers: 172.16.1.9,172.16.1.10 +--- +apiVersion: 'drydock/v1' +kind: Network +metadata: + name: private + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 2/3 attributes. Primarily CIs used for configuring server interfaces +spec: + vlan_id: '101' + mtu: 9000 + cidr: 172.16.2.0/24 + # Desribe IP address ranges + ranges: + # Type can be reserved (not used for baremetal), static (all explicit + # assignments should fall here), dhcp (will be used by a DHCP server on this network) + - 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 +--- +apiVersion: 'drydock/v1' +kind: Network +metadata: + name: public + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 2/3 attributes. Primarily CIs used for configuring server interfaces +spec: + vlan_id: '102' + # MTU size for the VLAN interface + mtu: 1500 + cidr: 172.16.3.0/24 + # Desribe IP address ranges + 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 +--- +apiVersion: 'drydock/v1' +kind: HostProfile +metadata: + name: defaults + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 2/3 attributes. Primarily CIs used for configuring server interfaces + # No magic to this host_profile, it just provides a way to specify + # sitewide settings. If it is absent from a node's inheritance chain + # then these values will NOT be applied +spec: + # OOB (iLO, iDRAC, etc...) settings. Should prefer open standards such + # as IPMI over vender-specific when possible. + oob: + type: ipmi + # OOB networking should be preconfigured, but we can include a network + # definition for validation or enhancement (DNS registration) + network: oob + account: admin + credential: admin + # Specify storage layout of base OS. Ceph out of scope + storage: + # How storage should be carved up: lvm (logical volumes), flat + # (single partition) + layout: lvm + # Info specific to the boot and root disk/partitions + bootdisk: + # Device will specify an alias defined in hwdefinition.yaml + device: primary_boot + # For LVM, the size of the partition added to VG as a PV + # For flat, the size of the partition formatted as ext4 + root_size: 50g + # The /boot partition. If not specified, /boot will in root + boot_size: 2g + # Info for additional partitions. Need to balance between + # flexibility and complexity + physical_devices: + name: + partitions: + name: + part_uuid: + size: + bootable: + filesystem: + mountpoint: + format: + mount_options: + fs_uuid: + fs_label: + volume_group: + logical_volumes: + name: + volume_group: + size: + lv_uuid: + filesystem: + mountpoint: + format: + mount_options: + fs_uuid: + fs_label: + # Platform (Operating System) settings + platform: + image: ubuntu_16.04 + kernel: generic + kernel_params: + quiet: true + console: ttyS2 + # Additional metadata to apply to a node + metadata: + # Freeform tags to be applied to the host + tags: + - deployment=initial + owner_data: + foo: bar +--- +apiVersion: 'drydock/v1' +kind: HostProfile +metadata: + name: k8-node + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 2/3 attributes. Primarily CIs used for configuring server interfaces +spec: + # host_profile inheritance allows for deduplication of common CIs + # Inheritance is additive for CIs that are lists of multiple items + # To remove an inherited list member, prefix the primary key value + # with '!'. + host_profile: defaults + # Hardware profile will map hardware specific details to the abstract + # names uses in the host profile as well as specify hardware specific + # configs. A viable model should be to build a host profile without a + # hardware_profile and then for each node inherit the host profile and + # specify a hardware_profile to map that node's hardware to the abstract + # settings of the host_profile + hardware_profile: HPGen9v3 + # Network interfaces. + primary_network: mgmt + interfaces: + # Keyed on device_name + # pxe is a special marker indicating which device should be used for pxe boot + - device_name: pxe + # The network link attached to this + device_link: pxe + # Slaves will specify aliases from hwdefinition.yaml + slaves: + - prim_nic01 + # Which networks will be configured on this interface + networks: + - pxe + - device_name: bond0 + network_link: gp + # If multiple slaves are specified, but no bonding config + # is applied to the link, design validation will fail + slaves: + - prim_nic01 + - prim_nic02 + # If multiple networks are specified, but no trunking + # config is applied to the link, design validation will fail + networks: + - mgmt + - private + metadata: + # Explicit tag assignment + tags: + - 'test' +--- +apiVersion: 'drydock/v1' +kind: BaremetalNode +metadata: + name: controller01 + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 2/3 attributes. Primarily CIs used for configuring server interfaces +spec: + host_profile: k8-node + # the hostname for a server, could be used in multiple DNS domains to + # represent different interfaces + interfaces: + - device_name: bond0 + networks: + # '!' prefix for the value of the primary key indicates a record should be removed + - '!private' + # Addresses assigned to network interfaces + addressing: + # Which network the address applies to. If a network appears in addressing + # that isn't assigned to an interface, design validation will fail + - network: pxe + # The address assigned. Either a explicit IPv4 or IPv6 address + # or dhcp or slaac + 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 +--- +apiVersion: 'drydock/v1' +kind: BaremetalNode +metadata: + name: compute01 + region: sitename + date: 17-FEB-2017 + author: sh8121@att.com + description: Describe layer 2/3 attributes. Primarily CIs used for configuring server interfaces +spec: + host_profile: k8-node + addressing: + - network: pxe + address: dhcp + - network: mgmt + address: 172.16.1.21 + - network: private + address: 172.16.2.21 + - network: oob + address: 172.16.100.21 + metadata: + rack: rack2 +--- +apiVersion: 'drydock/v1' +kind: HardwareProfile +metadata: + name: HPGen9v3 + region: sitename + date: 17-FEB-2017 + author: Scott Hussey +spec: + # Vendor of the server chassis + vendor: HP + # Generation of the chassis model + generation: '8' + # Version of the chassis model within its generation - not version of the hardware definition + hw_version: '3' + # The certified version of the chassis BIOS + bios_version: '2.2.3' + # Mode of the default boot of hardware - bios, uefi + boot_mode: bios + # Protocol of boot of the hardware - pxe, usb, hdd + bootstrap_protocol: pxe + # Which interface to use for network booting within the OOB manager, not OS device + pxe_interface: 0 + # Map hardware addresses to aliases/roles to allow a mix of hardware configs + # in a site to result in a consistent configuration + device_aliases: + - address: '0000:00:03.0' + alias: prim_nic01 + # type could identify expected hardware - used for hardware manifest validation + dev_type: '82540EM Gigabit Ethernet Controller' + bus_type: 'pci' + - address: '0000:00:04.0' + alias: prim_nic02 + dev_type: '82540EM Gigabit Ethernet Controller' + bus_type: 'pci' + - address: '2:0.0.0' + alias: primary_boot + dev_type: 'VBOX HARDDISK' + bus_type: 'scsi' +... diff --git a/tox.ini b/tox.ini index 9d763ef7..2385f79e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = unit,pep8,bandit +envlist = coverage-unit,pep8,bandit [testenv] setenv = YAMLDIR = {toxinidir}/tests/yaml_samples/ @@ -33,6 +33,16 @@ commands= py.test \ tests/unit/{posargs} +[testenv:coverage-unit] +usedevelop=True +setenv= + PYTHONWARNING=all + YAMLDIR={toxinidir}/tests/yaml_samples/ +commands= + py.test \ + --cov=drydock_provisioner \ + tests/unit/{posargs} + [testenv:integration] setenv= PYTHONWARNING=all