def process_host_common_fields(self, data, model): """Process fields common to the host-based documents. Update the provided model with the values of fields common to BaremetalNode and HostProfile documents. :param data: dictionary from YAML parsing of the document data/spec section :param model: instance of objects.HostProfile or objects.BaremetalNode to update """ model.parent_profile = data.get('host_profile', None) model.hardware_profile = data.get('hardware_profile', None) oob = data.get('oob', {}) model.oob_parameters = {} for k, v in oob.items(): if k == 'type': model.oob_type = oob.get('type', None) else: model.oob_parameters[k] = v (model.storage_devices, model.volume_groups) = self.process_node_storage( data.get('storage', {})) interfaces = data.get('interfaces', {}) model.interfaces = objects.HostInterfaceList() for k, v in interfaces.items(): int_model = objects.HostInterface() # A null value indicates this interface should be removed # from any parent profiles if v is None: int_model.device_name = '!' + k continue int_model.device_name = k int_model.network_link = v.get('device_link', None) int_model.hardware_slaves = [] slaves = v.get('slaves', []) for s in slaves: int_model.hardware_slaves.append(s) int_model.networks = [] networks = v.get('networks', []) for n in networks: int_model.networks.append(n) model.interfaces.append(int_model) platform = data.get('platform', {}) model.image = platform.get('image', None) model.kernel = platform.get('kernel', None) model.kernel_params = {} for k, v in platform.get('kernel_params', {}).items(): model.kernel_params[k] = v model.primary_network = data.get('primary_network', None) node_metadata = data.get('metadata', {}) metadata_tags = node_metadata.get('tags', []) model.tags = metadata_tags owner_data = node_metadata.get('owner_data', {}) model.owner_data = {} for k, v in owner_data.items(): model.owner_data[k] = v model.rack = node_metadata.get('rack', None) return model
def parse_docs(self, yaml_string): models = [] self.logger.debug( "yamlingester:parse_docs - Parsing YAML string \n%s" % (yaml_string)) 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 == 'Region': api_version = d.get('apiVersion', '') if api_version == 'v1.0': model = objects.Site() metadata = d.get('metadata', {}) # Need to add validation logic, we'll assume the input is # valid for now model.name = metadata.get('name', '') model.status = hd_fields.SiteStatus.Unknown model.source = hd_fields.ModelSource.Designed spec = d.get('spec', {}) model.tag_definitions = objects.NodeTagDefinitionList() tag_defs = spec.get('tag_definitions', []) for t in tag_defs: tag_model = objects.NodeTagDefinition() tag_model.tag = t.get('tag', '') tag_model.type = t.get('definition_type', '') tag_model.definition = t.get('definition', '') if tag_model.type not in ['lshw_xpath']: raise ValueError('Unknown definition type in ' \ 'NodeTagDefinition: %s' % (self.definition_type)) model.tag_definitions.append(tag_model) models.append(model) else: raise ValueError( 'Unknown API version %s of Region kind' % s(api_version)) elif kind == 'NetworkLink': api_version = d.get('apiVersion', '') if api_version == "v1.0": model = objects.NetworkLink() metadata = d.get('metadata', {}) spec = d.get('spec', {}) model.name = metadata.get('name', '') model.site = metadata.get('region', '') bonding = spec.get('bonding', {}) model.bonding_mode = bonding.get( 'mode', hd_fields.NetworkLinkBondingMode.Disabled) # How should we define defaults for CIs not in the input? if model.bonding_mode == hd_fields.NetworkLinkBondingMode.LACP: model.bonding_xmit_hash = bonding.get( 'hash', 'layer3+4') model.bonding_peer_rate = bonding.get( 'peer_rate', 'fast') model.bonding_mon_rate = bonding.get( 'mon_rate', '100') model.bonding_up_delay = bonding.get( 'up_delay', '200') model.bonding_down_delay = bonding.get( 'down_delay', '200') model.mtu = spec.get('mtu', None) model.linkspeed = spec.get('linkspeed', None) trunking = spec.get('trunking', {}) model.trunk_mode = trunking.get( 'mode', hd_fields.NetworkLinkTrunkingMode.Disabled) model.native_network = trunking.get( 'default_network', None) models.append(model) else: raise ValueError('Unknown API version of object') elif kind == 'Network': api_version = d.get('apiVersion', '') if api_version == "v1.0": model = objects.Network() metadata = d.get('metadata', {}) spec = d.get('spec', {}) model.name = metadata.get('name', '') model.site = metadata.get('region', '') model.cidr = spec.get('cidr', None) model.allocation_strategy = spec.get( 'allocation', 'static') model.vlan_id = spec.get('vlan_id', None) model.mtu = spec.get('mtu', None) dns = spec.get('dns', {}) model.dns_domain = dns.get('domain', 'local') model.dns_servers = dns.get('servers', None) ranges = spec.get('ranges', []) model.ranges = [] for r in ranges: model.ranges.append({ 'type': r.get('type', None), 'start': r.get('start', None), 'end': r.get('end', None), }) routes = spec.get('routes', []) model.routes = [] for r in routes: model.routes.append({ 'subnet': r.get('subnet', None), 'gateway': r.get('gateway', None), 'metric': r.get('metric', None), }) models.append(model) elif kind == 'HardwareProfile': api_version = d.get('apiVersion', '') if api_version == 'v1.0': metadata = d.get('metadata', {}) spec = d.get('spec', {}) model = objects.HardwareProfile() # Need to add validation logic, we'll assume the input is # valid for now model.name = metadata.get('name', '') model.site = metadata.get('region', '') model.source = hd_fields.ModelSource.Designed model.vendor = spec.get('vendor', None) model.generation = spec.get('generation', None) model.hw_version = spec.get('hw_version', None) model.bios_version = spec.get('bios_version', None) model.boot_mode = spec.get('boot_mode', None) model.bootstrap_protocol = spec.get( 'bootstrap_protocol', None) model.pxe_interface = spec.get('pxe_interface', None) model.devices = objects.HardwareDeviceAliasList() device_aliases = spec.get('device_aliases', {}) for d in device_aliases: dev_model = objects.HardwareDeviceAlias() dev_model.source = hd_fields.ModelSource.Designed dev_model.alias = d.get('alias', None) dev_model.bus_type = d.get('bus_type', None) dev_model.dev_type = d.get('dev_type', None) dev_model.address = d.get('address', None) model.devices.append(dev_model) models.append(model) elif kind == 'HostProfile' or kind == 'BaremetalNode': api_version = d.get('apiVersion', '') if api_version == "v1.0": model = None if kind == 'HostProfile': model = objects.HostProfile() else: model = objects.BaremetalNode() metadata = d.get('metadata', {}) spec = d.get('spec', {}) model.name = metadata.get('name', '') model.site = metadata.get('region', '') model.source = hd_fields.ModelSource.Designed model.parent_profile = spec.get('host_profile', None) model.hardware_profile = spec.get( 'hardware_profile', None) oob = spec.get('oob', {}) model.oob_type = oob.get('type', None) model.oob_network = oob.get('network', None) model.oob_account = oob.get('account', None) model.oob_credential = oob.get('credential', None) storage = spec.get('storage', {}) model.storage_layout = storage.get('layout', 'lvm') bootdisk = storage.get('bootdisk', {}) model.bootdisk_device = bootdisk.get('device', None) model.bootdisk_root_size = bootdisk.get( 'root_size', None) model.bootdisk_boot_size = bootdisk.get( 'boot_size', None) partitions = storage.get('partitions', []) model.partitions = objects.HostPartitionList() for p in partitions: part_model = objects.HostPartition() part_model.name = p.get('name', None) part_model.source = hd_fields.ModelSource.Designed part_model.device = p.get('device', None) part_model.part_uuid = p.get('part_uuid', None) part_model.size = p.get('size', None) part_model.mountpoint = p.get('mountpoint', None) part_model.fstype = p.get('fstype', 'ext4') part_model.mount_options = p.get( 'mount_options', 'defaults') part_model.fs_uuid = p.get('fs_uuid', None) part_model.fs_label = p.get('fs_label', None) model.partitions.append(part_model) interfaces = spec.get('interfaces', []) model.interfaces = objects.HostInterfaceList() for i in interfaces: int_model = objects.HostInterface() int_model.device_name = i.get('device_name', None) int_model.network_link = i.get('device_link', None) int_model.primary_netowrk = i.get('primary', False) int_model.hardware_slaves = [] slaves = i.get('slaves', []) for s in slaves: int_model.hardware_slaves.append(s) int_model.networks = [] networks = i.get('networks', []) for n in networks: int_model.networks.append(n) model.interfaces.append(int_model) node_metadata = spec.get('metadata', {}) metadata_tags = node_metadata.get('tags', []) model.tags = [] for t in metadata_tags: model.tags.append(t) owner_data = node_metadata.get('owner_data', {}) model.owner_data = {} for k, v in owner_data.items(): model.owner_data[k] = v model.rack = node_metadata.get('rack', None) if kind == 'BaremetalNode': addresses = spec.get('addressing', []) if len(addresses) == 0: raise ValueError('BaremetalNode needs at least' \ ' 1 assigned address') model.addressing = objects.IpAddressAssignmentList( ) for a in addresses: assignment = objects.IpAddressAssignment() address = a.get('address', '') if address == 'dhcp': assignment.type = 'dhcp' assignment.address = None assignment.network = a.get('network') model.addressing.append(assignment) elif address != '': assignment.type = 'static' assignment.address = a.get('address') assignment.network = a.get('network') model.addressing.append(assignment) else: self.log.error( "Invalid address assignment %s on Node %s" % (address, self.name)) models.append(model) else: raise ValueError( 'Unknown API version %s of Kind HostProfile' % (api_version)) else: self.log.error( "Error processing document in %s, no kind field" % (f)) continue return models
def merge_lists(child_list, parent_list): if child_list is None: return parent_list if parent_list is None: return child_list effective_list = [] if len(child_list) == 0 and len(parent_list) > 0: for p in parent_list: pp = deepcopy(p) pp.source = hd_fields.ModelSource.Compiled effective_list.append(pp) elif len(parent_list) == 0 and len(child_list) > 0: for i in child_list: if i.get_name().startswith('!'): continue else: ii = deepcopy(i) ii.source = hd_fields.ModelSource.Compiled effective_list.append(ii) elif len(parent_list) > 0 and len(child_list) > 0: parent_interfaces = [] for i in parent_list: parent_name = i.get_name() parent_interfaces.append(parent_name) add = True for j in child_list: if j.get_name() == ("!" + parent_name): add = False break elif j.get_name() == parent_name: m = objects.HostInterface() m.device_name = j.get_name() m.network_link = \ objects.Utils.apply_field_inheritance( getattr(j, 'network_link', None), getattr(i, 'network_link', None)) s = [ x for x in getattr(i, 'hardware_slaves', []) if ("!" + x ) not in getattr(j, 'hardware_slaves', []) ] s.extend([ x for x in getattr(j, 'hardware_slaves', []) if not x.startswith("!") ]) m.hardware_slaves = s n = [ x for x in getattr(i, 'networks', []) if ("!" + x) not in getattr(j, 'networks', []) ] n.extend([ x for x in getattr(j, 'networks', []) if not x.startswith("!") ]) m.networks = n m.source = hd_fields.ModelSource.Compiled effective_list.append(m) add = False break if add: ii = deepcopy(i) ii.source = hd_fields.ModelSource.Compiled effective_list.append(ii) for j in child_list: if (j.device_name not in parent_interfaces and not j.get_name().startswith("!")): jj = deepcopy(j) jj.source = hd_fields.ModelSource.Compiled effective_list.append(jj) return effective_list
def parse_docs(self, yaml_string): """Translate a YAML string into the internal Drydock model.""" models = [] self.logger.debug( "yamlingester:parse_docs - Parsing YAML string \n%s" % (yaml_string)) try: parsed_data = yaml.load_all(yaml_string) except yaml.YAMLError as err: raise ValueError("Error parsing YAML: %s" % (err)) for d in parsed_data: kind = d.get('kind', '') api = d.get('apiVersion', '') if api.startswith('drydock/'): (foo, api_version) = api.split('/') if kind != '': if kind == 'Region': if api_version == 'v1': model = objects.Site() metadata = d.get('metadata', {}) # Need to add validation logic, we'll assume the input is # valid for now model.name = metadata.get('name', '') model.status = hd_fields.SiteStatus.Unknown model.source = hd_fields.ModelSource.Designed spec = d.get('spec', {}) model.tag_definitions = objects.NodeTagDefinitionList( ) tag_defs = spec.get('tag_definitions', []) for t in tag_defs: tag_model = objects.NodeTagDefinition() tag_model.tag = t.get('tag', '') tag_model.type = t.get('definition_type', '') tag_model.definition = t.get('definition', '') if tag_model.type not in ['lshw_xpath']: raise ValueError( 'Unknown definition type in ' 'NodeTagDefinition: %s' % (t.definition_type)) model.tag_definitions.append(tag_model) auth_keys = spec.get('authorized_keys', []) model.authorized_keys = [k for k in auth_keys] models.append(model) else: raise ValueError( "Unknown API version %s of Region kind" % (api_version)) elif kind == 'Rack': if api_version == "v1": model = objects.Rack() metadata = d.get('metadata', {}) spec = d.get('spec', {}) model.name = metadata.get('name', None) model.site = metadata.get('region', None) model.tor_switches = objects.TorSwitchList() tors = spec.get('tor_switches', {}) for k, v in tors.items(): tor = objects.TorSwitch() tor.switch_name = k tor.mgmt_ip = v.get('mgmt_ip', None) tor.sdn_api_uri = v.get('sdn_api_url', None) model.tor_switches.append(tor) location = spec.get('location', {}) model.location = dict() for k, v in location.items(): model.location[k] = v model.local_networks = [ n for n in spec.get('local_networks', []) ] models.append(model) else: raise ValueError( "Unknown API version %s of Rack kind" % (api_version)) elif kind == 'NetworkLink': if api_version == "v1": model = objects.NetworkLink() metadata = d.get('metadata', {}) spec = d.get('spec', {}) model.name = metadata.get('name', '') model.site = metadata.get('region', '') metalabels = metadata.get('labels', []) for l in metalabels: if model.metalabels is None: model.metalabels = [l] else: model.metalabels.append(l) bonding = spec.get('bonding', {}) model.bonding_mode = bonding.get( 'mode', hd_fields.NetworkLinkBondingMode.Disabled) # How should we define defaults for CIs not in the input? if model.bonding_mode == hd_fields.NetworkLinkBondingMode.LACP: model.bonding_xmit_hash = bonding.get( 'hash', 'layer3+4') model.bonding_peer_rate = bonding.get( 'peer_rate', 'fast') model.bonding_mon_rate = bonding.get( 'mon_rate', '100') model.bonding_up_delay = bonding.get( 'up_delay', '200') model.bonding_down_delay = bonding.get( 'down_delay', '200') model.mtu = spec.get('mtu', None) model.linkspeed = spec.get('linkspeed', None) trunking = spec.get('trunking', {}) model.trunk_mode = trunking.get( 'mode', hd_fields.NetworkLinkTrunkingMode.Disabled) model.native_network = trunking.get( 'default_network', None) model.allowed_networks = spec.get( 'allowed_networks', None) models.append(model) else: raise ValueError('Unknown API version of object') elif kind == 'Network': if api_version == "v1": model = objects.Network() metadata = d.get('metadata', {}) spec = d.get('spec', {}) model.name = metadata.get('name', '') model.site = metadata.get('region', '') metalabels = metadata.get('labels', []) for l in metalabels: if model.metalabels is None: model.metalabels = [l] else: model.metalabels.append(l) model.cidr = spec.get('cidr', None) model.vlan_id = spec.get('vlan', None) model.mtu = spec.get('mtu', None) dns = spec.get('dns', {}) model.dns_domain = dns.get('domain', 'local') model.dns_servers = dns.get('servers', None) ranges = spec.get('ranges', []) model.ranges = [] for r in ranges: model.ranges.append({ 'type': r.get('type', None), 'start': r.get('start', None), 'end': r.get('end', None), }) routes = spec.get('routes', []) model.routes = [] for r in routes: model.routes.append({ 'subnet': r.get('subnet', None), 'gateway': r.get('gateway', None), 'metric': r.get('metric', None), }) dhcp_relay = spec.get('dhcp_relay', None) if dhcp_relay is not None: model.dhcp_relay_self_ip = dhcp_relay.get( 'self_ip', None) model.dhcp_relay_upstream_target = dhcp_relay.get( 'upstream_target', None) models.append(model) elif kind == 'HardwareProfile': if api_version == 'v1': metadata = d.get('metadata', {}) spec = d.get('spec', {}) model = objects.HardwareProfile() # Need to add validation logic, we'll assume the input is # valid for now model.name = metadata.get('name', '') model.site = metadata.get('region', '') model.source = hd_fields.ModelSource.Designed model.vendor = spec.get('vendor', None) model.generation = spec.get('generation', None) model.hw_version = spec.get('hw_version', None) model.bios_version = spec.get('bios_version', None) model.boot_mode = spec.get('boot_mode', None) model.bootstrap_protocol = spec.get( 'bootstrap_protocol', None) model.pxe_interface = spec.get( 'pxe_interface', None) model.devices = objects.HardwareDeviceAliasList() device_aliases = spec.get('device_aliases', {}) for d in device_aliases: dev_model = objects.HardwareDeviceAlias() dev_model.source = hd_fields.ModelSource.Designed dev_model.alias = d.get('alias', None) dev_model.bus_type = d.get('bus_type', None) dev_model.dev_type = d.get('dev_type', None) dev_model.address = d.get('address', None) model.devices.append(dev_model) models.append(model) elif kind == 'HostProfile' or kind == 'BaremetalNode': if api_version == "v1": model = None if kind == 'HostProfile': model = objects.HostProfile() else: model = objects.BaremetalNode() metadata = d.get('metadata', {}) spec = d.get('spec', {}) model.name = metadata.get('name', '') model.site = metadata.get('region', '') model.source = hd_fields.ModelSource.Designed model.parent_profile = spec.get( 'host_profile', None) model.hardware_profile = spec.get( 'hardware_profile', None) oob = spec.get('oob', {}) model.oob_parameters = {} for k, v in oob.items(): if k == 'type': model.oob_type = oob.get('type', None) else: model.oob_parameters[k] = v storage = spec.get('storage', {}) phys_devs = storage.get('physical_devices', {}) model.storage_devices = objects.HostStorageDeviceList( ) for k, v in phys_devs.items(): sd = objects.HostStorageDevice(name=k) sd.source = hd_fields.ModelSource.Designed if 'labels' in v: sd.labels = v.get('labels').copy() if 'volume_group' in v: vg = v.get('volume_group') sd.volume_group = vg elif 'partitions' in v: sd.partitions = objects.HostPartitionList() for vv in v.get('partitions', []): part_model = objects.HostPartition() part_model.name = vv.get('name') part_model.source = hd_fields.ModelSource.Designed part_model.part_uuid = vv.get( 'part_uuid', None) part_model.size = vv.get('size', None) if 'labels' in vv: part_model.labels = vv.get( 'labels').copy() if 'volume_group' in vv: part_model.volume_group = vv.get( 'vg') elif 'filesystem' in vv: fs_info = vv.get('filesystem', {}) part_model.mountpoint = fs_info.get( 'mountpoint', None) part_model.fstype = fs_info.get( 'fstype', 'ext4') part_model.mount_options = fs_info.get( 'mount_options', 'defaults') part_model.fs_uuid = fs_info.get( 'fs_uuid', None) part_model.fs_label = fs_info.get( 'fs_label', None) sd.partitions.append(part_model) model.storage_devices.append(sd) model.volume_groups = objects.HostVolumeGroupList() vol_groups = storage.get('volume_groups', {}) for k, v in vol_groups.items(): vg = objects.HostVolumeGroup(name=k) vg.vg_uuid = v.get('vg_uuid', None) vg.logical_volumes = objects.HostVolumeList() model.volume_groups.append(vg) for vv in v.get('logical_volumes', []): lv = objects.HostVolume( name=vv.get('name')) lv.size = vv.get('size', None) lv.lv_uuid = vv.get('lv_uuid', None) if 'filesystem' in vv: fs_info = vv.get('filesystem', {}) lv.mountpoint = fs_info.get( 'mountpoint', None) lv.fstype = fs_info.get( 'fstype', 'ext4') lv.mount_options = fs_info.get( 'mount_options', 'defaults') lv.fs_uuid = fs_info.get( 'fs_uuid', None) lv.fs_label = fs_info.get( 'fs_label', None) vg.logical_volumes.append(lv) interfaces = spec.get('interfaces', {}) model.interfaces = objects.HostInterfaceList() for k, v in interfaces.items(): int_model = objects.HostInterface() # A null value indicates this interface should be removed # from any parent profiles if v is None: int_model.device_name = '!' + k continue int_model.device_name = k int_model.network_link = v.get( 'device_link', None) int_model.hardware_slaves = [] slaves = v.get('slaves', []) for s in slaves: int_model.hardware_slaves.append(s) int_model.networks = [] networks = v.get('networks', []) for n in networks: int_model.networks.append(n) model.interfaces.append(int_model) platform = spec.get('platform', {}) model.image = platform.get('image', None) model.kernel = platform.get('kernel', None) model.kernel_params = {} for k, v in platform.get('kernel_params', {}).items(): model.kernel_params[k] = v model.primary_network = spec.get( 'primary_network', None) node_metadata = spec.get('metadata', {}) metadata_tags = node_metadata.get('tags', []) model.tags = metadata_tags owner_data = node_metadata.get('owner_data', {}) model.owner_data = {} for k, v in owner_data.items(): model.owner_data[k] = v model.rack = node_metadata.get('rack', None) if kind == 'BaremetalNode': model.boot_mac = node_metadata.get( 'boot_mac', None) addresses = spec.get('addressing', []) if len(addresses) == 0: raise ValueError( 'BaremetalNode needs at least' ' 1 assigned address') model.addressing = objects.IpAddressAssignmentList( ) for a in addresses: assignment = objects.IpAddressAssignment() address = a.get('address', '') if address == 'dhcp': assignment.type = 'dhcp' assignment.address = None assignment.network = a.get('network') model.addressing.append(assignment) elif address != '': assignment.type = 'static' assignment.address = a.get('address') assignment.network = a.get('network') model.addressing.append(assignment) else: self.log.error( "Invalid address assignment %s on Node %s" % (address, self.name)) models.append(model) else: raise ValueError( 'Unknown API version %s of Kind HostProfile' % (api_version)) else: self.log.error("Error processing document, no kind field") continue elif api.startswith('promenade/'): (foo, api_version) = api.split('/') if api_version == 'v1': metadata = d.get('metadata', {}) target = metadata.get('target', 'all') name = metadata.get('name', None) model = objects.PromenadeConfig( target=target, name=name, kind=kind, document=base64.b64encode( bytearray(yaml.dump(d), encoding='utf-8')).decode('ascii')) models.append(model) return models