From 7f2889ed5f5a37b13332e5f803ef22e373183a4b Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 10:40:33 +0200 Subject: [PATCH 01/20] small fixes for orion app when run without OCB --- .../src/orioncontextbroker/orion_api.py | 7 +++++++ .../src/orioncontextbroker/orion_context_broker.py | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/apps/OrionContextBroker/src/orioncontextbroker/orion_api.py b/apps/OrionContextBroker/src/orioncontextbroker/orion_api.py index d477f74..77a855b 100644 --- a/apps/OrionContextBroker/src/orioncontextbroker/orion_api.py +++ b/apps/OrionContextBroker/src/orioncontextbroker/orion_api.py @@ -43,6 +43,13 @@ class OrionAPI(LoggerMixin): self.logger.error('Type of "{}" unknown'.format(element)) return u"Unknown" + def is_host_alive(self): + req = self._request( + "{}/v2/entities".format(self.host), + method="get" + ) + return req['status'] >= 0 + def create_entity(self, entity_name, entity_type="openmtc", diff --git a/apps/OrionContextBroker/src/orioncontextbroker/orion_context_broker.py b/apps/OrionContextBroker/src/orioncontextbroker/orion_context_broker.py index 7a1c946..bd3e1c8 100644 --- a/apps/OrionContextBroker/src/orioncontextbroker/orion_context_broker.py +++ b/apps/OrionContextBroker/src/orioncontextbroker/orion_context_broker.py @@ -37,10 +37,13 @@ class OrionContextBroker(ResourceManagementXAE): accumulate_address = "http://" + self._get_auto_host(orion_host) + ":8080" # Orion API + self._dry_run = not orion_host self.orion_api = OrionAPI( orion_host=orion_host, api_version=orion_api, accumulate_endpoint="{}/accumulate".format(accumulate_address)) + if not self._dry_run: + self._dry_run = not self.orion_api.is_host_alive() # Subscription Sink for OCB self.app = Flask(__name__) @@ -116,6 +119,9 @@ class OrionContextBroker(ResourceManagementXAE): return re.sub('[\W]', '_', f_s), '%s-%s' % (e_pre, dev_id) def _sensor_data_cb(self, sensor_info, sensor_data): + if self._dry_run: + return + try: fiware_service, entity_name = self._entity_names[sensor_info['ID']] except KeyError: @@ -138,6 +144,10 @@ class OrionContextBroker(ResourceManagementXAE): 'ID']] self.logger.info("Create new Entity {} on Fiware Service {}".format( entity_name, fiware_service)) + + if self._dry_run: + return + self.orion_api.create_entity( entity_name, fiware_service=fiware_service) data_dummy = { From 6f923ec2cdfa33265dc996a72d1b47643229d267 Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 10:44:46 +0200 Subject: [PATCH 02/20] fixes headers and return codes --- common/openmtc-onem2m/src/openmtc_onem2m/client/http.py | 2 ++ common/openmtc-onem2m/src/openmtc_onem2m/exc.py | 4 ++++ .../src/openmtc_cse/methoddomain/controller/__init__.py | 7 ++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/client/http.py b/common/openmtc-onem2m/src/openmtc_onem2m/client/http.py index b8e8993..efc59c6 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/client/http.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/client/http.py @@ -167,6 +167,8 @@ class OneM2MHTTPClient(OneM2MClient): } headers['content-type'] = content_type + headers['accept'] = self.content_type + self.logger.debug("Added request params: %s", params) return { diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/exc.py b/common/openmtc-onem2m/src/openmtc_onem2m/exc.py index 913a8fc..d8baa86 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/exc.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/exc.py @@ -13,6 +13,10 @@ STATUS_ACCEPTED = STATUS( 1000, "ACCEPTED", 202) STATUS_OK = STATUS( 2000, "OK", 200) +STATUS_UPDATED = STATUS( + 2004, "UPDATED", 200) +STATUS_DELETED = STATUS( + 2002, "DELETED", 200) STATUS_CREATED = STATUS( 2001, "CREATED", 201) STATUS_BAD_REQUEST = STATUS( diff --git a/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py b/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py index 68b0f53..810a1f2 100644 --- a/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py +++ b/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py @@ -22,7 +22,8 @@ from openmtc_onem2m.exc import (CSEOperationNotAllowed, STATUS_OK, CSETypeError, CSEMissingValue, CSEValueError, STATUS_CREATED, CSEError, CSESyntaxError, CSEBadRequest, CSEPermissionDenied, STATUS_NOT_FOUND, CSEConflict, - CSEContentsUnacceptable, CSETargetNotReachable) + CSEContentsUnacceptable, CSETargetNotReachable, + STATUS_UPDATED, STATUS_DELETED) from openmtc_onem2m.model import (ExpiringResource, Notification, AccessControlOperationE, ResourceTypeE, NotificationContentTypeE, FilterUsageE, @@ -1000,7 +1001,7 @@ class OneM2MDefaultController(LoggerMixin): self.request) def _send_update_response(self): - return OneM2MResponse(STATUS_OK, pc=self.resource, + return OneM2MResponse(STATUS_UPDATED, pc=self.resource, request=self.request) # DELETE @@ -1045,7 +1046,7 @@ class OneM2MDefaultController(LoggerMixin): self.events.resource_deleted.fire(self.resource, self.request) def _send_delete_response(self): - return OneM2MResponse(STATUS_OK, request=self.request) + return OneM2MResponse(STATUS_DELETED, request=self.request) # see TS-0004 7.4.4 From bc819069f2b465ec7aa8c98311bd10846cdf1d6a Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 10:48:50 +0200 Subject: [PATCH 03/20] fixes virtual container parts addressing --- .../src/openmtc_cse/methoddomain/__init__.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/server/openmtc-cse/src/openmtc_cse/methoddomain/__init__.py b/server/openmtc-cse/src/openmtc_cse/methoddomain/__init__.py index 5fafc14..6d73da1 100644 --- a/server/openmtc-cse/src/openmtc_cse/methoddomain/__init__.py +++ b/server/openmtc-cse/src/openmtc_cse/methoddomain/__init__.py @@ -13,6 +13,12 @@ from openmtc_server.exc import ConfigurationError from openmtc_server.util import log_error +container_virtual_mapping = { + 'la': 'latest', + 'ol': 'oldest' +} + + class OneM2MMethodDomain(Component): def __init__(self, config, *args, **kw): super(OneM2MMethodDomain, self).__init__(*args, **kw) @@ -209,11 +215,11 @@ class OneM2MMethodDomain(Component): # oldest, latest -> Container # TODO(rst): fanOutPoint -> group # TODO(rst): pollingChannelURI -> pollingChannel - if path.endswith(('latest', 'oldest')): + if path.endswith(tuple(container_virtual_mapping.keys())): parent_path, virtual = path.rsplit('/', 1) parent = get_resource(parent_path) if isinstance(parent, model.Container): - resource = getattr(parent, virtual) + resource = getattr(parent, container_virtual_mapping[virtual]) if resource is None: raise CSENotFound() return resource From dfbae4880b5e07462b7609138c07edce867b4a53 Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 11:30:42 +0200 Subject: [PATCH 04/20] changes stateTag to be integer --- common/openmtc-onem2m/src/openmtc_onem2m/model.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/model.py b/common/openmtc-onem2m/src/openmtc_onem2m/model.py index a574224..c506d5f 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/model.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/model.py @@ -952,7 +952,7 @@ class ContentInstance(AnnounceableSubordinateResourceC, SubscribableResource): """See TS-0001 section 9.6.7""" - stateTag = UnicodeAttribute(accesstype=Attribute.RO) + stateTag = Attribute(int, accesstype=Attribute.RO) creator = UnicodeAttribute() # m2m:ID # contentInfo = typeOfContent(:EncodingType) # typeOfContent => Media Types @@ -969,7 +969,7 @@ class ContentInstance(AnnounceableSubordinateResourceC, class ContentInstanceAnnc(AnnouncedSubordinateResourceC): - stateTag = UnicodeAttribute(accesstype=Attribute.RO) + stateTag = Attribute(int, accesstype=Attribute.RO) contentInfo = UnicodeAttribute(EncodingTypeE) # m2m:contentInfo contentSize = Attribute(int, accesstype=Attribute.WO) ontologyRef = UnicodeAttribute(accesstype=Attribute.WO) @@ -983,7 +983,7 @@ class ContentInstanceAnnc(AnnouncedSubordinateResourceC): class Container(AnnounceableResourceC, SubscribableResource): """See TS-0001 section 9.6.6""" - stateTag = UnicodeAttribute(accesstype=Attribute.RO) + stateTag = Attribute(int, accesstype=Attribute.RO) creator = UnicodeAttribute() maxNrOfInstances = Attribute(int) maxByteSize = Attribute(int) @@ -1012,7 +1012,7 @@ Container.__child_types__ = ( class ContainerAnnc(AnnouncedResourceC, SubscribableResource): - stateTag = UnicodeAttribute(accesstype=Attribute.RO) + stateTag = Attribute(int, accesstype=Attribute.RO) maxNrOfInstances = Attribute(int) maxByteSize = Attribute(int) maxInstanceAge = UnicodeAttribute(mandatory=False) # todo From 15f5aac79ad8889d6606de44143b74c76766355a Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 11:42:03 +0200 Subject: [PATCH 05/20] handles stateTag attribute correctly --- .../methoddomain/controller/__init__.py | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py b/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py index 810a1f2..ebd1b4d 100644 --- a/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py +++ b/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py @@ -30,7 +30,8 @@ from openmtc_onem2m.model import (ExpiringResource, Notification, get_short_resource_name, URIList, DiscResTypeE, Container, AccessControlPolicy, AccessControlPolicyIDHolder, AccessControlRuleC, - DynAuthDasRequestC, SecurityInfo, SecurityInfoTypeE, AE) + DynAuthDasRequestC, SecurityInfo, SecurityInfoTypeE, + AE, ContentInstance) from openmtc_onem2m.transport import (OneM2MResponse, OneM2MRequest, OneM2MOperation, OneM2MErrorResponse) from openmtc_onem2m.util import split_onem2m_address @@ -52,9 +53,22 @@ class OneM2MDefaultController(LoggerMixin): def __init__(self, db_session, resource_type, handle_onem2m_request): super(OneM2MDefaultController, self).__init__() self.resource_type = resource_type - self.db_session = db_session self.handle_onem2m_request = handle_onem2m_request + # DB wrapper + + def _update(resource, fields=None): + if isinstance(resource, (Container, ContentInstance)): + resource.stateTag += 1 + return db_session.update(resource, fields) + self._create = db_session.store + self._get = db_session.get + self._update = _update + self._delete = db_session.delete + self._get_collection = db_session.get_collection + self._get_latest_content_instance = db_session.get_latest_content_instance + self._get_oldest_content_instance = db_session.get_oldest_content_instance + def __call__(self, request, target_resource): self.logger.debug("%s servicing request", type(self).__name__) @@ -201,7 +215,7 @@ class OneM2MDefaultController(LoggerMixin): self._check_privileges(parent) def _get_parent_of_resource(self, resource): - return self.db_session.get(resource.parentID) + return self._get(resource.parentID) def _check_privileges(self, resource): # get all ACPs @@ -375,7 +389,7 @@ class OneM2MDefaultController(LoggerMixin): try: for dac_id in resource.dynamicAuthorizationConsultationIDs: try: - dac = self.db_session.get(dac_id) + dac = self._get(dac_id) if dac.dynamicAuthorizationEnabled: return dac except DBNotFound: @@ -385,7 +399,7 @@ class OneM2MDefaultController(LoggerMixin): except AttributeError: return None else: - return self._get_dynamic_authorization_consultation(self.db_session.get(pid)) + return self._get_dynamic_authorization_consultation(self._get(pid)) def _create_dynamic_policy(self, resource, acp_info): acp = AccessControlPolicy( @@ -408,7 +422,7 @@ class OneM2MDefaultController(LoggerMixin): resp = self.api.handle_onem2m_request(req).get() dyn_acp_id = resp.content.resourceID resource.accessControlPolicyIDs.append(dyn_acp_id) - self.db_session.update(resource, ['accessControlPolicyIDs']) + self._update(resource, ['accessControlPolicyIDs']) def _perform_evaluation(self, policies, privilege_type): @@ -726,7 +740,7 @@ class OneM2MDefaultController(LoggerMixin): self.resource = resource - return self.db_session.store(resource) + return self._create(resource) def _set_resource_id(self, values): short_name = get_short_resource_name(self.resource_type.typename) @@ -858,7 +872,7 @@ class OneM2MDefaultController(LoggerMixin): self.logger.debug("is resource '%s' virtual? -> %s", s.name, s.virtual) if not s.virtual: - sub_node = self.db_session.get(s.path) + sub_node = self._get(s.path) self._do_discovery(sub_node) def _prepare_resource(self): @@ -883,7 +897,7 @@ class OneM2MDefaultController(LoggerMixin): def _retrieve_children_for_resource(self, resource): self.logger.debug("getting children of: %s", resource) - children = self.db_session.get_collection(None, resource) + children = self._get_collection(None, resource) resource.childResource = children # UPDATE @@ -989,8 +1003,8 @@ class OneM2MDefaultController(LoggerMixin): # self.resource = resource - return self.db_session.update(self.resource) - # return self.db_session.update(resource, values.keys()) + return self._update(self.resource) + # return self._update(resource, values.keys()) def _set_mandatory_update_attributes(self, values): values["lastModifiedTime"] = self.now @@ -1015,14 +1029,14 @@ class OneM2MDefaultController(LoggerMixin): return self._send_delete_response() def _get_parent(self): - self.parent = self.db_session.get(self.resource.parent_path) + self.parent = self._get(self.resource.parent_path) def _delete_resource(self): self._delete_children() self._do_delete_resource() def _do_delete_resource(self): - return self.db_session.delete(self.resource) + return self._delete(self.resource) def _delete_children(self): self._retrieve_children() @@ -1116,7 +1130,7 @@ class AEController(OneM2MDefaultController): ae_id = get_generic_ae_id() try: - self.db_session.get(ae_id) + self._get(ae_id) except DBNotFound: pass else: @@ -1291,10 +1305,10 @@ class ContentInstanceController(OneM2MDefaultController): self.parent.currentNrOfInstances -= 1 self.parent.currentByteSize -= self.parent.oldest.contentSize - self.db_session.delete(self.parent.oldest) + self._delete(self.parent.oldest) if self.parent.currentNrOfInstances >= 1: - oldest = self.db_session.get_oldest_content_instance( + oldest = self._get_oldest_content_instance( self.parent) self.logger.debug("Setting new oldest: %s", oldest) self.parent.oldest = oldest @@ -1310,7 +1324,7 @@ class ContentInstanceController(OneM2MDefaultController): self.resource) self.parent.oldest = self.resource self.parent.latest = self.resource - self.db_session.update(self.parent) + self._update(self.parent) def _set_mandatory_create_attributes(self, vals): self.request.name = None @@ -1324,11 +1338,11 @@ class ContentInstanceController(OneM2MDefaultController): def _delete_resource(self): super(ContentInstanceController, self)._delete_resource() - cnt = self.db_session.get(self.resource.parentID) + cnt = self._get(self.resource.parentID) # TODO(rst): handle byte size try: - ci_l = self.db_session.get_latest_content_instance(cnt) - ci_o = self.db_session.get_oldest_content_instance(cnt) + ci_l = self._get_latest_content_instance(cnt) + ci_o = self._get_oldest_content_instance(cnt) except (DBError, KeyError): cnt.latest = None cnt.oldest = None @@ -1338,7 +1352,7 @@ class ContentInstanceController(OneM2MDefaultController): cnt.oldest = ci_o cnt.currentNrOfInstances -= 1 - return self.db_session.update(cnt) + return self._update(cnt) class AccessControlPolicyController(OneM2MDefaultController): From 193778dec05d803bfd3b47291d4437a072a88154 Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 11:43:04 +0200 Subject: [PATCH 06/20] fixes contentInstance handling --- .../methoddomain/controller/__init__.py | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py b/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py index ebd1b4d..d066980 100644 --- a/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py +++ b/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py @@ -1298,10 +1298,7 @@ class ContentInstanceController(OneM2MDefaultController): def _create_resource(self): super(ContentInstanceController, self)._create_resource() - # handle_old_instances - max_nr_of_instances = self.parent.maxNrOfInstances - current_nr_of_instances = self.parent.currentNrOfInstances - if 0 < max_nr_of_instances <= current_nr_of_instances: + def remove_oldest_child(): self.parent.currentNrOfInstances -= 1 self.parent.currentByteSize -= self.parent.oldest.contentSize @@ -1316,6 +1313,14 @@ class ContentInstanceController(OneM2MDefaultController): self.logger.debug("Setting oldest to None") self.parent.oldest = None + # handle_old_instances + if 0 < self.parent.maxNrOfInstances <= self.parent.currentNrOfInstances: + remove_oldest_child() + + while (0 < self.parent.maxByteSize < + self.parent.currentByteSize + self.resource.contentSize): + remove_oldest_child() + # handle_new_instance self.parent.currentNrOfInstances += 1 self.parent.currentByteSize += self.resource.contentSize @@ -1326,6 +1331,12 @@ class ContentInstanceController(OneM2MDefaultController): self.parent.latest = self.resource self._update(self.parent) + def _check_create_representation(self): + super(ContentInstanceController, self)._check_create_representation() + + if self.request.content.resourceName in ('la', 'ol'): + raise CSEConflict() + def _set_mandatory_create_attributes(self, vals): self.request.name = None super(ContentInstanceController, @@ -1347,10 +1358,12 @@ class ContentInstanceController(OneM2MDefaultController): cnt.latest = None cnt.oldest = None cnt.currentNrOfInstances = 0 + cnt.currentByteSize = 0 else: cnt.latest = ci_l cnt.oldest = ci_o cnt.currentNrOfInstances -= 1 + cnt.currentByteSize -= self.resource.contentSize return self._update(cnt) From 5c83578524a2403c7a177113e5d143c2020d6936 Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 11:44:13 +0200 Subject: [PATCH 07/20] handles verification request correctly --- openmtc-app/src/openmtc_app/notification/__init__.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openmtc-app/src/openmtc_app/notification/__init__.py b/openmtc-app/src/openmtc_app/notification/__init__.py index a553c35..6526360 100644 --- a/openmtc-app/src/openmtc_app/notification/__init__.py +++ b/openmtc-app/src/openmtc_app/notification/__init__.py @@ -205,8 +205,9 @@ class MqttNotificationHandler(BaseNotificationHandler): from openmtc_onem2m.exc import get_response_status def wrapper(request): - notification = self._unpack_notification(request.content) - self._callback(request.originator, **notification) + if not request.content.verificationRequest: + notification = self._unpack_notification(request.content) + self._callback(request.originator, **notification) return OneM2MResponse(status_code=get_response_status(2000), request=request) self._client = get_client(self._endpoint.geturl(), handle_request_func=wrapper) @@ -256,8 +257,9 @@ class HttpNotificationHandler(BaseNotificationHandler): assert 'content-type' in request.headers, 'Unspecified content type' notification = get_onem2m_decoder(request.content_type).decode(request.data) - notification = self._unpack_notification(notification) - self._callback(request.headers['x-m2m-origin'], **notification) + if not notification.verificationRequest: + notification = self._unpack_notification(notification) + self._callback(request.headers['x-m2m-origin'], **notification) return Response( headers={ From f624ac1fe5aa186a07d6c885e3044c8afb41a24e Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 11:44:56 +0200 Subject: [PATCH 08/20] fixes chunked data receiving in notification http server --- openmtc-app/src/openmtc_app/notification/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openmtc-app/src/openmtc_app/notification/__init__.py b/openmtc-app/src/openmtc_app/notification/__init__.py index 6526360..f69c9fa 100644 --- a/openmtc-app/src/openmtc_app/notification/__init__.py +++ b/openmtc-app/src/openmtc_app/notification/__init__.py @@ -256,6 +256,13 @@ class HttpNotificationHandler(BaseNotificationHandler): assert 'x-m2m-ri' in request.headers, 'Missing request id' assert 'content-type' in request.headers, 'Unspecified content type' + if not request.data: + if request.environ.get('HTTP_TRANSFER_ENCODING') == 'chunked': + request.data = request.environ['wsgi.input'].read() + else: + cl = int(request.environ.get('CONTENT_LENGTH'), 0) + request.data = request.environ['wsgi.input'].read(cl) + notification = get_onem2m_decoder(request.content_type).decode(request.data) if not notification.verificationRequest: notification = self._unpack_notification(notification) From 2bfad1e360d28dd6d4ff1b90cc64ab2f88b11821 Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 11:45:37 +0200 Subject: [PATCH 09/20] updates to correct time format --- .../src/openmtc_onem2m/serializer/json/__init__.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/serializer/json/__init__.py b/common/openmtc-onem2m/src/openmtc_onem2m/serializer/json/__init__.py index 8c7076a..f14be0e 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/serializer/json/__init__.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/serializer/json/__init__.py @@ -30,12 +30,7 @@ del logger def _default(x): if isinstance(x, datetime): - try: - isoformat = x.isoformat - except AttributeError: - raise TypeError("%s (%s)" % (x, type(x))) - - return isoformat() + return x.strftime("%Y%m%dT%H%M%S") elif isinstance(x, ContentInstance): return x.resourceID else: From 1647abd1c1568159e1906ee8eac734b2fd350ccc Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 15:08:35 +0200 Subject: [PATCH 10/20] updates resourceTypeE and memberTypeE in model --- .../src/openmtc_onem2m/model.py | 46 +++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/model.py b/common/openmtc-onem2m/src/openmtc_onem2m/model.py index c506d5f..b9bbc20 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/model.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/model.py @@ -6,7 +6,7 @@ from openmtc.model import (Resource as Res, UnicodeAttribute, DatetimeAttribute, from openmtc.model.exc import ModelTypeError from futile import issubclass -LATEST_VERSION = "1.6" +LATEST_VERSION = "2a" class OneM2MIntEnum(IntEnum): @@ -24,7 +24,7 @@ class OneM2MContentResource(ContentResource, OneM2MEntity): class OneM2MResource(Res, OneM2MEntity): __model_name__ = "onem2m" - __model_version__ = "1.6" + __model_version__ = "2a" ################################################################################ @@ -41,8 +41,8 @@ class ResourceTypeE(OneM2MIntEnum): eventConfig = 7 execInstance = 8 group = 9 - localPolicy = 10 - m2mServiceSubscriptionProfile = 11 + locationPolicy = 10 + m2mServiceSubscription = 11 mgmtCmd = 12 mgmtObj = 13 node = 14 @@ -56,6 +56,16 @@ class ResourceTypeE(OneM2MIntEnum): statsConfig = 22 subscription = 23 semanticDescriptor = 24 + notificationTargetMgmtPolicyRef = 25 + notificationTargetPolicy = 26 + policyDeletionRules = 27 + flexContainer = 28 + timeSeries = 29 + timeSeriesInstance = 30 + role = 31 + token = 32 + trafficPattern = 33 + dynamicAuthorizationConsultation = 34 accessControlPolicyAnnc = 10001 AEAnnc = 10002 containerAnnc = 10003 @@ -66,6 +76,12 @@ class ResourceTypeE(OneM2MIntEnum): nodeAnnc = 10014 remoteCSEAnnc = 10016 scheduleAnnc = 10018 + semanticDescriptorAnnc = 10024 + flexContainerAnnc = 10028 + timeSeriesAnnc = 10029 + timeSeriesInstanceAnnc = 10030 + trafficPatternAnnc = 10033 + dynamicAuthorizationConsultationAnnc = 10034 @unique @@ -136,6 +152,7 @@ class RequestStatusE(OneM2MIntEnum): @unique class MemberTypeE(OneM2MIntEnum): + mixed = 0 accessControlPolicy = 1 AE = 2 container = 3 @@ -159,7 +176,16 @@ class MemberTypeE(OneM2MIntEnum): statsCollect = 21 statsConfig = 22 subscription = 23 + semanticDescriptor = 24 + notificationTargetMgmtPolicyRef = 25 + notificationTargetPolicy = 26 + policyDeletionRules = 27 + flexContainer = 28 + timeSeries = 29 + timeSeriesInstance = 30 + role = 31 token = 32 + trafficPattern = 33 dynamicAuthorizationConsultation = 34 accessControlPolicyAnnc = 10001 AEAnnc = 10002 @@ -170,11 +196,15 @@ class MemberTypeE(OneM2MIntEnum): mgmtObjAnnc = 10013 nodeAnnc = 10014 remoteCSEAnnc = 10016 - scheduleAnnc = 10019 + scheduleAnnc = 10018 + semanticDescriptorAnnc = 10024 + flexContainerAnnc = 10028 + timeSeriesAnnc = 10029 + timeSeriesInstanceAnnc = 10030 + trafficPatternAnnc = 10033 dynamicAuthorizationConsultationAnnc = 10034 - mixed = 24 - # Mixed is a mixture of the resource types from 1 to 23, 10001 to 10004, 10009 to 10010, - # 10013 to 10014 and 10016 to 10018 as listed above. + oldest = 20001 + latest = 20002 @unique From 8cf2ba09aec87e28912e1ba51236cee64fe7bbc2 Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 15:31:05 +0200 Subject: [PATCH 11/20] adds correct resultContent handling --- .../src/openmtc_onem2m/client/mqtt.py | 3 +- .../src/openmtc_onem2m/mapper/__init__.py | 1 + .../src/openmtc_onem2m/model.py | 20 ++++---- .../src/openmtc_onem2m/serializer/base.py | 50 +++---------------- .../src/openmtc_onem2m/serializer/util.py | 3 -- .../src/openmtc_onem2m/transport.py | 3 +- .../methoddomain/controller/__init__.py | 17 +++++-- .../plugins/transport_gevent_http/wsgi.py | 3 +- 8 files changed, 38 insertions(+), 62 deletions(-) diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/client/mqtt.py b/common/openmtc-onem2m/src/openmtc_onem2m/client/mqtt.py index 54050c2..66cd272 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/client/mqtt.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/client/mqtt.py @@ -370,7 +370,8 @@ class OneM2MMQTTClient(OneM2MClient): sp_id, cse_id, _ = split_onem2m_address(response.to) response.content = self._decode( encode_onem2m_content(response.content, 'application/json', - path=sp_id + cse_id)[1] + path=sp_id + cse_id, + fields=response.fields)[1] ) self._publish_message( diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/mapper/__init__.py b/common/openmtc-onem2m/src/openmtc_onem2m/mapper/__init__.py index ac0fba6..eb89c76 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/mapper/__init__.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/mapper/__init__.py @@ -105,6 +105,7 @@ class OneM2MMapper(BasicMapper): path, self.originator, filter_criteria=fc, + rcn=5, **request_options )).get() diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/model.py b/common/openmtc-onem2m/src/openmtc_onem2m/model.py index b9bbc20..828ed4d 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/model.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/model.py @@ -122,15 +122,17 @@ class ResponseType(OneM2MIntEnum): # @unique -# class ResultConentE(OneM2MIntEnum): -# nothing = 0 -# attributes = 1 -# hierarchical_address = 2 -# hierarchical_address_and_attributes = 3 -# attributes_and_child_resources = 4 -# attributes_and_child_resource_references = 6 -# child_resource_references = 6 -# original_resource = 7 +class ResultContentE(OneM2MIntEnum): + nothing = 0 + attributes = 1 + hierarchical_address = 2 + hierarchical_address_and_attributes = 3 + attributes_and_child_resources = 4 + attributes_and_child_resource_references = 5 + child_resource_references = 6 + original_resource = 7 + child_resources = 8 + modified_attributes = 9 @unique diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/serializer/base.py b/common/openmtc-onem2m/src/openmtc_onem2m/serializer/base.py index 2cb71fa..7312150 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/serializer/base.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/serializer/base.py @@ -49,7 +49,7 @@ class OneM2MSerializer(LoggerMixin): except (TypeError, AttributeError, KeyError, ValueError): raise CSEValueError("Invalid entry in child resources: %s", child_resource) - if resource_type is Notification and "notificationEvent" in data: + if resource_type is Notification and data.get("notificationEvent"): representation = data["notificationEvent"]["representation"] representation = self.decode(self.dumps(representation)) data["notificationEvent"]["representation"] = representation @@ -62,7 +62,10 @@ class OneM2MSerializer(LoggerMixin): class OneM2MDictSerializer(OneM2MSerializer): def encode_resource(self, resource, pretty=False, path=None, encoding="utf-8", fields=None, encapsulated=False): - representation = resource.values + if fields and isinstance(resource, OneM2MResource): + representation = {k: v for k, v in resource.values.items() if fields and k in fields} + else: + representation = resource.values self.logger.debug("Encoding representation: %s", representation) @@ -93,7 +96,7 @@ class OneM2MDictSerializer(OneM2MSerializer): return resource_id return val_path + resource_id - if isinstance(resource, OneM2MResource): + if isinstance(resource, OneM2MResource) and "childResource" in representation: def get_child_rep(c): return { @@ -112,53 +115,12 @@ class OneM2MDictSerializer(OneM2MSerializer): if isinstance(resource.oldest, ContentInstance): representation['oldest'] = resource.oldest.resourceID - # cleans representation - def clean_representation(o): - try: - # removes empty attributes - empty_keys = [] - for k, v in o.items(): - if v is None: - empty_keys.append(k) - elif isinstance(v, OneM2MEntity): - o[k] = self.encode_resource(v, pretty, path, encoding, fields) - elif isinstance(v, list): - - def encode_list_item(item): - if isinstance(item, OneM2MEntity): - return self.encode_resource(item, pretty, path, encoding, fields) - return item - if len(v): - o[k] = map(encode_list_item, v) - else: - empty_keys.append(k) - else: - try: - if len(v) == 0: - empty_keys.append(k) - except TypeError: - pass - - for k in empty_keys: - del o[k] - - for k, v in o.items(): - if not isinstance(v, (unicode, str, bool, datetime, - OneM2MIntEnum)): - clean_representation(v) - except AttributeError: - if isinstance(o, list): - for p in o: - clean_representation(p) - if not isinstance(resource, OneM2MContentResource): representation = { get_short_resource_name(k) or get_short_attribute_name(k) or get_short_member_name(k): v for k, v in representation.items()} - clean_representation(representation) - if not isinstance(resource, (OneM2MResource, Notification, SecurityInfo, OneM2MContentResource)): return representation diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/serializer/util.py b/common/openmtc-onem2m/src/openmtc_onem2m/serializer/util.py index c9a1f6e..a992a6b 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/serializer/util.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/serializer/util.py @@ -27,9 +27,6 @@ def encode_onem2m_content(content, content_type, pretty=False, path=None, if content is None: return None, None - fields = fields # TODO(rst): maybe necessary - # fields = ["resourceID"] - serializer = get_onem2m_encoder(content_type) data = serializer.encode_resource(content, pretty=pretty, path=path, diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/transport.py b/common/openmtc-onem2m/src/openmtc_onem2m/transport.py index 285655e..987d41c 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/transport.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/transport.py @@ -385,7 +385,7 @@ class OneM2MResponse(object): """Class representing a OneM2M response""" def __init__(self, status_code, request=None, rqi=None, pc=None, to=None, - fr=None, rsc=None): + fr=None, rsc=None, fields=None): # Operation result if isinstance(status_code, STATUS): self.response_status_code = status_code @@ -405,6 +405,7 @@ class OneM2MResponse(object): self.originator = fr # Resource content to be transferred. self.content = pc + self.fields = fields @property def status_code(self): diff --git a/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py b/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py index d066980..553c679 100644 --- a/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py +++ b/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py @@ -31,7 +31,7 @@ from openmtc_onem2m.model import (ExpiringResource, Notification, DiscResTypeE, Container, AccessControlPolicy, AccessControlPolicyIDHolder, AccessControlRuleC, DynAuthDasRequestC, SecurityInfo, SecurityInfoTypeE, - AE, ContentInstance) + AE, ResultContentE, ContentInstance) from openmtc_onem2m.transport import (OneM2MResponse, OneM2MRequest, OneM2MOperation, OneM2MErrorResponse) from openmtc_onem2m.util import split_onem2m_address @@ -804,6 +804,12 @@ class OneM2MDefaultController(LoggerMixin): self.fields = self.request.content and self.request.content.values def _handle_retrieve(self): + try: + self.request.rcn = ResultContentE(int(self.request.rcn)) + except ValueError: + raise CSEBadRequest() + except TypeError: + self.request.rcn = ResultContentE.attributes try: fu = self.request.filter_criteria.filterUsage except AttributeError: @@ -887,10 +893,15 @@ class OneM2MDefaultController(LoggerMixin): if self.fields and isinstance(self.fields, list): res.set_values({k: v if k in self.fields else None for k, v in res.get_values().items()}) - return self._retrieve_children() + + if self.request.rcn == ResultContentE.attributes_and_child_resource_references: + self._retrieve_children() def _send_retrieve_response(self): - return OneM2MResponse(STATUS_OK, pc=self.result, request=self.request) + fields = self.resource.values.keys() + if self.request.rcn != ResultContentE.attributes_and_child_resource_references: + fields = [k for k in fields if k != 'childResource'] + return OneM2MResponse(STATUS_OK, pc=self.result, request=self.request, fields=fields) def _retrieve_children(self): return self._retrieve_children_for_resource(self.resource) diff --git a/server/openmtc-cse/src/openmtc_cse/plugins/transport_gevent_http/wsgi.py b/server/openmtc-cse/src/openmtc_cse/plugins/transport_gevent_http/wsgi.py index 7314509..afe3bc4 100644 --- a/server/openmtc-cse/src/openmtc_cse/plugins/transport_gevent_http/wsgi.py +++ b/server/openmtc-cse/src/openmtc_cse/plugins/transport_gevent_http/wsgi.py @@ -339,7 +339,8 @@ class OpenMTCWSGIApplication(LoggerMixin): try: content_type, payload = encode_onem2m_content(response.content, accept, pretty, - path=resource_id_pre) + path=resource_id_pre, + fields=response.fields) except CSEContentsUnacceptable as e: status_code = e.status_code content_type = "text/plain" From 6cb4ee3d4188bb7a1db7eab23bfdb9830f02d266 Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 15:33:20 +0200 Subject: [PATCH 12/20] handles release version indicator and updates request/response attributes --- .../src/openmtc_onem2m/client/http.py | 7 +- .../src/openmtc_onem2m/client/mqtt.py | 20 ++- .../src/openmtc_onem2m/mapper/__init__.py | 10 +- .../src/openmtc_onem2m/transport.py | 133 ++++++++++++++++-- .../methoddomain/controller/__init__.py | 4 + .../plugins/transport_gevent_http/wsgi.py | 28 +++- 6 files changed, 180 insertions(+), 22 deletions(-) diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/client/http.py b/common/openmtc-onem2m/src/openmtc_onem2m/client/http.py index efc59c6..dc5c66b 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/client/http.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/client/http.py @@ -48,7 +48,7 @@ _method_map_to_http = { _clients = LRUCache(threadsafe=False) -_query_params = frozenset(['rt', 'rp', 'rcn', 'da', 'drt']) +_query_params = frozenset(['rt', 'rp', 'rcn', 'da', 'drt', 'rids', 'tids', 'ltids', 'tqi']) _header_to_field_map = { 'X-M2M-ORIGIN': 'originator', @@ -59,6 +59,8 @@ _header_to_field_map = { 'X-M2M-RET': 'rqet', 'X-M2M-OET': 'oet', 'X-M2M-EC': 'ec', + 'X-M2M-RVI': 'rvi', + 'X-M2M-VSI': 'vsi', } @@ -162,7 +164,8 @@ class OneM2MHTTPClient(OneM2MClient): content_type += '; ty=' + str(ResourceTypeE[onem2m_request.resource_type.typename]) headers = { - header: getattr(onem2m_request, field) for header, field in _header_to_field_map.iteritems() + header: getattr(onem2m_request, field) + for header, field in _header_to_field_map.iteritems() if getattr(onem2m_request, field) is not None } headers['content-type'] = content_type diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/client/mqtt.py b/common/openmtc-onem2m/src/openmtc_onem2m/client/mqtt.py index 66cd272..d714abf 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/client/mqtt.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/client/mqtt.py @@ -83,11 +83,12 @@ class OneM2MMQTTClient(OneM2MClient): __request_fields = frozenset([ 'op', + 'to', 'fr', 'rqi', 'ty', 'pc', - 'rol', + 'rids', 'ot', 'rqet', 'rset', @@ -98,17 +99,28 @@ class OneM2MMQTTClient(OneM2MClient): 'ec', 'da', 'gid', - 'drt', - 'to', 'fc', + 'drt', + 'tids', + 'ltids', + 'tqi', + 'rvi', + 'vsi', ]) __response_fields = frozenset([ 'rsc', 'rqi', 'pc', - 'fr', 'to', + 'fr', + 'ot', + 'rset', + 'ec', + 'cts', + 'cto', + 'rvi', + 'vsi', ]) @staticmethod diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/mapper/__init__.py b/common/openmtc-onem2m/src/openmtc_onem2m/mapper/__init__.py index eb89c76..1c25072 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/mapper/__init__.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/mapper/__init__.py @@ -49,7 +49,8 @@ class OneM2MMapper(BasicMapper): path, self.originator, ty=type(instance), - pc=instance + pc=instance, + rvi='2a' )).get() try: @@ -83,7 +84,8 @@ class OneM2MMapper(BasicMapper): OneM2MOperation.update, instance.path, self.originator, - pc=instance + pc=instance, + rvi='2a' )).get() try: @@ -105,6 +107,7 @@ class OneM2MMapper(BasicMapper): path, self.originator, filter_criteria=fc, + rvi='2a', rcn=5, **request_options )).get() @@ -113,7 +116,8 @@ class OneM2MMapper(BasicMapper): self._send_request(OneM2MRequest( OneM2MOperation.delete, getattr(instance, "path", instance), - self.originator + self.originator, + rvi='2a' )) # TODO(rst): check if this can be removed in parent class diff --git a/common/openmtc-onem2m/src/openmtc_onem2m/transport.py b/common/openmtc-onem2m/src/openmtc_onem2m/transport.py index 987d41c..4bc9394 100644 --- a/common/openmtc-onem2m/src/openmtc_onem2m/transport.py +++ b/common/openmtc-onem2m/src/openmtc_onem2m/transport.py @@ -201,10 +201,11 @@ class OneM2MRequest(object): """Class representing a OneM2M request""" - def __init__(self, op, to, fr=None, rqi=None, ty=None, pc=None, rol=None, + def __init__(self, op, to, fr=None, rqi=None, ty=None, pc=None, rids=None, ot=None, rqet=None, rset=None, oet=None, rt=None, rp=None, rcn=None, ec=None, da=None, gid=None, filter_criteria=None, - fc=None, drt=None): + fc=None, drt=None, tids=None, ltids=None, tqi=None, rvi=None, + vsi=None): # Operation self.operation = op # Target uri @@ -216,7 +217,7 @@ class OneM2MRequest(object): self.resource_type = ty # Resource content to be transferred. self.content = pc - self.role = rol + self.role_ids = rids self.originating_timestamp = ot self.request_expiration_timestamp = rqet self.result_expiration_timestamp = rset @@ -230,6 +231,11 @@ class OneM2MRequest(object): self.filter_criteria = filter_criteria or fc # Optional Discovery result type self.discovery_result_type = drt + self.token_ids = tids + self.local_token_ids = ltids + self.token_request_identifier = tqi + self.release_version_indicator = rvi + self.vendor_information = vsi @property def op(self): @@ -272,12 +278,12 @@ class OneM2MRequest(object): self.content = pc @property - def rol(self): - return self.role + def rids(self): + return self.role_ids - @rol.setter - def rol(self, rol): - self.role = rol + @rids.setter + def rids(self, rids): + self.role_ids = rids @property def ot(self): @@ -375,6 +381,46 @@ class OneM2MRequest(object): def drt(self, drt): self.discovery_result_type = drt + @property + def tids(self): + return self.token_ids + + @tids.setter + def tids(self, tids): + self.token_ids = tids + + @property + def ltids(self): + return self.local_token_ids + + @ltids.setter + def ltids(self, rvi): + self.local_token_ids = ltids + + @property + def tqi(self): + return self.token_request_identifier + + @tqi.setter + def tqi(self, tqi): + self.token_request_identifier = tqi + + @property + def rvi(self): + return self.release_version_indicator + + @rvi.setter + def rvi(self, rvi): + self.release_version_indicator = rvi + + @property + def vsi(self): + return self.vendor_information + + @vsi.setter + def vsi(self, vsi): + self.vendor_information = vsi + def __str__(self): return '%s: %s' % (self.__class__.__name__, ' | '.join([ '%s: %s' % (str(k), str(v)) for k, v in self.__dict__.iteritems() @@ -385,7 +431,8 @@ class OneM2MResponse(object): """Class representing a OneM2M response""" def __init__(self, status_code, request=None, rqi=None, pc=None, to=None, - fr=None, rsc=None, fields=None): + fr=None, rsc=None, ot=None, rset=None, ec=None, cts=None, + cto=None, rvi=None, vsi=None, fields=None): # Operation result if isinstance(status_code, STATUS): self.response_status_code = status_code @@ -397,14 +444,26 @@ class OneM2MResponse(object): self.to = request.to # Originator ID self.originator = request.fr + self.originating_timestamp = request.ot + self.result_expiration_timestamp = request.rset + self.event_category = request.ec + self.release_version_indicator = request.rvi + self.vendor_information = request.vsi else: self.request_identifier = rqi # Target uri self.to = to # Originator ID self.originator = fr + self.originating_timestamp = ot + self.release_version_indicator = rvi + self.vendor_information = vsi + self.result_expiration_timestamp = rset + self.event_category = ec # Resource content to be transferred. self.content = pc + self.content_status = cts + self.content_offset = cto self.fields = fields @property @@ -439,6 +498,62 @@ class OneM2MResponse(object): def fr(self, fr): self.originator = fr + @property + def ot(self): + return self.originating_timestamp + + @ot.setter + def ot(self, ot): + self.originating_timestamp = ot + + @property + def rset(self): + return self.result_expiration_timestamp + + @rset.setter + def rset(self, rset): + self.result_expiration_timestamp = rset + + @property + def ec(self): + return self.event_category + + @ec.setter + def ec(self, ec): + self.event_category = ec + + @property + def cts(self): + return self.content_status + + @cts.setter + def cts(self, cts): + self.content_status = cts + + @property + def cto(self): + return self.content_offset + + @cto.setter + def cto(self, cto): + self.content_offset = cto + + @property + def rvi(self): + return self.release_version_indicator + + @rvi.setter + def rvi(self, rvi): + self.release_version_indicator = rvi + + @property + def vsi(self): + return self.vendor_information + + @vsi.setter + def vsi(self, vsi): + self.vendor_information = vsi + def __str__(self): return '%s: %s' % (self.__class__.__name__, ' | '.join([ '%s: %s' % (str(k), str(v)) for k, v in self.__dict__.iteritems() diff --git a/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py b/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py index 553c679..4795c5e 100644 --- a/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py +++ b/server/openmtc-cse/src/openmtc_cse/methoddomain/controller/__init__.py @@ -106,6 +106,10 @@ class OneM2MDefaultController(LoggerMixin): self._dynamic_authorization_supported = dynamic_authorization.get('enabled', False) self._dynamic_authorization_poa = dynamic_authorization.get('poa', []) + # release version indicator + if not self.request.rvi: + self.request.rvi = '2a' + return self._handle_request() def _handle_request(self): diff --git a/server/openmtc-cse/src/openmtc_cse/plugins/transport_gevent_http/wsgi.py b/server/openmtc-cse/src/openmtc_cse/plugins/transport_gevent_http/wsgi.py index afe3bc4..d8711d3 100644 --- a/server/openmtc-cse/src/openmtc_cse/plugins/transport_gevent_http/wsgi.py +++ b/server/openmtc-cse/src/openmtc_cse/plugins/transport_gevent_http/wsgi.py @@ -249,11 +249,21 @@ class OpenMTCWSGIApplication(LoggerMixin): # request and response primitives, and vice versa, if applicable. ec = get_header("x-m2m-ec") + # The X-M2M-CTS header shall be mapped to the Content Status parameter + # of response primitives and vice versa, if applicable. + rvi = get_header("x-m2m-rvi") + + # The X-M2M-CTS header shall be mapped to the Content Status parameter + # of response primitives and vice versa, if applicable. + vsi = get_header("x-m2m-vsi") + onem2m_request = OneM2MRequest(op=op, to=to, fr=fr, rqi=rqi, ty=ty, pc=pc, ot=ot, rqet=rqet, rset=rset, - oet=oet, rt=rt, ec=ec, gid=gid) + oet=oet, rt=rt, ec=ec, gid=gid, rvi=rvi, + vsi=vsi) - not_filter_params = ('rt', 'rp', 'rcn', 'da', 'drt') + not_filter_params = ('rt', 'rp', 'rcn', 'da', 'drt', 'rids', 'tids', + 'ltids', 'tqi') multiple_params = ('lbl', 'ty', 'cty', 'atr') if http_request.query_string: @@ -315,9 +325,18 @@ class OpenMTCWSGIApplication(LoggerMixin): headers = { "x-m2m-ri": str(response.rqi), - "x-m2m-rsc": str(response.rsc) + "x-m2m-rsc": str(response.rsc), + 'x-m2m-rvi': str(response.rvi) } + if response.fr: + headers['x-m2m-origin'] = str(response.fr) + + response_fields = ['ot', 'rset', 'ec', 'cts', 'cto', 'vsi'] + for f in response_fields: + if getattr(response, f): + headers['x-m2m-%s' % f] = str(getattr(response, f)) + try: headers['Content-Location'] = (resource_id_pre + response.content.resourceID) except (AttributeError, TypeError): @@ -370,7 +389,8 @@ class OpenMTCWSGIApplication(LoggerMixin): headers = { "x-m2m-ri": str(response.rqi), - "x-m2m-rsc": str(response.rsc) + "x-m2m-rsc": str(response.rsc), + 'x-m2m-rvi': str(response.rvi) } except AttributeError: status_code = STATUS_INTERNAL_SERVER_ERROR.http_status_code From 06957bb9679b821f9400b855ab194b9ae0ab50dc Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 15:38:27 +0200 Subject: [PATCH 13/20] updates SDK to use la instead of latest --- openmtc-app/src/openmtc_app/onem2m.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmtc-app/src/openmtc_app/onem2m.py b/openmtc-app/src/openmtc_app/onem2m.py index 9d27095..6b791d5 100644 --- a/openmtc-app/src/openmtc_app/onem2m.py +++ b/openmtc-app/src/openmtc_app/onem2m.py @@ -547,7 +547,7 @@ class XAE(LoggerMixin): """ return self._get_content_from_cin( self.mapper.get( - getattr(container, 'path', container) + '/latest' + getattr(container, 'path', container) + '/la' ) ) @@ -851,7 +851,7 @@ class ResourceManagementXAE(XAE): self._discovered_sensors[sensor_path]['blacklisted'] = True def _handle_new_sensor(self, sensor_path): - latest = self.get_resource(sensor_path + '/latest') + latest = self.get_resource(sensor_path + '/la') if latest: spawn(self._handle_sensor_data, sensor_path, self._get_content_from_cin(latest)) From 61e688f921549aaae02af891751285ae980f77cd Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 5 Oct 2018 17:18:06 +0200 Subject: [PATCH 14/20] adds basic interoperability testing --- tests/interoperability/README.md | 27 ++ tests/interoperability/basic.yaml | 423 ++++++++++++++++++++++++++++++ 2 files changed, 450 insertions(+) create mode 100644 tests/interoperability/README.md create mode 100644 tests/interoperability/basic.yaml diff --git a/tests/interoperability/README.md b/tests/interoperability/README.md new file mode 100644 index 0000000..840aa77 --- /dev/null +++ b/tests/interoperability/README.md @@ -0,0 +1,27 @@ +# Conformance testing + +Based on [pyresttest](https://github.com/svanoort/pyresttest). It implements the tests from [TS-0013](http://www.onem2m.org/component/rsfiles/download-file/files?path=Release_2_Draft_TS%255CTS-0013-Interoperability_Testing-V2_6_0.DOC&Itemid=238). + +## Prerequisites + +The python module pyresttest has to be installed. + +```bash +$ pip install pyresttest +``` + +## Running the Tests + +The tests can be run from the command line. Make sure that a instance is running. + +Assuming that a gateway is running at localhost, port 8000. + +```bash +$ pyresttest http://localhost:8000 tests/conformance/basic.yaml +Test Group Openmtc Test 8.1.1 SUCCEEDED: : 1/1 Tests Passed! +Test Group Openmtc Test 8.1.2 SUCCEEDED: : 4/4 Tests Passed! +Test Group Openmtc Test 8.1.3 SUCCEEDED: : 4/4 Tests Passed! +Test Group Openmtc Test 8.1.4 SUCCEEDED: : 8/8 Tests Passed! +Test Group Openmtc Test 8.1.5 SUCCEEDED: : 13/13 Tests Passed! +Test Group Openmtc Test 8.1.6 SUCCEEDED: : 4/4 Tests Passed! +``` diff --git a/tests/interoperability/basic.yaml b/tests/interoperability/basic.yaml new file mode 100644 index 0000000..684dc00 --- /dev/null +++ b/tests/interoperability/basic.yaml @@ -0,0 +1,423 @@ +--- +- config: + - testset: "Openmtc pyresttests" + +############################################################################### +# ResourceType: CSEBASE +############################################################################### +- test: + - group: "Openmtc Test 8.1.1" + - name: "CSEBase Retrieve on Mca" + - url: "/onem2m" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', 'x-m2m-rvi': '2a'} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {header: x-m2m-rvi, comparator: 'eq', expected: '2a'} + - compare: {jsonpath_mini: 'm2m:cb.ty', comparator: 'eq', expected: 5} + +############################################################################### +# ResourceType: RemoteCSE +############################################################################### +- test: + - group: "Openmtc Test 8.1.2" + - name: "RemoteCSE Create" + - url: "/onem2m/" + - method: "POST" #Create + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:csr": {"csi":"/mn-cse-1", "cb":"onem2m", "rr":true, "cst":2, "rn":"mn-cse-1"}}' #pc + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:csr.ty', comparator: 'eq', expected: 16} + +- test: + - group: "Openmtc Test 8.1.2" + - name: "remoteCSE Retrieve" + - url: "/onem2m/mn-cse-1" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:csr.ty', comparator: 'eq', expected: 16} + +- test: + - group: "Openmtc Test 8.1.2" + - name: "RemoteCSE Update" + - url: "/onem2m/mn-cse-1" + - method: "PUT" #Update + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:csr": {"rr":false}}' #pc + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2004'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:csr.ty', comparator: 'eq', expected: 16} + +- test: + - group: "Openmtc Test 8.1.2" + - name: "remoteCSE Delete" + - url: "/onem2m/mn-cse-1" + - method: "DELETE" #Delete + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: [raw_body: "", expected: ""] + +############################################################################### +# ResourceType: AE +############################################################################### +- test: + - group: "Openmtc Test 8.1.3" + - name: "AE Create" + - url: "/onem2m/" + - method: "POST" #Create + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:ae": {"api":"/myAE","rr":true,"rn":"myAE"}}' #pc + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:ae.ty', comparator: 'eq', expected: 2} + +- test: + - group: "Openmtc Test 8.1.3" + - name: "AE Retrieve" + - url: "/onem2m/myAE" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:ae.ty', comparator: 'eq', expected: 2} + +- test: + - group: "Openmtc Test 8.1.3" + - name: "AE Update" + - url: "/onem2m/myAE" + - method: "PUT" #Update + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:csr": {"rr":false}}' #pc + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2004'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:ae.ty', comparator: 'eq', expected: 2} + +- test: + - group: "Openmtc Test 8.1.3" + - name: "AE Delete" + - url: "/onem2m/myAE" + - method: "DELETE" #Delete + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: [raw_body: "", expected: ""] + +############################################################################### +# ResourceType: Container +############################################################################### +- test: + - group: "Openmtc Test 8.1.4" + - name: "AE Create" + - url: "/onem2m/" + - method: "POST" #Create + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:ae": {"api":"/myAE","rr":true,"rn":"myAE"}}' #pc + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:ae.ty', comparator: 'eq', expected: 2} + +- test: + - group: "Openmtc Test 8.1.4" + - name: "Container Create" + - url: "/onem2m/myAE" + - method: "POST" #Create + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:cnt": {"rn":"myContainer"}}' #pc, , "li" = "Container1" + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:cnt.ty', comparator: 'eq', expected: 3} + +- test: + - group: "Openmtc Test 8.1.4" + - name: "Container Retrieve" + - url: "/onem2m/myAE/myContainer" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:cnt.ty', comparator: 'eq', expected: 3} + +- test: + - group: "Openmtc Test 8.1.4" + - name: "Container Update" + - url: "/onem2m/myAE/myContainer" + - method: "PUT" #Update + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:cnt": {"mni": 4}}' #pc + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2004'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:cnt.ty', comparator: 'eq', expected: 3} + +- test: + - group: "Openmtc Test 8.1.4" + - name: "Container Delete" + - url: "/onem2m/myAE/myContainer" + - method: "DELETE" #Delete + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: [raw_body: "", expected: ""] + +- test: + - group: "Openmtc Test 8.1.4" + - name: "AE Delete" + - url: "/onem2m/myAE" + - method: "DELETE" #Delete + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: [raw_body: "", expected: ""] + +############################################################################### +# ResourceType: ContentInstance +############################################################################### +- test: + - group: "Openmtc Test 8.1.4" + - name: "AE Create" + - url: "/onem2m/" + - method: "POST" #Create + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:ae": {"api":"/myAE","rr":true,"rn":"myAE"}}' #pc + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:ae.ty', comparator: 'eq', expected: 2} + +- test: + - group: "Openmtc Test 8.1.4" + - name: "Container Create" + - url: "/onem2m/myAE" + - method: "POST" #Create + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:cnt": {"rn":"myContainer"}}' #pc, , "li" = "Container1" + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:cnt.ty', comparator: 'eq', expected: 3} + +- test: + - group: "Openmtc Test 8.1.5" + - name: "ContentInstance Create" + - url: "/onem2m/myAE/myContainer" + - method: "POST" #Create + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:cin": {"con":"Type" , "rn":"Testcontent", "cnf": "text/plain:0" }}' #pc, , "li" = "Container1" + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4} + +- test: + - group: "Openmtc Test 8.1.5" + - name: "Container Retrieve" + - url: "/onem2m/myAE/myContainer" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - validators: + - compare: {jsonpath_mini: 'm2m:cnt.cni', comparator: 'eq', expected: 1} + +- test: + - group: "Openmtc Test 8.1.5" + - name: "ContentInstance Retrieve" + - url: "/onem2m/myAE/myContainer/Testcontent" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4} + +- test: + - group: "Openmtc Test 8.1.5" + - name: "ContentInstance Delete" + - url: "/onem2m/myAE/myContainer/Testcontent" + - method: "DELETE" #Delete + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: [raw_body: "", expected: ""] + +- test: + - group: "Openmtc Test 8.1.5" + - name: "ContentInstance Create" + - url: "/onem2m/myAE/myContainer" + - method: "POST" #Create + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:cin": {"con":"Type" , "rn":"Testcontent", "cnf": "text/plain:0" }}' #pc, , "li" = "Container1" + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4} + +- test: + - group: "Openmtc Test 8.1.5" + - name: "latest ContentInstance Delete" + - url: "/onem2m/myAE/myContainer/la" + - method: "DELETE" #Delete + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: [raw_body: "", expected: ""] + +- test: + - group: "Openmtc Test 8.1.5" + - name: "ContentInstance Create" + - url: "/onem2m/myAE/myContainer" + - method: "POST" #Create + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:cin": {"con":"Type" , "rn":"Testcontent", "cnf": "text/plain:0" }}' #pc, , "li" = "Container1" + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4} + +- test: + - group: "Openmtc Test 8.1.5" + - name: "oldest ContentInstance Delete" + - url: "/onem2m/myAE/myContainer/ol" + - method: "DELETE" #Delete + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: [raw_body: "", expected: ""] + +- test: + - group: "Openmtc Test 8.1.5" + - name: "ContentInstance Create" + - url: "/onem2m/myAE/myContainer" + - method: "POST" #Create + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - body: '{"m2m:cin": {"con":"Type" , "rn":"Testcontent", "cnf": "text/plain:0" }}' #pc, , "li" = "Container1" + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4} + +- test: + - group: "Openmtc Test 8.1.5" + - name: "latest ContentInstance Retrieve" + - url: "/onem2m/myAE/myContainer/la" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4} + +- test: + - group: "Openmtc Test 8.1.5" + - name: "oldest ContentInstance Retrieve" + - url: "/onem2m/myAE/myContainer/ol" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4} + +- test: + - group: "Openmtc Test 8.1.5" + - name: "Container Delete" + - url: "/onem2m/myAE/myContainer" + - method: "DELETE" #Delete + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: [raw_body: "", expected: ""] + +- test: + - group: "Openmtc Test 8.1.5" + - name: "AE Delete" + - url: "/onem2m/myAE" + - method: "DELETE" #Delete + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + - compare: [raw_body: "", expected: ""] + +############################################################################### +# Discovery +############################################################################### +- test: + - group: "Openmtc Test 8.1.6" + - name: "Discovery all resources" + - url: "/onem2m?fu=1" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + +- test: + - group: "Openmtc Test 8.1.6" + - name: "Discovery with filter criteria" + - url: "/onem2m?fu=1&lbl=key1" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + +- test: + - group: "Openmtc Test 8.1.6" + - name: "Discovery with limit filter criteria" + - url: "/onem2m?fu=1&lim=2" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + +- test: + - group: "Openmtc Test 8.1.6" + - name: "Discovery with mulriple filter criteria" + - url: "/onem2m?fu=1&lbl=key1&lbl=key2&lim=1" + - method: "GET" #Retrieve + - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f} + - validators: + - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} + - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + +#- test: +# - group: "Openmtc Test 8.1.6" +# - name: "Discovery with level filter criteria" +# - url: "/onem2m?fu=1&lvl=2" +# - method: "GET" #Retrieve +# - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f} +# - validators: +# - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} +# - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} + +#- test: +# - group: "Openmtc Test 8.1.6" +# - name: "Discovery with offset filter criteria" +# - url: "/onem2m?fu=1&ofst=1" +# - method: "GET" #Retrieve +# - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f} +# - validators: +# - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'} +# - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'} From 3fc8bdb14ee239c4164bc91a5c664ac67a201fe3 Mon Sep 17 00:00:00 2001 From: Jason Fox Date: Tue, 30 Oct 2018 16:18:37 +0100 Subject: [PATCH 15/20] Update to standard-readme format * Moved badges to top - two rows * Formatted Markdown file * Added lede at the top of file so a description paragraph will display on mobile * Standardized some Section names (e.g. Install) * Added standard QA section - TSC **must** requirement * Expanded License to include copyrights * Updated catalogue links to new GitHub location [standard-readme](https://github.com/RichardLitt/standard-readme) is a simple standard naming convention for README files which makes reading and navigation of the documentation easier - this is a TSC **should** requirement Created Readthedocs index file. --- README.md | 112 +++++++++++++++++++++++++++++++++++++-------------- doc/index.md | 9 +++++ mkdocs.yml | 51 +++++++++++++++++++++++ 3 files changed, 141 insertions(+), 31 deletions(-) create mode 100644 doc/index.md create mode 100644 mkdocs.yml diff --git a/README.md b/README.md index 9ca04a5..4252a6a 100644 --- a/README.md +++ b/README.md @@ -4,43 +4,93 @@

-The OpenMTC SDK aims to provide developers with a convenient yet flexible tool to write oneM2M compliant applications. This includes network applications (NAs), gateway application (GAs), device applications (DAs), as well as interworking proxy entities (IPEs). +[![FIWARE IoT Agents](https://nexus.lab.fiware.org/static/badges/chapters/iot-agents.svg)](https://www.fiware.org/developers/catalogue/) +[![License: Eclipse](https://img.shields.io/github/license/OpenMTC/OpenMTC.svg)](https://www.eclipse.org/legal/epl-v10.html) +[![Support badge](https://nexus.lab.fiware.org/repository/raw/public/badges/stackoverflow/iot-agents.svg)](https://stackoverflow.com/questions/tagged/fiware+iot) +
+[![Documentation badge](https://img.shields.io/readthedocs/fiware-openmtc.svg)](http://fiware-openmtc.readthedocs.org/en/latest/?badge=latest) +![Status](https://nexus.lab.fiware.org/static/badges/statuses/iot-openmtc.svg) -# Table of Content +The OpenMTC SDK aims to provide developers with a convenient yet flexible tool +to write oneM2M compliant applications. This includes network applications +(NAs), gateway application (GAs), device applications (DAs), as well as +interworking proxy entities (IPEs). -- [Quick Start](doc/openmtc-get-started.md) -- [Introduction](doc/introduction.md) -- [Deployment](doc/deployment-guide.md) -- [The MQTT Client](doc/onem2m-client-mqtt.md) -- [Authentication Guide](doc/authentication.md) -- [Installation of the OpenMTC SDK](doc/install-sdk.md) -- [Overview REST API](doc/overview-rest-api.md) -- [Write your first OpenMTC applications](doc/training/training-index.md) -- [SDK - Using the Application Framework](doc/sdk-framework.md) -- [SDK - The low-level CSE Client](doc/sdk-client.md) -- [SDK - The Data Model](doc/sdk-datamodel.md) -- Examples - - [IoT Data Visualization](doc/example-apps/IoT-data-visualization.py) - - [Data Aggregation](doc/example-apps/data-aggregation.py) - - [Simple Decision](doc/example-apps/simple-decision.py) - - [Simple Decision 2](doc/example-apps/simple-decision-2.py) -- Scripts - - [Create App Structure Script](doc/create-app-structure.md) - - [Create binary docker images Script](doc/create-binary-docker.md) -- [Code Repository Structure](doc/repository-structure.md) -- [Developer FAQ](doc/developer-faq.md) +This project is part of [FIWARE](https://www.fiware.org/). For more information +check the FIWARE Catalogue entry for the +[IoT Agents](https://github.com/Fiware/catalogue/tree/master/iot-agents). + +# Content + +- [Install](#install) +- [Usage](#usage) +- [API](#api) +- [Quality Assurance](#quality-assurance) +- [License](#license) -# Python +## Install -The OpenMTC SDK is written in and for the Python programming language. Users should therefore have at least a certain knowledge of Python and its paradigms. For this matter, the following material is recommended: +Information about how to install the JSON IoTAgent can be found at the +corresponding section of the +[Installation & Administration Guide](https://fiware-openmtc.readthedocs.io/en/latest/deployment-guide). -- [The Python Homepage](http://www.python.org) -- [Expert Python Programming by Tarek Ziadé](http://www.e-reading.by/bookreader.php/138816/Ziade_-_Expert_Python_programming.pdf) -- [Code Like a Pythonista: Idiomatic Python](http://www.omahapython.org/IdiomaticPython.html) +## Usage -# Feedback +Information about how to use the IoT Agent can be found in the +[User & Programmers Manual](https://fiware-openmtc.readthedocs.io/en/latest/introduction). -Please create issues for any problems and direct any comments or feedback you are having to support@openmtc.org +## API + +Information about the REST API can be found in the +[API Section](https://fiware-openmtc.readthedocs.io/en/latest/overview-rest-api) + + +## Python + +The OpenMTC SDK is written in and for the Python programming language. Users +should therefore have at least a certain knowledge of Python and its paradigms. +For this matter, the following material is recommended: + +- [The Python Homepage](http://www.python.org) +- [Expert Python Programming by Tarek Ziadé](http://www.e-reading.by/bookreader.php/138816/Ziade_-_Expert_Python_programming.pdf) +- [Code Like a Pythonista: Idiomatic Python](http://www.omahapython.org/IdiomaticPython.html) + +## Feedback + +Please create issues for any problems and direct any comments or feedback you +are having to support@openmtc.org + +Please let us know what you think. We are also very interested in any use case +you are _not_ able to implement with the SDK or if you find it difficult to do +so. + + +## Quality Assurance + +This project is part of [FIWARE](https://fiware.org/) and has been rated as +follows: + +- **Version Tested:** + ![ ](https://img.shields.io/badge/dynamic/json.svg?label=Version&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.version&colorB=blue) +- **Documentation:** + ![ ](https://img.shields.io/badge/dynamic/json.svg?label=Completeness&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.docCompleteness&colorB=blue) + ![ ](https://img.shields.io/badge/dynamic/json.svg?label=Usability&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.docSoundness&colorB=blue) +- **Responsiveness:** + ![ ](https://img.shields.io/badge/dynamic/json.svg?label=Time%20to%20Respond&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.timeToCharge&colorB=blue) + ![ ](https://img.shields.io/badge/dynamic/json.svg?label=Time%20to%20Fix&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.timeToFix&colorB=blue) +- **FIWARE Testing:** + ![ ](https://img.shields.io/badge/dynamic/json.svg?label=Tests%20Passed&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.failureRate&colorB=blue) + ![ ](https://img.shields.io/badge/dynamic/json.svg?label=Scalability&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.scalability&colorB=blue) + ![ ](https://img.shields.io/badge/dynamic/json.svg?label=Performance&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.performance&colorB=blue) + ![ ](https://img.shields.io/badge/dynamic/json.svg?label=Stability&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.stability&colorB=blue) + +--- + +## Licence + +The OpenMTC SDK is licensed under the Eclipse Public License (EPL) +version 1. + +© 2018 OpenMTC -Please let us know what you think. We are also very interested in any use case you are *not* able to implement with the SDK or if you find it difficult to do so. diff --git a/doc/index.md b/doc/index.md new file mode 100644 index 0000000..689917d --- /dev/null +++ b/doc/index.md @@ -0,0 +1,9 @@ +# Open MTC IoT Agent + +[![FIWARE IoT Agents](https://nexus.lab.fiware.org/repository/raw/public/badges/chapters/iot-agents.svg)](https://www.fiware.org/developers/catalogue/) +[![](https://nexus.lab.fiware.org/repository/raw/public/badges/stackoverflow/iot-agents.svg)](https://stackoverflow.com/questions/tagged/fiware+iot) + +The OpenMTC SDK aims to provide developers with a convenient yet flexible tool +to write oneM2M compliant applications. This includes network applications +(NAs), gateway application (GAs), device applications (DAs), as well as +interworking proxy entities (IPEs). diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..8790e3c --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,51 @@ +site_name: Open MTC +site_url: https://github.com/OpenMTC/OpenMTC +repo_url: https://github.com/OpenMTC/OpenMTC.git +site_description: FIWARE Open MTC IoT Agent document site +docs_dir: doc/ +site_dir: html +markdown_extensions: [toc,tables, fenced_code] +use_directory_urls: false +theme: readthedocs +extra_css: ["https://fiware.org/style/fiware_readthedocs.css", "https://fiware.org/style/fiware_readthedocs_iot.css"] +pages: + - Home: index.md + - 'User & Programmers Manual': + - Introduction: introduction.md + - Quick Start: openmtc-get-started.md + - The MQTT Client: onem2m-client-mqtt.md + - Authentication Guide: authentication.md + - Overview REST API: overview-rest-api.md + - Write your first OpenMTC applications: training/training-index.md + - Console Outputs: + - Sensor Backend: training/console-outputs/training-sensor-backend.md + - Sensor Gateway: training/console-outputs/training-sensor-gateway.md + - Sensor IPE: training/console-outputs/training-sensor-ipe.md + - Sensor GUI: training/console-outputs/training-sensor-gui.md + - Sensor Actuator Backend: training/console-outputs/training-sensor-actuator-backend.md + - Sensor Actuator Gateway: training/console-outputs/training-sensor-actuator-gateway.md + - Sensor Actuator IPE: training/console-outputs/training-sensor-actuator-ipe.md + - Sensor Actuator GUI: training/console-outputs/training-sensor-actuator-gui.md + - Training: + - IPE Sensors: training/training-ipe-sensors.md + - IPE Sensors Actuators: training/training-ipe-sensors-actuators.md + - GUI Sensors: training/training-gui-sensors.md + - GUI Sensors Actuators: training/training-gui-sensors-actuators.md + - SDK - Using the Application Framework: sdk-framework.md + - SDK - The low-level CSE Client: sdk-client.md + - SDK - The Data Model: sdk-datamodel.md + - Examples: + - IoT Data Visualization: example-apps/IoT-data-visualization.py + - Data Aggregation: example-apps/data-aggregation.py + - Simple Decision: example-apps/simple-decision.py + - Simple Decision 2: example-apps/simple-decision-2.py + - Scripts: + - Create App Structure Script: create-app-structure.md + - Create binary docker images Script: create-binary-docker.md + - Code Repository Structure: repository-structure.md + - Developer FAQ: developer-faq.md + - 'Installation & Administration Manual': + - Deployment: deployment-guide.md + - Installation of the OpenMTC SDK: install-sdk.md + - Appendix : various.md + - Resource Names & Types : reference-doc/resource-names-and-types.md From 58560b757334b77f443cc25248a162ef954775c7 Mon Sep 17 00:00:00 2001 From: aor-fokus <46489184+aor-fokus@users.noreply.github.com> Date: Wed, 9 Jan 2019 15:49:58 +0100 Subject: [PATCH 16/20] Added Travis badge to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4252a6a..104c9a7 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@
[![Documentation badge](https://img.shields.io/readthedocs/fiware-openmtc.svg)](http://fiware-openmtc.readthedocs.org/en/latest/?badge=latest) ![Status](https://nexus.lab.fiware.org/static/badges/statuses/iot-openmtc.svg) +[![Build Status](https://travis-ci.org/OpenMTC/OpenMTC.svg?branch=master)](https://travis-ci.org/OpenMTC/OpenMTC) The OpenMTC SDK aims to provide developers with a convenient yet flexible tool to write oneM2M compliant applications. This includes network applications From c737effe0e7f74ec7c48f564d8bbe42e6643b96c Mon Sep 17 00:00:00 2001 From: aor-fokus Date: Wed, 9 Jan 2019 16:05:41 +0100 Subject: [PATCH 17/20] New Chapter for the configuration of gateway&backend --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index 8790e3c..99e0578 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -49,3 +49,4 @@ pages: - Installation of the OpenMTC SDK: install-sdk.md - Appendix : various.md - Resource Names & Types : reference-doc/resource-names-and-types.md + - Gateway & Backend Configuration : reference-doc/gateway-and-backend-configuration.md From 9b73c6d337ef57789c2b3340a5d08f81348e4562 Mon Sep 17 00:00:00 2001 From: aor-fokus <46489184+aor-fokus@users.noreply.github.com> Date: Wed, 9 Jan 2019 16:09:47 +0100 Subject: [PATCH 18/20] Added docker pulls badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 104c9a7..40fd52c 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@
[![Documentation badge](https://img.shields.io/readthedocs/fiware-openmtc.svg)](http://fiware-openmtc.readthedocs.org/en/latest/?badge=latest) ![Status](https://nexus.lab.fiware.org/static/badges/statuses/iot-openmtc.svg) +[![](https://img.shields.io/docker/pulls/openmtc/gateway-amd64.svg)](https://hub.docker.com/u/openmtc) [![Build Status](https://travis-ci.org/OpenMTC/OpenMTC.svg?branch=master)](https://travis-ci.org/OpenMTC/OpenMTC) The OpenMTC SDK aims to provide developers with a convenient yet flexible tool From b75be75384c0b775f92ec3c501c78cea124d38c8 Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 11 Jan 2019 17:52:58 +0100 Subject: [PATCH 19/20] fixes typo --- tests/interoperability/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/interoperability/README.md b/tests/interoperability/README.md index 840aa77..85e4381 100644 --- a/tests/interoperability/README.md +++ b/tests/interoperability/README.md @@ -17,7 +17,7 @@ The tests can be run from the command line. Make sure that a instance is running Assuming that a gateway is running at localhost, port 8000. ```bash -$ pyresttest http://localhost:8000 tests/conformance/basic.yaml +$ pyresttest http://localhost:8000 tests/interoperability/basic.yaml Test Group Openmtc Test 8.1.1 SUCCEEDED: : 1/1 Tests Passed! Test Group Openmtc Test 8.1.2 SUCCEEDED: : 4/4 Tests Passed! Test Group Openmtc Test 8.1.3 SUCCEEDED: : 4/4 Tests Passed! From ea4745296eff4b2aa80d897170bbabb0d0d62fa0 Mon Sep 17 00:00:00 2001 From: Ronald Steinke Date: Fri, 11 Jan 2019 17:55:26 +0100 Subject: [PATCH 20/20] bump version to 1.2.0 --- apps/InfluxdbApp/src/influxdbapp/__init__.py | 2 +- apps/OrionContextBroker/src/orioncontextbroker/__init__.py | 2 +- apps/csvInjector/src/csvinjector/__init__.py | 2 +- apps/mqttConnector/src/mqttconnector/__init__.py | 2 +- ipes/CUL868IPE/src/cul868ipe/__init__.py | 2 +- setup-gevent-all.py | 2 +- setup-sdk.py | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/InfluxdbApp/src/influxdbapp/__init__.py b/apps/InfluxdbApp/src/influxdbapp/__init__.py index fc0b947..9693e9d 100644 --- a/apps/InfluxdbApp/src/influxdbapp/__init__.py +++ b/apps/InfluxdbApp/src/influxdbapp/__init__.py @@ -2,7 +2,7 @@ Transfer OpenMTC Data to an InfluxDB """ -__version__ = "1.1.0" +__version__ = "1.2.0" __description__ = "InfluxdbApp" __author_name__ = "Christian Klopp" __author_mail__ = "christian.klopp@fokus.fraunhofer.de" diff --git a/apps/OrionContextBroker/src/orioncontextbroker/__init__.py b/apps/OrionContextBroker/src/orioncontextbroker/__init__.py index 0707151..f059b87 100644 --- a/apps/OrionContextBroker/src/orioncontextbroker/__init__.py +++ b/apps/OrionContextBroker/src/orioncontextbroker/__init__.py @@ -3,7 +3,7 @@ This App will forward all incoming sensor traffic to the Fiware Orion Context Broker """ -__version__ = "1.1.0" +__version__ = "1.2.0" __description__ = "OrionContextBroker" __author_name__ = "Christian Klopp" __author_mail__ = "christian.klopp@fokus.fraunhofer.de" diff --git a/apps/csvInjector/src/csvinjector/__init__.py b/apps/csvInjector/src/csvinjector/__init__.py index 9ad430c..6c7af5c 100644 --- a/apps/csvInjector/src/csvinjector/__init__.py +++ b/apps/csvInjector/src/csvinjector/__init__.py @@ -2,7 +2,7 @@ App to inject data from a csv file to OpenMTC """ -__version__ = "1.1.0" +__version__ = "1.2.0" __description__ = "csvInjector" __author_name__ = "Christian Klopp" __author_mail__ = "christian.klopp@fokus.fraunhofer.de" diff --git a/apps/mqttConnector/src/mqttconnector/__init__.py b/apps/mqttConnector/src/mqttconnector/__init__.py index 0916b7b..527730c 100644 --- a/apps/mqttConnector/src/mqttconnector/__init__.py +++ b/apps/mqttConnector/src/mqttconnector/__init__.py @@ -2,7 +2,7 @@ TODO: Add description here """ -__version__ = "1.1.0" +__version__ = "1.2.0" __description__ = "mqttConnector" __author_name__ = "Ronald Steinke" __author_mail__ = "ronald.steinke@fokus.fraunhofer.de" diff --git a/ipes/CUL868IPE/src/cul868ipe/__init__.py b/ipes/CUL868IPE/src/cul868ipe/__init__.py index 571fd54..33beef1 100644 --- a/ipes/CUL868IPE/src/cul868ipe/__init__.py +++ b/ipes/CUL868IPE/src/cul868ipe/__init__.py @@ -2,7 +2,7 @@ Interworking Proxy for Cul868 devices. """ -__version__ = "1.1.0" +__version__ = "1.2.0" __description__ = "The OpenMTC Cul868IPE" __author_name__ = "Ronny Kreuch" __author_mail__ = "ronny.kreuch@fokus.fraunhofer.de" diff --git a/setup-gevent-all.py b/setup-gevent-all.py index 344778e..2d367ce 100755 --- a/setup-gevent-all.py +++ b/setup-gevent-all.py @@ -13,7 +13,7 @@ from utils import (get_packages, OpenMTCSdist, OpenMTCBuildPy, # name and version SETUP_NAME = "openmtc-all" -SETUP_VERSION = "1.1.0" +SETUP_VERSION = "1.2.0" SETUP_DESCRIPTION = "The OpenMTC Backend and Gateway (GEvent version)" # meta diff --git a/setup-sdk.py b/setup-sdk.py index ea69f8c..8d2df28 100755 --- a/setup-sdk.py +++ b/setup-sdk.py @@ -7,7 +7,7 @@ from utils import get_packages, OpenMTCSdist # name and version NAME = "sdk" SETUP_NAME = "openmtc-" + NAME -SETUP_VERSION = "1.1.0" +SETUP_VERSION = "1.2.0" SETUP_DESCRIPTION = "The OpenMTC Python SDK" # meta