Skip to content
MEC application.ipynb 102 KiB
Newer Older
    "                result[attr] = dict(map(\n",
    "                    lambda item: (item[0], item[1].to_dict())\n",
    "                    if hasattr(item[1], \"to_dict') else item,\n",
    "                    value.items()\n",
    "                ))\n",
    "            else:\n",
    "                result[attr] = value\n",
    "        if issubclass(V2xMsgSubscription, dict):\n",
    "            for key, value in self.items():\n",
    "                result[key] = value\n",
    "        return result\n",
    "    def to_str(self):\n",
    "        return pprint.pformat(self.to_dict())\n",
    "    def __repr__(self):\n",
    "        return self.to_str()\n",
    "    def __eq__(self, other):\n",
    "        if not isinstance(other, V2xMsgSubscription):\n",
    "            return False\n",
    "        return self.__dict__ == other.__dict__\n",
    "    def __ne__(self, other):\n",
    "        return not self == other\n",
    "\n",
    "class V2xMsgSubscriptionFilterCriteria(object):\n",
    "    swagger_types = {'msg_type': 'list[str]', 'std_organization': 'str'}\n",
    "    attribute_map = {'msg_type': 'MsgType', 'std_organization': 'stdOrganization'}\n",
    "    def __init__(self, msg_type, std_organization):  # noqa: E501\n",
    "        self._msg_type = None\n",
    "        self._std_organization = None\n",
    "        self.msg_type = msg_type\n",
    "        self.std_organization = std_organization\n",
    "    @property\n",
    "    def msg_type(self):\n",
    "        return self._msg_type\n",
    "    @msg_type.setter\n",
    "    def msg_type(self, msg_type):\n",
    "        self._msg_type = msg_type\n",
    "    @property\n",
    "    def std_organization(self):\n",
    "        return self._std_organization\n",
    "    @std_organization.setter\n",
    "    def std_organization(self, std_organization):\n",
    "        self._std_organization = std_organization\n",
    "    def to_dict(self):\n",
    "        result = {}\n",
    "        for attr, _ in six.iteritems(self.swagger_types):\n",
    "            value = getattr(self, attr)\n",
    "            if isinstance(value, list):\n",
    "                result[attr] = list(map(\n",
    "                    lambda x: x.to_dict() if hasattr(x, \"to_dict') else x,\n",
    "                    value\n",
    "                ))\n",
    "            elif hasattr(value, \"to_dict'):\n",
    "                result[attr] = value.to_dict()\n",
    "            elif isinstance(value, dict):\n",
    "                result[attr] = dict(map(\n",
    "                    lambda item: (item[0], item[1].to_dict())\n",
    "                    if hasattr(item[1], \"to_dict') else item,\n",
    "                    value.items()\n",
    "                ))\n",
    "            else:\n",
    "                result[attr] = value\n",
    "        if issubclass(V2xMsgSubscriptionFilterCriteria, dict):\n",
    "            for key, value in self.items():\n",
    "                result[key] = value\n",
    "        return result\n",
    "    def to_str(self):\n",
    "        return pprint.pformat(self.to_dict())\n",
    "    def __repr__(self):\n",
    "        return self.to_str()\n",
    "    def __eq__(self, other):\n",
    "        if not isinstance(other, V2xMsgSubscriptionFilterCriteria):\n",
    "            return False\n",
    "        return self.__dict__ == other.__dict__\n",
    "    def __ne__(self, other):\n",
    "        return not self == other"
   ]
  },
