Make YAML ingester not AIC specific

Add test case for federated design

Fix issues with inheritance
This commit is contained in:
Scott Hussey 2017-03-02 17:04:57 -06:00
parent 3a331f6c51
commit ace0e47762
14 changed files with 674 additions and 82 deletions

View File

@ -22,7 +22,7 @@ import logging
import helm_drydock.model as model
from helm_drydock.ingester.plugins import IngesterPlugin
class AicYamlIngester(IngesterPlugin):
class YamlIngester(IngesterPlugin):
kind_map = {
"Region": model.Site,
@ -34,10 +34,10 @@ class AicYamlIngester(IngesterPlugin):
}
def __init__(self):
super(AicYamlIngester, self).__init__()
super(YamlIngester, self).__init__()
def get_name(self):
return "aic_yaml"
return "yaml"
"""
AIC YAML ingester params
@ -48,6 +48,8 @@ class AicYamlIngester(IngesterPlugin):
"""
def ingest_data(self, **kwargs):
models = []
if 'filenames' in kwargs:
# TODO validate filenames is array
for f in kwargs.get('filenames'):
@ -55,45 +57,52 @@ class AicYamlIngester(IngesterPlugin):
file = open(f,'rt')
contents = file.read()
file.close()
models.extend(self.parse_docs(contents))
except OSError as err:
self.log.error(
"Error opening input file %s for ingestion: %s"
% (filename, err))
continue
try:
parsed_data = yaml.load_all(contents)
except yaml.YAMLError as err:
self.log.error("Error parsing YAML in %s: %s" % (f, err))
continue
models = []
for d in parsed_data:
kind = d.get('kind', '')
if kind != '':
if kind in AicYamlIngester.kind_map:
try:
model = AicYamlIngester.kind_map[kind](**d)
models.append(model)
except Exception as err:
self.log.error("Error building model %s: %s"
% (kind, str(err)))
else:
self.log.error(
"Error processing document, unknown kind %s"
% (kind))
continue
else:
self.log.error(
"Error processing document in %s, no kind field"
% (f))
continue
return models
elif 'content' in kwargs:
models.extend(self.parse_docs(kwargs.get('content')))
else:
raise ValueError('Missing parameter "filename"')
return processed_data
return models
"""
Translate a YAML string into the internal Drydock model
"""
def parse_docs(self, yaml_string):
models = []
try:
parsed_data = yaml.load_all(yaml_string)
except yaml.YAMLError as err:
raise ValueError("Error parsing YAML in %s: %s" % (f,err))
for d in parsed_data:
kind = d.get('kind', '')
if kind != '':
if kind in YamlIngester.kind_map:
try:
model = YamlIngester.kind_map[kind](**d)
models.append(model)
except Exception as err:
self.log.error("Error building model %s: %s"
% (kind, str(err)))
continue
else:
self.log.error(
"Error processing document, unknown kind %s"
% (kind))
continue
else:
self.log.error(
"Error processing document in %s, no kind field"
% (f))
continue
return models

View File

