diff options
Diffstat (limited to 'onap_data_provider/resources')
22 files changed, 2167 insertions, 0 deletions
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() |