Yann Garcia's avatar
Yann Garcia committed
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is the V2X message subscription function. The body contains a 'JSON' serialized instance of the class V2xMsgSubscription."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def subscribe_v2x_message(sandbox_name: str, v2xMsgSubscription: V2xMsgSubscription) -> int:\n",
    "    global MEC_SANDBOX_URL, MEC_PLTF, CALLBACK_URI, logger\n",
    "\n",
    "    try:\n",
    "        url = MEC_SANDBOX_URL + '/' + sandbox_name + '/' + MEC_PLTF + '/vis/v2/subscriptions'\n",
    "        logger.debug('subscribe_v2x_message: url: ' + url)\n",
    "        header_params = {}\n",
    "        # HTTP header `Accept`\n",
    "        header_params['Accept'] = service_api.select_header_accept(['application/json'])  # noqa: E501\n",
    "        # HTTP header `Content-Type`\n",
    "        header_params['Content-Type'] = service_api.select_header_accept(['application/json'])  # noqa: E501\n",
    "        # Subscription body\n",
    "        body = json.dumps(v2xMsgSubscription.to_dict())\n",
    "        logger.debug('subscribe_v2x_message: body: ' + body)\n",
    "        (result, status, headers) = sandbox_api.call_api(url, 'POST', header_params=header_params, body=body, async_req=False)\n",
    "        logger.debug('subscribe_v2x_message: result: ' + result)\n",
    "        logger.debug('subscribe_v2x_message: status: ' + status)\n",
    "        logger.debug('subscribe_v2x_message: headers: ' + headers)\n",
    "        return (result, status, headers)\n",
    "    except ApiException as e:\n",
    "        logger.error('Exception when calling call_api: %s\\n' % e)\n",
    "    return -1\n",
    "    # End of function subscribe_v2x_message"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, here is how to implement the V2XMessage subscription:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def process_main():\n",
    "    \"\"\"\n",
    "    This is the second sprint of our skeleton of our MEC application:\n",
    "        - Mec application setup\n",
    "        - Subscribe to V2XMessage\n",
    "        - Mec application termination\n",
    "    \"\"\" \n",
    "    global MEC_SANDBOX_URL, MEC_PLTF, CALLBACK_URI, logger\n",
    "\n",
    "    logger.debug('Starting at ' + time.strftime('%Y%m%d-%H%M%S'))\n",
    "    logger.debug('\\t pwd= ' + os.getcwd())\n",
    "\n",
    "    # Login\n",
    "    (sandbox, app_inst_id, sub_id) = mec_app_setup()\n",
    "\n",
    "    filter_criteria = V2xMsgSubscriptionFilterCriteria(['1', '2'], 'ETSI')\n",
    "    v2xMsgSubscription = V2xMsgSubscription(callback_reference = CALLBACK_URI + '/vis/v2/v2x_msg_notification', filter_criteria = filter_criteria)\n",
    "    result = subscribe_v2x_message(sandbox, v2xMsgSubscription)\n",
    "    if result is None:\n",
    "        logger.error('Failed to get UU unicast provisioning information')\n",
    "    else:\n",
    "        logger.info('UU unicast provisioning information: \", result)\n",
    "\n",
    "    mec_app_termination(sandbox, app_inst_id, sub_id)\n",
    "\n",
    "    logger.debug('Stopped at ' + time.strftime('%Y%m%d-%H%M%S'))\n",
    "    # End of function process_main\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    process_main()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Notification support\n",
Yann Garcia's avatar
Yann Garcia committed
    "\n",
    "To recieve notifcation, our MEC application is required to support an HTTP listenener to recieve POST request from the MEC Sandbox and replto repry to them: this is the notification mechanism.\n",
    "\n",
    "The class HTTPRequestHandler (see cell below) provides the suport of such mechanism.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class HTTPRequestHandler(BaseHTTPRequestHandler):\n",
    "\n",
    "    def do_POST(self):\n",
    "        if re.search(CALLBACK_URI, self.path):\n",
    "            ctype, pdict = _parse_header(self.headers.get('content-type'))\n",
Yann Garcia's avatar
Yann Garcia committed
    "            if ctype == \"application/json\":\n",
    "                length = int(self.headers.get('content-length'))\n",
    "                rfile_str = self.rfile.read(length).decode('utf8')\n",
Yann Garcia's avatar
Yann Garcia committed
    "                data = parse.parse_qs(rfile_str, keep_blank_values=True)\n",
    "                record_id = self.path.split('/')[-1]\n",
Yann Garcia's avatar
Yann Garcia committed
    "                LocalData.records[record_id] = data\n",
    "                print('addrecord %s: %s' % (record_id, data))\n",
Yann Garcia's avatar
Yann Garcia committed
    "                self.send_response(HTTPStatus.OK)\n",
    "            else:\n",
    "                self.send_response(HTTPStatus.BAD_REQUEST, 'Only application/json is supported')\n",
    "        else:\n",
    "            self.send_response(HTTPStatus.BAD_REQUEST, 'Unsupported URI')\n",
    "        self.end_headers()\n",
    "\n",
    "    def do_GET(self):\n",
    "        self.send_response(HTTPStatus.BAD_REQUEST)\n",
    "        self.end_headers()\n",
    "    # End of class HTTPRequestHandler\n",
    "\n",
    "class LocalData(object):\n",
    "    records = {}\n",
    "    # End of class LocalData"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Put all together\n",
    "\n",
    "let's add a subscription the our previous MEC application.\n",
    "The sequence is the following:\n",
    "- Mec application setup\n",
    "- Get UU unicast provisioning information\n",
    "- Add subscription\n",
    "- Mec application termination"
   ]
  },
Yann Garcia's avatar
Yann Garcia committed
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def process_main():\n",
    "    \"\"\"\n",
    "    This is the second sprint of our skeleton of our MEC application:\n",
    "        - Mec application setup\n",
    "        - Get UU unicast provisioning information\n",
    "        - Add subscription\n",
    "        - Mec application termination\n",
    "    \"\"\" \n",
    "    global logger, nw_scenarios\n",
    "\n",
    "    logger.debug('Starting at ' + time.strftime('%Y%m%d-%H%M%S'))\n",
    "    logger.debug('\\t pwd= ' + os.getcwd())\n",
    "\n",
    "    # Login\n",
    "    (sandbox, app_inst_id, sub_id) = mec_app_setup()\n",
    "\n",
    "    ecgi = \"268708941961,268711972264\" # List of ecgi spearated by a ','\n",
    "    result = send_uu_unicast_provisioning_info(sandbox_name, ecgi)\n",
    "    if result is None:\n",
    "        logger.error('Failed to get UU unicast provisioning information')\n",
    "    else:\n",
    "        logger.info('UU unicast provisioning information: \", result)\n",
    "\n",
