diff --git a/.github/workflows/pr-checker.yml b/.github/workflows/pr-checker.yml new file mode 100644 index 0000000..3ed5198 --- /dev/null +++ b/.github/workflows/pr-checker.yml @@ -0,0 +1,126 @@ +name: PR-check +run-name: ${{ github.actor }} PR checker +on: [push] +jobs: + run_tox_on_ubuntu22: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - uses: actions/setup-python@v4 + with: + python-version: '3.7' + - run: python -m pip install wheel --user + - run: python -m pip install pipx-in-pipx --user + - run: pipx install tox + # No py36 available in ubuntu 22.04, skip it + - run: tox + run_tox_on_ubuntu20: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - uses: actions/setup-python@v4 + with: + python-version: '3.7' + - run: python -m pip install wheel --user + - run: python -m pip install pipx-in-pipx --user + - run: pipx install tox + - run: tox + + run_tox_on_windows2022: + runs-on: windows-2022 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - uses: actions/setup-python@v4 + with: + python-version: '3.7' + - run: python -m pip install wheel --user + - run: python -m pip install pipx-in-pipx --user + - run: pipx install tox + - run: tox + + run_tox_on_windows2019: + runs-on: windows-2019 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - uses: actions/setup-python@v4 + with: + python-version: '3.7' + - run: wmic os get osarchitecture + - run: python -m pip install wheel --user + - run: python -m pip install pipx-in-pipx --user + - run: pipx install tox + - run: tox + + run_tox_on_mac: + runs-on: macos-11 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + - uses: actions/setup-python@v4 + with: + python-version: '3.8' + - uses: actions/setup-python@v4 + with: + python-version: '3.7' + - run: python -m pip install wheel --user + - run: python -m pip install pipx-in-pipx --user + - run: pipx install tox + - run: tox + +# We are not ready for this yet... +# run-pysh-check: +# runs-on: ubuntu-22.04 +# steps: +# - uses: actions/checkout@v3 +# # Install pyshcheck tooling +# - run: sudo apt install pycodestyle pydocstyle black +# # git instead of rules to use access token +# - run: git config --global url."https://${{ secrets.ACCESS_TOKEN }}@github.com/".insteadOf "git@github.com:" +# - run: git config --global url."https://${{ secrets.ACCESS_TOKEN }}@github".insteadOf "https://github" +# - run: git config --list +# # Linux coreutils is already installed wc -command can be found. +# - run: git clone git@github.com:PelionIoT/scripts-internal.git +# #- run: git clone https://github.com/PelionIoT/scripts-internal.git +# - run: echo "." >scripts-internal/.nopyshcheck +# - run: .github/workflows/pysh-checker.sh ${{ github.event.repository.default_branch }} ${{ github.ref_name }} \ No newline at end of file diff --git a/.pylintrc b/.pylintrc index 09fe8b4..3add543 100644 --- a/.pylintrc +++ b/.pylintrc @@ -60,16 +60,7 @@ confidence= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use "--disable=all --enable=classes # --disable=W". -disable=print-statement, - parameter-unpacking, - unpacking-in-except, - old-raise-syntax, - backtick, - long-suffix, - old-ne-operator, - old-octal-literal, - import-star-module-level, - non-ascii-bytes-literal, +disable= raw-checker-failed, bad-inline-option, locally-disabled, @@ -78,67 +69,6 @@ disable=print-statement, useless-suppression, deprecated-pragma, use-symbolic-message-instead, - apply-builtin, - basestring-builtin, - buffer-builtin, - cmp-builtin, - coerce-builtin, - execfile-builtin, - file-builtin, - long-builtin, - raw_input-builtin, - reduce-builtin, - standarderror-builtin, - unicode-builtin, - xrange-builtin, - coerce-method, - delslice-method, - getslice-method, - setslice-method, - no-absolute-import, - old-division, - dict-iter-method, - dict-view-method, - next-method-called, - metaclass-assignment, - indexing-exception, - raising-string, - reload-builtin, - oct-method, - hex-method, - nonzero-method, - cmp-method, - input-builtin, - round-builtin, - intern-builtin, - unichr-builtin, - map-builtin-not-iterating, - zip-builtin-not-iterating, - range-builtin-not-iterating, - filter-builtin-not-iterating, - using-cmp-argument, - eq-without-hash, - div-method, - idiv-method, - rdiv-method, - exception-message-attribute, - invalid-str-codec, - sys-max-int, - bad-python3-import, - deprecated-string-function, - deprecated-str-translate-call, - deprecated-itertools-function, - deprecated-types-field, - next-method-defined, - dict-items-not-iterating, - dict-keys-not-iterating, - dict-values-not-iterating, - deprecated-operator-function, - deprecated-urllib-function, - xreadlines-attribute, - deprecated-sys-function, - exception-escape, - comprehension-escape, too-many-arguments, too-many-locals, missing-docstring, @@ -333,13 +263,6 @@ max-line-length=100 # Maximum number of lines in a module. max-module-lines=1000 -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -no-space-check=trailing-comma, - dict-separator - # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no diff --git a/PELION_LICENSE b/IZUMA_NETWORKS_LICENSE similarity index 95% rename from PELION_LICENSE rename to IZUMA_NETWORKS_LICENSE index c2da580..9253da5 100644 --- a/PELION_LICENSE +++ b/IZUMA_NETWORKS_LICENSE @@ -1,5 +1,6 @@ # ---------------------------------------------------------------------------- # Copyright 2021 Pelion +# Copyright 2022-2023 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # diff --git a/README.md b/README.md index 4fc08fd..c0c112d 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,8 @@ We recommend installing the `manifest-tool` Python package in a isolated **Prerequisites:** -* [Python 3.6 or higher](https://www.python.org/downloads/). +* [Python 3.7 or higher](https://www.python.org/downloads/). + * Python 3.11 support is not in place yet. * [pip (Python Package Installer)](https://pip.pypa.io/en/stable/). * Internet connectivity @@ -57,11 +58,18 @@ We recommend installing the `manifest-tool` Python package in a isolated pip install manifest-tool ``` +**NOTE!** If your system has only Python 3.6 or older - you must an older version of this tool. + +``` +pip install manifest-tool==2.4.1 +``` + + ### Installing from local source tree **Prerequisites:** -* [Python 3.6 or later](https://www.python.org/downloads/). +* [Python 3.7 or later](https://www.python.org/downloads/). * [pip (Python Package Installer)](https://pip.pypa.io/en/stable/). * Native toolchain: * GCC/Clang for Linux/MacOS. @@ -132,7 +140,7 @@ describing the update type. Configuration file format: ```yaml vendor: # One of "domain" or "vendor-id" fields are expected. - domain: pelion.com # FW owner domain. Used to generate a vendor UUID. + domain: izumanetworks.com # FW owner domain. Used to generate a vendor UUID. # Expected to include a dot ("."). # OR vendor-id: fa6b4a53d5ad5fdfbe9de663e4d41ffe # Valid vendor UUID. @@ -194,7 +202,7 @@ describing the update type. ```yaml vendor: - domain: pelion.com + domain: izumanetworks.com device: model-name: Smart Flip-flops priority: 1 @@ -496,7 +504,7 @@ configuration file. ```shell manifest-dev-tool create \ - --payload-url http://test.pdmc.pelion.com?fileId=1256 \ + --payload-url http://test.pdmc.izumanetworks.com?fileId=1256 \ --payload-path new_fw.bin \ --fw-version 1.2.3 \ --component-name MAIN \ @@ -516,7 +524,7 @@ configuration file. ```shell manifest-dev-tool create-v1 \ - --payload-url http://test.pdmc.pelion.com?fileId=1256 \ + --payload-url http://test.pdmc.izumanetworks.com?fileId=1256 \ --payload-path new-fw.bin \ --output update-manifest.bin ``` diff --git a/build_manylinux_wheels_entry_point.sh b/build_manylinux_wheels_entry_point.sh index 0e931bb..120b873 100755 --- a/build_manylinux_wheels_entry_point.sh +++ b/build_manylinux_wheels_entry_point.sh @@ -1,6 +1,6 @@ #!/bin/bash # ---------------------------------------------------------------------------- -# Copyright 2020-2021 Pelion +# Copyright 2020-2022 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # diff --git a/changelog.md b/changelog.md index e61295d..32fc27f 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,18 @@ # Changelog +## 2.5.0 +- Izuma branding, contact email/author updated, Cloud documentation links updated. +- Timeouts for `requests.put/post/delete` operations. +- Pinned down critical Python module versions in `dev-requirements.txt`. +- Module name fixes for some tests. +- Removed obsolete options from `.pylintrc`. +- Support for / testing on Python 3.6 dropped. +- Support for / testing on Python 3.10 added. + +## 2.4.1 + +- Aarch64 support. + ## 2.4.0 - Add `manifest-package-tool`: - New tool to generate combined package files for combined updates. diff --git a/dev-README.md b/dev-README.md index d138d27..29b1548 100644 --- a/dev-README.md +++ b/dev-README.md @@ -7,10 +7,11 @@ Example: ```shell +$ pyenv install 3.10.0 +$ pyenv install 3.9.0 $ pyenv install 3.8.0 $ pyenv install 3.7.5 -$ pyenv install 3.6.9 -$ pyenv local 3.8.0 3.7.5 3.6.9 +$ pyenv local 3.9.0 3.8.0 3.7.5 $ python --version Python 3.8.0 ``` @@ -61,7 +62,7 @@ Execute `tox -e py38` to test only the python3.8 environment. ```shell $ pyenv local 3.7.5 $ python setup.py bdist_wheel -$ pyenv local 3.6.9 +$ pyenv local 3.8.9 $ python setup.py bdist_wheel ``` do the same on each platform (Windows, Linux, macOS) per Python @@ -112,7 +113,7 @@ the release creation time. 1. Run `tox` on Windows, Linux and Mac. 1. Create release on GitHub. 1. Run `build_manylinux_wheels.sh` on Linux. The dist folder should contain 4 wheels for every Linux distribution (16 wheels overall). -1. Gather wheels and tar.gz from all `dist` folder into one dist folder: +1. Gather all the wheels and 1 tar.gz from all `dist` folders from 3 OSes (Windows, Linux, Mac) into one dist folder: ``` scp $USER@/manifest-tool/dist/*.whl dist/ ``` diff --git a/dev-requirements.txt b/dev-requirements.txt index 4748b7c..c199e28 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,8 +1,8 @@ -pytest +pytest==6.2.5 pytest-mock pytest-cov tox -pylint +pylint==2.13.9 pycodestyle coverage wheel diff --git a/dev_init.bat b/dev_init.bat index 51a6ff9..9939191 100644 --- a/dev_init.bat +++ b/dev_init.bat @@ -1,5 +1,5 @@ @REM ---------------------------------------------------------------------------- -@REM Copyright 2021 Pelion +@REM Copyright 2021-2022 Izuma Networks @REM @REM SPDX-License-Identifier: Apache-2.0 @REM diff --git a/dev_init.sh b/dev_init.sh index 90a814f..bdf70ef 100755 --- a/dev_init.sh +++ b/dev_init.sh @@ -1,6 +1,6 @@ #!/bin/bash -ex # ---------------------------------------------------------------------------- -# Copyright 2019-2021 Pelion +# Copyright 2019-2022 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # diff --git a/manifesttool/__init__.py b/manifesttool/__init__.py index 0b613f8..e0064c2 100644 --- a/manifesttool/__init__.py +++ b/manifesttool/__init__.py @@ -1,5 +1,6 @@ # ---------------------------------------------------------------------------- # Copyright 2019-2021 Pelion +# Copyright (c) 2022 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # @@ -16,4 +17,4 @@ # limitations under the License. # ---------------------------------------------------------------------------- -__version__ = "2.4.1" +__version__ = "2.5.0" diff --git a/manifesttool/dev_tool/actions/init.py b/manifesttool/dev_tool/actions/init.py index c06b62f..c345da7 100644 --- a/manifesttool/dev_tool/actions/init.py +++ b/manifesttool/dev_tool/actions/init.py @@ -1,5 +1,6 @@ # ---------------------------------------------------------------------------- # Copyright 2019-2021 Pelion +# Copyright 2022-2023 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # @@ -96,21 +97,21 @@ def register_parser(parser: argparse.ArgumentParser): ) service = parser.add_argument_group( - 'optional arguments (Pelion Device Management service configuration)') + 'optional arguments (Izuma Device Management service configuration)') service.add_argument( '-p', '--gw-preset', help='The preset name defined in {}, ' ' which specifies a URL and ' - 'access key.'.format(defaults.PELION_GW_PATH), - choices=defaults.PELION_GW.keys() if defaults.PELION_GW else [] + 'access key.'.format(defaults.IZUMA_GW_PATH), + choices=defaults.IZUMA_GW.keys() if defaults.IZUMA_GW else [] ) service.add_argument( '-a', '--access-key', '--api-key', - help='Access key for accessing a Pelion Device Management API.' + help='Access key for accessing a Izuma Device Management API.' ) service.add_argument( '-u', '--api-url', - help='Pelion Device Management API URL. ' + help='Izuma Device Management API URL. ' '[Default: {}]'.format(defaults.API_GW), default=defaults.API_GW ) @@ -440,14 +441,14 @@ def entry_point( access_key = args.access_key if not access_key and hasattr(args, 'gw_preset') and args.gw_preset: access_key = \ - defaults.PELION_GW[args.gw_preset].get('access_key') + defaults.IZUMA_GW[args.gw_preset].get('access_key') if not access_key: access_key = \ - defaults.PELION_GW[args.gw_preset].get('api_key') + defaults.IZUMA_GW[args.gw_preset].get('api_key') api_url = args.api_url if hasattr(args, 'gw_preset') and args.gw_preset: - api_url = defaults.PELION_GW[args.gw_preset].get('host') + api_url = defaults.IZUMA_GW[args.gw_preset].get('host') generate_service_config( access_key=access_key, diff --git a/manifesttool/dev_tool/actions/update.py b/manifesttool/dev_tool/actions/update.py index c52fa47..47cc6b7 100644 --- a/manifesttool/dev_tool/actions/update.py +++ b/manifesttool/dev_tool/actions/update.py @@ -1,5 +1,6 @@ # ---------------------------------------------------------------------------- # Copyright 2019-2021 Pelion +# Copyright 2022-2023 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # @@ -29,7 +30,7 @@ from manifesttool.dev_tool.actions.create \ import register_parser as register_create_parser from manifesttool.dev_tool.actions.create import create_dev_manifest -from manifesttool.dev_tool.pelion import pelion +from manifesttool.dev_tool.izuma import izuma from manifesttool.common.common_helpers import get_non_negative_int_argument from manifesttool.mtool.asn1 import ManifestAsnCodecBase @@ -79,8 +80,8 @@ def register_parser(parser: argparse.ArgumentParser, schema_version: str): 'Only relevant if --wait-for-completion was provided.' ) -def _manage_campaign(api: pelion.PelionServiceApi, - campaign_id: pelion.ID, +def _manage_campaign(api: izuma.IzumaServiceApi, + campaign_id: izuma.ID, end_time: int, do_wait: bool): starting = True @@ -151,11 +152,11 @@ def _print_summary(summary: dict, summary_reasons: dict): logger.warning(" %s", reasons.get('description')) -def _finalize(api: pelion.PelionServiceApi, +def _finalize(api: izuma.IzumaServiceApi, do_cleanup: bool, - campaign_id: pelion.ID, - manifest_id: pelion.ID, - fw_image_id: pelion.ID, + campaign_id: izuma.ID, + manifest_id: izuma.ID, + fw_image_id: izuma.ID, manifest_path: Path): summary = {} summary_reasons = {} @@ -219,7 +220,7 @@ def update( encrypt_payload: bool, combined_package: bool ): - api = pelion.PelionServiceApi(service_config) + api = izuma.IzumaServiceApi(service_config) manifest_path = None fw_image_id = None manifest_id = None diff --git a/manifesttool/dev_tool/defaults.py b/manifesttool/dev_tool/defaults.py index 7e81b57..74fb18d 100644 --- a/manifesttool/dev_tool/defaults.py +++ b/manifesttool/dev_tool/defaults.py @@ -1,5 +1,6 @@ # ---------------------------------------------------------------------------- # Copyright 2019-2021 Pelion +# Copyright 2022-2023 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # @@ -28,8 +29,8 @@ API_GW = 'https://api.us-east-1.mbedcloud.com' UPDATE_VERSION = 'update.version.yaml' -PELION_GW_PATH = Path.home() / '.pelion-dev-presets.yaml' -PELION_GW = None -if PELION_GW_PATH.is_file(): - with PELION_GW_PATH.open('rb') as fh: - PELION_GW = yaml.safe_load(fh) +IZUMA_GW_PATH = Path.home() / '.izuma-dev-presets.yaml' +IZUMA_GW = None +if IZUMA_GW_PATH.is_file(): + with IZUMA_GW_PATH.open('rb') as fh: + IZUMA_GW = yaml.safe_load(fh) diff --git a/manifesttool/dev_tool/pelion/__init__.py b/manifesttool/dev_tool/izuma/__init__.py similarity index 100% rename from manifesttool/dev_tool/pelion/__init__.py rename to manifesttool/dev_tool/izuma/__init__.py diff --git a/manifesttool/dev_tool/pelion/pelion.py b/manifesttool/dev_tool/izuma/izuma.py similarity index 89% rename from manifesttool/dev_tool/pelion/pelion.py rename to manifesttool/dev_tool/izuma/izuma.py index f445719..43145df 100644 --- a/manifesttool/dev_tool/pelion/pelion.py +++ b/manifesttool/dev_tool/izuma/izuma.py @@ -1,5 +1,6 @@ # ---------------------------------------------------------------------------- -# Copyright 2019-2021 Pelion +# Copyright 2019-2021 +# Copyright 2022-2023 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # @@ -27,11 +28,11 @@ import yaml # APIs documentation: -# https://developer.pelion.com/docs/device-management/current/service-api-references/service-api-documentation.html +# https://developer.izumanetworks.com/docs/device-management/current/service-api-references/service-api-documentation.html # Device directory - -# https://developer.pelion.com/docs/device-management-api/device-directory +# https://developer.izumanetworks.com/docs/device-management-api/device-directory # Update Service - -# https://developer.pelion.com/docs/device-management-api/update-service +# https://developer.izumanetworks.com/docs/device-management-api/update-service DEVICES = 'v3/devices' DEVICE = 'v3/devices/{id}' @@ -70,17 +71,21 @@ # must be greater than 5MB - AWS limitation FW_UPLOAD_CHUNK_SIZE = int(6 * 1024 * 1024) -LOG = logging.getLogger('pelion') +LOG = logging.getLogger('izuma') URL = NewType('URL', str) ID = NewType('ID', str) Phase = NewType('Phase', str) -class PelionServiceApi: +GET_TIMEOUT = 15 * 60 +POST_TIMEOUT = 15 * 60 +DEL_TIMEOUT = 5 * 60 + +class IzumaServiceApi: def __init__(self, config_file: Path): """ Create REST API provider for Update Service APIs - :param host: Pelion service URL + :param host: Izuma service URL :param access_key: account access key """ @@ -102,14 +107,14 @@ def __init__(self, config_file: Path): } return - raise AssertionError('Pelion service configurations ' + raise AssertionError('Izuma service configurations ' '(URL and access key) are not provided') def _url(self, api, **kwargs) -> str: """ Helper function for constructing full REST API URL - Concatenates Pelion host URL with the desired REST API url and expands + Concatenates Izuma host URL with the desired REST API url and expands any patterns present in the URL (e.g. v3/manifests/{id}) :param api: REST API URL part :param kwargs: dictionary for expanding the the URL patterns @@ -163,8 +168,8 @@ def fw_upload(self, fw_name: str, image: Path, encrypt: bool) \ -> dict: """ Upload FW image - :param fw_name: update candidate image name as will appear on Pelion - portal + :param fw_name: update candidate image name as will appear on + Izuma portal :param image: candidate FW image :param encrypt: request to encrypt FW image :return: uploaded image meta @@ -197,7 +202,8 @@ def _upload_image_chunk(self, chunk: bytes, job_id: ID): 'Content-MD5': self._chunk_md5(chunk) } ), - data=chunk + data=chunk, + timeout=POST_TIMEOUT ) response.raise_for_status() @@ -260,7 +266,8 @@ def _upload_small_image( data={ 'name': fw_name, 'datafile_encryption': encrypt - } + }, + timeout=POST_TIMEOUT ) response.raise_for_status() return response.json() @@ -273,12 +280,14 @@ def _get_fw_image_meta(self, job_id: ID) -> dict: """ response = requests.get( self._url(FW_UPLOAD_JOB, id=job_id), - headers=self._headers()) + headers=self._headers(), + timeout=GET_TIMEOUT) response.raise_for_status() image_id = response.json()['firmware_image_id'] response = requests.get( self._url(FW_IMAGE, id=image_id), - headers=self._headers()) + headers=self._headers(), + timeout=GET_TIMEOUT) response.raise_for_status() return response.json() @@ -290,7 +299,8 @@ def _delete_upload_job(self, job_id: ID): """ response = requests.delete( self._url(FW_UPLOAD_JOB, id=job_id), - headers=self._headers() + headers=self._headers(), + timeout=DEL_TIMEOUT ) response.raise_for_status() LOG.debug('FW upload job %s deleted', job_id) @@ -308,7 +318,8 @@ def _create_upload_job(self, fw_name: str, encrypt: bool) -> ID: json={ 'name': fw_name, 'datafile_encryption': encrypt - } + }, + timeout=POST_TIMEOUT ) response.raise_for_status() response_data = response.json() @@ -318,20 +329,21 @@ def _create_upload_job(self, fw_name: str, encrypt: bool) -> ID: def fw_delete(self, image_id: ID): """ - Delete candidate image from Pelion portal + Delete candidate image from Izuma portal :param image_id: image ID as appears on the portal """ response = requests.delete( self._url(FW_IMAGE, id=image_id), - headers=self._headers() + headers=self._headers(), + timeout=DEL_TIMEOUT ) response.raise_for_status() LOG.info('Deleted FW image %s', image_id) def manifest_upload(self, name: str, manifest: Path) -> ID: """ - Upload manifest file to Pelion service - :param name: manifest name as will appear on Pelion portal + Upload manifest file to Izuma service + :param name: manifest name as will appear on Izuma portal :param manifest: manifest file :return: manifest ID as reported by portal """ @@ -345,7 +357,8 @@ def manifest_upload(self, name: str, manifest: Path) -> ID: }, data={ 'name': name - } + }, + timeout=POST_TIMEOUT ) response.raise_for_status() manifest_id = response.json()['id'] @@ -357,12 +370,13 @@ def manifest_upload(self, name: str, manifest: Path) -> ID: def manifest_delete(self, manifest_id: ID): """ - Delete manifest file from Pelion portal + Delete manifest file from Izuma portal :param manifest_id: manifest ID to be deleted """ response = requests.delete( self._url(FW_MANIFEST, id=manifest_id), - headers=self._headers() + headers=self._headers(), + timeout=DEL_TIMEOUT ) response.raise_for_status() LOG.info('Deleted manifest ID: %s', manifest_id) @@ -374,9 +388,9 @@ def campaign_create( device_filter: str ) -> ID: """ - Create update campaign on Pelion portal + Create update campaign on Izuma portal - :param name: campaign name as will appear on Pelion portal + :param name: campaign name as will appear on Izuma portal :param manifest_id: manifest ID as :param device_filter: device filter query :return: campaign ID as reported by portal @@ -391,7 +405,8 @@ def campaign_create( 'device_filter': device_filter, 'name': name, 'root_manifest_id': manifest_id - } + }, + timeout=POST_TIMEOUT ) response.raise_for_status() campaign_id = response.json()['id'] @@ -408,7 +423,8 @@ def campaign_delete(self, campaign_id: ID): """ response = requests.delete( self._url(FW_CAMPAIGN, id=campaign_id), - headers=self._headers() + headers=self._headers(), + timeout=DEL_TIMEOUT ) response.raise_for_status() LOG.info('Deleted campaign %s', campaign_id) @@ -427,7 +443,8 @@ def campaign_stop(self, campaign_id: ID, timeout: int = 60): # send request to stop response = requests.post( self._url(FW_CAMPAIGN_STOP, id=campaign_id), - headers=self._headers() + headers=self._headers(), + timeout=POST_TIMEOUT ) response.raise_for_status() curr_phase = self.campaign_get(campaign_id)['phase'] @@ -451,7 +468,8 @@ def campaign_start(self, campaign_id: ID): """ response = requests.post( self._url(FW_CAMPAIGN_START, id=campaign_id), - headers=self._headers() + headers=self._headers(), + timeout=POST_TIMEOUT ) response.raise_for_status() @@ -463,7 +481,8 @@ def campaign_get(self, campaign_id: ID) -> dict: """ response = requests.get( self._url(FW_CAMPAIGN, id=campaign_id), - headers=self._headers() + headers=self._headers(), + timeout=GET_TIMEOUT ) response.raise_for_status() return response.json() @@ -478,7 +497,8 @@ def campaign_statistics(self, campaign_id: ID) -> List[dict]: try: response = requests.get( self._url(FW_CAMPAIGN_STATISTICS, id=campaign_id), - headers=self._headers() + headers=self._headers(), + timeout=GET_TIMEOUT ) response.raise_for_status() return response.json()['data'] @@ -501,7 +521,8 @@ def campaign_statistic_events(self, response = requests.get( self._url(FW_CAMPAIGN_STATISTICS_EVENTS, id=campaign_id, summary_id=summary_id), - headers=self._headers() + headers=self._headers(), + timeout=GET_TIMEOUT ) response.raise_for_status() return response.json()['data'] @@ -522,7 +543,8 @@ def campaign_device_metadata(self, campaign_id: ID) -> List[dict]: """ response = requests.get( self._url(FW_CAMPAIGN_DEV_METADATA, id=campaign_id), - headers=self._headers() + headers=self._headers(), + timeout=GET_TIMEOUT ) response.raise_for_status() return response.json()['data'] @@ -553,7 +575,8 @@ def device_delete(self, device_id: ID): """ response = requests.delete( self._url(DEVICE, id=device_id), - headers=self._headers() + headers=self._headers(), + timeout=DEL_TIMEOUT ) response.raise_for_status() LOG.info('Deleted device %s', device_id) @@ -568,7 +591,8 @@ def _get_objects(self, api_url: str, api_filter: str = '') -> dict: url = '{}?limit=1000&include=total_count{}'.format(api_url, api_filter) response = requests.get( self._url(url), - headers=self._headers() + headers=self._headers(), + timeout=GET_TIMEOUT ) response.raise_for_status() total_count = response.json()['total_count'] @@ -580,7 +604,8 @@ def _get_objects(self, api_url: str, api_filter: str = '') -> dict: last_object_id = objects[-1]['id'] response = requests.get( self._url(url, after=last_object_id), - headers=self._headers() + headers=self._headers(), + timeout=GET_TIMEOUT ) response.raise_for_status() objects.extend(response.json()['data']) diff --git a/manifesttool/mtool/asn1/generate-python-schema.sh b/manifesttool/mtool/asn1/generate-python-schema.sh index 34b577c..09986ec 100755 --- a/manifesttool/mtool/asn1/generate-python-schema.sh +++ b/manifesttool/mtool/asn1/generate-python-schema.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash -e # ---------------------------------------------------------------------------- # Copyright 2019-2021 Pelion +# Copyright (c) 2022-2023 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # @@ -21,7 +22,7 @@ generate() { local input=$1 local output=$2 echo "asn1ate $input > $output" - cat ../../../PELION_LICENSE > $output + cat ../../../IZUMA_NETWORKS_LICENSE > $output asn1ate $input >> $output } diff --git a/manifesttool/package_tool/asn1/generate-package-python-schema.sh b/manifesttool/package_tool/asn1/generate-package-python-schema.sh index 6692b2a..1d1b5ef 100644 --- a/manifesttool/package_tool/asn1/generate-package-python-schema.sh +++ b/manifesttool/package_tool/asn1/generate-package-python-schema.sh @@ -21,7 +21,7 @@ generate() { local input=$1 local output=$2 echo "asn1ate $input > $output" - cat ../../../PELION_LICENSE > $output + cat ../../../IZUMA_NETWORKS_LICENSE > $output asn1ate $input >> $output } diff --git a/requirements.txt b/requirements.txt index 9a10e58..9d17a77 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ -PyYAML>=4.2b1,<=5.4.1 +PyYAML>=6.0,<7.0.0a asn1ate>=0.5,<=0.6.0 cryptography>=2.5,<=3.4.8 jsonschema>=2.6.0,<=3.2.0 pyasn1>=0.3.1,<=0.4.8 -requests>=2.20.0,<=2.26.0 \ No newline at end of file +requests>=2.20.0,<=2.28.1 \ No newline at end of file diff --git a/setup.py b/setup.py index 813daff..1c326ad 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,6 @@ # ---------------------------------------------------------------------------- # Copyright 2019-2021 Pelion +# Copyright (c) 2022 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # @@ -44,8 +45,8 @@ long_description=open("README.md").read(), long_description_content_type="text/markdown", url='https://github.com/PelionIoT/manifest-tool', - author='Pelion', - author_email='pdm-support@pelion.com', + author='Izuma Networks', + author_email="opensource@izumanetworks.com", license='Apache 2.0', packages=find_packages(exclude=['tests']), zip_safe=False, diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..cab0a46 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,17 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2022 Izuma Networks +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- diff --git a/tests/conftest.py b/tests/conftest.py index f92c93e..140154b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,5 @@ # ---------------------------------------------------------------------------- -# Copyright 2019-2021 Pelion +# Copyright 2019-2022 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # diff --git a/tests/dev_tool/test_dev_create.py b/tests/dev_tool/test_dev_create.py index 2049c63..f8fe88d 100644 --- a/tests/dev_tool/test_dev_create.py +++ b/tests/dev_tool/test_dev_create.py @@ -23,7 +23,7 @@ from manifesttool.dev_tool import dev_tool from manifesttool.dev_tool.actions.init import generate_developer_config from manifesttool.package_tool.actions.create import CreateAction as PackageCreateAction -from tests import conftest +from tests.conftest import working_directory @pytest.mark.parametrize( @@ -62,7 +62,7 @@ def test_cli_developer(happy_day_data, action): '--priority', '100500', '--output', output_manifest.as_posix(), '--cache-dir', happy_day_data['tmp_path'].as_posix(), - '--payload-url', 'https://pelion.com/foo.bin?id=67567565576857', + '--payload-url', 'https://izumanetworks.com/foo.bin?id=67567565576857', '--payload-path', payload_path, '--vendor-data', dev_cfg.as_posix(), ] @@ -74,7 +74,7 @@ def test_cli_developer(happy_day_data, action): else: cmd.extend(['--fw-version', '100.500.666']) - with conftest.working_directory(happy_day_data['tmp_path']): + with working_directory(happy_day_data['tmp_path']): assert 0 == dev_tool.entry_point(cmd) def generate_package(happy_day_data): diff --git a/tests/dev_tool/test_dev_init.py b/tests/dev_tool/test_dev_init.py index ea8536d..29c9db2 100644 --- a/tests/dev_tool/test_dev_init.py +++ b/tests/dev_tool/test_dev_init.py @@ -20,7 +20,7 @@ from manifesttool.delta_tool.delta_tool import digest_file from manifesttool.dev_tool import dev_tool, defaults -from tests import conftest +from tests.conftest import working_directory def test_cli(tmp_path): @@ -39,7 +39,7 @@ def test_cli(tmp_path): 'init' ] - with conftest.working_directory(tmp_path): + with working_directory(tmp_path): assert 0 == dev_tool.entry_point(cmd) assert not api_cfg.is_file() @@ -55,8 +55,8 @@ def test_cli(tmp_path): '--api-url', dummy_api_url ] - with conftest.working_directory(tmp_path): - assert 0 == dev_tool.entry_point(cmd + ['--api-url', 'https://some.url.pelion.com']) + with working_directory(tmp_path): + assert 0 == dev_tool.entry_point(cmd + ['--api-url', 'https://some.url.izumanetworks.com']) assert c_source_digest != digest_file(c_source) assert cert_digest != digest_file(cert) @@ -64,7 +64,7 @@ def test_cli(tmp_path): assert dev_cfg_digest != digest_file(dev_cfg) assert api_cfg.is_file() - with conftest.working_directory(tmp_path): + with working_directory(tmp_path): assert 0 == dev_tool.entry_point(cmd + ['--force']) assert c_source_digest != digest_file(c_source) diff --git a/tests/dev_tool/test_dev_update.py b/tests/dev_tool/test_dev_update.py index aff1a9b..4ff5c1c 100644 --- a/tests/dev_tool/test_dev_update.py +++ b/tests/dev_tool/test_dev_update.py @@ -21,8 +21,8 @@ import pytest from manifesttool.dev_tool import dev_tool -from manifesttool.dev_tool.pelion import pelion -from tests import conftest +from manifesttool.dev_tool.izuma import izuma +from tests.conftest import working_directory # phase to state: @@ -58,13 +58,13 @@ def api_url(api, **kwargs): class CampaignFsm: CAMPAIGN_STATUSES = [ - (pelion.Phase('draft'), 'draft'), - (pelion.Phase('starting'), 'scheduled'), - (pelion.Phase('active'), 'publishing'), - (pelion.Phase('active'), 'publishing'), - (pelion.Phase('active'), 'publishing'), - (pelion.Phase('stopping'), 'stopping'), - (pelion.Phase('stopped'), 'auto_stopped') + (izuma.Phase('draft'), 'draft'), + (izuma.Phase('starting'), 'scheduled'), + (izuma.Phase('active'), 'publishing'), + (izuma.Phase('active'), 'publishing'), + (izuma.Phase('active'), 'publishing'), + (izuma.Phase('stopping'), 'stopping'), + (izuma.Phase('stopped'), 'auto_stopped') ] PHASE_DRAFT = 0 @@ -78,7 +78,7 @@ def __init__(self, campaign_id: int, last_phase_in_test: Optional[int] = None): else: self.last_idx = len(self.CAMPAIGN_STATUSES) - 1 - def next_phase(self) -> Tuple[pelion.Phase, str]: + def next_phase(self) -> Tuple[izuma.Phase, str]: if self.current_idx < self.last_idx: self.current_idx += 1 # return Phase, State @@ -147,26 +147,26 @@ def mock_update_apis( # FW upload job - create requests_mock.post( - api_url(pelion.FW_UPLOAD_JOBS), + api_url(izuma.FW_UPLOAD_JOBS), json={'id': job_id}, status_code=http_status_code ) # FW upload job - upload chunk requests_mock.post( - api_url(pelion.FW_UPLOAD_JOB_CHUNK, id=job_id), + api_url(izuma.FW_UPLOAD_JOB_CHUNK, id=job_id), status_code=http_status_code ) # FW upload job - delete requests_mock.delete( - api_url(pelion.FW_UPLOAD_JOB, id=job_id), + api_url(izuma.FW_UPLOAD_JOB, id=job_id), status_code=http_status_code ) # FW upload job - get metadata requests_mock.get( - api_url(pelion.FW_UPLOAD_JOB, id=job_id), + api_url(izuma.FW_UPLOAD_JOB, id=job_id), json={'firmware_image_id': firmware_image_id}, status_code=http_status_code ) @@ -184,21 +184,21 @@ def mock_update_apis( # FW image - get URL requests_mock.get( - api_url(pelion.FW_IMAGE, id=firmware_image_id), + api_url(izuma.FW_IMAGE, id=firmware_image_id), json=fw_meta_res, status_code=http_status_code ) # FW one shot upload requests_mock.post( - api_url(pelion.FW_UPLOAD), + api_url(izuma.FW_UPLOAD), json=fw_meta_res, status_code=http_status_code ) # FW image - delete requests_mock.delete( - api_url(pelion.FW_IMAGE, id=firmware_image_id), + api_url(izuma.FW_IMAGE, id=firmware_image_id), status_code=http_status_code ) @@ -208,14 +208,14 @@ def mock_update_apis( manifest_id = 987 # Manifest upload requests_mock.post( - api_url(pelion.FW_MANIFESTS), + api_url(izuma.FW_MANIFESTS), json={'id': manifest_id}, status_code=http_status_code ) # Manifest delete requests_mock.delete( - api_url(pelion.FW_MANIFEST, id=manifest_id), + api_url(izuma.FW_MANIFEST, id=manifest_id), status_code=http_status_code ) @@ -228,42 +228,42 @@ def mock_update_apis( # Campaign create requests_mock.post( - api_url(pelion.FW_CAMPAIGNS), + api_url(izuma.FW_CAMPAIGNS), json=campaign_create_callback, status_code=http_status_code ) # Campaign delete requests_mock.delete( - api_url(pelion.FW_CAMPAIGN, id=campaign_id), + api_url(izuma.FW_CAMPAIGN, id=campaign_id), json=campaign_delete_callback, status_code=http_status_code ) # Campaign stop requests_mock.post( - api_url(pelion.FW_CAMPAIGN_STOP, id=campaign_id), + api_url(izuma.FW_CAMPAIGN_STOP, id=campaign_id), json=campaign_stop_callback, status_code=http_status_code ) # Campaign start requests_mock.post( - api_url(pelion.FW_CAMPAIGN_START, id=campaign_id), + api_url(izuma.FW_CAMPAIGN_START, id=campaign_id), json=campaign_start_callback, status_code=http_status_code ) # Campaign get metadata requests_mock.get( - api_url(pelion.FW_CAMPAIGN, id=campaign_id), + api_url(izuma.FW_CAMPAIGN, id=campaign_id), json=campaign_get_callback, status_code=http_status_code ) # Campaign statistics requests_mock.get( - api_url(pelion.FW_CAMPAIGN_STATISTICS, id=campaign_id), + api_url(izuma.FW_CAMPAIGN_STATISTICS, id=campaign_id), json={ 'data': [ { @@ -305,7 +305,7 @@ def mock_update_apis( # Campaign statistics fail events requests_mock.get( - api_url(pelion.FW_CAMPAIGN_STATISTICS_EVENTS, id=campaign_id, summary_id='fail'), + api_url(izuma.FW_CAMPAIGN_STATISTICS_EVENTS, id=campaign_id, summary_id='fail'), json={ 'data': [ { @@ -325,7 +325,7 @@ def mock_update_apis( # Campaign statistics skipped events requests_mock.get( - api_url(pelion.FW_CAMPAIGN_STATISTICS_EVENTS, id=campaign_id, summary_id='skipped'), + api_url(izuma.FW_CAMPAIGN_STATISTICS_EVENTS, id=campaign_id, summary_id='skipped'), json={ 'data': [ { @@ -345,7 +345,7 @@ def mock_update_apis( # Campaign devices requests_mock.get( - api_url(pelion.FW_CAMPAIGN_DEV_METADATA, id=campaign_id), + api_url(izuma.FW_CAMPAIGN_DEV_METADATA, id=campaign_id), json={ 'data': [ { @@ -398,7 +398,7 @@ def _common(happy_day_data, action, payload_path): else: cmd.extend(['--fw-version', '100.500.666']) - with conftest.working_directory(happy_day_data['tmp_path']): + with working_directory(happy_day_data['tmp_path']): return dev_tool.entry_point(cmd) @@ -432,8 +432,8 @@ def test_cli_update_happy_day( ) if force_chunks: - monkeypatch.setattr(pelion, 'FW_UPLOAD_MAX_SMALL_SIZE', 10, raising=True) - monkeypatch.setattr(pelion, 'FW_UPLOAD_CHUNK_SIZE', 10, raising=True) + monkeypatch.setattr(izuma, 'FW_UPLOAD_MAX_SMALL_SIZE', 10, raising=True) + monkeypatch.setattr(izuma, 'FW_UPLOAD_CHUNK_SIZE', 10, raising=True) assert _common( happy_day_data, diff --git a/tests/mtool/test_create.py b/tests/mtool/test_create.py index a8548f1..9429ba3 100644 --- a/tests/mtool/test_create.py +++ b/tests/mtool/test_create.py @@ -68,7 +68,7 @@ def test_create_happy_day_full( input_cfg = { 'vendor': { - 'domain': 'pelion.com' + 'domain': 'izumanetworks.com' }, 'device': { 'model-name': 'my-device' @@ -223,7 +223,7 @@ def test_create_happy_day_delta( for manifest_version in ManifestVersion.list_codecs(): input_cfg = { 'vendor': { - 'domain': 'pelion.com' + 'domain': 'izumanetworks.com' }, 'device': { 'model-name': 'my-device' @@ -359,7 +359,7 @@ def cli_test_common(happy_day_data, manifest_version, update_type): yaml.dump( { 'vendor': { - 'domain': 'pelion.com' + 'domain': 'izumanetworks.com' }, 'device': { 'model-name': 'my-device' diff --git a/tests/mtool/test_parse.py b/tests/mtool/test_parse.py index 1dd482b..eee182e 100644 --- a/tests/mtool/test_parse.py +++ b/tests/mtool/test_parse.py @@ -56,7 +56,7 @@ def happy_day_data( input_cfg = { "manifest-version": manifest_version.get_name(), "vendor": { - "domain": "pelion.com", + "domain": "izumanetworks.com", "custom-data-path": fw_file.as_posix() }, diff --git a/tox.ini b/tox.ini index 58931b3..2089bae 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,6 @@ # ---------------------------------------------------------------------------- # Copyright 2019-2021 Pelion +# Copyright (c) 2022 Izuma Networks # # SPDX-License-Identifier: Apache-2.0 # @@ -25,20 +26,20 @@ skips = B101 [tox] envlist = - py{36,37,38,39} - py{36,37,38,39}-x86 + py{37,38,39,310} + py{37,38,39,310}-x64 sdist -[testenv:py{36,37,38,39}] +[testenv:py{37,38,39,310}] platform = linux|darwin|win32 -[testenv:py{36,37,38,39}-x86] -platform = win32 +[testenv:py{37,38,39,310}-x64] +platform = win64 basepython = - py36-x86: python3.6-32 - py37-x86: python3.7-32 - py38-x86: python3.8-32 - py39-x86: python3.9-32 + py37-x64: python3.7-64 + py38-x64: python3.8-64 + py39-x64: python3.9-64 + py310-x64: python3.10-64 [testenv] usedevelop=True @@ -60,7 +61,7 @@ skip_install=True deps = # FIXME - use '{envpython} setup.py --fullname' setenv = - SDIST_TAR_NAME = manifest-tool-2.4.1.tar.gz + SDIST_TAR_NAME = manifest-tool-2.5.0.tar.gz commands = {envpython} setup.py egg_info {envpython} setup.py sdist @@ -68,3 +69,4 @@ commands = manifest-tool --version manifest-dev-tool --version manifest-delta-tool --version + manifest-dev-tool init