aboutsummaryrefslogtreecommitdiffstats
path: root/onap_data_provider
diff options
context:
space:
mode:
authorMichal Jagiello <michal.jagiello@t-mobile.pl>2021-11-30 08:25:09 +0000
committerMichal Jagiello <michal.jagiello@t-mobile.pl>2021-12-03 09:58:59 +0000
commit66e44262b8eb996c06670dcededd899dd1cbd7dc (patch)
tree3fcea0fe3317f8069281cb93c61add4b1599ab83 /onap_data_provider
parent2416a1a546c1d2922c37d513df42e9d26bbaaa42 (diff)
Data provider release
Change-Id: Ia041a07152e8dabd87de05992d3670cbdc1ddaae Issue-ID: INT-2010 Signed-off-by: Michal Jagiello <michal.jagiello@t-mobile.pl>
Diffstat (limited to 'onap_data_provider')
-rw-r--r--onap_data_provider/__init__.py16
-rw-r--r--onap_data_provider/config_loader.py70
-rw-r--r--onap_data_provider/config_parser.py173
-rw-r--r--onap_data_provider/data_provider.py106
-rw-r--r--onap_data_provider/resources/__init__.py16
-rw-r--r--onap_data_provider/resources/aai_service_resource.py83
-rw-r--r--onap_data_provider/resources/cloud_region_resource.py177
-rw-r--r--onap_data_provider/resources/complex_resource.py92
-rw-r--r--onap_data_provider/resources/customer_resource.py189
-rw-r--r--onap_data_provider/resources/esr_system_info_resource.py114
-rw-r--r--onap_data_provider/resources/line_of_business_resource.py73
-rw-r--r--onap_data_provider/resources/msb_k8s_definition.py85
-rw-r--r--onap_data_provider/resources/msb_k8s_profile.py80
-rw-r--r--onap_data_provider/resources/owning_entity_resource.py75
-rw-r--r--onap_data_provider/resources/platform_resource.py73
-rw-r--r--onap_data_provider/resources/pnf_resource.py78
-rw-r--r--onap_data_provider/resources/project_resource.py73
-rw-r--r--onap_data_provider/resources/resource.py45
-rw-r--r--onap_data_provider/resources/resource_creator.py177
-rw-r--r--onap_data_provider/resources/service_instance_resource.py271
-rw-r--r--onap_data_provider/resources/service_resource.py100
-rw-r--r--onap_data_provider/resources/tenant_resource.py85
-rw-r--r--onap_data_provider/resources/vendor_resource.py75
-rw-r--r--onap_data_provider/resources/vnf_resource.py75
-rw-r--r--onap_data_provider/resources/vsp_resource.py71
-rw-r--r--onap_data_provider/resources/xnf_resource.py60
-rw-r--r--onap_data_provider/schemas/infra.schema533
-rw-r--r--onap_data_provider/schemas/infra_1_1.schema533
-rw-r--r--onap_data_provider/tag_handlers.py52
-rw-r--r--onap_data_provider/validator.py52
-rw-r--r--onap_data_provider/versions.py68
31 files changed, 3770 insertions, 0 deletions
diff --git a/onap_data_provider/__init__.py b/onap_data_provider/__init__.py
new file mode 100644
index 0000000..710af4e
--- /dev/null
+++ b/onap_data_provider/__init__.py
@@ -0,0 +1,16 @@
+"""ONAP data provider package."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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.
+"""
diff --git a/onap_data_provider/config_loader.py b/onap_data_provider/config_loader.py
new file mode 100644
index 0000000..5757e1e
--- /dev/null
+++ b/onap_data_provider/config_loader.py
@@ -0,0 +1,70 @@
+"""Data loader module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 pathlib import Path
+from typing import Any, Iterator, List
+import yaml
+from onap_data_provider.tag_handlers import join, generate_random_uuid
+
+# register custom tag handlers in yaml.SafeLoader
+yaml.add_constructor("!join", join, yaml.SafeLoader)
+yaml.add_constructor("!uuid4", generate_random_uuid, yaml.SafeLoader)
+
+
+class ConfigLoader:
+ """Configuration loader class.
+
+ Loads data from file resource.
+ """
+
+ YAML_EXTENSIONS = {".yml", ".yaml"}
+
+ def __init__(self, config_file_path: List[Path]) -> None:
+ """Initialize configuration loader class.
+
+ Args:
+ config_file_path (str): Path to yaml data source file.
+
+ """
+ self.config_file_path: List[Path] = config_file_path
+
+ def _yamls_from_dir(self, dir: Path) -> Iterator[Path]:
+ for child in dir.iterdir(): # type: Path
+ if child.suffix in self.YAML_EXTENSIONS:
+ yield child
+
+ @property
+ def _yamls(self) -> Iterator[Path]:
+ for config_file_path in self.config_file_path: # type: Path
+ if config_file_path.is_file():
+ yield config_file_path
+ elif config_file_path.is_dir():
+ yield from self._yamls_from_dir(config_file_path)
+ else:
+ raise ValueError("Provided path is neither file nor directory")
+
+ def load(self) -> Iterator[Any]:
+ """Get data from the config file.
+
+ Get data from the config file and return parsed to dictionary resource.
+
+ Returns:
+ Any: Data from yaml file.
+
+ """
+ for yaml_path in self._yamls: # type: Path
+ with yaml_path.open() as f:
+ yield yaml.safe_load(f)
diff --git a/onap_data_provider/config_parser.py b/onap_data_provider/config_parser.py
new file mode 100644
index 0000000..e734b72
--- /dev/null
+++ b/onap_data_provider/config_parser.py
@@ -0,0 +1,173 @@
+"""Data parser module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 collections import OrderedDict
+from pathlib import Path
+from typing import Any, Dict, Iterator, List, Optional
+from .config_loader import ConfigLoader
+from .resources.resource import Resource
+from .resources.resource_creator import ResourceCreator
+from .validator import Validator
+from .versions import VersionsEnum
+
+
+class Config:
+ """Config class."""
+
+ VERSION_TAG = "odpSchemaVersion"
+
+ def __init__(self, config: Dict[str, Any]) -> None:
+ """Initialize config object.
+
+ Args:
+ config (Dict[str, Any]): Entites files content loaded by loader.
+
+ """
+ self.config: Dict[str, Any] = config
+
+ @property
+ def version(self) -> VersionsEnum:
+ """Config file version.
+
+ Files with entities are versioned to keep backward compatibility.
+ Each config keep the version number and that value is represented
+ by that property.
+
+ Returns:
+ VersionsEnum: VersionsEnum class object
+
+ """
+ return VersionsEnum.get_version_by_number(
+ str(self.config.get(self.VERSION_TAG))
+ )
+
+ @property
+ def resources(self) -> Dict[str, Any]:
+ """Resources dictionary.
+
+ Dictionary with definition of objects to be created in ONAP.
+
+ Returns:
+ Dict[str, Any]: Resources dictionary
+
+ """
+ if self.version == VersionsEnum.NONE:
+ return self.config
+ resources: Dict[str, Any] = self.config["resources"]
+ return resources
+
+
+class ConfigParser:
+ """Configuration parser class.
+
+ Processes data loaded from resource.
+ """
+
+ def __init__(self, config_file_path: List[Path]) -> None:
+ """Initialize configuration parser class.
+
+ Args:
+ config_file_path (str): Path to yaml data source file.
+
+ """
+ self._config_file_path: List[Path] = config_file_path
+ self._config_loader: ConfigLoader = ConfigLoader(self._config_file_path)
+ self._configs: Optional[List[Config]] = None
+ self._validator: Optional[Validator] = None
+ self._PRIORITY_ORDER = (
+ "complexes",
+ "cloud-regions",
+ "vendors",
+ "vsps",
+ "pnfs",
+ "vnfs",
+ "services",
+ "customers",
+ "msb-k8s-definitions",
+ "aai-services",
+ "service-instances",
+ )
+
+ def parse(self) -> Iterator[Resource]:
+ """Parser method.
+
+ Invokes factory method to create objects from nested data dictionary.
+
+ Returns:
+ Iterator[Resource]: Iterator of Resource type objects.
+
+ """
+ for config in self.configs:
+ for resource in self._get_ordered_resources(config.resources):
+ for resource_type, data in resource.items():
+ yield ResourceCreator.create(resource_type, data, config.version)
+
+ def _get_ordered_resources(
+ self, resources_data: Dict[str, Any]
+ ) -> Iterator[Dict[str, Any]]:
+ """Resources helper method.
+
+ Generates data in fixed order defined in _PRIORITY_ORDER property.
+
+ Args:
+ resources_data (Dict[str, Any]): Dictionary generated from YAML infra file.
+
+ Returns:
+ Dict[str, Any]: Iterator of Dict type objects where key is the name
+ of resource type, and the value is actual resource data.
+
+ """
+ ordered_resources: Dict[str, Any] = OrderedDict.fromkeys(
+ self._PRIORITY_ORDER, {}
+ )
+ ordered_resources.update(resources_data)
+ for ordered_resource in ordered_resources.values():
+ for resource_data in ordered_resource:
+ yield resource_data
+
+ @property
+ def configs(self) -> List[Config]:
+ """Config loaded using loader.
+
+ Returns:
+ Dict[str, Any]: Config
+
+ """
+ if self._configs is None:
+ self._configs = [Config(config) for config in self._config_loader.load()]
+ return self._configs
+
+ @property
+ def validator(self) -> Validator:
+ """Property which stores validator object.
+
+ Used to validate provided data.
+
+ Returns:
+ Validator: Validator object
+
+ """
+ if not self._validator:
+ self._validator = Validator()
+ return self._validator
+
+ def validate(self) -> None:
+ """Validate provided resources.
+
+ Checks whether the data provided by the user are correct.
+ """
+ for config in self.configs:
+ self.validator.validate(config.version, config.resources)
diff --git a/onap_data_provider/data_provider.py b/onap_data_provider/data_provider.py
new file mode 100644
index 0000000..0cf941e
--- /dev/null
+++ b/onap_data_provider/data_provider.py
@@ -0,0 +1,106 @@
+"""Main project class."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 argparse
+import logging
+import logging.config
+import os
+import sys
+from pathlib import Path
+
+from onapsdk.onap_service import OnapService # type: ignore
+
+from onap_data_provider.config_parser import ConfigParser
+
+
+logging.config.dictConfig(
+ {
+ "version": 1,
+ "disable_existing_loggers": False,
+ "formatters": {
+ "odp": {
+ "class": "logging.Formatter",
+ "format": "%(asctime)s [%(levelname)s] %(module)s: %(message)s",
+ }
+ },
+ "handlers": {
+ "console": {
+ "class": "logging.StreamHandler",
+ "level": os.getenv("LOGGING_LEVEL", "INFO").upper(),
+ "formatter": "odp",
+ },
+ "file": {
+ "class": "logging.FileHandler",
+ "level": "DEBUG",
+ "filename": "odp.log",
+ "mode": "w",
+ "formatter": "odp",
+ },
+ },
+ "loggers": {
+ "": {"level": "DEBUG", "handlers": ["console", "file"]},
+ },
+ }
+)
+
+
+def create_parser() -> argparse.ArgumentParser:
+ """Create argument parser."""
+ parser: argparse.ArgumentParser = argparse.ArgumentParser(
+ description="ONAP data provider"
+ )
+ parser.add_argument(
+ "-f",
+ "--filename",
+ type=Path,
+ action="append",
+ dest="infra_files",
+ required=True,
+ help="Path to the infra file which describes resources to create. Can be directory as well",
+ )
+ parser.add_argument(
+ "--validate-only",
+ action="store_true",
+ help="Doesn't create any resources - checks only if data in infra file has valid format",
+ )
+ parser.add_argument(
+ "--proxy",
+ nargs="*",
+ help="Setup proxy connection with given url. Provide full URL with protocol, eg. http://localhost:8080",
+ )
+ return parser
+
+
+def run() -> None:
+ """Project main function."""
+ parser: argparse.ArgumentParser = create_parser()
+ args: argparse.Namespace = parser.parse_args()
+ if args.proxy:
+ OnapService.set_proxy(
+ {url.split("://")[0]: url.split("://")[1] for url in args.proxy}
+ )
+ conf_parser = ConfigParser(args.infra_files)
+ conf_parser.validate()
+ if args.validate_only:
+ print("Input data is valid!")
+ sys.exit(0)
+ for x in conf_parser.parse():
+ x.create()
+
+
+if __name__ == "__main__":
+ run()
diff --git a/onap_data_provider/resources/__init__.py b/onap_data_provider/resources/__init__.py
new file mode 100644
index 0000000..dbcdf74
--- /dev/null
+++ b/onap_data_provider/resources/__init__.py
@@ -0,0 +1,16 @@
+"""Resources package."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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.
+"""
diff --git a/onap_data_provider/resources/aai_service_resource.py b/onap_data_provider/resources/aai_service_resource.py
new file mode 100644
index 0000000..8fbc119
--- /dev/null
+++ b/onap_data_provider/resources/aai_service_resource.py
@@ -0,0 +1,83 @@
+"""A&AI service model resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict
+
+from onapsdk.aai.service_design_and_creation import Service as AaiService # type: ignore
+from onapsdk.exceptions import ResourceNotFound # type: ignore
+
+from .resource import Resource
+
+
+class AaiServiceResource(Resource):
+ """A&AI service model resource class."""
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize A&AI SDC service resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._aai_service: AaiService = None
+
+ def create(self) -> None:
+ """Create aai service resource."""
+ if not self.exists:
+ logging.debug("Create AaiService %s", self.data["service-id"])
+ AaiService.create(
+ service_id=self.data["service-id"],
+ service_description=self.data["service-description"],
+ )
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.aai_service is not None
+
+ @property
+ def aai_service(self) -> AaiService:
+ """A&AI service property.
+
+ A&AI servic emodel which is represented by the data provided by user.
+
+ Returns:
+ AaiService: A&AI service model object
+
+ """
+ if not self._aai_service:
+ try:
+ for aai_service in AaiService.get_all():
+ if (
+ aai_service.service_id == self.data["service-id"]
+ and aai_service.service_description
+ == self.data["service-description"]
+ ):
+ self._aai_service = aai_service
+ return self._aai_service
+ except ResourceNotFound:
+ logging.error(
+ "A&AI service %s does not exist",
+ self.data["service-id"],
+ )
+ return self._aai_service
diff --git a/onap_data_provider/resources/cloud_region_resource.py b/onap_data_provider/resources/cloud_region_resource.py
new file mode 100644
index 0000000..7bcc3b4
--- /dev/null
+++ b/onap_data_provider/resources/cloud_region_resource.py
@@ -0,0 +1,177 @@
+"""Cloud region resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 onap_data_provider.resources.esr_system_info_resource import (
+ EsrSystemInfoResource,
+)
+import logging
+from typing import Any, Dict
+
+from onapsdk.aai.cloud_infrastructure import CloudRegion, Complex # type: ignore
+from onapsdk.msb.k8s.connectivity_info import ConnectivityInfo # type: ignore
+from onapsdk.so.so_db_adapter import SoDbAdapter, IdentityService # type: ignore
+
+from .resource import Resource
+from .tenant_resource import TenantResource
+from onapsdk.exceptions import APIError, ResourceNotFound # type: ignore
+
+
+class CloudRegionResource(Resource):
+ """Cloud region resource class.
+
+ Creates cloud region.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize cloud region resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._cloud_region: CloudRegion = None
+
+ def create(self) -> None:
+ """Create cloud region resource.
+
+ Create cloud region resource and all related resources.
+
+ """
+ logging.debug("Create CloudRegion %s", self.data["cloud-region-id"])
+ if not self.exists:
+ self._cloud_region = CloudRegion.create(
+ cloud_owner=self.data["cloud-owner"],
+ cloud_region_id=self.data["cloud-region-id"],
+ orchestration_disabled=self.data["orchestration-disabled"],
+ in_maint=self.data["in-maint"],
+ cloud_type=self.data.get("cloud-region-type", "openstack"),
+ cloud_region_version="pike",
+ )
+
+ # Create tenants
+ for tenant_data in self.data.get("tenants", []):
+ tenant_resource = TenantResource(
+ tenant_data, cloud_region=self._cloud_region
+ )
+ tenant_resource.create()
+
+ # Link with complex
+ if (
+ complex_physical_id := self.data.get("complex", {}).get(
+ "physical-location-id"
+ )
+ ) is not None:
+ self._link_to_complex(complex_physical_id)
+
+ # Add availability zones
+ try:
+ for az_data in self.data.get("availability-zones", []):
+ self.cloud_region.add_availability_zone(
+ availability_zone_name=az_data["availability-zone-name"],
+ availability_zone_hypervisor_type=az_data["hypervisor-type"],
+ )
+ except APIError:
+ logging.error("Availability zone update not supported.")
+
+ # Create external system infos
+ for esr_system_info_data in self.data.get("esr-system-infos", []):
+ esr_system_info_resource: EsrSystemInfoResource = EsrSystemInfoResource(
+ esr_system_info_data, cloud_region=self._cloud_region
+ )
+ esr_system_info_resource.create()
+
+ if self.data.get("register-to-multicloud", False):
+ self.cloud_region.register_to_multicloud()
+
+ # Create connectivity info for Cloud region if it's type is k8s
+ if self.cloud_region.cloud_type == "k8s":
+ try:
+ ConnectivityInfo.get_connectivity_info_by_region_id(
+ self.cloud_region.cloud_region_id
+ )
+ except APIError:
+ with open(self.data["kube-config"], "rb") as kube_config:
+ ConnectivityInfo.create(
+ cloud_owner=self.cloud_region.cloud_owner,
+ cloud_region_id=self.cloud_region.cloud_region_id,
+ kubeconfig=kube_config.read(),
+ )
+ if not self.cloud_region.complex:
+ logging.error(
+ "k8s cloud region should have complex linked to create SO cloud site DB entry"
+ )
+ else:
+ SoDbAdapter.add_cloud_site(
+ self.cloud_region.cloud_region_id,
+ self.cloud_region.complex.physical_location_id,
+ IdentityService("DEFAULT_KEYSTONE"),
+ )
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.cloud_region is not None
+
+ @property
+ def cloud_region(self) -> CloudRegion:
+ """Cloud region property.
+
+ Cloud region which is represented by the data provided by user.
+
+ Returns:
+ CloudRegion: Cloud region object
+
+ """
+ if not self._cloud_region:
+ try:
+ self._cloud_region = CloudRegion.get_by_id(
+ self.data["cloud-owner"], self.data["cloud-region-id"]
+ )
+ except ResourceNotFound:
+ logging.error(
+ "Cloud region %s does not exist",
+ self.data["cloud-region-id"],
+ )
+ return None
+ return self._cloud_region
+
+ def _link_to_complex(self, complex_physical_id: str) -> None:
+ try: # TODO: change it when https://gitlab.com/Orange-OpenSource/lfn/onap/python-onapsdk/-/issues/120 is fixed
+ if self.cloud_region.complex:
+ logging.info(
+ "Cloud region has relationship with complex: %s. New relationship can't be created",
+ self.cloud_region.complex.physical_location_id,
+ )
+ return
+ except ResourceNotFound:
+ logging.debug("Cloud region has no complex linked with")
+ try:
+ complex: Complex = next(
+ Complex.get_all(physical_location_id=complex_physical_id)
+ )
+ self.cloud_region.link_to_complex(complex)
+ except StopIteration:
+ logging.error(
+ "Complex %s does not exist, please create it before cloud region creation",
+ complex_physical_id,
+ )
diff --git a/onap_data_provider/resources/complex_resource.py b/onap_data_provider/resources/complex_resource.py
new file mode 100644
index 0000000..82ab462
--- /dev/null
+++ b/onap_data_provider/resources/complex_resource.py
@@ -0,0 +1,92 @@
+"""Complex resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict
+
+from onapsdk.aai.cloud_infrastructure import Complex # type: ignore
+
+from .resource import Resource
+from onapsdk.exceptions import ResourceNotFound # type: ignore
+
+
+class ComplexResource(Resource):
+ """Complex resource class."""
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Complex resource initialization.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create complex
+
+ """
+ super().__init__(data)
+ self._complex: Complex = None
+
+ def create(self) -> None:
+ """Create complex resource."""
+ if not self.exists:
+ self._complex = Complex.create(
+ physical_location_id=self.data["physical-location-id"],
+ name=self.data.get("complex-name"),
+ data_center_code=self.data.get("data-center-code"),
+ identity_url=self.data.get("identity-url"),
+ physical_location_type=self.data.get("physical-location-type"),
+ street1=self.data.get("street1"),
+ street2=self.data.get("street2"),
+ city=self.data.get("city"),
+ state=self.data.get("state"),
+ postal_code=self.data.get("postal-code"),
+ country=self.data.get("country"),
+ region=self.data.get("region"),
+ latitude=self.data.get("latitude"),
+ longitude=self.data.get("longitude"),
+ elevation=self.data.get("elevation"),
+ lata=self.data.get("lata"),
+ )
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.complex is not None
+
+ @property
+ def complex(self) -> Complex:
+ """Complex property.
+
+ Returns:
+ Complex: Complex object
+
+ """
+ if not self._complex:
+ try:
+ self._complex = next(
+ Complex.get_all(
+ physical_location_id=self.data["physical-location-id"]
+ )
+ )
+ except ResourceNotFound:
+ logging.error(
+ "Complex %s does not exist", self.data["physical-location-id"]
+ )
+ return None
+ return self._complex
diff --git a/onap_data_provider/resources/customer_resource.py b/onap_data_provider/resources/customer_resource.py
new file mode 100644
index 0000000..2bbb1ef
--- /dev/null
+++ b/onap_data_provider/resources/customer_resource.py
@@ -0,0 +1,189 @@
+"""Customer resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict
+
+from onapsdk.aai.business import Customer, ServiceSubscription # type: ignore
+from onapsdk.aai.cloud_infrastructure import CloudRegion, Tenant # type: ignore
+
+from onapsdk.sdc.service import Service # type: ignore
+
+from .resource import Resource
+from onapsdk.exceptions import ResourceNotFound # type: ignore
+
+
+class CustomerResource(Resource):
+ """Customer resource class.
+
+ Creates customer.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize customer resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._customer: Customer = None
+
+ def create(self) -> None:
+ """Create customer resource.
+
+ Create customer resource and all related resources.
+
+ """
+ logging.debug("Create Customer %s", self.data["global-customer-id"])
+ if not self.exists:
+ self._customer = Customer.create(
+ global_customer_id=self.data["global-customer-id"],
+ subscriber_name=self.data["subscriber-name"],
+ subscriber_type=self.data["subscriber-type"],
+ )
+
+ for service_subscription in self.data.get("service-subscriptions", []):
+ resource = CustomerResource.ServiceSubscriptionResource(
+ service_subscription, self._customer
+ )
+ resource.create()
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.customer is not None
+
+ @property
+ def customer(self) -> Customer:
+ """Access to customer property.
+
+ Customer property containing Customer object.
+
+ Returns:
+ Customer: Customer object
+
+ """
+ if not self._customer:
+ try:
+ self._customer = Customer.get_by_global_customer_id(
+ self.data["global-customer-id"]
+ )
+ except ResourceNotFound:
+ logging.error(
+ "Customer %s does not exist",
+ self.data["global-customer-id"],
+ )
+ return None
+ return self._customer
+
+ class ServiceSubscriptionResource(Resource):
+ """Service subscription class.
+
+ Creates service subscription.
+ """
+
+ def __init__(self, data: Dict[str, str], customer: Customer) -> None:
+ """Initialize service subscription resource.
+
+ Args:
+ data (Dict[str, str]): Data needed to create resource.
+ customer (Customer): Related Customer object.
+
+ """
+ super().__init__(data)
+ self._service_subscription: ServiceSubscription = None
+ self._customer: Customer = customer
+
+ def create(self) -> None:
+ """Create Service subscription resource.
+
+ Create service subscription resource belonging to a customer.
+
+ """
+ logging.debug("Create ServiceSubscription %s", self.data["service-type"])
+ if not self.exists:
+ self._service_subscription = self._customer.subscribe_service(
+ Service(self.data["service-type"])
+ )
+
+ for tenant_cloud_region_data in self.data.get("tenants", []):
+ try:
+ cloud_region: CloudRegion = CloudRegion.get_by_id(
+ tenant_cloud_region_data["cloud-owner"],
+ tenant_cloud_region_data["cloud-region-id"],
+ )
+ except ResourceNotFound:
+ logging.error(
+ f"Cloud region {tenant_cloud_region_data['cloud-owner']} {tenant_cloud_region_data['cloud-region-id']} does not exists"
+ )
+ continue
+ try:
+ tenant: Tenant = cloud_region.get_tenant(
+ tenant_cloud_region_data["tenant-id"]
+ )
+ except ResourceNotFound:
+ logging.error(
+ f"Tenant {tenant_cloud_region_data['tenant-id']} does not exist"
+ )
+ continue
+
+ self.service_subscription.link_to_cloud_region_and_tenant(
+ cloud_region, tenant
+ )
+ logging.debug(
+ f"Service subscription linked to {tenant.name} tenant and {cloud_region.cloud_region_id} cloud region"
+ )
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.service_subscription is not None
+
+ @property
+ def service_subscription(self) -> ServiceSubscription:
+ """Get ServiceSubscription instance.
+
+ Get ServiceSubscription instance.
+
+ Returns:
+ ServiceSubscription: Created `ServiceSubscription` subclass instance.
+ """
+ if not self._service_subscription:
+ try:
+ self._service_subscription = (
+ self._customer.get_service_subscription_by_service_type(
+ self.data["service-type"]
+ )
+ )
+ except ResourceNotFound:
+ logging.error(
+ "Service type %s does not exist",
+ self.data["service-type"],
+ )
+ return None
+ return self._service_subscription
diff --git a/onap_data_provider/resources/esr_system_info_resource.py b/onap_data_provider/resources/esr_system_info_resource.py
new file mode 100644
index 0000000..4c26bbb
--- /dev/null
+++ b/onap_data_provider/resources/esr_system_info_resource.py
@@ -0,0 +1,114 @@
+"""External system info resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict
+
+from onapsdk.aai.cloud_infrastructure import CloudRegion, EsrSystemInfo # type: ignore
+from onapsdk.exceptions import APIError # type: ignore
+
+from .resource import Resource
+
+
+class EsrSystemInfoResource(Resource):
+ """ESR system info resource class."""
+
+ def __init__(self, data: Dict[str, Any], cloud_region: CloudRegion) -> None:
+ """ESR system info resource initialization.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create esr system info
+ cloud_region (CloudRegion): Cloud region for which esr system info is going to be created
+
+ """
+ super().__init__(data)
+ self.cloud_region: CloudRegion = cloud_region
+ self._esr_system_info: EsrSystemInfo = None
+
+ @staticmethod
+ def get_esr_info_by_id(
+ cloud_region: CloudRegion, esr_syste_info_id: str
+ ) -> EsrSystemInfo:
+ """Get esr system info from Cloud region by it's ID.
+
+ Iterate through cloud region's esr system infos and check
+ if it's already have some with provided ID.
+
+ Args:
+ cloud_region (CloudRegion): CloudRegion object to check if esr system info already exists
+ esr_syste_info_id (str): ESR system info ID to check.
+
+ Returns:
+ EsrSystemInfo: ESR system info object
+ """
+ for esr_system_info in cloud_region.esr_system_infos:
+ if esr_system_info.esr_system_info_id == esr_syste_info_id:
+ return esr_system_info
+
+ def create(self) -> None:
+ """Create ESR system info resource.
+
+ Add ESR system info to provided cloud region
+
+ """
+ logging.debug(
+ "Create ESR system info for %s cloud region",
+ self.cloud_region.cloud_region_id,
+ )
+ if not self.exists:
+ self.cloud_region.add_esr_system_info(
+ esr_system_info_id=self.data["esr-system-info-id"],
+ user_name=self.data["user-name"],
+ password=self.data["password"],
+ system_type=self.data["system-type"],
+ service_url=self.data["service-url"],
+ system_status="active",
+ cloud_domain=self.data["cloud-domain"],
+ default_tenant=self.data.get("default-tenant"),
+ )
+ self._esr_system_info = self.get_esr_info_by_id(
+ self.cloud_region, self.data["esr-system-info-id"]
+ )
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.esr_system_info is not None
+
+ @property
+ def esr_system_info(self) -> EsrSystemInfo:
+ """External system info property.
+
+ Returns:
+ EsrSystemInfo: EsrSystemInfo object
+
+ """
+ if self._esr_system_info is None:
+ try:
+ if (
+ esr_system_info := self.get_esr_info_by_id(
+ self.cloud_region, self.data["esr-system-info-id"]
+ )
+ ) is not None:
+ self._esr_system_info = esr_system_info
+ except APIError:
+ logging.info("No esr system infos")
+ return self._esr_system_info
diff --git a/onap_data_provider/resources/line_of_business_resource.py b/onap_data_provider/resources/line_of_business_resource.py
new file mode 100644
index 0000000..0150746
--- /dev/null
+++ b/onap_data_provider/resources/line_of_business_resource.py
@@ -0,0 +1,73 @@
+"""Line of business resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict, Optional
+
+from onapsdk.aai.business import LineOfBusiness # type: ignore
+from onapsdk.exceptions import ResourceNotFound # type: ignore
+
+from .resource import Resource
+
+
+class LineOfBusinessResource(Resource):
+ """Line of business resource class.
+
+ Creates A&AI line of business.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize line of business resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._line_of_business: Optional[LineOfBusiness] = None
+
+ def create(self) -> None:
+ """Create line of business resource."""
+ logging.debug(f"Create Line of business {self.data['name']}")
+ if not self.exists:
+ self._line_of_business = LineOfBusiness.create(self.data["name"])
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return bool(self.line_of_business)
+
+ @property
+ def line_of_business(self) -> LineOfBusiness:
+ """Line of business property.
+
+ Line of business which is represented by the data provided by user.
+
+ Returns:
+ LineOfBusiness: Line of business object
+
+ """
+ if not self._line_of_business:
+ try:
+ self._line_of_business = LineOfBusiness.get_by_name(self.data["name"])
+ except ResourceNotFound:
+ return None
+ return self._line_of_business
diff --git a/onap_data_provider/resources/msb_k8s_definition.py b/onap_data_provider/resources/msb_k8s_definition.py
new file mode 100644
index 0000000..b4b3342
--- /dev/null
+++ b/onap_data_provider/resources/msb_k8s_definition.py
@@ -0,0 +1,85 @@
+"""MSB K8S definition resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict, Optional
+
+from onapsdk.exceptions import ResourceNotFound # type: ignore
+from onapsdk.msb.k8s.definition import Definition # type: ignore
+
+from .msb_k8s_profile import MsbK8SProfileResource
+from .resource import Resource
+
+
+class MsbK8SDefinitionResource(Resource):
+ """Definition resource class.
+
+ Creates MSB Kubernetes plugin's definition.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize definition resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._definition: Optional[Definition] = None
+
+ def create(self) -> None:
+ """Create definition if not already exists."""
+ if not self.exists:
+ self._definition = Definition.create(
+ self.data["name"],
+ self.data["version"],
+ self.data.get("chart-name"),
+ self.data.get("description"),
+ )
+ with open(self.data["artifact"], "rb") as artifact:
+ self._definition.upload_artifact(artifact.read())
+ for profile_data in self.data.get("profiles", []):
+ MsbK8SProfileResource(profile_data, self.definition).create()
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.definition is not None
+
+ @property
+ def definition(self) -> Optional[Definition]:
+ """Definition property.
+
+ Definition which is represented by the data provided by user.
+
+ Returns:
+ Definition: Definition object
+
+ """
+ if not self._definition:
+ try:
+ self._definition = Definition.get_definition_by_name_version(
+ self.data["name"], self.data["version"]
+ )
+ except ResourceNotFound:
+ logging.error("Definition %s does not exist", self.data["rb-name"])
+ return self._definition
diff --git a/onap_data_provider/resources/msb_k8s_profile.py b/onap_data_provider/resources/msb_k8s_profile.py
new file mode 100644
index 0000000..ae884c2
--- /dev/null
+++ b/onap_data_provider/resources/msb_k8s_profile.py
@@ -0,0 +1,80 @@
+"""MSB K8S definition profile resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict, Optional
+
+from onapsdk.exceptions import ResourceNotFound # type: ignore
+from onapsdk.msb.k8s.definition import Definition, Profile # type: ignore
+
+from .resource import Resource
+
+
+class MsbK8SProfileResource(Resource):
+ """Profile resource class.
+
+ Creates MSB Kubernetes plugin's profile
+ """
+
+ def __init__(self, data: Dict[str, Any], definition: Definition) -> None:
+ """Initialize definition resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._profile: Optional[Profile] = None
+ self.definition: Definition = definition
+
+ def create(self) -> None:
+ """Create profile if not already exists."""
+ if not self.exists:
+ self._profile = self.definition.create_profile(
+ self.data["name"], self.data["namespace"], self.data["k8s-version"]
+ )
+ with open(self.data["artifact"], "rb") as artifact:
+ self._profile.upload_artifact(artifact.read())
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.profile is not None
+
+ @property
+ def profile(self) -> Optional[Profile]:
+ """Profile property.
+
+ Profile which is represented by the data provided by user.
+
+ Returns:
+ Profile: Profile object
+
+ """
+ if not self._profile:
+ try:
+ self._profile = self.definition.get_profile_by_name(
+ self.data["rb-name"]
+ )
+ except ResourceNotFound:
+ logging.error("Profile %s not found", self.data["name"])
+ return self._profile
diff --git a/onap_data_provider/resources/owning_entity_resource.py b/onap_data_provider/resources/owning_entity_resource.py
new file mode 100644
index 0000000..496ec22
--- /dev/null
+++ b/onap_data_provider/resources/owning_entity_resource.py
@@ -0,0 +1,75 @@
+"""Owning entity resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict, Optional
+
+from onapsdk.aai.business import OwningEntity # type: ignore
+from onapsdk.exceptions import ResourceNotFound # type: ignore
+
+from .resource import Resource
+
+
+class OwningEntityResource(Resource):
+ """Owning entity resource class.
+
+ Creates A&AI line of business.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize line of business resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._owning_entity: Optional[OwningEntity] = None
+
+ def create(self) -> None:
+ """Create line of business resource."""
+ logging.debug(f"Create Owning entity {self.data['name']}")
+ if not self.exists:
+ self._owning_entity = OwningEntity.create(self.data["name"])
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return bool(self.owning_entity)
+
+ @property
+ def owning_entity(self) -> OwningEntity:
+ """Owning entity property.
+
+ Owning entity which is represented by the data provided by user.
+
+ Returns:
+ OwningEntity: Owning entity object
+
+ """
+ if not self._owning_entity:
+ try:
+ self._owning_entity = OwningEntity.get_by_owning_entity_name(
+ self.data["name"]
+ )
+ except ResourceNotFound:
+ return None
+ return self._owning_entity
diff --git a/onap_data_provider/resources/platform_resource.py b/onap_data_provider/resources/platform_resource.py
new file mode 100644
index 0000000..5e8893c
--- /dev/null
+++ b/onap_data_provider/resources/platform_resource.py
@@ -0,0 +1,73 @@
+"""Platform resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict, Optional
+
+from onapsdk.aai.business import Platform # type: ignore
+from onapsdk.exceptions import ResourceNotFound # type: ignore
+
+from .resource import Resource
+
+
+class PlatformResource(Resource):
+ """Platform resource class.
+
+ Creates A&AI platform.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize platform resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._platform: Optional[Platform] = None
+
+ def create(self) -> None:
+ """Create platform resource."""
+ logging.debug(f"Create Platform {self.data['name']}")
+ if not self.exists:
+ self._platform = Platform.create(self.data["name"])
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return bool(self.platform)
+
+ @property
+ def platform(self) -> Platform:
+ """Platform property.
+
+ Platform which is represented by the data provided by user.
+
+ Returns:
+ Platform: Platform object
+
+ """
+ if not self._platform:
+ try:
+ self._platform = Platform.get_by_name(self.data["name"])
+ except ResourceNotFound:
+ return None
+ return self._platform
diff --git a/onap_data_provider/resources/pnf_resource.py b/onap_data_provider/resources/pnf_resource.py
new file mode 100644
index 0000000..553018b
--- /dev/null
+++ b/onap_data_provider/resources/pnf_resource.py
@@ -0,0 +1,78 @@
+"""Pnf resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict
+
+from onapsdk.sdc.pnf import Pnf # type: ignore
+from onapsdk.sdc.vendor import Vendor # type: ignore
+from .resource import Resource
+from .xnf_resource import XnfResource
+
+
+class PnfResource(Resource, XnfResource):
+ """Pnf resource class.
+
+ Creates pnf.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize pnf resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+
+ def create(self) -> None:
+ """Create pnf resource.
+
+ Create pnf resource and link to provided resources.
+
+ """
+ if not self.exists:
+ logging.debug("Create Pnf %s", self.data["name"])
+ self._xnf = Pnf(self.data["name"])
+ if (vendor_name := self.data.get("vendor")) is not None:
+ self._xnf.vendor = Vendor(vendor_name)
+ self.onboard_resource_with_properties(self.data)
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.pnf is not None
+
+ @property
+ def pnf(self) -> Pnf:
+ """Pnf property.
+
+ Pnf which is represented by the data provided by user.
+
+ Returns:
+ Pnf: Pnf object
+
+ """
+ if (pnf := Pnf(name=self.data["name"])).created():
+ self._xnf = pnf
+ return self._xnf
+ return None
diff --git a/onap_data_provider/resources/project_resource.py b/onap_data_provider/resources/project_resource.py
new file mode 100644
index 0000000..e4c19c2
--- /dev/null
+++ b/onap_data_provider/resources/project_resource.py
@@ -0,0 +1,73 @@
+"""Project resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict, Optional
+
+from onapsdk.aai.business import Project # type: ignore
+from onapsdk.exceptions import ResourceNotFound # type: ignore
+
+from .resource import Resource
+
+
+class ProjectResource(Resource):
+ """Project resource class.
+
+ Creates A&AI project.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize project resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._project: Optional[Project] = None
+
+ def create(self) -> None:
+ """Create project resource."""
+ logging.debug(f"Create Project {self.data['name']}")
+ if not self.exists:
+ self._project = Project.create(self.data["name"])
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return bool(self.project)
+
+ @property
+ def project(self) -> Project:
+ """Project property.
+
+ Project which is represented by the data provided by user.
+
+ Returns:
+ Project: Project object
+
+ """
+ if not self._project:
+ try:
+ self._project = Project.get_by_name(self.data["name"])
+ except ResourceNotFound:
+ return None
+ return self._project
diff --git a/onap_data_provider/resources/resource.py b/onap_data_provider/resources/resource.py
new file mode 100644
index 0000000..10477d1
--- /dev/null
+++ b/onap_data_provider/resources/resource.py
@@ -0,0 +1,45 @@
+"""Resource base module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 abc import ABC, abstractmethod
+from typing import Dict, Any
+
+
+class Resource(ABC):
+ """Base Resource class.
+
+ Abstract class which is a base for all other resource classes.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize resource.
+
+ Data contains all needed information to create resource.
+ It's readed from configuration file.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ self.data = data
+
+ @abstractmethod
+ def create(self) -> None:
+ """Create resource.
+
+ Abstract method to create resource
+
+ """
diff --git a/onap_data_provider/resources/resource_creator.py b/onap_data_provider/resources/resource_creator.py
new file mode 100644
index 0000000..34cbafd
--- /dev/null
+++ b/onap_data_provider/resources/resource_creator.py
@@ -0,0 +1,177 @@
+"""Resource creator module."""
+from __future__ import annotations
+
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 onap_data_provider.resources.platform_resource import PlatformResource
+import typing
+from abc import ABC
+
+from .aai_service_resource import AaiServiceResource
+from .cloud_region_resource import CloudRegionResource
+from .complex_resource import ComplexResource
+from .customer_resource import CustomerResource
+from .line_of_business_resource import LineOfBusinessResource
+from .msb_k8s_definition import MsbK8SDefinitionResource
+from .owning_entity_resource import OwningEntityResource
+from .pnf_resource import PnfResource
+from .project_resource import ProjectResource
+from .service_resource import ServiceResource
+from .service_instance_resource import (
+ ServiceInstanceResource,
+ ServiceInstanceResource_1_1,
+)
+from .vendor_resource import VendorResource
+from .vnf_resource import VnfResource
+from .vsp_resource import VspResource
+from ..versions import VersionsEnum
+
+if typing.TYPE_CHECKING:
+ from .resource import Resource
+
+
+class ResourceCreator(ABC):
+ """Resource creator.
+
+ Provides a method to create `Resource` instances.
+ """
+
+ RESOURCES_TYPES_DICT: typing.Mapping[
+ str, typing.Mapping[VersionsEnum, typing.Type[Resource]]
+ ] = {
+ "aai-service": {
+ VersionsEnum.NONE: AaiServiceResource,
+ VersionsEnum.V1_0: AaiServiceResource,
+ VersionsEnum.V1_1: AaiServiceResource,
+ },
+ "cloud-region": {
+ VersionsEnum.NONE: CloudRegionResource,
+ VersionsEnum.V1_0: CloudRegionResource,
+ VersionsEnum.V1_1: CloudRegionResource,
+ },
+ "complex": {
+ VersionsEnum.NONE: ComplexResource,
+ VersionsEnum.V1_0: ComplexResource,
+ VersionsEnum.V1_1: ComplexResource,
+ },
+ "customer": {
+ VersionsEnum.NONE: CustomerResource,
+ VersionsEnum.V1_0: CustomerResource,
+ VersionsEnum.V1_1: CustomerResource,
+ },
+ "vsp": {
+ VersionsEnum.NONE: VspResource,
+ VersionsEnum.V1_0: VspResource,
+ VersionsEnum.V1_1: VspResource,
+ },
+ "service": {
+ VersionsEnum.NONE: ServiceResource,
+ VersionsEnum.V1_0: ServiceResource,
+ VersionsEnum.V1_1: ServiceResource,
+ },
+ "vendor": {
+ VersionsEnum.NONE: VendorResource,
+ VersionsEnum.V1_0: VendorResource,
+ VersionsEnum.V1_1: VendorResource,
+ },
+ "pnf": {
+ VersionsEnum.NONE: PnfResource,
+ VersionsEnum.V1_0: PnfResource,
+ VersionsEnum.V1_1: PnfResource,
+ },
+ "vnf": {
+ VersionsEnum.NONE: VnfResource,
+ VersionsEnum.V1_0: VnfResource,
+ VersionsEnum.V1_1: VnfResource,
+ },
+ "service-instance": {
+ VersionsEnum.NONE: ServiceInstanceResource,
+ VersionsEnum.V1_0: ServiceInstanceResource,
+ VersionsEnum.V1_1: ServiceInstanceResource_1_1,
+ },
+ "line-of-business": {
+ VersionsEnum.NONE: LineOfBusinessResource,
+ VersionsEnum.V1_0: LineOfBusinessResource,
+ VersionsEnum.V1_1: LineOfBusinessResource,
+ },
+ "project": {
+ VersionsEnum.NONE: ProjectResource,
+ VersionsEnum.V1_0: ProjectResource,
+ VersionsEnum.V1_1: ProjectResource,
+ },
+ "platform": {
+ VersionsEnum.NONE: PlatformResource,
+ VersionsEnum.V1_0: PlatformResource,
+ VersionsEnum.V1_1: PlatformResource,
+ },
+ "owning-entity": {
+ VersionsEnum.NONE: OwningEntityResource,
+ VersionsEnum.V1_0: OwningEntityResource,
+ VersionsEnum.V1_1: OwningEntityResource,
+ },
+ "msb-k8s-definition": {
+ VersionsEnum.NONE: MsbK8SDefinitionResource,
+ VersionsEnum.V1_0: MsbK8SDefinitionResource,
+ VersionsEnum.V1_1: MsbK8SDefinitionResource,
+ },
+ }
+
+ @classmethod
+ def create(
+ cls,
+ resource_type: str,
+ data: typing.Dict[str, typing.Any],
+ version: VersionsEnum,
+ ) -> Resource:
+ """Resources factory method.
+
+ Based on provided `resource_type` creates `Resource` subclass.
+
+ Supported `resource_type` values:
+ - aai-service: AaiServiceResource
+ - cloud-region: CloudRegionResource
+ - complex: ComplexResource
+ - customer: CustomerResource
+ - vsp: VspResource
+ - service: ServiceResource
+ - vendor: VendorResource
+ - pnf: PnfResource
+ - vnf: VnfResource
+ - service-instance: ServiceInstanceResource
+ - line-of-business: LineOfBusinessResource
+ - project: ProjectResource
+ - platform: PlatformResource
+ - owning-entity: OwningEntityResource
+ - msb-k8s-definition: MsbK8SDefinitionResource
+
+ Args:
+ resource_type (str): Resource type to create
+ data (typing.Dict[str, typing.Any]): Resource data
+
+ Raises:
+ ValueError: Not support `resource_type` value provided.
+
+ Returns:
+ Resource: Created `Resource` subclass instance.
+
+ """
+ try:
+ return cls.RESOURCES_TYPES_DICT[resource_type][version](data)
+ except KeyError as key_error:
+ raise ValueError(
+ "Invalid resource type provided: %d", resource_type
+ ) from key_error
diff --git a/onap_data_provider/resources/service_instance_resource.py b/onap_data_provider/resources/service_instance_resource.py
new file mode 100644
index 0000000..b89f9df
--- /dev/null
+++ b/onap_data_provider/resources/service_instance_resource.py
@@ -0,0 +1,271 @@
+"""Service instance resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict
+
+from onapsdk.aai.cloud_infrastructure import CloudRegion, Tenant # type: ignore
+from onapsdk.aai.business import Customer, OwningEntity # type: ignore
+from onapsdk.aai.service_design_and_creation import Service as AaiService # type: ignore
+from onapsdk.sdc.service import Service # type: ignore
+from onapsdk.vid import LineOfBusiness, Platform, Project # type: ignore
+from onapsdk.aai.business import ServiceSubscription
+from onapsdk.aai.business import ServiceInstance
+from onapsdk.so.instantiation import ( # type: ignore
+ ServiceInstantiation,
+ SoService,
+)
+
+from .resource import Resource
+from onapsdk.exceptions import APIError, ResourceNotFound # type: ignore
+
+
+class ServiceInstanceResource(Resource):
+ """Service instance resource class.
+
+ Creates service instance.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Service instance resource initialization.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create service instance
+
+ """
+ super().__init__(data)
+ self._customer: Customer = None
+ self._service_subscription: ServiceSubscription = None
+ self._service_instance: ServiceInstance = None
+ self._aai_service: AaiService = None
+
+ def create(self) -> None:
+ """Create ServiceInstance resource."""
+ if not self.exists:
+
+ service: Service = Service(name=self.data["service_name"])
+ if not service.distributed:
+ raise AttributeError(
+ "Service not distrbuted - instance can't be created"
+ )
+ if (cloud_region_id := self.data["cloud_region_id"]) is not None:
+ cloud_region: CloudRegion = CloudRegion.get_by_id(
+ cloud_owner=self.data["cloud_owner"],
+ cloud_region_id=cloud_region_id,
+ )
+ tenant: Tenant = cloud_region.get_tenant(self.data["tenant_id"])
+ self.service_subscription.link_to_cloud_region_and_tenant(
+ cloud_region, tenant
+ )
+ else:
+ cloud_region, tenant = None, None
+ try:
+ owning_entity = OwningEntity.get_by_owning_entity_name(
+ self.data["owning_entity"]
+ )
+ except APIError:
+ owning_entity = OwningEntity.create(self.data["owning_entity"])
+
+ try:
+ aai_service = next(
+ AaiService.get_all(service_id=self.data["aai_service"])
+ )
+ except StopIteration:
+ raise ValueError(
+ f"A&AI Service {self.data['aai_service']} does not exist"
+ )
+
+ service_instantiation: ServiceInstantiation = (
+ ServiceInstantiation.instantiate_macro(
+ sdc_service=service,
+ customer=self.customer,
+ owning_entity=owning_entity,
+ project=Project(self.data["project"]),
+ line_of_business=LineOfBusiness(self.data["line_of_business"]),
+ platform=Platform(self.data["platform"]),
+ cloud_region=cloud_region,
+ tenant=tenant,
+ service_instance_name=self.data["service_instance_name"],
+ so_service=self.so_service,
+ aai_service=aai_service,
+ )
+ )
+ service_instantiation.wait_for_finish(
+ timeout=self.data.get("timeout")
+ ) # 20 minutes timeout
+
+ if service_instantiation.failed == True:
+ logging.error(
+ "Service instantiation failed for %s",
+ self.data["service_instance_name"],
+ )
+ return
+ self._service_instance = (
+ self.service_subscription.get_service_instance_by_name(
+ self.data["service_instance_name"]
+ )
+ )
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.service_instance is not None
+
+ @property
+ def service_instance(self) -> ServiceInstance:
+ """Serviceinstance property.
+
+ Returns:
+ ServiceInstance: ServiceInstance object
+
+ """
+ if not self._service_instance:
+ try:
+ service_instance: ServiceInstance = (
+ self.service_subscription.get_service_instance_by_name(
+ self.data["service_instance_name"]
+ )
+ )
+ if service_instance:
+ self._service_instance = service_instance
+ except ResourceNotFound:
+ logging.error(
+ "Customer %s does not exist",
+ self.data["customer_id"],
+ )
+ return self._service_instance
+
+ @property
+ def customer(self) -> Customer:
+ """Access to Customer object property.
+
+ Returns:
+ Customer: Customer object
+
+ """
+ if not self._customer:
+ self._customer = Customer.get_by_global_customer_id(
+ self.data["customer_id"]
+ )
+ return self._customer
+
+ @property
+ def service_subscription(self) -> ServiceSubscription:
+ """Service subscription property.
+
+ Returns:
+ ServiceSubscription: ServiceSubscription object
+
+ """
+ if not self._service_subscription and self.customer:
+ self._service_subscription = (
+ self.customer.get_service_subscription_by_service_type(
+ service_type=self.data.get(
+ "service_subscription_type", self.data["service_name"]
+ )
+ )
+ )
+ return self._service_subscription
+
+ @property
+ def so_service(self) -> SoService:
+ """Create an object with parameters for the service instantiation.
+
+ Based on the instance definition data create an object
+ which is used for instantiation.
+
+ Returns:
+ SoService: SoService object
+
+ """
+ return SoService(
+ subscription_service_type=self.data.get(
+ "service_subscription_type", self.data["service_name"]
+ ),
+ vnfs=[
+ {
+ "model_name": vnf["vnf_name"],
+ "vnf_name": vnf.get("instance_name", vnf["vnf_name"]),
+ "parameters": vnf.get("parameters", {}),
+ "vf_modules": [
+ {
+ "model_name": vf_module["name"],
+ "vf_module_name": vf_module.get(
+ "instance_name", vf_module["name"]
+ ),
+ "parameters": vf_module.get("parameters", {}),
+ }
+ for vf_module in vnf.get("vf_modules", [])
+ ],
+ }
+ for vnf in self.data.get("instantiation_parameters", [])
+ ],
+ )
+
+ @property
+ def aai_service(self) -> AaiService:
+ """A&AI service which is used during the instantiation.
+
+ Raises:
+ ValueError: AaiService with given service id doesn't exist
+
+ Returns:
+ AaiService: AaiService object
+
+ """
+ if (
+ not self._aai_service
+ and (aai_service_id := self.data.get("aai_service")) is not None
+ ):
+ try:
+ self._aai_service = next(AaiService.get_all(service_id=aai_service_id))
+ except StopIteration:
+ raise ValueError(f"A&AI Service {aai_service_id} does not exist")
+ return self._aai_service
+
+
+class ServiceInstanceResource_1_1(ServiceInstanceResource):
+ """Service instance resource class.
+
+ That's the Service instance resource class for 1.1 schema version.
+ """
+
+ @property
+ def aai_service(self) -> AaiService:
+ """A&AI service which is used during the instantiation.
+
+ Raises:
+ ValueError: AaiService with given service id doesn't exist
+
+ Returns:
+ AaiService: AaiService object
+
+ """
+ if not self._aai_service:
+ try:
+ self._aai_service = next(
+ AaiService.get_all(service_id=self.data["aai_service"])
+ )
+ except StopIteration:
+ raise ValueError(
+ f"A&AI Service {self.data['aai_service']} does not exist"
+ )
+ return self._aai_service
diff --git a/onap_data_provider/resources/service_resource.py b/onap_data_provider/resources/service_resource.py
new file mode 100644
index 0000000..8489982
--- /dev/null
+++ b/onap_data_provider/resources/service_resource.py
@@ -0,0 +1,100 @@
+"""Service resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 typing import Any, Dict, Mapping, Optional, Type
+
+from onapsdk.sdc.pnf import Pnf # type: ignore
+from onapsdk.sdc.properties import Property # type: ignore
+from onapsdk.sdc.sdc_resource import SdcResource # type: ignore
+from onapsdk.sdc.service import Service, ServiceInstantiationType # type: ignore
+from onapsdk.sdc.vf import Vf # type: ignore
+from onapsdk.sdc.vl import Vl # type: ignore
+
+from .resource import Resource
+
+
+class ServiceResource(Resource):
+ """Service resource class."""
+
+ RESOURCES: Mapping[str, Type[SdcResource]] = {
+ "PNF": Pnf,
+ "VF": Vf,
+ "VL": Vl,
+ }
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize Service resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._service: Optional[Service] = None
+
+ def create(self) -> None:
+ """Create Service resource."""
+ if not self.exists:
+ service = Service(
+ name=self.data["name"],
+ instantiation_type=ServiceInstantiationType.MACRO,
+ )
+ service.create()
+ for resource_data in self.data.get("resources", []):
+ resource = self.RESOURCES[resource_data["type"].upper()](
+ name=resource_data["name"]
+ )
+ service.add_resource(resource)
+ component = service.get_component(resource)
+ for prop_key, prop_value in resource_data.get("properties", {}).items():
+ prop = component.get_property(prop_key)
+ prop.value = prop_value
+ for property_data in self.data.get("properties", []):
+ service.add_property(
+ Property(
+ property_data["name"],
+ property_data["type"],
+ value=property_data.get("value"),
+ )
+ )
+ service.checkin()
+ service.onboard()
+ self._service = service
+
+ @property
+ def exists(self) -> bool:
+ """Check if Service exists in SDC.
+
+ Returns:
+ bool: True if Service exists, False otherwise
+
+ """
+ return self.service is not None and self.service.distributed
+
+ @property
+ def service(self) -> Optional[Service]:
+ """Service property.
+
+ Returns:
+ Service: Service object which is describer by provided data. None if does not exist yet.
+
+ """
+ if not self._service:
+ service: Service = Service(name=self.data["name"])
+ if not service.created():
+ return None
+ self._service = service
+ return self._service
diff --git a/onap_data_provider/resources/tenant_resource.py b/onap_data_provider/resources/tenant_resource.py
new file mode 100644
index 0000000..13d003f
--- /dev/null
+++ b/onap_data_provider/resources/tenant_resource.py
@@ -0,0 +1,85 @@
+"""Tenant resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict, Optional
+
+from onapsdk.aai.cloud_infrastructure import CloudRegion, Tenant # type: ignore
+
+from .resource import Resource
+from onapsdk.exceptions import ResourceNotFound # type: ignore
+
+
+class TenantResource(Resource):
+ """Tenant resource class.
+
+ Creates tenant.
+ """
+
+ def __init__(self, data: Dict[str, Any], cloud_region: CloudRegion) -> None:
+ """Tenant resource initialization.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create tenant
+ cloud_region (CloudRegion): Cloud region for which tenant is going to be created
+
+ """
+ super().__init__(data)
+ self.cloud_region: CloudRegion = cloud_region
+ self._tenant: Optional[Tenant] = None
+
+ def create(self) -> None:
+ """Create tenant resource.
+
+ Add tenant to provided cloud region
+
+ """
+ if not self.exists:
+ self.cloud_region.add_tenant(
+ tenant_id=self.data["tenant-id"],
+ tenant_name=self.data["tenant-name"],
+ tenant_context=self.data.get("tenant-context"),
+ )
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.tenant is not None
+
+ @property
+ def tenant(self) -> Tenant:
+ """Tenant property.
+
+ Returns:
+ Tenant: Tenant object
+
+ """
+ if not self._tenant:
+ try:
+ self._tenant = self.cloud_region.get_tenant(self.data["tenant-id"])
+ except ResourceNotFound:
+ logging.error(
+ "Tenant %s does not exist in %s cloud region",
+ self.data["tenant-id"],
+ self.cloud_region.cloud_region_id,
+ )
+ return None
+ return self._tenant
diff --git a/onap_data_provider/resources/vendor_resource.py b/onap_data_provider/resources/vendor_resource.py
new file mode 100644
index 0000000..14f2b18
--- /dev/null
+++ b/onap_data_provider/resources/vendor_resource.py
@@ -0,0 +1,75 @@
+"""Vendor resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict
+
+from onapsdk.sdc.vendor import Vendor # type: ignore
+from .resource import Resource
+
+
+class VendorResource(Resource):
+ """Vendor resource class.
+
+ Creates vendor.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize vendor resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._vendor: Vendor = None
+
+ def create(self) -> None:
+ """Create vendor resource.
+
+ Create vendor resource.
+
+ """
+ if not self.exists:
+ logging.debug("Create Vendor %s", self.data["name"])
+ self._vendor = Vendor(name=self.data["name"])
+ self._vendor.onboard()
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.vendor is not None
+
+ @property
+ def vendor(self) -> Vendor:
+ """Vendor property.
+
+ Vendor which is represented by the data provided by user.
+
+ Returns:
+ Vendor: Vendor object
+
+ """
+ if (vendor := Vendor(name=self.data["name"])).created():
+ self._vendor = vendor
+ return self._vendor
+ return None
diff --git a/onap_data_provider/resources/vnf_resource.py b/onap_data_provider/resources/vnf_resource.py
new file mode 100644
index 0000000..1d47413
--- /dev/null
+++ b/onap_data_provider/resources/vnf_resource.py
@@ -0,0 +1,75 @@
+"""Vnf resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from typing import Any, Dict
+
+from onapsdk.sdc.vf import Vf # type: ignore
+from .resource import Resource
+from .xnf_resource import XnfResource
+
+
+class VnfResource(Resource, XnfResource):
+ """Vnf resource class.
+
+ Creates vnf.
+ """
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize vnf resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+
+ def create(self) -> None:
+ """Create vnf resource.
+
+ Create vnf resource and link to specified resources.
+
+ """
+ if not self.exists:
+ logging.debug("Create Vnf %s", self.data["name"])
+ self._xnf = Vf(name=self.data["name"])
+ self.onboard_resource_with_properties(self.data)
+
+ @property
+ def exists(self) -> bool:
+ """Determine if resource already exists or not.
+
+ Returns:
+ bool: True if object exists, False otherwise
+
+ """
+ return self.vnf is not None
+
+ @property
+ def vnf(self) -> Vf:
+ """Vnf property.
+
+ Vnf which is represented by the data provided by user.
+
+ Returns:
+ Vf: Vf object
+
+ """
+ if (vnf := Vf(name=self.data["name"])).created():
+ self._xnf = vnf
+ return self._xnf
+ return None
diff --git a/onap_data_provider/resources/vsp_resource.py b/onap_data_provider/resources/vsp_resource.py
new file mode 100644
index 0000000..17a4d5b
--- /dev/null
+++ b/onap_data_provider/resources/vsp_resource.py
@@ -0,0 +1,71 @@
+"""VSP resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 typing import Any, Dict, Optional
+from onapsdk.sdc.vendor import Vendor # type: ignore
+from onapsdk.sdc.vsp import Vsp # type: ignore
+
+from .resource import Resource
+
+
+class VspResource(Resource):
+ """VSP resource class."""
+
+ def __init__(self, data: Dict[str, Any]) -> None:
+ """Initialize VSP resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ super().__init__(data)
+ self._vsp: Optional[Vsp] = None
+
+ def create(self) -> None:
+ """Create VSP resource."""
+ if not self.exists:
+ with open(self.data["package"], "rb") as package:
+ self._vsp = Vsp(
+ name=self.data["name"],
+ vendor=Vendor(self.data["vendor"]),
+ package=package,
+ )
+ self._vsp.onboard()
+
+ @property
+ def exists(self) -> bool:
+ """Check if VSP exists.
+
+ Returns:
+ bool: True if VSP exists, False otherwise
+
+ """
+ return self.vsp is not None
+
+ @property
+ def vsp(self) -> Vsp:
+ """VSP property.
+
+ Returns:
+ Vsp: VSP object which is describer by provided data. None if does not exist yet.
+
+ """
+ if not self._vsp:
+ vsp: Vsp = Vsp(name=self.data["name"])
+ if not vsp.created():
+ return None
+ self._vsp = vsp
+ return self._vsp
diff --git a/onap_data_provider/resources/xnf_resource.py b/onap_data_provider/resources/xnf_resource.py
new file mode 100644
index 0000000..cada088
--- /dev/null
+++ b/onap_data_provider/resources/xnf_resource.py
@@ -0,0 +1,60 @@
+"""Xnf resource module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 abc import ABC
+from typing import Any, Dict
+from onapsdk.sdc.vsp import Vsp # type: ignore
+from onapsdk.sdc.sdc_resource import SdcResource # type: ignore
+from onapsdk.sdc.properties import Property # type: ignore
+
+
+class XnfResource(ABC):
+ """Xnf resource class.
+
+ Network function base class.
+ """
+
+ def __init__(self) -> None:
+ """Initialize xnf resource."""
+ self._xnf: SdcResource = None
+
+ def onboard_resource_with_properties(self, data: Dict[str, Any]) -> None:
+ """Set properties provided and instantiate SDC resource.
+
+ Args:
+ data (Dict[str, Any]): Data needed to create resource.
+
+ """
+ if (vsp_name := data.get("vsp")) is not None:
+ self._xnf.vsp = Vsp(vsp_name)
+ self._xnf.create()
+ if (artifact_data := data.get("deployment_artifact")) is not None:
+ self._xnf.add_deployment_artifact(
+ artifact_type=data["deployment_artifact"]["artifact_type"],
+ artifact_name=data["deployment_artifact"]["artifact_name"],
+ artifact_label=data["deployment_artifact"]["artifact_label"],
+ artifact=data["deployment_artifact"]["artifact_file_name"],
+ )
+ for property_data in data.get("properties", []):
+ self._xnf.add_property(
+ Property(
+ name=property_data["name"],
+ property_type=property_data["type"],
+ value=property_data.get("value"),
+ )
+ )
+ self._xnf.onboard()
diff --git a/onap_data_provider/schemas/infra.schema b/onap_data_provider/schemas/infra.schema
new file mode 100644
index 0000000..61e7bf2
--- /dev/null
+++ b/onap_data_provider/schemas/infra.schema
@@ -0,0 +1,533 @@
+---
+"$schema": http://json-schema.org/draft-04/schema#
+type: object
+properties:
+ aai-services:
+ type: array
+ items:
+ - type: object
+ properties:
+ aai-service:
+ type: object
+ properties:
+ service-id:
+ type: string
+ service-description:
+ type: string
+ required:
+ - service-id
+ - service-description
+ required:
+ - aai-service
+ complexes:
+ type: array
+ items:
+ - type: object
+ properties:
+ complex:
+ type: object
+ properties:
+ physical-location-id:
+ type: string
+ complex-name:
+ type: string
+ data-center-code:
+ type: string
+ identity-url:
+ type: string
+ physical-location-type:
+ type: string
+ street1:
+ type: string
+ street2:
+ type: string
+ city:
+ type: string
+ state:
+ type: string
+ postal-code:
+ type: string
+ country:
+ type: string
+ region:
+ type: string
+ latitude:
+ type: string
+ longitude:
+ type: string
+ elevation:
+ type: string
+ lata:
+ type: string
+ required:
+ - physical-location-id
+ required:
+ - complex
+ cloud-regions:
+ type: array
+ items:
+ - type: object
+ properties:
+ cloud-region:
+ type: object
+ properties:
+ cloud-owner:
+ type: string
+ cloud-region-id:
+ type: string
+ orchestration-disabled:
+ type: boolean
+ in-maint:
+ type: boolean
+ cloud-type:
+ type: string
+ kube-config:
+ type: string
+ tenants:
+ type: array
+ items:
+ - type: object
+ properties:
+ tenant-id:
+ type: string
+ tenant-name:
+ type: string
+ tenant-context:
+ type: string
+ required:
+ - tenant-id
+ - tenant-name
+ esr-system-infos:
+ type: array
+ items:
+ - type: object
+ properties:
+ esr-system-info-id:
+ type: string
+ user-name:
+ type: string
+ password:
+ type: string
+ system-type:
+ type: string
+ service-url:
+ type: string
+ cloud-domain:
+ type: string
+ default-tenant:
+ type: string
+ required:
+ - esr-system-info-id
+ - user-name
+ - password
+ - system-type
+ - service-url
+ - cloud-domain
+ complex:
+ type: object
+ properties:
+ physical-location-id:
+ type: string
+ required:
+ - physical-location-id
+ availability-zones:
+ type: array
+ items:
+ - type: object
+ properties:
+ availability-zone-name:
+ type: string
+ hypervisor-type:
+ type: string
+ required:
+ - availability-zone-name
+ - hypervisor-type
+ required:
+ - cloud-owner
+ - cloud-region-id
+ - orchestration-disabled
+ - in-maint
+ required:
+ - cloud-region
+ customers:
+ type: array
+ items:
+ - type: object
+ properties:
+ customer:
+ type: object
+ properties:
+ global-customer-id:
+ type: string
+ subscriber-name:
+ type: string
+ subscriber-type:
+ type: string
+ service-subscriptions:
+ type: array
+ items:
+ - type: object
+ properties:
+ service-type:
+ type: string
+ tenants:
+ type: array
+ items:
+ - type: object
+ properities:
+ tenant-id:
+ type: string
+ cloud-owner:
+ type: string
+ cloud-region-id:
+ type: string
+ required:
+ - tenant-id
+ - cloud-owner
+ - cloud-region-id
+ required:
+ - service-type
+ required:
+ - global-customer-id
+ - subscriber-name
+ - subscriber-type
+ required:
+ - customer
+ vendors:
+ type: array
+ items:
+ - type: object
+ properties:
+ vendor:
+ type: object
+ properties:
+ name:
+ type: string
+ required:
+ - name
+ required:
+ - vendor
+ vsps:
+ type: array
+ items:
+ - type: object
+ properties:
+ vsp:
+ type: object
+ properties:
+ name:
+ type: string
+ vendor:
+ type: string
+ package:
+ type: string
+ required:
+ - name
+ - vendor
+ - package
+ required:
+ - vsp
+ services:
+ type: array
+ items:
+ - type: object
+ properties:
+ service:
+ type: object
+ properties:
+ name:
+ type: string
+ resources:
+ type: array
+ items:
+ - type: object
+ properties:
+ name:
+ type: string
+ type:
+ type: string
+ required:
+ - name
+ - type
+ properties:
+ type: array
+ items:
+ - type: object
+ properties:
+ name:
+ type: string
+ type:
+ type: string
+ value:
+ type: string
+ required:
+ - name
+ - type
+ required:
+ - name
+ required:
+ - service
+ pnfs:
+ type: array
+ items:
+ - type: object
+ properties:
+ pnf:
+ type: object
+ properties:
+ name:
+ type: string
+ vendor:
+ type: string
+ vsp:
+ type: string
+ deployment_artifact:
+ type: object
+ properties:
+ artifact_type:
+ type: string
+ artifact_name:
+ type: string
+ artifact_label:
+ type: string
+ artifact_file_name:
+ type: string
+ required:
+ - artifact_type
+ - artifact_name
+ - artifact_label
+ - artifact_file_name
+ properties:
+ type: array
+ items:
+ - type: object
+ properties:
+ name:
+ type: string
+ type:
+ type: string
+ value:
+ type: string
+ required:
+ - name
+ - type
+ required:
+ - name
+ required:
+ - pnf
+ vnfs:
+ type: array
+ items:
+ - type: object
+ properties:
+ vnf:
+ type: object
+ properties:
+ name:
+ type: string
+ vsp:
+ type: string
+ deployment_artifact:
+ type: object
+ properties:
+ artifact_type:
+ type: string
+ artifact_name:
+ type: string
+ artifact_label:
+ type: string
+ artifact_file_name:
+ type: string
+ required:
+ - artifact_type
+ - artifact_name
+ - artifact_label
+ - artifact_file_name
+ properties:
+ type: array
+ items:
+ - type: object
+ properties:
+ name:
+ type: string
+ type:
+ type: string
+ value:
+ type: string
+ required:
+ - name
+ - type
+ required:
+ - name
+ required:
+ - vnf
+ service-instances:
+ type: array
+ items:
+ - type: object
+ properties:
+ service-instance:
+ type: object
+ properties:
+ service_instance_name:
+ type: string
+ service_name:
+ type: string
+ cloud_region:
+ type: string
+ customer_id:
+ type: string
+ owning_entity:
+ type: string
+ project:
+ type: string
+ platform:
+ type: string
+ line_of_business:
+ type: string
+ cloud_region_id:
+ type: string
+ cloud_owner:
+ type: string
+ timeout:
+ type: number
+ minimum: 1
+ maximum: 99999
+ aai_service:
+ type: string
+ service_subscription_type:
+ type: string
+ instantiation_parameters:
+ type: array
+ items:
+ - type: object
+ properties:
+ vnf_name:
+ type: string
+ sec_group:
+ type: string
+ public_net_id:
+ type: string
+ onap_private_net_id:
+ type: string
+ onap_private_subnet_id:
+ type: string
+ image_name:
+ type: string
+ flavor_name:
+ type: string
+ install_script_version:
+ type: string
+ demo_artifacts_version:
+ type: string
+ cloud_env:
+ type: string
+ aic-cloud-region:
+ type: string
+ pub_key:
+ type: string
+ required:
+ - service_instance_name
+ - service_name
+ - cloud_region
+ - customer_id
+ - owning_entity
+ - project
+ - platform
+ - line_of_business
+ - cloud_region_id
+ - cloud_owner
+ - instantiation_parameters
+ owning-entities:
+ type: array
+ items:
+ - type: object
+ properities:
+ owning-entity:
+ type: object
+ properties:
+ name:
+ type: string
+ required:
+ - name
+ required:
+ - owning-entity
+ projects:
+ type: array
+ items:
+ - type: object
+ properties:
+ project:
+ type: object
+ properities:
+ name:
+ type: string
+ required:
+ - name
+ required:
+ - project
+ platforms:
+ type: array
+ items:
+ - type: object
+ properities:
+ platform:
+ type: object
+ properities:
+ name:
+ type: string
+ required:
+ - name
+ required:
+ - platform
+ lines-of-business:
+ type: array
+ items:
+ - type: object
+ properties:
+ line-of-business:
+ type: object
+ properities:
+ name:
+ type: string
+ required:
+ - name
+ required:
+ - line-of-business
+ msb-k8s-definitions:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ version:
+ type: string
+ chart-name:
+ type: string
+ description:
+ type: string
+ artifact:
+ type: string
+ profiles:
+ type: array
+ items:
+ - type: object
+ properties:
+ name:
+ type: string
+ namespace:
+ type: string
+ k8s-version:
+ type: string
+ artifact:
+ type: string
+ required:
+ - name
+ - namespace
+ - k8s-version
+ - artifact
+ required:
+ - name
+ - version
+ - artifact
diff --git a/onap_data_provider/schemas/infra_1_1.schema b/onap_data_provider/schemas/infra_1_1.schema
new file mode 100644
index 0000000..9cb1f09
--- /dev/null
+++ b/onap_data_provider/schemas/infra_1_1.schema
@@ -0,0 +1,533 @@
+---
+"$schema": http://json-schema.org/draft-04/schema#
+type: object
+properties:
+ aai-services:
+ type: array
+ items:
+ - type: object
+ properties:
+ aai-service:
+ type: object
+ properties:
+ service-id:
+ type: string
+ service-description:
+ type: string
+ required:
+ - service-id
+ - service-description
+ required:
+ - aai-service
+ complexes:
+ type: array
+ items:
+ - type: object
+ properties:
+ complex:
+ type: object
+ properties:
+ physical-location-id:
+ type: string
+ complex-name:
+ type: string
+ data-center-code:
+ type: string
+ identity-url:
+ type: string
+ physical-location-type:
+ type: string
+ street1:
+ type: string
+ street2:
+ type: string
+ city:
+ type: string
+ state:
+ type: string
+ postal-code:
+ type: string
+ country:
+ type: string
+ region:
+ type: string
+ latitude:
+ type: string
+ longitude:
+ type: string
+ elevation:
+ type: string
+ lata:
+ type: string
+ required:
+ - physical-location-id
+ required:
+ - complex
+ cloud-regions:
+ type: array
+ items:
+ - type: object
+ properties:
+ cloud-region:
+ type: object
+ properties:
+ cloud-owner:
+ type: string
+ cloud-region-id:
+ type: string
+ orchestration-disabled:
+ type: boolean
+ in-maint:
+ type: boolean
+ cloud-type:
+ type: string
+ kube-config:
+ type: string
+ tenants:
+ type: array
+ items:
+ - type: object
+ properties:
+ tenant-id:
+ type: string
+ tenant-name:
+ type: string
+ tenant-context:
+ type: string
+ required:
+ - tenant-id
+ - tenant-name
+ esr-system-infos:
+ type: array
+ items:
+ - type: object
+ properties:
+ esr-system-info-id:
+ type: string
+ user-name:
+ type: string
+ password:
+ type: string
+ system-type:
+ type: string
+ service-url:
+ type: string
+ cloud-domain:
+ type: string
+ default-tenant:
+ type: string
+ required:
+ - esr-system-info-id
+ - user-name
+ - password
+ - system-type
+ - service-url
+ - cloud-domain
+ complex:
+ type: object
+ properties:
+ physical-location-id:
+ type: string
+ required:
+ - physical-location-id
+ availability-zones:
+ type: array
+ items:
+ - type: object
+ properties:
+ availability-zone-name:
+ type: string
+ hypervisor-type:
+ type: string
+ required:
+ - availability-zone-name
+ - hypervisor-type
+ required:
+ - cloud-owner
+ - cloud-region-id
+ - orchestration-disabled
+ - in-maint
+ required:
+ - cloud-region
+ customers:
+ type: array
+ items:
+ - type: object
+ properties:
+ customer:
+ type: object
+ properties:
+ global-customer-id:
+ type: string
+ subscriber-name:
+ type: string
+ subscriber-type:
+ type: string
+ service-subscriptions:
+ type: array
+ items:
+ - type: object
+ properties:
+ service-type:
+ type: string
+ tenants:
+ type: array
+ items:
+ - type: object
+ properities:
+ tenant-id:
+ type: string
+ cloud-owner:
+ type: string
+ cloud-region-id:
+ type: string
+ required:
+ - tenant-id
+ - cloud-owner
+ - cloud-region-id
+ required:
+ - service-type
+ required:
+ - global-customer-id
+ - subscriber-name
+ - subscriber-type
+ required:
+ - customer
+ vendors:
+ type: array
+ items:
+ - type: object
+ properties:
+ vendor:
+ type: object
+ properties:
+ name:
+ type: string
+ required:
+ - name
+ required:
+ - vendor
+ vsps:
+ type: array
+ items:
+ - type: object
+ properties:
+ vsp:
+ type: object
+ properties:
+ name:
+ type: string
+ vendor:
+ type: string
+ package:
+ type: string
+ required:
+ - name
+ - vendor
+ - package
+ required:
+ - vsp
+ services:
+ type: array
+ items:
+ - type: object
+ properties:
+ service:
+ type: object
+ properties:
+ name:
+ type: string
+ resources:
+ type: array
+ items:
+ - type: object
+ properties:
+ name:
+ type: string
+ type:
+ type: string
+ required:
+ - name
+ - type
+ properties:
+ type: array
+ items:
+ - type: object
+ properties:
+ name:
+ type: string
+ type:
+ type: string
+ value:
+ type: string
+ required:
+ - name
+ - type
+ required:
+ - name
+ required:
+ - service
+ pnfs:
+ type: array
+ items:
+ - type: object
+ properties:
+ pnf:
+ type: object
+ properties:
+ name:
+ type: string
+ vendor:
+ type: string
+ vsp:
+ type: string
+ deployment_artifact:
+ type: object
+ properties:
+ artifact_type:
+ type: string
+ artifact_name:
+ type: string
+ artifact_label:
+ type: string
+ artifact_file_name:
+ type: string
+ required:
+ - artifact_type
+ - artifact_name
+ - artifact_label
+ - artifact_file_name
+ properties:
+ type: array
+ items:
+ - type: object
+ properties:
+ name:
+ type: string
+ type:
+ type: string
+ value:
+ type: string
+ required:
+ - name
+ - type
+ required:
+ - name
+ required:
+ - pnf
+ vnfs:
+ type: array
+ items:
+ - type: object
+ properties:
+ vnf:
+ type: object
+ properties:
+ name:
+ type: string
+ vsp:
+ type: string
+ deployment_artifact:
+ type: object
+ properties:
+ artifact_type:
+ type: string
+ artifact_name:
+ type: string
+ artifact_label:
+ type: string
+ artifact_file_name:
+ type: string
+ required:
+ - artifact_type
+ - artifact_name
+ - artifact_label
+ - artifact_file_name
+ properties:
+ type: array
+ items:
+ - type: object
+ properties:
+ name:
+ type: string
+ type:
+ type: string
+ value:
+ type: string
+ required:
+ - name
+ - type
+ required:
+ - name
+ required:
+ - vnf
+ service-instances:
+ type: array
+ items:
+ - type: object
+ properties:
+ service-instance:
+ type: object
+ properties:
+ service_instance_name:
+ type: string
+ service_name:
+ type: string
+ cloud_region:
+ type: string
+ customer_id:
+ type: string
+ owning_entity:
+ type: string
+ project:
+ type: string
+ platform:
+ type: string
+ line_of_business:
+ type: string
+ cloud_region_id:
+ type: string
+ cloud_owner:
+ type: string
+ timeout:
+ type: number
+ minimum: 1
+ maximum: 99999
+ aai_service:
+ type: string
+ service_subscription_type:
+ type: string
+ instantiation_parameters:
+ type: array
+ items:
+ - type: object
+ properties:
+ vnf_name:
+ type: string
+ sec_group:
+ type: string
+ public_net_id:
+ type: string
+ onap_private_net_id:
+ type: string
+ onap_private_subnet_id:
+ type: string
+ image_name:
+ type: string
+ flavor_name:
+ type: string
+ install_script_version:
+ type: string
+ demo_artifacts_version:
+ type: string
+ cloud_env:
+ type: string
+ aic-cloud-region:
+ type: string
+ pub_key:
+ type: string
+ required:
+ - service_instance_name
+ - service_name
+ - cloud_region
+ - customer_id
+ - owning_entity
+ - project
+ - platform
+ - line_of_business
+ - cloud_region_id
+ - cloud_owner
+ - aai_service
+ owning-entities:
+ type: array
+ items:
+ - type: object
+ properities:
+ owning-entity:
+ type: object
+ properties:
+ name:
+ type: string
+ required:
+ - name
+ required:
+ - owning-entity
+ projects:
+ type: array
+ items:
+ - type: object
+ properties:
+ project:
+ type: object
+ properities:
+ name:
+ type: string
+ required:
+ - name
+ required:
+ - project
+ platforms:
+ type: array
+ items:
+ - type: object
+ properities:
+ platform:
+ type: object
+ properities:
+ name:
+ type: string
+ required:
+ - name
+ required:
+ - platform
+ lines-of-business:
+ type: array
+ items:
+ - type: object
+ properties:
+ line-of-business:
+ type: object
+ properities:
+ name:
+ type: string
+ required:
+ - name
+ required:
+ - line-of-business
+ msb-k8s-definitions:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ version:
+ type: string
+ chart-name:
+ type: string
+ description:
+ type: string
+ artifact:
+ type: string
+ profiles:
+ type: array
+ items:
+ - type: object
+ properties:
+ name:
+ type: string
+ namespace:
+ type: string
+ k8s-version:
+ type: string
+ artifact:
+ type: string
+ required:
+ - name
+ - namespace
+ - k8s-version
+ - artifact
+ required:
+ - name
+ - version
+ - artifact
diff --git a/onap_data_provider/tag_handlers.py b/onap_data_provider/tag_handlers.py
new file mode 100644
index 0000000..8f29d0d
--- /dev/null
+++ b/onap_data_provider/tag_handlers.py
@@ -0,0 +1,52 @@
+"""Custom yaml tag handlers module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 yaml
+import uuid
+
+
+def join(loader: yaml.SafeLoader, node: yaml.Node) -> str:
+ """Concatinates the nodes fields for !join tag.
+
+ Concatinates multiple strings in yaml value f.e. !join [a, b, c] results in 'abc'.
+ join supports separator syntax f.e. !join ['_', [a, b, c]] results in 'a_b_c'.
+
+ Args:
+ node (yaml.Node): the yaml node
+
+ Returns:
+ str: the joined string of node
+
+ """
+ seq = loader.construct_sequence(node, deep=True) # type: ignore
+ if len(seq) == 2 and isinstance(seq[0], str) and isinstance(seq[1], list):
+ sep = seq[0]
+ return sep.join([str(i) for i in seq[1]])
+ else:
+ return "".join([str(i) for i in seq])
+
+
+def generate_random_uuid(*_) -> str:
+ """Random UUID generator.
+
+ Args:
+ loader (yaml.SafeLoader): SafeLoader object
+ node (yaml.Node): Node object
+
+ Returns:
+ str: randomly generated UUID
+ """
+ return str(uuid.uuid4())
diff --git a/onap_data_provider/validator.py b/onap_data_provider/validator.py
new file mode 100644
index 0000000..3589f85
--- /dev/null
+++ b/onap_data_provider/validator.py
@@ -0,0 +1,52 @@
+"""Infra file schema validatior module."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 typing import Any, Dict
+
+import yaml
+from jsonschema import validate # type: ignore
+
+from .versions import VersionsEnum
+
+
+class Validator:
+ """Validate input schema class."""
+
+ def __init__(self) -> None:
+ """Validate class initialization.
+
+ Load schema file.
+
+ """
+ self.schemas: Dict[str, Any] = {}
+
+ def validate(self, version: VersionsEnum, input_data: Dict[str, Any]) -> None:
+ """Check if given input is valid from schema perspective.
+
+ Args:
+ input_data (Dict[str, Any]): Input to check
+
+ Raises:
+ ValidationError: Raises if input is invalid
+
+ """
+ if not version.value.version_number in self.schemas:
+ with open(version.value.schema_path, "r") as schema_file:
+ self.schemas[version.value.version_number] = yaml.safe_load(
+ schema_file.read()
+ )
+ validate(input_data, schema=self.schemas[version.value.version_number])
diff --git a/onap_data_provider/versions.py b/onap_data_provider/versions.py
new file mode 100644
index 0000000..7651bec
--- /dev/null
+++ b/onap_data_provider/versions.py
@@ -0,0 +1,68 @@
+"""Versions class."""
+"""
+ Copyright 2021 Deutsche Telekom AG
+
+ 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 logging
+from collections import namedtuple
+from enum import Enum
+from pathlib import Path
+
+
+Version = namedtuple("Version", ["version_number", "schema_path", "deprecated"])
+
+
+class VersionsEnum(Enum):
+ """Class for storing information about supported versions."""
+
+ V1_1 = Version(
+ version_number="1.1",
+ schema_path=Path(Path(__file__).parent, "schemas/infra_1_1.schema"),
+ deprecated=False,
+ )
+ V1_0 = Version(
+ version_number="1.0",
+ schema_path=Path(Path(__file__).parent, "schemas/infra.schema"),
+ deprecated=False,
+ )
+ NONE = Version(
+ version_number="None",
+ schema_path=Path(Path(__file__).parent, "schemas/infra.schema"),
+ deprecated=True,
+ )
+
+ @classmethod
+ def get_version_by_number(cls, version_number: str) -> "VersionsEnum":
+ """Get an enum element based on the given string version value.
+
+ Because the version enum elements are not simple objects,
+ but also have information about the path to the supported schema and
+ whether this version is deprecated this method allows to retrieve
+ the version only based on its value stored in the string format.
+
+ Raises:
+ ValueError: Provided version number is not supported
+
+ Returns:
+ VersionsEnum: The version enum
+
+ """
+ for version in cls:
+ if version.value.version_number == version_number:
+ if version.value.deprecated:
+ logging.warning(
+ f"This version [{version.value.version_number}] is deprecated, consider using the newer one!"
+ )
+ return version
+ raise ValueError(f"Version number {version_number} not supported")