@ -14,12 +14,16 @@
#
# Models for helm_drydock
#
import logging
from copy import deepcopy
class HardwareProfile(object):
def __init__(self, **kwargs):
self.log = logging.Logger('model')
self.api_version = kwargs.get('apiVersion', '')
if self.api_version == "v1.0":
@ -55,14 +59,19 @@ class HardwareProfile(object):
self.devices.append(
HardwareDeviceAlias(self.api_version, **d))
else:
self.log.error("Unknown API version %s of %s" %
(self.api_version, self.__class__))
raise ValueError('Unknown API version of object')
return
def resolve_alias(self, alias_type, alias):
selector = {}
for d in self.devices:
if d.alias == alias and d.bus_type == alias_type:
return deepcopy(d)
selector['address'] = d.address
selector['device_type'] = d.type
return selector
return None
@ -70,6 +79,8 @@ class HardwareProfile(object):
class HardwareDeviceAlias(object):
def __init__(self, api_version, **kwargs):
self.log = logging.Logger('model')
self.api_version = api_version
if self.api_version == "v1.0":
@ -78,12 +89,16 @@ class HardwareDeviceAlias(object):
self.alias = kwargs.get('alias', None)
self.type = kwargs.get('type', None)
else:
self.log.error("Unknown API version %s of %s" %
(self.api_version, self.__class__))
raise ValueError('Unknown API version of object')
class Site(object):
def __init__(self, **kwargs):
self.log = logging.Logger('model')
self.api_version = kwargs.get('apiVersion', '')
if self.api_version == "v1.0":
@ -100,6 +115,8 @@ class Site(object):
self.baremetal_nodes = []
else:
self.log.error("Unknown API version %s of %s" %
(self.api_version, self.__class__))
raise ValueError('Unknown API version of object')
def get_network(self, network_name):
@ -140,6 +157,8 @@ class Site(object):
class NetworkLink(object):
def __init__(self, **kwargs):
self.log = logging.Logger('model')
self.api_version = kwargs.get('apiVersion', '')
if self.api_version == "v1.0":
@ -152,13 +171,13 @@ class NetworkLink(object):
bonding = spec.get('bonding', {})
self.bonding_mode = bonding.get('mode', 'none')
# TODO How should we define defaults for CIs not in the input?
# How should we define defaults for CIs not in the input?
if self.bonding_mode == '802.3ad':
self.bonding_xmit_hash = bonding.get('hash', 'layer3+4')
self.bonding_peer_rate = bonding.get('peer_rate', 'fast')
self.bonding_mon_rate = bonding.get('mon_rate', '')
self.bonding_up_delay = bonding.get('up_delay', '')
self.bonding_down_delay = bonding.get('down_delay', '')
self.bonding_mon_rate = bonding.get('mon_rate', '100')
self.bonding_up_delay = bonding.get('up_delay', '200')
self.bonding_down_delay = bonding.get('down_delay', '200')
self.mtu = spec.get('mtu', 1500)
self.linkspeed = spec.get('linkspeed', 'auto')
@ -168,12 +187,16 @@ class NetworkLink(object):
self.native_network = spec.get('default_network', '')
else:
self.log.error("Unknown API version %s of %s" %
(self.api_version, self.__class__))
raise ValueError('Unknown API version of object')
class Network(object):
def __init__(self, **kwargs):
self.log = logging.Logger('model')
self.api_version = kwargs.get('apiVersion', '')
if self.api_version == "v1.0":
@ -204,12 +227,16 @@ class Network(object):
for r in routes:
self.routes.append(NetworkRoute(self.api_version, **r))
else:
self.log.error("Unknown API version %s of %s" %
(self.api_version, self.__class__))
raise ValueError('Unknown API version of object')
class NetworkAddressRange(object):
def __init__(self, api_version, **kwargs):
self.log = logging.Logger('model')
self.api_version = api_version
if self.api_version == "v1.0":
@ -217,12 +244,16 @@ class NetworkAddressRange(object):
self.start = kwargs.get('start', None)
self.end = kwargs.get('end', None)
else:
self.log.error("Unknown API version %s of %s" %
(self.api_version, self.__class__))
raise ValueError('Unknown API version of object')
class NetworkRoute(object):
def __init__(self, api_version, **kwargs):
self.log = logging.Logger('model')
self.api_version = api_version
if self.api_version == "v1.0":
@ -230,12 +261,16 @@ class NetworkRoute(object):
self.start = kwargs.get('gateway', None)
self.end = kwargs.get('metric', 100)
else:
self.log.error("Unknown API version %s of %s" %
(self.api_version, self.__class__))
raise ValueError('Unknown API version of object')
class HostProfile(object):
def __init__(self, **kwargs):
self.log = logging.Logger('model')
self.api_version = kwargs.get('apiVersion', '')
if self.api_version == "v1.0":
@ -291,6 +326,8 @@ class HostProfile(object):
self.rack = metadata.get('rack', None)
else:
self.log.error("Unknown API version %s of %s" %
(self.api_version, self.__class__))
raise ValueError('Unknown API version of object')
def apply_inheritance(self, site):
@ -304,7 +341,8 @@ class HostProfile(object):
parent = site.get_host_profile(self.parent_profile)
if parent is None:
return self_copy
raise NameError("Cannot find parent profile %s for %s"
% (self.parent_profile, self.name))
parent = parent.apply_inheritance(site)
@ -338,6 +376,8 @@ class HostProfile(object):
class HostInterface(object):
def __init__(self, api_version, **kwargs):
self.log = logging.Logger('model')
self.api_version = api_version
if self.api_version == "v1.0":
@ -355,8 +395,9 @@ class HostInterface(object):
for n in networks:
self.networks.append(n)
else:
self.log.error("Unknown API version %s of %s" %
(self.api_version, self.__class__))
raise ValueError('Unknown API version of object')
# The device attribute may be hardware alias that translates to a
@ -365,16 +406,24 @@ class HostInterface(object):
# apply_hardware_profile method is called on the parent Node of this
# device, the selector will be decided and applied
def add_selector(self, sel_type, selector):
def add_selector(self, sel_type, address='', dev_type=''):
if getattr(self, 'selectors', None) is None:
self.selectors = []
new_selector = {}
new_selector['selector_type'] = sel_type
new_selector['selector'] = selector
new_selector['address'] = address
new_selector['device_type'] = dev_type
self.selectors.append(new_selector)
def get_slave_selectors(self):
return self.selectors
# Return number of slaves for this interface
def get_slave_count(self):
return len(self.hardware_slaves)
"""
Merge two lists of HostInterface models with child_list taking
priority when conflicts. If a member of child_list has a device_name
@ -394,13 +443,16 @@ class HostInterface(object):
continue
else:
effective_list.append(deepcopy(i))
return effective_list
parent_interfaces = []
for i in parent_list:
parent_name = i.device_name
parent_interfaces.append(parent_name)
add = True
for j in child_list:
if j.device_name == ("!" + parent_name):
add = False
break
elif j.device_name == parent_name:
m = HostInterface(j.api_version)
@ -425,9 +477,15 @@ class HostInterface(object):
m.networks = n
effective_list.append(m)
add = False
break
if add:
effective_list.append(deepcopy(i))
for j in child_list:
if j.device_name not in parent_list:
if (j.device_name not in parent_interfaces
and not j.device_name.startswith("!")):
effective_list.append(deepcopy(j))
return effective_list
@ -457,10 +515,17 @@ class HostPartition(object):
# apply_hardware_profile method is called on the parent Node of this
# device, the selector will be decided and applied
def set_selector(self, sel_type, selector):
self.selector_type = sel_type
def set_selector(self, sel_type, address='', dev_type=''):
selector = {}
selector['type'] = sel_type
selector['address'] = address
selector['device_type'] = dev_type
self.selector = selector
def get_selector(self):
return self.selector
"""
Merge two lists of HostPartition models with child_list taking
priority when conflicts. If a member of child_list has a name
@ -489,8 +554,10 @@ class HostPartition(object):
for i in parent_list:
parent_name = i.name
parent_partitions.append(parent_name)
add = True
for j in child_list:
if j.name == ("!" + parent_name):
add = False
break
elif j.name == parent_name:
p = HostPartition(j.api_version)
@ -500,8 +567,10 @@ class HostPartition(object):
setattr(p, Utils.apply_field_inheritance(getattr(j, f),
getattr(i, f))
)
add = False
effective_list.append(p)
if add:
effective_list.append(deepcopy(i))
for j in child_list:
if j.name not in parent_list:
@ -534,16 +603,18 @@ class BaremetalNode(HostProfile):
for s in i.hardware_slaves:
selector = hw_profile.resolve_alias("pci", s)
if selector is None:
i.add_selector("name", s)
i.add_selector("name", address=p.device)
else:
i.add_selector("address", selector)
i.add_selector("address", address=selector['address'],
dev_type=selector['device_type'])
for p in self_copy.partitions:
selector = hw_profile.resolve_alias("scsi", p.device)
if selector is None:
p.set_selector("name", p.device)
p.set_selector("name", address=p.device)
else:
p.set_selector("address", selector)
p.set_selector("address", address=selector['address'],
dev_type=selector['device_type'])
hardware = {"vendor": getattr(hw_profile, 'vendor', None),
@ -561,6 +632,11 @@ class BaremetalNode(HostProfile):
return self_copy
def get_interface(self, iface_name):
for i in self.interfaces:
if i.device_name == iface_name:
return i
return None
# Utility class for calculating inheritance

View File

@ -31,13 +31,8 @@ class DesignStateClient(object):
return a Site model populated with all components from the design state
"""
def load_design_data(self, design_state=None):
if len(design_state.get_sites()) != 1:
self.log.error("Invalid design state, should only have 1 Site model")
raise Exception("Invalid design state, should only have 1 Site model")
site = design_state.get_sites()[0]
site_name = site.name
def load_design_data(self, site_name, design_state=None):
site = design_state.get_site(site_name)
networks = design_state.get_networks()
@ -96,5 +91,3 @@ class DesignStateClient(object):
site_copy.baremetal_nodes = effective_nodes
return site_copy

View File

@ -21,7 +21,7 @@ from copy import deepcopy
import pytest
import shutil
import os
import helm_drydock.ingester.plugins.aicyaml
import helm_drydock.ingester.plugins.yaml
import yaml
class TestClass(object):
@ -33,15 +33,23 @@ class TestClass(object):
def test_design_inheritance(self, loaded_design):
client = DesignStateClient()
design_data = client.load_design_data(design_state=loaded_design)
design_data = client.load_design_data("sitename", design_state=loaded_design)
design_data = client.compute_model_inheritance(design_data)
print(yaml.dump(design_data, default_flow_style=False))
node = design_data.get_baremetal_node("controller01")
print(yaml.dump(node, default_flow_style=False))
assert node.hardware_profile == 'HPGen9v3'
iface = node.get_interface('bond0')
assert iface.get_slave_count() == 2
iface = node.get_interface('pxe')
assert iface.get_slave_count() == 1
@pytest.fixture(scope='module')
def loaded_design(self, input_files):
input_file = input_files.join("fullsite.yaml")
@ -49,8 +57,8 @@ class TestClass(object):
module_design_state = DesignState()
ingester = Ingester()
ingester.enable_plugins([helm_drydock.ingester.plugins.aicyaml.AicYamlIngester])
ingester.ingest_data(plugin_name='aic_yaml', design_state=module_design_state, filenames=[str(input_file)])
ingester.enable_plugins([helm_drydock.ingester.plugins.yaml.YamlIngester])
ingester.ingest_data(plugin_name='yaml', design_state=module_design_state, filenames=[str(input_file)])
return module_design_state
@ -59,7 +67,7 @@ class TestClass(object):
@pytest.fixture(scope='module')
def input_files(self, tmpdir_factory, request):
tmpdir = tmpdir_factory.mktemp('data')
samples_dir = os.path.dirname(str(request.fspath)) + "/aicyaml_samples"
samples_dir = os.path.dirname(str(request.fspath)) + "/yaml_samples"
samples = os.listdir(samples_dir)
for f in samples:

View File

@ -18,26 +18,42 @@ from helm_drydock.statemgmt import DesignState
import pytest
import shutil
import os
import helm_drydock.ingester.plugins.aicyaml
import helm_drydock.ingester.plugins.yaml
class TestClass(object):
def setup_method(self, method):
print("Running test {0}".format(method.__name__))
def test_ingest_full_site(self, design_state,input_files):
def test_ingest_full_site(self, input_files):
input_file = input_files.join("fullsite.yaml")
design_state = DesignState()
ingester = Ingester()
ingester.enable_plugins([helm_drydock.ingester.plugins.aicyaml.AicYamlIngester])
ingester.ingest_data(plugin_name='aic_yaml', design_state=design_state, filenames=[str(input_file)])
ingester.enable_plugins([helm_drydock.ingester.plugins.yaml.YamlIngester])
ingester.ingest_data(plugin_name='yaml', design_state=design_state, filenames=[str(input_file)])
assert len(design_state.get_host_profiles()) == 3
assert len(design_state.get_baremetal_nodes()) == 2
def test_ingest_federated_design(self, input_files):
profiles_file = input_files.join("fullsite_profiles.yaml")
networks_file = input_files.join("fullsite_networks.yaml")
nodes_file = input_files.join("fullsite_nodes.yaml")
design_state = DesignState()
ingester = Ingester()
ingester.enable_plugins([helm_drydock.ingester.plugins.yaml.YamlIngester])
ingester.ingest_data(plugin_name='yaml', design_state=design_state,
filenames=[str(profiles_file), str(networks_file), str(nodes_file)])
assert len(design_state.host_profiles) == 3
@pytest.fixture(scope='module')
def input_files(self, tmpdir_factory, request):
tmpdir = tmpdir_factory.mktemp('data')
samples_dir = os.path.dirname(str(request.fspath)) + "/aicyaml_samples"
samples_dir = os.path.dirname(str(request.fspath)) + "/yaml_samples"
samples = os.listdir(samples_dir)
for f in samples:
@ -45,9 +61,4 @@ class TestClass(object):
dst_file = str(tmpdir) + "/" + f
shutil.copyfile(src_file, dst_file)
return tmpdir
@pytest.fixture(scope='session')
def design_state(self):
design_state = DesignState()
return design_state
return tmpdir

View File

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from helm_drydock.ingester.plugins.aicyaml import AicYamlIngester
from helm_drydock.ingester.plugins.yaml import YamlIngester
import pytest
import shutil
import os
@ -25,7 +25,7 @@ class TestClass(object):
def test_ingest_singledoc(self, input_files):
input_file = input_files.join("singledoc.yaml")
ingester = AicYamlIngester()
ingester = YamlIngester()
models = ingester.ingest_data(filenames=[str(input_file)])
@ -34,7 +34,7 @@ class TestClass(object):
def test_ingest_multidoc(self, input_files):
input_file = input_files.join("multidoc.yaml")
ingester = AicYamlIngester()
ingester = YamlIngester()
models = ingester.ingest_data(filenames=[str(input_file)])
@ -43,7 +43,7 @@ class TestClass(object):
@pytest.fixture(scope='module')
def input_files(self, tmpdir_factory, request):
tmpdir = tmpdir_factory.mktemp('data')
samples_dir = os.path.dirname(str(request.fspath)) + "/aicyaml_samples"
samples_dir = os.path.dirname(str(request.fspath)) + "/yaml_samples"
samples = os.listdir(samples_dir)
for f in samples:

View File

@ -0,0 +1,228 @@
# 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: 'v1.0'
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: none
mtu: 1500
linkspeed: 100full
trunking:
mode: none
default_network: 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: 'v1.0'
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: none
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: none
# use name, will translate to VLAN ID
default_network: pxe
---
apiVersion: 'v1.0'
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
mon_rate: default
up_delay: default
down_delay: default
mtu: 9000
linkspeed: auto
# Is this link supporting multiple layer 2 networks?
trunking:
mode: tagged
default_network: mgmt
---
apiVersion: 'v1.0'
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:
allocation: static
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: 'v1.0'
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'
# How are addresses assigned?
allocation: dhcp
# 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: 'v1.0'
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'
# How are addresses assigned?
allocation: static
# 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: 'v1.0'
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'
allocation: static
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: 'v1.0'
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'
# How are addresses assigned?
allocation: static
# 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: 9
dns:
domain: sitename.example.com
servers: 8.8.8.8

View File

@ -0,0 +1,70 @@
# 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: 'v1.0'
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-public
# 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
metadata:
roles: os_ctl
rack: rack01
---
apiVersion: 'v1.0'
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

View File

@ -0,0 +1,197 @@
# 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: 'v1.0'
kind: Region
metadata:
name: sitename
date: 17-FEB-2017
description: Sample site design
author: sh8121@att.com
spec:
# Not sure if we have site wide data that doesn't fall into another 'Kind'
---
apiVersion: 'v1.0'
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
partitions:
- name: logs
device: primary_boot
# Partition uuid if needed
part_uuid: 84db9664-f45e-11e6-823d-080027ef795a
size: 10g
# Optional, can carve up unformatted block devices
mountpoint: /var/log
fstype: ext4
mount_options: defaults
# Filesystem UUID or label can be specified. UUID recommended
fs_uuid: cdb74f1c-9e50-4e51-be1d-068b0e9ff69e
fs_label: logs
# Platform (Operating System) settings
platform:
image: ubuntu_16.04_hwe
kernel_params: default
# Additional metadata to apply to a node
metadata:
# Base URL of the introspection service - may go in curtin data
introspection_url: http://172.16.1.10:9090
---
apiVersion: 'v1.0'
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.
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
network_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'
# MaaS supports key/value pairs. Not sure of the use yet
owner_data:
foo: bar
---
apiVersion: 'v1.0'
kind: HostProfile
metadata:
name: k8-node-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:
host_profile: k8-node
interfaces:
- device_name: bond0
networks:
# This is additive, so adds a network to those defined in the host_profile
# inheritance chain
- public
---
apiVersion: 'v1.0'
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:
pci:
- address: pci@0000:00:03.0
alias: prim_nic01
# type could identify expected hardware - used for hardware manifest validation
type: '82540EM Gigabit Ethernet Controller'
- address: pci@0000:00:04.0
alias: prim_nic02
type: '82540EM Gigabit Ethernet Controller'
scsi:
- address: scsi@2:0.0.0
alias: primary_boot
type: 'VBOX HARDDISK'