Yann Garcia's avatar
Yann Garcia committed
    "    # Start notification server in a daemonized thread\n",
    "    notification_server = threading.Thread(name='notification_server', target=start_server, args=(LISTENER_IP, LISTENER_PORT))\n",
    "    notification_server.setDaemon(True) # Set as a daemon so it will be killed once the main thread is dead.\n",
    "    notification_server.start()\n",
    "    # Continue\n",
    "    subscribe_v2x_message()\n",
    "\n",
    "    # Wait for notification\n",
    "    time.sleep(STABLE_TIME_OUT)\n",
    "\n",
    "    delete_subscribe_v2x_message()\n",
    "\n",
    "    mec_app_termination(sandbox, app_inst_id, sub_id)\n",
    "\n",
    "    logger.debug('Stopped at ' + time.strftime('%Y%m%d-%H%M%S'))\n",
    "    # End of function process_main\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    process_main()\n"
Yann Garcia's avatar
Yann Garcia committed
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Annexes\n",
    "\n",
    "## Annex A: How to use an existing MEC sandbox instance\n",
    "\n",
    "This case is used when the MEC Sandbox API is not used. The procedure is the following:\n",
    "- Log to the MEC Sandbox using a WEB browser\n",
    "- Select a network scenario\n",
    "- Create a new application instance\n",
    "\n",
    "When it is done, the newly created application instance is used by your application when required. This application instance is usually pass to your application in command line or using a confoiguation file\n"
Yann Garcia's avatar
Yann Garcia committed
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Bibliography\n",
Yann Garcia's avatar
Yann Garcia committed
    "\n",
    "1. ETSI GS MEC 002 (V2.2.1) (01-2022): \"Multi-access Edge Computing (MEC); Phase 2: Use Cases and Requirements\".\n",
    "2. ETSI GS MEC 010-1 (V1.1.1) (10-2017): \"Mobile Edge Computing (MEC); Mobile Edge Management; Part 1: System, host and platform management\".\n",
    "3. ETSI GS MEC 010-2 (V2.2.1) (02-2022): \"Multi-access Edge Computing (MEC); MEC Management; Part 2: Application lifecycle, rules and requirements management\".\n",
    "4. ETSI GS MEC 011 (V3.1.1) (09-2022): \"Multi-access Edge Computing (MEC); Edge Platform Application Enablement\".\n",
    "5. ETSI GS MEC 012 (V2.2.1) (02-2022): \"Multi-access Edge Computing (MEC); Radio Network Information API\".\n",
    "6. ETSI GS MEC 013 (V2.2.1) (01-2022): \"Multi-access Edge Computing (MEC); Location API\".\n",
    "7. ETSI GS MEC 014 (V2.1.1) (03-2021): \"Multi-access Edge Computing (MEC); UE Identity API\".\n",
    "8. ETSI GS MEC 015 (V2.1.1) (06-2020): \"Multi-Access Edge Computing (MEC); Traffic Management APIs\".\n",
    "9. ETSI GS MEC 016 (V2.2.1) (04-2020): \"Multi-access Edge Computing (MEC); Device application interface\".\n",
    "10. ETSI GS MEC 021 (V2.2.1) (02-2022): \"Multi-access Edge Computing (MEC); Application Mobility Service API\".\n",
    "11. ETSI GS MEC 028 (V2.3.1) (07-2022): \"Multi-access Edge Computing (MEC); WLAN Access Information API\".\n",
    "12. ETSI GS MEC 029 (V2.2.1) (01-2022): \"Multi-access Edge Computing (MEC); Fixed Access Information API\".\n",
    "13. ETSI GS MEC 030 (V3.2.1) (05-2022): \"Multi-access Edge Computing (MEC); V2X Information Service API\".\n",
Yann Garcia's avatar
Yann Garcia committed
    "14. ETSI GR MEC-DEC 025 (V2.1.1) (06-2019): \"Multi-access Edge Computing (MEC); MEC Testing Framework\".\n",
    "15. ETSI GR MEC 001 (V3.1.1) (01-2022): \"Multi-access Edge Computing (MEC); Terminology\".\n",
    "16. ETSI GR MEC 003 (V3.1.1): Multi-access Edge Computing (MEC); \n",
    "Framework and Reference Architecture\n",
    "17. [The Wiki MEC web site](https://www.etsi.org/technologies/multi-access-edge-computing)\n"
Yann Garcia's avatar
Yann Garcia committed
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}