From: garciaale Date: Fri, 15 Jan 2021 16:04:05 +0000 (-0300) Subject: Adds SOL004 package validator with package examples and tests X-Git-Tag: branch-sol006v331-start~3 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=refs%2Fchanges%2F81%2F10181%2F6;p=osm%2Fcommon.git Adds SOL004 package validator with package examples and tests Change-Id: I173700241415c3cc131c99d221a193e8b60e3ded Signed-off-by: garciaale --- diff --git a/osm_common/sol004_package.py b/osm_common/sol004_package.py new file mode 100644 index 0000000..7d402f5 --- /dev/null +++ b/osm_common/sol004_package.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 Whitestack, LLC +# ************************************************************* +# +# This file is part of OSM common repository. +# All Rights Reserved to Whitestack, LLC +# +# 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: agarcia@whitestack.com +## + +"""Python module for interacting with ETSI GS NFV-SOL004 compliant packages + +This module provides a SOL004Package class for validating and interacting with +ETSI SOL004 packages. A valid SOL004 package may have its files arranged according +to one of the following two structures: + +SOL004 with metadata directory SOL004 without metadata directory + +native_charm_vnf/ native_charm_vnf/ +├── TOSCA-Metadata ├── native_charm_vnfd.mf +│ └── TOSCA.meta ├── native_charm_vnfd.yaml +├── manifest.mf ├── ChangeLog.txt +├── Definitions ├── Licenses +│ └── native_charm_vnfd.yaml │ └── license.lic +├── Files ├── Files +│ ├── icons │ └── icons +│ │ └── osm.png │ └── osm.png +│ ├── Licenses └── Scripts +│ │ └── license.lic ├── cloud_init +│ └── changelog.txt │ └── cloud-config.txt +└── Scripts └── charms + ├── cloud_init └── simple + │ └── cloud-config.txt ├── config.yaml + └── charms ├── hooks + └── simple │ ├── install + ├── config.yaml ... + ├── hooks │ + │ ├── install └── src + ... └── charm.py + └── src + └── charm.py +""" + +import yaml +import os +import hashlib + + +_METADATA_FILE_PATH = 'TOSCA-Metadata/TOSCA.meta' +_METADATA_DESCRIPTOR_FIELD = 'Entry-Definitions' +_METADATA_MANIFEST_FIELD = 'ETSI-Entry-Manifest' +_METADATA_CHANGELOG_FIELD = 'ETSI-Entry-Change-Log' +_METADATA_LICENSES_FIELD = 'ETSI-Entry-Licenses' +_METADATA_DEFAULT_CHANGELOG_PATH = 'ChangeLog.txt' +_METADATA_DEFAULT_LICENSES_PATH = 'Licenses' +_MANIFEST_FILE_PATH_FIELD = 'Source' +_MANIFEST_FILE_HASH_ALGORITHM_FIELD = 'Algorithm' +_MANIFEST_FILE_HASH_DIGEST_FIELD = 'Hash' + + +class SOL004PackageException(Exception): + pass + + +class SOL004Package: + def __init__(self, package_path=''): + self._package_path = package_path + self._package_metadata = self._parse_package_metadata() + self._manifest_data = self._parse_manifest_data() + + def _parse_package_metadata(self): + try: + return self._parse_package_metadata_with_metadata_dir() + except FileNotFoundError: + return self._parse_package_metadata_without_metadata_dir() + + def _parse_package_metadata_with_metadata_dir(self): + try: + return self._parse_file_in_blocks(_METADATA_FILE_PATH) + except FileNotFoundError as e: + raise e + except (Exception, OSError) as e: + raise SOL004PackageException('Error parsing {}: {}'.format(_METADATA_FILE_PATH, e)) + + def _parse_package_metadata_without_metadata_dir(self): + package_root_files = {f for f in os.listdir(self._package_path)} + package_root_yamls = [f for f in package_root_files if f.endswith('.yml') or f.endswith('.yaml')] + if len(package_root_yamls) != 1: + error_msg = 'Error parsing package metadata: there should be exactly 1 descriptor YAML, found {}' + raise SOL004PackageException(error_msg.format(len(package_root_yamls))) + # TODO: Parse extra metadata from descriptor YAML? + return [{ + _METADATA_DESCRIPTOR_FIELD: package_root_yamls[0], + _METADATA_MANIFEST_FIELD: '{}.mf'.format(os.path.splitext(package_root_yamls[0])[0]), + _METADATA_CHANGELOG_FIELD: _METADATA_DEFAULT_CHANGELOG_PATH, + _METADATA_LICENSES_FIELD: _METADATA_DEFAULT_LICENSES_PATH + }] + + def _parse_manifest_data(self): + manifest_path = None + for tosca_meta in self._package_metadata: + if _METADATA_MANIFEST_FIELD in tosca_meta: + manifest_path = tosca_meta[_METADATA_MANIFEST_FIELD] + break + else: + error_msg = 'Error parsing {}: no {} field on path'.format(_METADATA_FILE_PATH, _METADATA_MANIFEST_FIELD) + raise SOL004PackageException(error_msg) + + try: + return self._parse_file_in_blocks(manifest_path) + except (Exception, OSError) as e: + raise SOL004PackageException('Error parsing {}: {}'.format(manifest_path, e)) + + def _get_package_file_full_path(self, file_relative_path): + return os.path.join(self._package_path, file_relative_path) + + def _parse_file_in_blocks(self, file_relative_path): + file_path = self._get_package_file_full_path(file_relative_path) + with open(file_path) as f: + blocks = f.read().split('\n\n') + parsed_blocks = map(yaml.safe_load, blocks) + return [block for block in parsed_blocks if block is not None] + + def _get_package_file_manifest_data(self, file_relative_path): + for file_data in self._manifest_data: + if file_data.get(_MANIFEST_FILE_PATH_FIELD, '') == file_relative_path: + return file_data + + error_msg = 'Error parsing {} manifest data: file not found on manifest file'.format(file_relative_path) + raise SOL004PackageException(error_msg) + + def get_package_file_hash_digest_from_manifest(self, file_relative_path): + """Returns the hash digest of a file inside this package as specified on the manifest file.""" + file_manifest_data = self._get_package_file_manifest_data(file_relative_path) + try: + return file_manifest_data[_MANIFEST_FILE_HASH_DIGEST_FIELD] + except Exception as e: + raise SOL004PackageException('Error parsing {} hash digest: {}'.format(file_relative_path, e)) + + def get_package_file_hash_algorithm_from_manifest(self, file_relative_path): + """Returns the hash algorithm of a file inside this package as specified on the manifest file.""" + file_manifest_data = self._get_package_file_manifest_data(file_relative_path) + try: + return file_manifest_data[_MANIFEST_FILE_HASH_ALGORITHM_FIELD] + except Exception as e: + raise SOL004PackageException('Error parsing {} hash digest: {}'.format(file_relative_path, e)) + + @staticmethod + def _get_hash_function_from_hash_algorithm(hash_algorithm): + function_to_algorithm = { + 'SHA-256': hashlib.sha256, + 'SHA-512': hashlib.sha512 + } + if hash_algorithm not in function_to_algorithm: + error_msg = 'Error checking hash function: hash algorithm {} not supported'.format(hash_algorithm) + raise SOL004PackageException(error_msg) + return function_to_algorithm[hash_algorithm] + + def _calculate_file_hash(self, file_relative_path, hash_algorithm): + file_path = self._get_package_file_full_path(file_relative_path) + hash_function = self._get_hash_function_from_hash_algorithm(hash_algorithm) + try: + with open(file_path, "rb") as f: + return hash_function(f.read()).hexdigest() + except Exception as e: + raise SOL004PackageException('Error hashing {}: {}'.format(file_relative_path, e)) + + def validate_package_file_hash(self, file_relative_path): + """Validates the integrity of a file using the hash algorithm and digest on the package manifest.""" + hash_algorithm = self.get_package_file_hash_algorithm_from_manifest(file_relative_path) + file_hash = self._calculate_file_hash(file_relative_path, hash_algorithm) + expected_file_hash = self.get_package_file_hash_digest_from_manifest(file_relative_path) + if file_hash != expected_file_hash: + error_msg = 'Error validating {} hash: calculated hash {} is different than manifest hash {}' + raise SOL004PackageException(error_msg.format(file_relative_path, file_hash, expected_file_hash)) + + def validate_package_hashes(self): + """Validates the integrity of all files listed on the package manifest.""" + for file_data in self._manifest_data: + if _MANIFEST_FILE_PATH_FIELD in file_data: + file_relative_path = file_data[_MANIFEST_FILE_PATH_FIELD] + self.validate_package_file_hash(file_relative_path) + + def get_descriptor_location(self): + """Returns this package descriptor location as a relative path from the package root.""" + for tosca_meta in self._package_metadata: + if _METADATA_DESCRIPTOR_FIELD in tosca_meta: + return tosca_meta[_METADATA_DESCRIPTOR_FIELD] + + error_msg = 'Error: no {} entry found on {}'.format(_METADATA_DESCRIPTOR_FIELD, _METADATA_FILE_PATH) + raise SOL004PackageException(error_msg) diff --git a/osm_common/tests/packages/invalid_package_vnf/Definitions/invalid_package_vnfd.yaml b/osm_common/tests/packages/invalid_package_vnf/Definitions/invalid_package_vnfd.yaml new file mode 100644 index 0000000..cd94158 --- /dev/null +++ b/osm_common/tests/packages/invalid_package_vnf/Definitions/invalid_package_vnfd.yaml @@ -0,0 +1,97 @@ +# +# 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. +# + +vnfd: + description: A VNF consisting of 1 VDU connected to two external VL, and one for + data and another one for management + df: + - id: default-df + instantiation-level: + - id: default-instantiation-level + vdu-level: + - number-of-instances: 1 + vdu-id: mgmtVM + vdu-profile: + - id: mgmtVM + min-number-of-instances: 1 + vdu-configuration-id: mgmtVM-vdu-configuration + ext-cpd: + - id: vnf-mgmt-ext + int-cpd: + cpd: mgmtVM-eth0-int + vdu-id: mgmtVM + - id: vnf-data-ext + int-cpd: + cpd: dataVM-xe0-int + vdu-id: mgmtVM + id: native_charm-vnf + mgmt-cp: vnf-mgmt-ext + product-name: native_charm-vnf + sw-image-desc: + - id: ubuntu18.04 + image: ubuntu18.04 + name: ubuntu18.04 + vdu: + - cloud-init-file: cloud-config.txt + id: mgmtVM + int-cpd: + - id: mgmtVM-eth0-int + virtual-network-interface-requirement: + - name: mgmtVM-eth0 + position: 1 + virtual-interface: + type: PARAVIRT + - id: dataVM-xe0-int + virtual-network-interface-requirement: + - name: dataVM-xe0 + position: 2 + virtual-interface: + type: PARAVIRT + name: mgmtVM + sw-image-desc: ubuntu18.04 + virtual-compute-desc: mgmtVM-compute + virtual-storage-desc: + - mgmtVM-storage + vdu-configuration: + - config-access: + ssh-access: + default-user: ubuntu + required: true + config-primitive: + - name: touch + parameter: + - data-type: STRING + default-value: /home/ubuntu/touched + name: filename + id: mgmtVM-vdu-configuration + initial-config-primitive: + - name: touch + parameter: + - data-type: STRING + name: filename + value: /home/ubuntu/first-touch + seq: 1 + juju: + charm: simple + proxy: false + version: 1.0 + virtual-compute-desc: + - id: mgmtVM-compute + virtual-cpu: + num-virtual-cpu: 1 + virtual-memory: + size: 1.0 + virtual-storage-desc: + - id: mgmtVM-storage + size-of-storage: 10 diff --git a/osm_common/tests/packages/invalid_package_vnf/Scripts/charms/simple/src/charm.py b/osm_common/tests/packages/invalid_package_vnf/Scripts/charms/simple/src/charm.py new file mode 100755 index 0000000..409f286 --- /dev/null +++ b/osm_common/tests/packages/invalid_package_vnf/Scripts/charms/simple/src/charm.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +## + +import sys +import subprocess + +from ops.charm import CharmBase +from ops.main import main +from ops.model import ActiveStatus + +sys.path.append("lib") + + +class MyNativeCharm(CharmBase): + + def __init__(self, framework, key): + super().__init__(framework, key) + + # Listen to charm events + self.framework.observe(self.on.config_changed, self.on_config_changed) + self.framework.observe(self.on.install, self.on_install) + self.framework.observe(self.on.start, self.on_start) + + # Listen to the touch action event + self.framework.observe(self.on.touch_action, self.on_touch_action) + + def on_config_changed(self, event): + """Handle changes in configuration""" + self.model.unit.status = ActiveStatus() + + def on_install(self, event): + """Called when the charm is being installed""" + self.model.unit.status = ActiveStatus() + + def on_start(self, event): + """Called when the charm is being started""" + self.model.unit.status = ActiveStatus() + + def on_touch_action(self, event): + """Touch a file.""" + + filename = event.params["filename"] + try: + subprocess.run(["touch", filename], check=True) + event.set_results({"created": True, "filename": filename}) + except subprocess.CalledProcessError as e: + event.fail("Action failed: {}".format(e)) + self.model.unit.status = ActiveStatus() + + +if __name__ == "__main__": + main(MyNativeCharm) diff --git a/osm_common/tests/packages/invalid_package_vnf/Scripts/cloud_init/cloud-config.txt b/osm_common/tests/packages/invalid_package_vnf/Scripts/cloud_init/cloud-config.txt new file mode 100755 index 0000000..7a83e12 --- /dev/null +++ b/osm_common/tests/packages/invalid_package_vnf/Scripts/cloud_init/cloud-config.txt @@ -0,0 +1,32 @@ +# +# Copyright 2020 Whitestack, LLC +# ************************************************************* +# +# This file is part of OSM common repository. +# All Rights Reserved to Whitestack, LLC +# +# 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. +# + +#cloud-config +password: osm4u +chpasswd: { expire: False } +ssh_pwauth: True + +write_files: +- content: | + # My new helloworld file + + owner: root:root + permissions: '0644' + path: /root/helloworld.txt diff --git a/osm_common/tests/packages/invalid_package_vnf/TOSCA-Metadata/TOSCA.meta b/osm_common/tests/packages/invalid_package_vnf/TOSCA-Metadata/TOSCA.meta new file mode 100644 index 0000000..ddbdf13 --- /dev/null +++ b/osm_common/tests/packages/invalid_package_vnf/TOSCA-Metadata/TOSCA.meta @@ -0,0 +1,38 @@ +# +# Copyright 2020 Whitestack, LLC +# ************************************************************* +# +# This file is part of OSM common repository. +# All Rights Reserved to Whitestack, LLC +# +# 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: agarcia@whitestack.com +## + +TOSCA-Meta-Version: 1.0 +CSAR-Version: 1.0 +Created-By: Diego Armando Maradona +Entry-Definitions: Definitions/native_charm_vnfd.yaml # Points to the main descriptor of the package +ETSI-Entry-Manifest: manifest.mf # Points to the ETSI manifest file +ETSI-Entry-Change-Log: Files/Changelog.txt # Points to package changelog +ETSI-Entry-Licenses: Files/Licenses # Points to package licenses folder + +# In principle, we could add one block per package file to specify MIME types +Name: Definitions/native_charm_vnfd.yaml # path to file within package +Content-Type: application/yaml # MIME type of file + +Name: Scripts/cloud_init/cloud-config.txt +Content-Type: application/yaml + diff --git a/osm_common/tests/packages/invalid_package_vnf/manifest.mf b/osm_common/tests/packages/invalid_package_vnf/manifest.mf new file mode 100644 index 0000000..dacf77f --- /dev/null +++ b/osm_common/tests/packages/invalid_package_vnf/manifest.mf @@ -0,0 +1,57 @@ +# +# Copyright 2020 Whitestack, LLC +# ************************************************************* +# +# This file is part of OSM common repository. +# All Rights Reserved to Whitestack, LLC +# +# 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: agarcia@whitestack.com +## + +# General definitions of the package +vnfd_id: native_charm-vnf +vnf_product_name: native_charm-vnf +vnf_provider_id: AFA +vnf_software_version: 1.0 +vnf_package_version: 1.0 +vnf_release_date_time: 2021.12.01T11:36-03:00 +compatible_specification_versions: 3.3.1 +vnfm_info: OSM + +Source: Definitions/native_charm_vnfd.yaml +Algorithm: SHA-256 +Hash: ede8daf9748ac4849e1a1aac955d6c84cafef9ea34067eaef76ee4e5996974c2 + +Source: Scripts/cloud_init/cloud-config.txt +Algorithm: SHA-256 +Hash: 7455ca868843cc5da1f0a2255cdedb64a69df3b618c344b83b82848a94540eda + + +# The below sections are all wrong on purpose as they are intended for testing + +# Invalid hash algorithm +Source: Scripts/charms/simple/src/charm.py +Algorithm: SHA-733 +Hash: 7895f7b9e1b7ed5b5bcd64398950ca95b456d7fc973334351474eed466c2f480 + +# Wrong hash +Source: Scripts/charms/simple/hooks/start +Algorithm: SHA-256 +Hash: 123456aaaaaa123456aaaaaae2bb9d0197f41619165dde6cf205c974f9aa86ae + +# Unspecified hash +Source: Scripts/charms/simple/hooks/upgrade-charm +Algorithm: SHA-256 diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Definitions/native_charm_vnfd.yaml b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Definitions/native_charm_vnfd.yaml new file mode 100644 index 0000000..cd94158 --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Definitions/native_charm_vnfd.yaml @@ -0,0 +1,97 @@ +# +# 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. +# + +vnfd: + description: A VNF consisting of 1 VDU connected to two external VL, and one for + data and another one for management + df: + - id: default-df + instantiation-level: + - id: default-instantiation-level + vdu-level: + - number-of-instances: 1 + vdu-id: mgmtVM + vdu-profile: + - id: mgmtVM + min-number-of-instances: 1 + vdu-configuration-id: mgmtVM-vdu-configuration + ext-cpd: + - id: vnf-mgmt-ext + int-cpd: + cpd: mgmtVM-eth0-int + vdu-id: mgmtVM + - id: vnf-data-ext + int-cpd: + cpd: dataVM-xe0-int + vdu-id: mgmtVM + id: native_charm-vnf + mgmt-cp: vnf-mgmt-ext + product-name: native_charm-vnf + sw-image-desc: + - id: ubuntu18.04 + image: ubuntu18.04 + name: ubuntu18.04 + vdu: + - cloud-init-file: cloud-config.txt + id: mgmtVM + int-cpd: + - id: mgmtVM-eth0-int + virtual-network-interface-requirement: + - name: mgmtVM-eth0 + position: 1 + virtual-interface: + type: PARAVIRT + - id: dataVM-xe0-int + virtual-network-interface-requirement: + - name: dataVM-xe0 + position: 2 + virtual-interface: + type: PARAVIRT + name: mgmtVM + sw-image-desc: ubuntu18.04 + virtual-compute-desc: mgmtVM-compute + virtual-storage-desc: + - mgmtVM-storage + vdu-configuration: + - config-access: + ssh-access: + default-user: ubuntu + required: true + config-primitive: + - name: touch + parameter: + - data-type: STRING + default-value: /home/ubuntu/touched + name: filename + id: mgmtVM-vdu-configuration + initial-config-primitive: + - name: touch + parameter: + - data-type: STRING + name: filename + value: /home/ubuntu/first-touch + seq: 1 + juju: + charm: simple + proxy: false + version: 1.0 + virtual-compute-desc: + - id: mgmtVM-compute + virtual-cpu: + num-virtual-cpu: 1 + virtual-memory: + size: 1.0 + virtual-storage-desc: + - id: mgmtVM-storage + size-of-storage: 10 diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Files/Changelog.txt b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Files/Changelog.txt new file mode 100644 index 0000000..a9abe70 --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Files/Changelog.txt @@ -0,0 +1,15 @@ +# +# 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. +# + +1.0.0: First version diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Files/Licenses/License.lic b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Files/Licenses/License.lic new file mode 100644 index 0000000..d120f18 --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Files/Licenses/License.lic @@ -0,0 +1,19 @@ +# +# Copyright 2020 Whitestack, LLC +# ************************************************************* +# +# This file is part of OSM common repository. +# All Rights Reserved to Whitestack, LLC +# +# 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/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/actions.yaml b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/actions.yaml new file mode 100644 index 0000000..53a706b --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/actions.yaml @@ -0,0 +1,25 @@ +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# 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. +## +touch: + description: "Touch a file on the VNF." + params: + filename: + description: "The name of the file to touch." + type: string + default: "" + required: + - filename diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/config.yaml b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/config.yaml new file mode 100644 index 0000000..2be6231 --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/config.yaml @@ -0,0 +1,17 @@ +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# 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. +## +options: {} \ No newline at end of file diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/hooks/install b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/hooks/install new file mode 100755 index 0000000..9ef7d07 --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/hooks/install @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +## + +import sys +import subprocess + +sys.path.append("lib") + +from ops.charm import CharmBase +from ops.main import main +from ops.model import ActiveStatus + +class MyNativeCharm(CharmBase): + + def __init__(self, framework, key): + super().__init__(framework, key) + + # Listen to charm events + self.framework.observe(self.on.config_changed, self.on_config_changed) + self.framework.observe(self.on.install, self.on_install) + self.framework.observe(self.on.start, self.on_start) + + # Listen to the touch action event + self.framework.observe(self.on.touch_action, self.on_touch_action) + + def on_config_changed(self, event): + """Handle changes in configuration""" + self.model.unit.status = ActiveStatus() + + def on_install(self, event): + """Called when the charm is being installed""" + self.model.unit.status = ActiveStatus() + + def on_start(self, event): + """Called when the charm is being started""" + self.model.unit.status = ActiveStatus() + + def on_touch_action(self, event): + """Touch a file.""" + + filename = event.params["filename"] + try: + subprocess.run(["touch", filename], check=True) + event.set_results({"created": True, "filename": filename}) + except subprocess.CalledProcessError as e: + event.fail("Action failed: {}".format(e)) + self.model.unit.status = ActiveStatus() + + +if __name__ == "__main__": + main(MyNativeCharm) + diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/hooks/start b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/hooks/start new file mode 100755 index 0000000..9ef7d07 --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/hooks/start @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +## + +import sys +import subprocess + +sys.path.append("lib") + +from ops.charm import CharmBase +from ops.main import main +from ops.model import ActiveStatus + +class MyNativeCharm(CharmBase): + + def __init__(self, framework, key): + super().__init__(framework, key) + + # Listen to charm events + self.framework.observe(self.on.config_changed, self.on_config_changed) + self.framework.observe(self.on.install, self.on_install) + self.framework.observe(self.on.start, self.on_start) + + # Listen to the touch action event + self.framework.observe(self.on.touch_action, self.on_touch_action) + + def on_config_changed(self, event): + """Handle changes in configuration""" + self.model.unit.status = ActiveStatus() + + def on_install(self, event): + """Called when the charm is being installed""" + self.model.unit.status = ActiveStatus() + + def on_start(self, event): + """Called when the charm is being started""" + self.model.unit.status = ActiveStatus() + + def on_touch_action(self, event): + """Touch a file.""" + + filename = event.params["filename"] + try: + subprocess.run(["touch", filename], check=True) + event.set_results({"created": True, "filename": filename}) + except subprocess.CalledProcessError as e: + event.fail("Action failed: {}".format(e)) + self.model.unit.status = ActiveStatus() + + +if __name__ == "__main__": + main(MyNativeCharm) + diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/metadata.yaml b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/metadata.yaml new file mode 100644 index 0000000..5e832fb --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/metadata.yaml @@ -0,0 +1,25 @@ +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# 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. +## + +name: simple-native +summary: A simple native charm +description: | + Simple native charm +series: + - bionic + - xenial + - focal \ No newline at end of file diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/src/charm.py b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/src/charm.py new file mode 100755 index 0000000..409f286 --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/charms/simple/src/charm.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +## + +import sys +import subprocess + +from ops.charm import CharmBase +from ops.main import main +from ops.model import ActiveStatus + +sys.path.append("lib") + + +class MyNativeCharm(CharmBase): + + def __init__(self, framework, key): + super().__init__(framework, key) + + # Listen to charm events + self.framework.observe(self.on.config_changed, self.on_config_changed) + self.framework.observe(self.on.install, self.on_install) + self.framework.observe(self.on.start, self.on_start) + + # Listen to the touch action event + self.framework.observe(self.on.touch_action, self.on_touch_action) + + def on_config_changed(self, event): + """Handle changes in configuration""" + self.model.unit.status = ActiveStatus() + + def on_install(self, event): + """Called when the charm is being installed""" + self.model.unit.status = ActiveStatus() + + def on_start(self, event): + """Called when the charm is being started""" + self.model.unit.status = ActiveStatus() + + def on_touch_action(self, event): + """Touch a file.""" + + filename = event.params["filename"] + try: + subprocess.run(["touch", filename], check=True) + event.set_results({"created": True, "filename": filename}) + except subprocess.CalledProcessError as e: + event.fail("Action failed: {}".format(e)) + self.model.unit.status = ActiveStatus() + + +if __name__ == "__main__": + main(MyNativeCharm) diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt new file mode 100755 index 0000000..f5d56f6 --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt @@ -0,0 +1,33 @@ +# +# Copyright 2020 Whitestack, LLC +# ************************************************************* +# +# This file is part of OSM common repository. +# All Rights Reserved to Whitestack, LLC +# +# 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. +# + + +#cloud-config +password: osm4u +chpasswd: { expire: False } +ssh_pwauth: True + +write_files: +- content: | + # My new helloworld file + + owner: root:root + permissions: '0644' + path: /root/helloworld.txt diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/TOSCA-Metadata/TOSCA.meta b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/TOSCA-Metadata/TOSCA.meta new file mode 100644 index 0000000..21b6dea --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/TOSCA-Metadata/TOSCA.meta @@ -0,0 +1,31 @@ +# +# 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: agarcia@whitestack.com +## + +TOSCA-Meta-Version: 1.0 +CSAR-Version: 1.0 +Created-By: Diego Armando Maradona +Entry-Definitions: Definitions/native_charm_vnfd.yaml # Points to the main descriptor of the package +ETSI-Entry-Manifest: manifest.mf # Points to the ETSI manifest file +ETSI-Entry-Change-Log: Files/Changelog.txt # Points to package changelog +ETSI-Entry-Licenses: Files/Licenses # Points to package licenses folder + +# In principle, we could add one block per package file to specify MIME types +Name: Definitions/native_charm_vnfd.yaml # path to file within package +Content-Type: application/yaml # MIME type of file + +Name: Scripts/cloud_init/cloud-config.txt +Content-Type: application/yaml \ No newline at end of file diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/manifest.mf b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/manifest.mf new file mode 100644 index 0000000..b42c240 --- /dev/null +++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/manifest.mf @@ -0,0 +1,72 @@ +# +# Copyright 2020 Whitestack, LLC +# ************************************************************* +# +# This file is part of OSM common repository. +# All Rights Reserved to Whitestack, LLC +# +# 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: agarcia@whitestack.com +## + +# General definitions of the package +vnfd_id: native_charm-vnf +vnf_product_name: native_charm-vnf +vnf_provider_id: AFA +vnf_software_version: 1.0 +vnf_package_version: 1.0 +vnf_release_date_time: 2021.12.01T11:36-03:00 +compatible_specification_versions: 3.3.1 +vnfm_info: OSM + +# One block for every file in the package +Source: Definitions/native_charm_vnfd.yaml +Algorithm: SHA-256 +Hash: ede8daf9748ac4849e1a1aac955d6c84cafef9ea34067eaef76ee4e5996974c2 + + + +Source: Scripts/cloud_init/cloud-config.txt +Algorithm: SHA-256 +Hash: 0eef3f1a642339e2053af48a7e370dac1952f9cb81166e439e8f72afd6f03621 + +# Charms files + +Source: Scripts/charms/simple/src/charm.py +Algorithm: SHA-256 +Hash: 7895f7b9e1b7ed5b5bcd64398950ca95b456d7fc973334351474eed466c2f480 + +Source: Scripts/charms/simple/hooks/start +Algorithm: SHA-256 +Hash: 312490afd82cc86ad823e4d9e2bb9d0197f41619165dde6cf205c974f9aa86ae + +Source: Scripts/charms/simple/hooks/install +Algorithm: SHA-256 +Hash: 312490afd82cc86ad823e4d9e2bb9d0197f41619165dde6cf205c974f9aa86ae + +Source: Scripts/charms/simple/actions.yaml +Algorithm: SHA-256 +Hash: 988ca2653ae6a3977149faaebd664a12858e0025f226b27d2cee1fa954c9462d + +Source: Scripts/charms/simple/metadata.yaml +Algorithm: SHA-256 +Hash: e00cfaf41a518aef0f486e4ae04a5ae19feffa774abfbdb68379bb5b5b102479 + +Source: Scripts/charms/simple/config.yaml +Algorithm: SHA-256 +Hash: f5cbf31b9c299504f3b577417b6c82bde5e3eafd74ee11fdeecf8c8bff6cf3e2 + + +# And on and on diff --git a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/ChangeLog.txt b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/ChangeLog.txt new file mode 100644 index 0000000..a9abe70 --- /dev/null +++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/ChangeLog.txt @@ -0,0 +1,15 @@ +# +# 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. +# + +1.0.0: First version diff --git a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Licenses/License.lic b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Licenses/License.lic new file mode 100644 index 0000000..d120f18 --- /dev/null +++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Licenses/License.lic @@ -0,0 +1,19 @@ +# +# Copyright 2020 Whitestack, LLC +# ************************************************************* +# +# This file is part of OSM common repository. +# All Rights Reserved to Whitestack, LLC +# +# 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/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/actions.yaml b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/actions.yaml new file mode 100644 index 0000000..53a706b --- /dev/null +++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/actions.yaml @@ -0,0 +1,25 @@ +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# 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. +## +touch: + description: "Touch a file on the VNF." + params: + filename: + description: "The name of the file to touch." + type: string + default: "" + required: + - filename diff --git a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/config.yaml b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/config.yaml new file mode 100644 index 0000000..2be6231 --- /dev/null +++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/config.yaml @@ -0,0 +1,17 @@ +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# 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. +## +options: {} \ No newline at end of file diff --git a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/hooks/install b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/hooks/install new file mode 100755 index 0000000..9ef7d07 --- /dev/null +++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/hooks/install @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +## + +import sys +import subprocess + +sys.path.append("lib") + +from ops.charm import CharmBase +from ops.main import main +from ops.model import ActiveStatus + +class MyNativeCharm(CharmBase): + + def __init__(self, framework, key): + super().__init__(framework, key) + + # Listen to charm events + self.framework.observe(self.on.config_changed, self.on_config_changed) + self.framework.observe(self.on.install, self.on_install) + self.framework.observe(self.on.start, self.on_start) + + # Listen to the touch action event + self.framework.observe(self.on.touch_action, self.on_touch_action) + + def on_config_changed(self, event): + """Handle changes in configuration""" + self.model.unit.status = ActiveStatus() + + def on_install(self, event): + """Called when the charm is being installed""" + self.model.unit.status = ActiveStatus() + + def on_start(self, event): + """Called when the charm is being started""" + self.model.unit.status = ActiveStatus() + + def on_touch_action(self, event): + """Touch a file.""" + + filename = event.params["filename"] + try: + subprocess.run(["touch", filename], check=True) + event.set_results({"created": True, "filename": filename}) + except subprocess.CalledProcessError as e: + event.fail("Action failed: {}".format(e)) + self.model.unit.status = ActiveStatus() + + +if __name__ == "__main__": + main(MyNativeCharm) + diff --git a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/hooks/start b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/hooks/start new file mode 100755 index 0000000..9ef7d07 --- /dev/null +++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/hooks/start @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +## + +import sys +import subprocess + +sys.path.append("lib") + +from ops.charm import CharmBase +from ops.main import main +from ops.model import ActiveStatus + +class MyNativeCharm(CharmBase): + + def __init__(self, framework, key): + super().__init__(framework, key) + + # Listen to charm events + self.framework.observe(self.on.config_changed, self.on_config_changed) + self.framework.observe(self.on.install, self.on_install) + self.framework.observe(self.on.start, self.on_start) + + # Listen to the touch action event + self.framework.observe(self.on.touch_action, self.on_touch_action) + + def on_config_changed(self, event): + """Handle changes in configuration""" + self.model.unit.status = ActiveStatus() + + def on_install(self, event): + """Called when the charm is being installed""" + self.model.unit.status = ActiveStatus() + + def on_start(self, event): + """Called when the charm is being started""" + self.model.unit.status = ActiveStatus() + + def on_touch_action(self, event): + """Touch a file.""" + + filename = event.params["filename"] + try: + subprocess.run(["touch", filename], check=True) + event.set_results({"created": True, "filename": filename}) + except subprocess.CalledProcessError as e: + event.fail("Action failed: {}".format(e)) + self.model.unit.status = ActiveStatus() + + +if __name__ == "__main__": + main(MyNativeCharm) + diff --git a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/metadata.yaml b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/metadata.yaml new file mode 100644 index 0000000..5e832fb --- /dev/null +++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/metadata.yaml @@ -0,0 +1,25 @@ +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# 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. +## + +name: simple-native +summary: A simple native charm +description: | + Simple native charm +series: + - bionic + - xenial + - focal \ No newline at end of file diff --git a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/src/charm.py b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/src/charm.py new file mode 100755 index 0000000..409f286 --- /dev/null +++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/charms/simple/src/charm.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +## +# Copyright 2020 Canonical Ltd. +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +## + +import sys +import subprocess + +from ops.charm import CharmBase +from ops.main import main +from ops.model import ActiveStatus + +sys.path.append("lib") + + +class MyNativeCharm(CharmBase): + + def __init__(self, framework, key): + super().__init__(framework, key) + + # Listen to charm events + self.framework.observe(self.on.config_changed, self.on_config_changed) + self.framework.observe(self.on.install, self.on_install) + self.framework.observe(self.on.start, self.on_start) + + # Listen to the touch action event + self.framework.observe(self.on.touch_action, self.on_touch_action) + + def on_config_changed(self, event): + """Handle changes in configuration""" + self.model.unit.status = ActiveStatus() + + def on_install(self, event): + """Called when the charm is being installed""" + self.model.unit.status = ActiveStatus() + + def on_start(self, event): + """Called when the charm is being started""" + self.model.unit.status = ActiveStatus() + + def on_touch_action(self, event): + """Touch a file.""" + + filename = event.params["filename"] + try: + subprocess.run(["touch", filename], check=True) + event.set_results({"created": True, "filename": filename}) + except subprocess.CalledProcessError as e: + event.fail("Action failed: {}".format(e)) + self.model.unit.status = ActiveStatus() + + +if __name__ == "__main__": + main(MyNativeCharm) diff --git a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt new file mode 100755 index 0000000..f5d56f6 --- /dev/null +++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt @@ -0,0 +1,33 @@ +# +# Copyright 2020 Whitestack, LLC +# ************************************************************* +# +# This file is part of OSM common repository. +# All Rights Reserved to Whitestack, LLC +# +# 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. +# + + +#cloud-config +password: osm4u +chpasswd: { expire: False } +ssh_pwauth: True + +write_files: +- content: | + # My new helloworld file + + owner: root:root + permissions: '0644' + path: /root/helloworld.txt diff --git a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/native_charm_vnfd.mf b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/native_charm_vnfd.mf new file mode 100644 index 0000000..d948858 --- /dev/null +++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/native_charm_vnfd.mf @@ -0,0 +1,72 @@ +# +# Copyright 2020 Whitestack, LLC +# ************************************************************* +# +# This file is part of OSM common repository. +# All Rights Reserved to Whitestack, LLC +# +# 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: agarcia@whitestack.com +## + +# General definitions of the package +vnfd_id: native_charm-vnf +vnf_product_name: native_charm-vnf +vnf_provider_id: AFA +vnf_software_version: 1.0 +vnf_package_version: 1.0 +vnf_release_date_time: 2021.12.01T11:36-03:00 +compatible_specification_versions: 3.3.1 +vnfm_info: OSM + +# One block for every file in the package +Source: native_charm_vnfd.yaml +Algorithm: SHA-256 +Hash: ae06780c082041676df4ca4130ef223548eee6389007ba259416f59044450a7c + + + +Source: Scripts/cloud_init/cloud-config.txt +Algorithm: SHA-256 +Hash: 0eef3f1a642339e2053af48a7e370dac1952f9cb81166e439e8f72afd6f03621 + +# Charms files + +Source: Scripts/charms/simple/src/charm.py +Algorithm: SHA-256 +Hash: 7895f7b9e1b7ed5b5bcd64398950ca95b456d7fc973334351474eed466c2f480 + +Source: Scripts/charms/simple/hooks/start +Algorithm: SHA-256 +Hash: 312490afd82cc86ad823e4d9e2bb9d0197f41619165dde6cf205c974f9aa86ae + +Source: Scripts/charms/simple/hooks/install +Algorithm: SHA-256 +Hash: 312490afd82cc86ad823e4d9e2bb9d0197f41619165dde6cf205c974f9aa86ae + +Source: Scripts/charms/simple/actions.yaml +Algorithm: SHA-256 +Hash: 988ca2653ae6a3977149faaebd664a12858e0025f226b27d2cee1fa954c9462d + +Source: Scripts/charms/simple/metadata.yaml +Algorithm: SHA-256 +Hash: e00cfaf41a518aef0f486e4ae04a5ae19feffa774abfbdb68379bb5b5b102479 + +Source: Scripts/charms/simple/config.yaml +Algorithm: SHA-256 +Hash: f5cbf31b9c299504f3b577417b6c82bde5e3eafd74ee11fdeecf8c8bff6cf3e2 + + +# And on and on diff --git a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/native_charm_vnfd.yaml b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/native_charm_vnfd.yaml new file mode 100644 index 0000000..2af0f0f --- /dev/null +++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/native_charm_vnfd.yaml @@ -0,0 +1,103 @@ +# +# 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. +# + +metadata: + template_name: native_charm-vnf + template_author: AFA + template_version: 1.1 + +vnfd: + description: A VNF consisting of 1 VDU connected to two external VL, and one for + data and another one for management + df: + - id: default-df + instantiation-level: + - id: default-instantiation-level + vdu-level: + - number-of-instances: 1 + vdu-id: mgmtVM + vdu-profile: + - id: mgmtVM + min-number-of-instances: 1 + vdu-configuration-id: mgmtVM-vdu-configuration + ext-cpd: + - id: vnf-mgmt-ext + int-cpd: + cpd: mgmtVM-eth0-int + vdu-id: mgmtVM + - id: vnf-data-ext + int-cpd: + cpd: dataVM-xe0-int + vdu-id: mgmtVM + id: native_charm-vnf + mgmt-cp: vnf-mgmt-ext + product-name: native_charm-vnf + provider: AFA + sw-image-desc: + - id: ubuntu18.04 + image: ubuntu18.04 + name: ubuntu18.04 + vdu: + - cloud-init-file: cloud-config.txt + id: mgmtVM + int-cpd: + - id: mgmtVM-eth0-int + virtual-network-interface-requirement: + - name: mgmtVM-eth0 + position: 1 + virtual-interface: + type: PARAVIRT + - id: dataVM-xe0-int + virtual-network-interface-requirement: + - name: dataVM-xe0 + position: 2 + virtual-interface: + type: PARAVIRT + name: mgmtVM + sw-image-desc: ubuntu18.04 + virtual-compute-desc: mgmtVM-compute + virtual-storage-desc: + - mgmtVM-storage + vdu-configuration: + - config-access: + ssh-access: + default-user: ubuntu + required: true + config-primitive: + - name: touch + parameter: + - data-type: STRING + default-value: /home/ubuntu/touched + name: filename + id: mgmtVM-vdu-configuration + initial-config-primitive: + - name: touch + parameter: + - data-type: STRING + name: filename + value: /home/ubuntu/first-touch + seq: 1 + juju: + charm: simple + proxy: false + version: 1.0 + virtual-compute-desc: + - id: mgmtVM-compute + virtual-cpu: + num-virtual-cpu: 1 + virtual-memory: + size: 1.0 + virtual-storage-desc: + - id: mgmtVM-storage + size-of-storage: 10 diff --git a/osm_common/tests/test_sol004_package.py b/osm_common/tests/test_sol004_package.py new file mode 100644 index 0000000..b9f13af --- /dev/null +++ b/osm_common/tests/test_sol004_package.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- + +# Copyright 2020 Whitestack, LLC +# ************************************************************* +# +# This file is part of OSM common repository. +# All Rights Reserved to Whitestack, LLC +# +# 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: agarcia@whitestack.com +## + +from osm_common.sol004_package import SOL004Package, SOL004PackageException +import unittest + + +class SOL004ValidatorTest(unittest.TestCase): + def test_get_package_file_hash_algorithm_from_manifest_with_metadata_dir(self): + package = SOL004Package('osm_common/tests/packages/native_charm_with_metadata_dir_vnf') + algorithm = package.get_package_file_hash_algorithm_from_manifest('Scripts/charms/simple/src/charm.py') + self.assertEqual(algorithm, 'SHA-256') + + def test_get_package_file_hash_algorithm_from_manifest_without_metadata_dir(self): + package = SOL004Package('osm_common/tests/packages/native_charm_without_metadata_dir_vnf') + algorithm = package.get_package_file_hash_algorithm_from_manifest('Scripts/charms/simple/src/charm.py') + self.assertEqual(algorithm, 'SHA-256') + + def test_get_package_file_hash_algorithm_from_manifest_on_non_existent_file(self): + package = SOL004Package('osm_common/tests/packages/native_charm_with_metadata_dir_vnf') + with self.assertRaises(SOL004PackageException): + package.get_package_file_hash_algorithm_from_manifest('Non/Existing/file') + + def test_get_package_file_hash_digest_from_manifest_with_metadata_dir(self): + package = SOL004Package('osm_common/tests/packages/native_charm_with_metadata_dir_vnf') + digest = package.get_package_file_hash_digest_from_manifest('Scripts/charms/simple/src/charm.py') + self.assertEqual(digest, '7895f7b9e1b7ed5b5bcd64398950ca95b456d7fc973334351474eed466c2f480') + + def test_get_package_file_hash_digest_from_manifest_without_metadata_dir(self): + package = SOL004Package('osm_common/tests/packages/native_charm_without_metadata_dir_vnf') + digest = package.get_package_file_hash_digest_from_manifest('Scripts/charms/simple/src/charm.py') + self.assertEqual(digest, '7895f7b9e1b7ed5b5bcd64398950ca95b456d7fc973334351474eed466c2f480') + + def test_get_package_file_hash_digest_from_manifest_on_non_existent_file(self): + package = SOL004Package('osm_common/tests/packages/native_charm_with_metadata_dir_vnf') + with self.assertRaises(SOL004PackageException): + package.get_package_file_hash_digest_from_manifest('Non/Existing/file') + + def test_get_package_file_hash_digest_from_manifest_on_non_existing_hash_entry(self): + package = SOL004Package('osm_common/tests/packages/invalid_package_vnf') + with self.assertRaises(SOL004PackageException): + package.get_package_file_hash_digest_from_manifest('Scripts/charms/simple/hooks/upgrade-charm') + + def test_validate_package_file_hash_with_metadata_dir(self): + package = SOL004Package('osm_common/tests/packages/native_charm_with_metadata_dir_vnf') + package.validate_package_file_hash('Scripts/charms/simple/src/charm.py') + + def test_validate_package_file_hash_without_metadata_dir(self): + package = SOL004Package('osm_common/tests/packages/native_charm_without_metadata_dir_vnf') + package.validate_package_file_hash('Scripts/charms/simple/src/charm.py') + + def test_validate_package_file_hash_on_non_existing_file(self): + package = SOL004Package('osm_common/tests/packages/native_charm_with_metadata_dir_vnf') + with self.assertRaises(SOL004PackageException): + package.validate_package_file_hash('Non/Existing/file') + + def test_validate_package_file_hash_on_wrong_manifest_hash(self): + package = SOL004Package('osm_common/tests/packages/invalid_package_vnf') + with self.assertRaises(SOL004PackageException): + package.validate_package_file_hash('Scripts/charms/simple/hooks/start') + + def test_validate_package_file_hash_on_unsupported_hash_algorithm(self): + package = SOL004Package('osm_common/tests/packages/invalid_package_vnf') + with self.assertRaises(SOL004PackageException): + package.validate_package_file_hash('Scripts/charms/simple/src/charm.py') + + def test_validate_package_hashes_with_metadata_dir(self): + package = SOL004Package('osm_common/tests/packages/native_charm_with_metadata_dir_vnf') + package.validate_package_hashes() + + def test_validate_package_hashes_without_metadata_dir(self): + package = SOL004Package('osm_common/tests/packages/native_charm_without_metadata_dir_vnf') + package.validate_package_hashes() + + def test_validate_package_hashes_on_invalid_package(self): + package = SOL004Package('osm_common/tests/packages/invalid_package_vnf') + with self.assertRaises(SOL004PackageException): + package.validate_package_hashes() + + def test_get_descriptor_location_with_metadata_dir(self): + package = SOL004Package('osm_common/tests/packages/native_charm_with_metadata_dir_vnf') + descriptor_path = package.get_descriptor_location() + self.assertEqual(descriptor_path, 'Definitions/native_charm_vnfd.yaml') + + def test_get_descriptor_location_without_metadata_dir(self): + package = SOL004Package('osm_common/tests/packages/native_charm_without_metadata_dir_vnf') + descriptor_path = package.get_descriptor_location() + self.assertEqual(descriptor_path, 'native_charm_vnfd.yaml')