spyglass/spyglass/data_extractor/base.py

245 lines
6.9 KiB
Python
Executable File

# Copyright 2018 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.
import abc
import logging
from spyglass.data_extractor import models
LOG = logging.getLogger(__name__)
class BaseDataSourcePlugin(metaclass=abc.ABCMeta):
"""Provide basic hooks for data source plugins"""
def __init__(self, region, **kwargs):
self.source_type = None
self.source_name = None
self.region = region
self.raw_data = None
self.data = None
@abc.abstractmethod
def load_raw_data(self):
"""Loads raw data from data source"""
return
@abc.abstractmethod
def parse_racks(self):
"""Return list of racks in the region
:returns: list of Rack objects
:rtype: list
"""
return []
@abc.abstractmethod
def parse_hosts(self, rack=None):
"""Return list of hosts in the region
:param string rack: Rack name
:returns: list of Host objects containing a rack's host data
:rtype: list of models.Host
"""
return []
@abc.abstractmethod
def parse_networks(self):
"""Return list of networks in the region
:returns: list of network data
:rtype: list of models.VLANNetworkData
"""
# TODO(nh863p): Expand the return type if they are rack level subnets
# TODO(nh863p): Is ingress information can be provided here?
return []
@abc.abstractmethod
def parse_ips(self, host):
"""Return list of IPs on the host
:param string host: Host name
:returns: IPs per network on the host
:rtype: models.IPList
The network name from get_networks is expected to be the keys of this
dict. In case some networks are missed, they are expected to be either
DHCP or internally generated n the next steps by the design rules.
"""
return {}
@abc.abstractmethod
def parse_dns_servers(self):
"""Return the DNS servers
:param string region: Region name
:returns: DNS servers to be configured on host
:rtype: models.ServerList
"""
return []
@abc.abstractmethod
def parse_ntp_servers(self):
"""Return the NTP servers
:returns: NTP servers to be configured on host
:rtype: models.ServerList
"""
return []
@abc.abstractmethod
def parse_ldap_information(self):
"""Return the LDAP server information
:returns: LDAP server information
:rtype: dict
Example: {'url': 'ldap.example.com',
'common_name': 'ldap-site1',
'domain': 'test',
'subdomain': 'test_sub1'}
"""
return {}
@abc.abstractmethod
def parse_location_information(self):
"""Return location information
:returns: Dict of location information
:rtype: dict
Example: {'name': 'Dallas',
'physical_location': 'DAL01',
'state': 'Texas',
'country': 'US',
'corridor': 'CR1'}
"""
return {}
@abc.abstractmethod
def parse_domain_name(self):
"""Return the Domain name
:returns: Domain name
:rtype: str
Example: example.com
"""
return ""
def parse_baremetal_information(self):
"""Get baremetal information from plugin
:returns: racks and hosts as a list of Rack objects containing Host
data
:rtype: list of models.Rack
"""
LOG.info("Extract baremetal information from plugin")
return self.parse_racks()
def parse_site_information(self):
"""Get site information from plugin
:returns: site information including location, dns servers, ntp servers
ldap, and domain name
:rtpe: models.SiteInfo
"""
LOG.info("Extract site information from plugin")
# Extract location information
data = {
'region_name': self.region,
'dns': self.parse_dns_servers(),
'ntp': self.parse_ntp_servers(),
'ldap': self.parse_ldap_information(),
'domain': self.parse_domain_name()
}
data.update(self.parse_location_information() or {})
site_info = models.SiteInfo(**data)
return site_info
def parse_network_information(self):
"""Get network details from plugin like Subnets, DNS, NTP and LDAP
:returns: networking data as a Network object
:rtype: models.Network
"""
LOG.info("Extract network information from plugin")
networks = self.parse_networks()
# We are interested in only the below networks mentioned in
# networks_to_scan, so look for these networks from the data
# returned by plugin
networks_to_scan = [
"calico",
"overlay",
"pxe",
"storage",
"oam",
"oob",
"ingress",
]
desired_networks = []
for network in networks:
if network.name in networks_to_scan:
desired_networks.append(network)
return models.Network(desired_networks)
def parse_data_objects(self):
"""Parses raw data into SiteDocumentData object"""
self.data = models.SiteDocumentData(
self.parse_site_information(), self.parse_network_information(),
self.parse_baremetal_information())
def merge_additional_data(self, extra_data):
"""Apply any additional inputs from user
In case plugin does not provide some data, user can specify
the same as part of additional data in form of dict. The user
provided dict will be merged recursively to site_data.
If there is repetition of data then additional data supplied
shall take precedence.
"""
LOG.info("Update site data with additional input")
self.data.merge_additional_data(extra_data)
def get_data(self, extra_data=None):
"""Extract and return SiteDocumentData object
Load raw data, parse data objects, merge additional data if
necessary, and return the resulting SiteDocumentData object
"""
LOG.info("Extract data from plugin")
self.load_raw_data()
self.parse_data_objects()
if extra_data:
self.merge_additional_data(extra_data)
return self.data