curl -k http(s)://<OAM IP>:30205/o2ims_infrastructureInventory/v1
-3 Register O-Cloud to SMO
+3. Register O-Cloud to SMO
+--------------------------
- assumed you have setup SMO O2 endpoint for registration
- O2 service will post the O-Cloud registration data to that SMO O2 endpoint
::
- curl -k -X POST http(s)://<OAM IP>:30205/provision/smo-endpoint/v1 -d '{"smo-o2-endpoint": "<SMO O2 endpoint for registration>"}'
+ curl -k -X POST http(s)://<OAM IP>:30205/provision/v1/smo-endpoint -d '{"endpoint": "<SMO O2 endpoint for registration>"}'
References
.ResourceSqlAlchemyRepository(self.session)\r
self.subscriptions = ocloud_repository\\r
.SubscriptionSqlAlchemyRepository(self.session)\r
- self.registrations = ocloud_repository\\r
- .RegistrationSqlAlchemyRepository(self.session)\r
+ self.configurations = ocloud_repository\\r
+ .ConfigurationSqlAlchemyRepository(self.session)\r
self.deployment_managers = ocloud_repository\\r
.DeploymentManagerSqlAlchemyRepository(self.session)\r
self.nfdeployment_descs = dms_repository\\r
for entry in self.subscriptions.seen:\r
while hasattr(entry, 'events') and len(entry.events) > 0:\r
yield entry.events.pop(0)\r
- for entry in self.registrations.seen:\r
+ for entry in self.configurations.seen:\r
while hasattr(entry, 'events') and len(entry.events) > 0:\r
yield entry.events.pop(0)\r
for entry in self.nfdeployment_descs.seen:\r
from flask_restx import Api\r
\r
from o2app import bootstrap\r
-from o2ims.views import ocloud_route as ims_route\r
+from o2ims.views import configure_namespace as ims_route_configure_namespace\r
from o2dms.api import configure_namespace as dms_route_configure_namespace\r
\r
\r
)\r
bus = bootstrap.bootstrap()\r
\r
-ims_route.configure_namespace(api, bus)\r
+ims_route_configure_namespace(api)\r
dms_route_configure_namespace(api)\r
from o2ims.domain import commands as imscmd
from o2common.helper import o2logging
-from o2ims.domain.subscription_obj import Message2SMO, NotificationEventEnum, RegistrationMessage
+from o2ims.domain.subscription_obj import Message2SMO, NotificationEventEnum,\
+ RegistrationMessage
logger = o2logging.get_logger(__name__)
r = redis.Redis(**config.get_redis_host_and_port())
pubsub = r.pubsub(ignore_subscribe_messages=True)
pubsub.subscribe("NfDeploymentStateChanged")
pubsub.subscribe('ResourceChanged')
- pubsub.subscribe('RegistrationChanged')
+ pubsub.subscribe('ConfigurationChanged')
pubsub.subscribe('OcloudChanged')
for m in pubsub.listen():
eventtype=data['notificationEventType'],
updatetime=data['updatetime']))
bus.handle(cmd)
- elif channel == 'RegistrationChanged':
+ elif channel == 'ConfigurationChanged':
datastr = m['data']
data = json.loads(datastr)
- logger.info('RegistrationChanged with cmd:{}'.format(data))
+ logger.info('ConfigurationChanged with cmd:{}'.format(data))
cmd = imscmd.Register2SMO(data=RegistrationMessage(id=data['id']))
bus.handle(cmd)
elif channel == 'OcloudChanged':
pserver_eth_handler
from o2ims.service.command import notify_handler, registration_handler
from o2ims.service.event import ocloud_event, resource_event, \
- resource_pool_event, registration_event
+ resource_pool_event, configuration_event
# if TYPE_CHECKING:
# from . import unit_of_work
events.ResourceChanged: [resource_event.notify_resource_change],
events.ResourcePoolChanged: [resource_pool_event.\
notify_resourcepool_change],
- events.RegistrationChanged: [registration_event.\
- notify_registration_change],
+ events.ConfigurationChanged: [configuration_event.\
+ notify_configuration_change],
} # type: Dict[Type[events.Event], Callable]
return get_root_api_base() + 'o2ims_infrastructureInventory/v1'
+def get_provision_api_base():
+ return get_root_api_base() + 'provision/v1'
+
+
def get_o2dms_api_base():
return get_root_api_base() + "o2dms"
from typing import List
-from o2ims.domain import ocloud, subscription_obj
+from o2ims.domain import ocloud, subscription_obj, configuration_obj
from o2ims.domain.ocloud_repo import OcloudRepository, ResourceTypeRepository,\
ResourcePoolRepository, ResourceRepository, DeploymentManagerRepository
-from o2ims.domain.subscription_repo import SubscriptionRepository, \
- RegistrationRepository
+from o2ims.domain.subscription_repo import SubscriptionRepository
+from o2ims.domain.configuration_repo import ConfigurationRepository
from o2common.helper import o2logging
logger = o2logging.get_logger(__name__)
subscriptionId=subscription_id).delete()
-class RegistrationSqlAlchemyRepository(RegistrationRepository):
+class ConfigurationSqlAlchemyRepository(ConfigurationRepository):
def __init__(self, session):
super().__init__()
self.session = session
- def _add(self, registration: subscription_obj.Registration):
- self.session.add(registration)
+ def _add(self, configuration: configuration_obj.Configuration):
+ self.session.add(configuration)
- def _get(self, registration_id) -> subscription_obj.Registration:
- return self.session.query(subscription_obj.Registration).filter_by(
- registrationId=registration_id).first()
+ def _get(self, configuration_id) -> configuration_obj.Configuration:
+ return self.session.query(configuration_obj.Configuration).filter_by(
+ configurationId=configuration_id).first()
- def _list(self) -> List[subscription_obj.Registration]:
- return self.session.query(subscription_obj.Registration)
+ def _list(self) -> List[configuration_obj.Configuration]:
+ return self.session.query(configuration_obj.Configuration)
- def _update(self, registration: subscription_obj.Registration):
- self.session.add(registration)
+ def _update(self, configuration: configuration_obj.Configuration):
+ self.session.add(configuration)
- def _delete(self, registration_id):
- self.session.query(subscription_obj.Registration).filter_by(
- registrationId=registration_id).delete()
+ def _delete(self, configuration_id):
+ self.session.query(configuration_obj.Configuration).filter_by(
+ configurationId=configuration_id).delete()
\r
from o2ims.domain import ocloud as ocloudModel\r
from o2ims.domain import subscription_obj as subModel\r
+from o2ims.domain import configuration_obj as confModel\r
from o2ims.domain.resource_type import ResourceTypeEnum\r
\r
from o2common.helper import o2logging\r
Column("filter", String(255)),\r
)\r
\r
-registration = Table(\r
- "registration",\r
+configuration = Table(\r
+ "configuration",\r
metadata,\r
Column("updatetime", DateTime),\r
Column("createtime", DateTime),\r
\r
- Column("registrationId", String(255), primary_key=True),\r
+ Column("configurationId", String(255), primary_key=True),\r
+ Column("conftype", String(255)),\r
Column("callback", String(255)),\r
Column("status", String(255)),\r
Column("comments", String(255)),\r
}\r
)\r
mapper(subModel.Subscription, subscription)\r
- mapper(subModel.Registration, registration)\r
+ mapper(confModel.Configuration, configuration)\r
\r
if engine is not None:\r
metadata.create_all(engine)\r
--- /dev/null
+# Copyright (C) 2021 Wind River Systems, Inc.
+#
+# 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 __future__ import annotations
+from enum import Enum
+# from dataclasses import dataclass
+
+from o2common.domain.base import AgRoot, Serializer
+
+
+class RegistrationStatusEnum(str, Enum):
+ CREATED = 'CREATED'
+ NOTIFIED = 'NOTIFIED'
+ FAILED = 'FAILED'
+
+
+class ConfigurationTypeEnum(str, Enum):
+ SMO = 'SMO'
+
+
+class Configuration(AgRoot, Serializer):
+ def __init__(self, id: str, url: str,
+ conf_type: ConfigurationTypeEnum,
+ status: RegistrationStatusEnum =
+ RegistrationStatusEnum.CREATED,
+ comments: str = '') -> None:
+ super().__init__()
+ self.configurationId = id
+ self.conftype = conf_type
+ self.callback = url
+ self.status = status
+ self.comments = comments
+
+ def serialize_smo(self):
+ if self.conftype != ConfigurationTypeEnum.SMO:
+ return
+
+ d = Serializer.serialize(self)
+
+ d['endpoint'] = d['callback']
+ return d
--- /dev/null
+# Copyright (C) 2021 Wind River Systems, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import abc
+from typing import List, Set
+from o2ims.domain import configuration_obj as obj
+
+
+class ConfigurationRepository(abc.ABC):
+ def __init__(self):
+ self.seen = set() # type: Set[obj.Configuration]
+
+ def add(self, configuration: obj.Configuration):
+ self._add(configuration)
+ self.seen.add(configuration)
+
+ def get(self, configuration_id) -> obj.Configuration:
+ configuration = self._get(configuration_id)
+ if configuration:
+ self.seen.add(configuration)
+ return configuration
+
+ def list(self) -> List[obj.Configuration]:
+ return self._list()
+
+ def update(self, configuration: obj.Configuration):
+ self._update(configuration)
+
+ def delete(self, configuration_id):
+ self._delete(configuration_id)
+
+ @abc.abstractmethod
+ def _add(self, configuration: obj.Configuration):
+ raise NotImplementedError
+
+ @abc.abstractmethod
+ def _get(self, configuration_id) -> obj.Configuration:
+ raise NotImplementedError
+
+ @abc.abstractmethod
+ def _update(self, configuration: obj.Configuration):
+ raise NotImplementedError
+
+ @abc.abstractmethod
+ def _delete(self, configuration_id):
+ raise NotImplementedError
@dataclass
-class RegistrationChanged(Event):
+class ConfigurationChanged(Event):
id: str
updatetime: datetime.now()
self.updatetime = updatetime
-class RegistrationStatusEnum(str, Enum):
- CREATED = 'CREATED'
- NOTIFIED = 'NOTIFIED'
- FAILED = 'FAILED'
-
-
-class Registration(AgRoot, Serializer):
- def __init__(self, id: str, url: str,
- status: RegistrationStatusEnum =
- RegistrationStatusEnum.CREATED,
- comments: str = '') -> None:
- super().__init__()
- self.registrationId = id
- self.callback = url
- self.status = status
- self.comments = comments
-
-
class RegistrationMessage(Serializer):
def __init__(self, is_all: bool = None, id: str = '') -> None:
self.all = is_all if is_all is not None else False
@abc.abstractmethod
def _delete(self, subscription_id):
raise NotImplementedError
-
-
-class RegistrationRepository(abc.ABC):
- def __init__(self):
- self.seen = set() # type: Set[subobj.Subscription]
-
- def add(self, registration: subobj.Registration):
- self._add(registration)
- self.seen.add(registration)
-
- def get(self, registration_id) -> subobj.Registration:
- registration = self._get(registration_id)
- if registration:
- self.seen.add(registration)
- return registration
-
- def list(self) -> List[subobj.Registration]:
- return self._list()
-
- def update(self, registration: subobj.Registration):
- self._update(registration)
-
- def delete(self, registration_id):
- self._delete(registration_id)
-
- @abc.abstractmethod
- def _add(self, registration: subobj.Registration):
- raise NotImplementedError
-
- @abc.abstractmethod
- def _get(self, registration_id) -> subobj.Registration:
- raise NotImplementedError
-
- @abc.abstractmethod
- def _update(self, registration: subobj.Registration):
- raise NotImplementedError
-
- @abc.abstractmethod
- def _delete(self, registration_id):
- raise NotImplementedError
from o2common.service.unit_of_work import AbstractUnitOfWork\r
from o2common.config import config\r
from o2ims.domain import commands\r
-from o2ims.domain.subscription_obj import RegistrationStatusEnum\r
+from o2ims.domain.configuration_obj import ConfigurationTypeEnum, \\r
+ RegistrationStatusEnum\r
\r
from o2common.helper import o2logging\r
logger = o2logging.get_logger(__name__)\r
data = cmd.data\r
logger.info('The Register2SMO all is {}'.format(data.all))\r
if data.all:\r
- regs = uow.registrations.list()\r
- for reg in regs:\r
- reg_data = reg.serialize()\r
- logger.debug('Registration: {}'.format(reg_data['registrationId']))\r
+ confs = uow.configrations.list()\r
+ for conf in confs:\r
+ if conf.conftype != ConfigurationTypeEnum.SMO:\r
+ continue\r
+ reg_data = conf.serialize()\r
+ logger.debug('Configuration: {}'.format(\r
+ reg_data['configurationId']))\r
\r
register_smo(uow, reg_data)\r
else:\r
with uow:\r
- reg = uow.registrations.get(data.id)\r
- if reg is None:\r
+ conf = uow.configurations.get(data.id)\r
+ if conf is None:\r
return\r
- logger.debug('Registration: {}'.format(reg.registrationId))\r
- reg_data = reg.serialize()\r
- register_smo(uow, reg_data)\r
+ logger.debug('Configuration: {}'.format(conf.configurationId))\r
+ conf_data = conf.serialize()\r
+ register_smo(uow, conf_data)\r
\r
\r
def register_smo(uow, reg_data):\r
call_res = call_smo(reg_data)\r
logger.debug('Call SMO response is {}'.format(call_res))\r
if call_res:\r
- reg = uow.registrations.get(reg_data['registrationId'])\r
+ reg = uow.configurations.get(reg_data['configurationId'])\r
if reg is None:\r
return\r
reg.status = RegistrationStatusEnum.NOTIFIED\r
- logger.debug('Updating Registration: {}'.format(\r
- reg.registrationId))\r
- uow.registrations.update(reg)\r
+ logger.debug('Updating Configurations: {}'.format(\r
+ reg.configurationId))\r
+ uow.configurations.update(reg)\r
uow.commit()\r
\r
\r
@retry((ConnectionRefusedError), tries=2, delay=2)\r
def call_smo(reg_data: dict):\r
callback_data = json.dumps({\r
- 'consumerSubscriptionId': reg_data['registrationId'],\r
+ 'consumerSubscriptionId': reg_data['configurationId'],\r
'imsUrl': config.get_api_url()\r
})\r
logger.info('URL: {}, data: {}'.format(\r
logger = o2logging.get_logger(__name__)\r
\r
\r
-def notify_registration_change(\r
- event: events.RegistrationChanged,\r
+def notify_configuration_change(\r
+ event: events.ConfigurationChanged,\r
publish: Callable,\r
):\r
logger.info('In notify_registration_change')\r
- publish("RegistrationChanged", event)\r
+ publish("ConfigurationChanged", event)\r
logger.debug("published Registration Changed: {}".format(\r
event.id))\r
# See the License for the specific language governing permissions and
# limitations under the License.
-from flask_restx import Namespace
-api_ims_inventory_v1 = Namespace(
- "O2IMS_Inventory",
- description='IMS Inventory related operations.')
+from o2common.config import config
+from . import ocloud_route, provision_route
+from . import api_ns
+
+from o2common.helper import o2logging
+logger = o2logging.get_logger(__name__)
+
+
+def configure_namespace(app):
+ apiims = config.get_o2ims_api_base()
+ apiprovision = config.get_provision_api_base()
+ logger.info(
+ "Expose IMS API:{}\nExpose Provision API: {}".
+ format(apiims, apiprovision))
+
+ ocloud_route.configure_api_route()
+ provision_route.configure_api_route()
+ app.add_namespace(api_ns.api_ims_inventory_v1, path=apiims)
+ app.add_namespace(api_ns.api_provision_v1, path=apiprovision)
--- /dev/null
+from flask_restx import Namespace\r
+\r
+\r
+api_ims_inventory_v1 = Namespace(\r
+ "O2IMS_Inventory",\r
+ description='IMS Inventory related operations.')\r
+\r
+api_provision_v1 = Namespace(\r
+ "PROVISION",\r
+ description='Provision related operations.')\r
from flask_restx import fields
-from o2ims.views import api_ims_inventory_v1
+from o2ims.views.api_ns import api_ims_inventory_v1
class OcloudDTO:
description='Subscription ID'),
}
)
-
-
-class RegistrationDTO:
-
- registration_get = api_ims_inventory_v1.model(
- "RegistrationGetDto",
- {
- 'registrationId': fields.String(required=True,
- description='Registration ID'),
- 'callback': fields.String,
- 'notified': fields.Boolean,
- }
- )
-
- registration = api_ims_inventory_v1.model(
- "RegistrationCreateDto",
- {
- 'callback': fields.String(
- required=True, description='Registration SMO callback address')
- }
- )
-
- registration_post_resp = api_ims_inventory_v1.model(
- "RegistrationCreatedRespDto",
- {
- 'registrationId': fields.String(required=True,
- description='registration ID'),
- }
- )
from flask_restx import Resource
-from o2ims.views import ocloud_view, api_ims_inventory_v1
-from o2common.config import config
+from o2common.service.messagebus import MessageBus
+from o2ims.views import ocloud_view
+from o2ims.views.api_ns import api_ims_inventory_v1
from o2ims.views.ocloud_dto import OcloudDTO, ResourceTypeDTO,\
- ResourcePoolDTO, ResourceDTO, DeploymentManagerDTO, SubscriptionDTO,\
- RegistrationDTO
+ ResourcePoolDTO, ResourceDTO, DeploymentManagerDTO, SubscriptionDTO
-apibase = config.get_o2ims_api_base()
+def configure_api_route():
+ # Set global bus for resource
+ global bus
+ bus = MessageBus.get_instance()
# ---------- OClouds ---------- #
def delete(self, subscriptionID):
result = ocloud_view.subscription_delete(subscriptionID, bus.uow)
return result, 204
-
-
-# ---------- Registration ---------- #
-@api_ims_inventory_v1.route("/registrations")
-class RegistrationListRouter(Resource):
-
- model = RegistrationDTO.registration_get
- expect = RegistrationDTO.registration
- post_resp = RegistrationDTO.registration_post_resp
-
- @api_ims_inventory_v1.doc('List registrations')
- @api_ims_inventory_v1.marshal_list_with(model)
- def get(self):
- return ocloud_view.registrations(bus.uow)
-
- @api_ims_inventory_v1.doc('Create a registration')
- @api_ims_inventory_v1.expect(expect)
- @api_ims_inventory_v1.marshal_with(post_resp, code=201)
- def post(self):
- data = api_ims_inventory_v1.payload
- result = ocloud_view.registration_create(data, bus)
- return result, 201
-
-
-@api_ims_inventory_v1.route("/registrations/<registrationID>")
-@api_ims_inventory_v1.param('registrationID', 'ID of the registration')
-@api_ims_inventory_v1.response(404, 'Registration not found')
-class RegistrationGetDelRouter(Resource):
-
- model = RegistrationDTO.registration_get
-
- @api_ims_inventory_v1.doc('Get registration by ID')
- @api_ims_inventory_v1.marshal_with(model)
- def get(self, registrationID):
- result = ocloud_view.registration_one(
- registrationID, bus.uow)
- if result is not None:
- return result
- api_ims_inventory_v1.abort(404, "Registration {} doesn't exist".format(
- registrationID))
-
- @api_ims_inventory_v1.doc('Delete registration by ID')
- @api_ims_inventory_v1.response(204, 'Registration deleted')
- def delete(self, registrationID):
- result = ocloud_view.registration_delete(registrationID, bus.uow)
- return result, 204
-
-
-def configure_namespace(app, bus_new):
-
- # Set global bus for resource
- global bus
- bus = bus_new
-
- app.add_namespace(api_ims_inventory_v1, path=apibase)
# See the License for the specific language governing permissions and\r
# limitations under the License.\r
\r
-import logging\r
import uuid\r
-from datetime import datetime\r
\r
-from o2common.service import unit_of_work, messagebus\r
-from o2ims.domain import events\r
-from o2ims.views.ocloud_dto import RegistrationDTO, SubscriptionDTO\r
-from o2ims.domain.subscription_obj import Registration, Subscription\r
+from o2common.service import unit_of_work\r
+from o2ims.views.ocloud_dto import SubscriptionDTO\r
+from o2ims.domain.subscription_obj import Subscription\r
\r
\r
def oclouds(uow: unit_of_work.AbstractUnitOfWork):\r
uow.subscriptions.delete(subscriptionId)\r
uow.commit()\r
return True\r
-\r
-\r
-def registrations(uow: unit_of_work.AbstractUnitOfWork):\r
- with uow:\r
- li = uow.registrations.list()\r
- return [r.serialize() for r in li]\r
-\r
-\r
-def registration_one(registrationId: str,\r
- uow: unit_of_work.AbstractUnitOfWork):\r
- with uow:\r
- first = uow.registrations.get(registrationId)\r
- return first.serialize() if first is not None else None\r
-\r
-\r
-def registration_create(registrationDto: RegistrationDTO.registration,\r
- bus: messagebus.MessageBus):\r
-\r
- reg_uuid = str(uuid.uuid4())\r
- registration = Registration(\r
- reg_uuid, registrationDto['callback'])\r
- with bus.uow as uow:\r
- uow.registrations.add(registration)\r
- logging.debug('before event length {}'.format(\r
- len(registration.events)))\r
- registration.events.append(events.RegistrationChanged(\r
- reg_uuid,\r
- datetime.now()))\r
- logging.debug('after event length {}'.format(len(registration.events)))\r
- uow.commit()\r
- _handle_events(bus)\r
- return {"registrationId": reg_uuid}\r
-\r
-\r
-def registration_delete(registrationId: str,\r
- uow: unit_of_work.AbstractUnitOfWork):\r
- with uow:\r
- uow.registrations.delete(registrationId)\r
- uow.commit()\r
- return True\r
-\r
-\r
-def _handle_events(bus: messagebus.MessageBus):\r
- # handle events\r
- events = bus.uow.collect_new_events()\r
- for event in events:\r
- bus.handle(event)\r
- return True\r
--- /dev/null
+# Copyright (C) 2021 Wind River Systems, Inc.
+#
+# 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 flask_restx import fields
+
+from o2ims.views.api_ns import api_provision_v1
+
+
+class SmoEndpointDTO:
+
+ endpoint_get = api_provision_v1.model(
+ "SmoEndpointGetDto",
+ {
+ 'configurationId': fields.String(required=True,
+ description='Configuration ID'),
+ 'endpoint': fields.String,
+ 'status': fields.String,
+ 'comments': fields.String,
+ }
+ )
+
+ endpoint = api_provision_v1.model(
+ "SmoEndpointCreateDto",
+ {
+ 'endpoint': fields.String(
+ required=True,
+ description='Configuration SMO callback address',
+ example='http://mock_smo:80/registration')
+ }
+ )
+
+ endpoint_post_resp = api_provision_v1.model(
+ "SmoEndpointCreatedRespDto",
+ {
+ 'configurationId': fields.String(required=True,
+ description='Configuration ID'),
+ }
+ )
--- /dev/null
+# Copyright (C) 2021 Wind River Systems, Inc.
+#
+# 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 flask_restx import Resource
+
+from o2common.service.messagebus import MessageBus
+from o2ims.views import provision_view
+from o2ims.views.api_ns import api_provision_v1
+from o2ims.views.provision_dto import SmoEndpointDTO
+
+
+def configure_api_route():
+ # Set global bus for resource
+ global bus
+ bus = MessageBus.get_instance()
+
+
+# ---------- SMO endpoint ---------- #
+@api_provision_v1.route("/smo-endpoint")
+class SmoEndpointListRouter(Resource):
+
+ model = SmoEndpointDTO.endpoint_get
+ expect = SmoEndpointDTO.endpoint
+ post_resp = SmoEndpointDTO.endpoint_post_resp
+
+ @api_provision_v1.doc('List SMO endpoints')
+ @api_provision_v1.marshal_list_with(model)
+ def get(self):
+ return provision_view.configurations(bus.uow)
+
+ @api_provision_v1.doc('Create a SMO endpoint')
+ @api_provision_v1.expect(expect)
+ @api_provision_v1.marshal_with(post_resp, code=201)
+ def post(self):
+ data = api_provision_v1.payload
+ result = provision_view.configuration_create(data, bus)
+ return result, 201
+
+
+@api_provision_v1.route("/smo-endpoint/<configurationID>")
+@api_provision_v1.param('configurationID',
+ 'ID of the SMO endpoint configuration')
+@api_provision_v1.response(404, 'SMO Endpoint configuration not found')
+class SmoEndpointGetDelRouter(Resource):
+
+ model = SmoEndpointDTO.endpoint_get
+
+ @api_provision_v1.doc('Get configuration by ID')
+ @api_provision_v1.marshal_with(model)
+ def get(self, configurationID):
+ result = provision_view.configuration_one(
+ configurationID, bus.uow)
+ if result is not None:
+ return result
+ api_provision_v1.abort(404,
+ "SMO Endpoint configuration {} doesn't exist".
+ format(configurationID))
+
+ @api_provision_v1.doc('Delete configuration by ID')
+ @api_provision_v1.response(204, 'Configuration deleted')
+ def delete(self, configurationID):
+ result = provision_view.configuration_delete(configurationID, bus.uow)
+ return result, 204
--- /dev/null
+# Copyright (C) 2021 Wind River Systems, Inc.\r
+#\r
+# Licensed under the Apache License, Version 2.0 (the "License");\r
+# you may not use this file except in compliance with the License.\r
+# You may obtain a copy of the License at\r
+#\r
+# http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+# Unless required by applicable law or agreed to in writing, software\r
+# distributed under the License is distributed on an "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+# See the License for the specific language governing permissions and\r
+# limitations under the License.\r
+\r
+import logging\r
+import uuid\r
+from datetime import datetime\r
+\r
+from o2common.service import unit_of_work, messagebus\r
+from o2ims.domain import events\r
+from o2ims.views.provision_dto import SmoEndpointDTO\r
+from o2ims.domain.configuration_obj import Configuration, ConfigurationTypeEnum\r
+\r
+\r
+def configurations(uow: unit_of_work.AbstractUnitOfWork):\r
+ with uow:\r
+ li = uow.configurations.list()\r
+ return [r.serialize_smo() for r in li]\r
+\r
+\r
+def configuration_one(configurationId: str,\r
+ uow: unit_of_work.AbstractUnitOfWork):\r
+ with uow:\r
+ first = uow.configurations.get(configurationId)\r
+ return first.serialize_smo() if first is not None else None\r
+\r
+\r
+def configuration_create(configurationDto: SmoEndpointDTO.endpoint,\r
+ bus: messagebus.MessageBus):\r
+\r
+ conf_uuid = str(uuid.uuid4())\r
+ configuration = Configuration(\r
+ conf_uuid, configurationDto['endpoint'], ConfigurationTypeEnum.SMO)\r
+ with bus.uow as uow:\r
+ uow.configurations.add(configuration)\r
+ logging.debug('before event length {}'.format(\r
+ len(configuration.events)))\r
+ configuration.events.append(events.ConfigurationChanged(\r
+ conf_uuid,\r
+ datetime.now()))\r
+ logging.debug('after event length {}'.format(\r
+ len(configuration.events)))\r
+ uow.commit()\r
+ _handle_events(bus)\r
+ return {"configurationId": conf_uuid}\r
+\r
+\r
+def configuration_delete(configurationId: str,\r
+ uow: unit_of_work.AbstractUnitOfWork):\r
+ with uow:\r
+ uow.configurations.delete(configurationId)\r
+ uow.commit()\r
+ return True\r
+\r
+\r
+def _handle_events(bus: messagebus.MessageBus):\r
+ # handle events\r
+ events = bus.uow.collect_new_events()\r
+ for event in events:\r
+ bus.handle(event)\r
+ return True\r
# from o2ims.adapter.clients.orm_stx import start_o2ims_stx_mappers\r
\r
from o2app.adapter import unit_of_work\r
-from o2ims.views.ocloud_route import configure_namespace\r
+from o2ims.views import configure_namespace\r
\r
from o2app.bootstrap import bootstrap\r
\r
app = Flask(__name__)\r
app.config["TESTING"] = True\r
api = Api(app)\r
- bus = bootstrap(False, uow)\r
- configure_namespace(api, bus)\r
+ bootstrap(False, uow)\r
+ configure_namespace(api)\r
return session, app\r
\r
\r
app = Flask(__name__)\r
app.config["TESTING"] = True\r
api = Api(app)\r
- bus = bootstrap(False, sqlite_uow)\r
- configure_namespace(api, bus)\r
+ bootstrap(False, sqlite_uow)\r
+ configure_namespace(api)\r
yield sqlite_uow, app\r
\r
\r
app = Flask(__name__)\r
app.config["TESTING"] = True\r
api = Api(app)\r
- bus = bootstrap(False, postgres_uow)\r
- configure_namespace(api, bus)\r
+ bootstrap(False, postgres_uow)\r
+ configure_namespace(api)\r
yield postgres_uow, app\r
\r
\r
import uuid
from unittest.mock import MagicMock
-from o2ims.domain import ocloud, subscription_obj
+from o2ims.domain import ocloud, subscription_obj, configuration_obj
from o2ims.domain import resource_type as rt
from o2ims.views import ocloud_view
from o2common.config import config
subscription1.subscriptionId == subscription_id1
-def test_new_registration():
- registration_id1 = str(uuid.uuid4())
- registration1 = subscription_obj.Registration(
- registration_id1, "https://callback/uri/write/here")
- assert registration_id1 is not None and\
- registration1.registrationId == registration_id1
+def test_new_configuration():
+ configuration_id1 = str(uuid.uuid4())
+ configuration1 = configuration_obj.Configuration(
+ configuration_id1, "https://callback/uri/write/here",
+ "SMO")
+ assert configuration_id1 is not None and\
+ configuration1.configurationId == configuration_id1
def test_view_olcouds(mock_uow):
"subscriptionId")) == subscription_id1
-def test_view_registrations(mock_uow):
- session, uow = mock_uow
-
- registration_id1 = str(uuid.uuid4())
- reg1 = MagicMock()
- reg1.serialize.return_value = {
- "registrationId": registration_id1,
- }
- session.return_value.query.return_value = [reg1]
-
- registration_list = ocloud_view.registrations(uow)
- assert str(registration_list[0].get(
- "registrationId")) == registration_id1
-
-
-def test_view_registration_one(mock_uow):
- session, uow = mock_uow
-
- registration_id1 = str(uuid.uuid4())
- session.return_value.query.return_value.filter_by.return_value.first.\
- return_value.serialize.return_value = None
-
- # Query return None
- registration_res = ocloud_view.registration_one(
- registration_id1, uow)
- assert registration_res is None
-
- session.return_value.query.return_value.filter_by.return_value.first.\
- return_value.serialize.return_value = {
- "registrationId": registration_id1,
- }
-
- registration_res = ocloud_view.registration_one(
- registration_id1, uow)
- assert str(registration_res.get(
- "registrationId")) == registration_id1
-
-
def test_flask_get_list(mock_flask_uow):
session, app = mock_flask_uow
session.query.return_value = []
resp = client.get(apibase+"/subscriptions")
assert resp.get_data() == b'[]\n'
- resp = client.get(apibase+"/registrations")
- assert resp.get_data() == b'[]\n'
-
def test_flask_get_one(mock_flask_uow):
session, app = mock_flask_uow
resp = client.get(apibase+"/subscriptions/"+subscription_id1)
assert resp.status_code == 404
- registration_id1 = str(uuid.uuid4())
- resp = client.get(apibase+"/registrations/"+registration_id1)
- assert resp.status_code == 404
-
def test_flask_post(mock_flask_uow):
session, app = mock_flask_uow
assert resp.status_code == 201
assert 'subscriptionId' in resp.get_json()
- reg_callback = 'http://registration/callback/url'
- resp = client.post(apibase+'/registrations', json={
- 'callback': reg_callback,
- })
- assert resp.status_code == 201
- assert 'registrationId' in resp.get_json()
-
def test_flask_delete(mock_flask_uow):
session, app = mock_flask_uow
resp = client.delete(apibase+"/subscriptions/"+subscription_id1)
assert resp.status_code == 204
- registration_id1 = str(uuid.uuid4())
- resp = client.delete(apibase+"/registrations/"+registration_id1)
- assert resp.status_code == 204
-
def test_flask_not_allowed(mock_flask_uow):
_, app = mock_flask_uow
assert resp.status == '405 METHOD NOT ALLOWED'
resp = client.patch(uri)
assert resp.status == '405 METHOD NOT ALLOWED'
-
- # Testing registrations not support method
- ##########################
- uri = apibase + "/registrations"
- resp = client.put(uri)
- assert resp.status == '405 METHOD NOT ALLOWED'
- resp = client.patch(uri)
- assert resp.status == '405 METHOD NOT ALLOWED'
- resp = client.delete(uri)
- assert resp.status == '405 METHOD NOT ALLOWED'
-
- subscription_id1 = str(uuid.uuid4())
- uri = apibase + "/registrations/" + subscription_id1
- resp = client.post(uri)
- assert resp.status == '405 METHOD NOT ALLOWED'
- resp = client.put(uri)
- assert resp.status == '405 METHOD NOT ALLOWED'
- resp = client.patch(uri)
- assert resp.status == '405 METHOD NOT ALLOWED'
--- /dev/null
+# Copyright (C) 2021 Wind River Systems, Inc.
+#
+# 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 uuid
+from unittest.mock import MagicMock
+
+from o2ims.domain import configuration_obj
+from o2ims.views import provision_view
+from o2common.config import config
+
+
+def test_new_smo_endpoint():
+ configuration_id1 = str(uuid.uuid4())
+ configuration1 = configuration_obj.Configuration(
+ configuration_id1, "https://callback/uri/write/here",
+ "SMO")
+ assert configuration_id1 is not None and\
+ configuration1.configurationId == configuration_id1
+
+
+def test_view_smo_endpoint(mock_uow):
+ session, uow = mock_uow
+
+ configuration_id1 = str(uuid.uuid4())
+ conf1 = MagicMock()
+ conf1.serialize_smo.return_value = {
+ "configurationId": configuration_id1,
+ }
+ session.return_value.query.return_value = [conf1]
+
+ configuration_list = provision_view.configurations(uow)
+ assert str(configuration_list[0].get(
+ "configurationId")) == configuration_id1
+
+
+def test_view_smo_endpoint_one(mock_uow):
+ session, uow = mock_uow
+
+ configuration_id1 = str(uuid.uuid4())
+ session.return_value.query.return_value.filter_by.return_value.first.\
+ return_value.serialize_smo.return_value = None
+
+ # Query return None
+ configuration_res = provision_view.configuration_one(
+ configuration_id1, uow)
+ assert configuration_res is None
+
+ session.return_value.query.return_value.filter_by.return_value.first.\
+ return_value.serialize_smo.return_value = {
+ "configurationId": configuration_id1,
+ }
+
+ configuration_res = provision_view.configuration_one(
+ configuration_id1, uow)
+ assert str(configuration_res.get(
+ "configurationId")) == configuration_id1
+
+
+def test_flask_get_list(mock_flask_uow):
+ session, app = mock_flask_uow
+ session.query.return_value = []
+ apibase = config.get_provision_api_base()
+
+ with app.test_client() as client:
+ # Get list and return empty list
+ ##########################
+ resp = client.get(apibase+"/smo-endpoint")
+ assert resp.get_data() == b'[]\n'
+
+
+def test_flask_get_one(mock_flask_uow):
+ session, app = mock_flask_uow
+
+ session.return_value.query.return_value.filter_by.return_value.\
+ first.return_value = None
+ apibase = config.get_provision_api_base()
+
+ with app.test_client() as client:
+ # Get one and return 404
+ ###########################
+ configuration_id1 = str(uuid.uuid4())
+ resp = client.get(apibase+"/smo-endpoint/"+configuration_id1)
+ assert resp.status_code == 404
+
+
+def test_flask_post(mock_flask_uow):
+ session, app = mock_flask_uow
+ apibase = config.get_provision_api_base()
+
+ with app.test_client() as client:
+ session.return_value.execute.return_value = []
+
+ conf_callback = 'http://registration/callback/url'
+ resp = client.post(apibase+'/smo-endpoint', json={
+ 'endpoint': conf_callback
+ })
+ assert resp.status_code == 201
+ assert 'configurationId' in resp.get_json()
+
+
+def test_flask_delete(mock_flask_uow):
+ session, app = mock_flask_uow
+ apibase = config.get_provision_api_base()
+
+ with app.test_client() as client:
+ session.return_value.execute.return_value.first.return_value = {}
+
+ configuration_id1 = str(uuid.uuid4())
+ resp = client.delete(apibase+"/smo-endpoint/"+configuration_id1)
+ assert resp.status_code == 204
+
+
+def test_flask_not_allowed(mock_flask_uow):
+ _, app = mock_flask_uow
+ apibase = config.get_provision_api_base()
+
+ with app.test_client() as client:
+
+ # Testing SMO endpoint not support method
+ ##########################
+ uri = apibase + "/smo-endpoint"
+ resp = client.put(uri)
+ assert resp.status == '405 METHOD NOT ALLOWED'
+ resp = client.patch(uri)
+ assert resp.status == '405 METHOD NOT ALLOWED'
+ resp = client.delete(uri)
+ assert resp.status == '405 METHOD NOT ALLOWED'
+
+ configuration_id1 = str(uuid.uuid4())
+ uri = apibase + "/smo-endpoint/" + configuration_id1
+ resp = client.post(uri)
+ assert resp.status == '405 METHOD NOT ALLOWED'
+ resp = client.put(uri)
+ assert resp.status == '405 METHOD NOT ALLOWED'
+ resp = client.patch(uri)
+ assert resp.status == '405 METHOD NOT ALLOWED'