--- /dev/null
+# Copyright 2019 ATOS
+#
+# 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.
+
+include osmclient/templates/*.yaml.j2
\ No newline at end of file
--- /dev/null
+# /bin/env python3
+# Copyright 2019 ATOS
+#
+# 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.
+
+from osmclient.common.exceptions import ClientException
+import os
+import glob
+import time
+import tarfile
+import hashlib
+from osm_im.validation import Validation as validation_im
+from jinja2 import Environment, PackageLoader
+
+
+class PackageTool(object):
+ def __init__(self, client=None):
+ self._client = client
+
+ def create(self, package_type, base_directory, package_name, override, image, vdus, vcpu, memory, storage,
+ interfaces, vendor, detailed, netslice_subnets, netslice_vlds):
+ """
+ **Create a package descriptor**
+
+ :params:
+ - package_type: [vnf, ns, nst]
+ - base directory: path of destination folder
+ - package_name: is the name of the package to be created
+ - image: specify the image of the vdu
+ - vcpu: number of virtual cpus of the vdu
+ - memory: amount of memory in MB pf the vdu
+ - storage: amount of storage in GB of the vdu
+ - interfaces: number of interfaces besides management interface
+ - vendor: vendor name of the vnf/ns
+ - detailed: include all possible values for NSD, VNFD, NST
+ - netslice_subnets: number of netslice_subnets for the NST
+ - netslice_vlds: number of virtual link descriptors for the NST
+
+ :return: status
+ """
+
+ # print("location: {}".format(osmclient.__path__))
+ file_loader = PackageLoader("osmclient")
+ env = Environment(loader=file_loader)
+ if package_type == 'ns':
+ template = env.get_template('nsd.yaml.j2')
+ content = {"name": package_name, "vendor": vendor, "vdus": vdus, "clean": False, "interfaces": interfaces,
+ "detailed": detailed}
+ elif package_type == 'vnf':
+ template = env.get_template('vnfd.yaml.j2')
+ content = {"name": package_name, "vendor": vendor, "vdus": vdus, "clean": False, "interfaces": interfaces,
+ "image": image, "vcpu": vcpu, "memory": memory, "storage": storage, "detailed": detailed}
+ elif package_type == 'nst':
+ template = env.get_template('nst.yaml.j2')
+ content = {"name": package_name, "vendor": vendor, "interfaces": interfaces,
+ "netslice_subnets": netslice_subnets, "netslice_vlds": netslice_vlds, "detailed": detailed}
+ else:
+ raise ClientException("Wrong descriptor type {}. Options: ns, vnf, nst".format(package_type))
+
+ # print("To be rendered: {}".format(content))
+ output = template.render(content)
+ # print(output)
+
+ structure = self.discover_folder_structure(base_directory, package_name, override)
+ if structure.get("folders"):
+ self.create_folders(structure["folders"], package_type)
+ if structure.get("files"):
+ self.create_files(structure["files"], output, package_type)
+ return "Created"
+
+ def validate(self, base_directory):
+ """
+ **Validate OSM Descriptors given a path**
+
+ :params:
+ - base_directory is the root path for all descriptors
+
+ :return: List of dict of validated descriptors. keys: type, path, valid, error
+ """
+ table = []
+ descriptors_paths = [f for f in glob.glob(base_directory + "/**/*.yaml", recursive=True)]
+ print("Base directory: {}".format(base_directory))
+ print("{} Descriptors found to validate".format(len(descriptors_paths)))
+ for desc_path in descriptors_paths:
+ with open(desc_path) as descriptor_file:
+ descriptor_data = descriptor_file.read()
+ desc_type = "-"
+ try:
+ desc_type, descriptor_data = validation_im.yaml_validation(self, descriptor_data)
+ validation_im.pyangbind_validation(self, desc_type, descriptor_data)
+ table.append({"type": desc_type, "path": desc_path, "valid": "OK", "error": "-"})
+ except Exception as e:
+ table.append({"type": desc_type, "path": desc_path, "valid": "ERROR", "error": str(e)})
+ return table
+
+ def build(self, package_folder, skip_validation=True):
+ """
+ **Creates a .tar.gz file given a package_folder**
+
+ :params:
+ - package_folder: is the name of the folder to be packaged
+ - skip_validation: is the flag to validate or not the descriptors on the folder before build
+
+ :returns: message result for the build process
+ """
+
+ if not os.path.exists("{}".format(package_folder)):
+ return "Fail, package is not in the specified route"
+ if not skip_validation:
+ results = self.validate(package_folder)
+ for result in results:
+ if result["valid"] != "OK":
+ return("There was an error validating the file: {} with error: {}".format(result["path"],
+ result["error"]))
+ self.calculate_checksum(package_folder)
+ with tarfile.open("{}.tar.gz".format(package_folder), mode='w:gz') as archive:
+ print("Adding File: {}".format(package_folder))
+ archive.add('{}'.format(package_folder), recursive=True)
+ return "Created {}.tar.gz".format(package_folder)
+
+ def calculate_checksum(self, package_folder):
+ """
+ **Function to calculate the checksum given a folder**
+
+ :params:
+ - package_folder: is the folder where we have the files to calculate the checksum
+ :returns: None
+ """
+ files = [f for f in glob.glob(package_folder + "/**/*.*", recursive=True)]
+ checksum = open("{}/checksum.txt".format(package_folder), "w+")
+ for file_item in files:
+ if "checksum.txt" in file_item:
+ continue
+ # from https://www.quickprogrammingtips.com/python/how-to-calculate-md5-hash-of-a-file-in-python.html
+ md5_hash = hashlib.md5()
+ with open(file_item, "rb") as f:
+ # Read and update hash in chunks of 4K
+ for byte_block in iter(lambda: f.read(4096), b""):
+ md5_hash.update(byte_block)
+ checksum.write("{}\t{}\n".format(md5_hash.hexdigest(), file_item))
+ checksum.close()
+
+ def create_folders(self, folders, package_type):
+ """
+ **Create folder given a list of folders**
+
+ :params:
+ - folders: [List] list of folders paths to be created
+ - package_type: is the type of package to be created
+ :return: None
+ """
+
+ for folder in folders:
+ try:
+ # print("Folder {} == package_type {}".format(folder[1], package_type))
+ if folder[1] == package_type:
+ print("Creating folder:\t{}".format(folder[0]))
+ os.makedirs(folder[0])
+ except FileExistsError:
+ pass
+
+ def save_file(self, file_name, file_body):
+ """
+ **Create a file given a name and the content**
+
+ :params:
+ - file_name: is the name of the file with the relative route
+ - file_body: is the content of the file
+ :return: None
+ """
+ print("Creating file: \t{}".format(file_name))
+ try:
+ with open(file_name, "w+") as f:
+ f.write(file_body)
+ except Exception as e:
+ raise ClientException(e)
+
+ def generate_readme(self):
+ """
+ **Creates the README content**
+
+ :returns: readme content
+ """
+ return """# Descriptor created by OSM descriptor package generated\n\n**Created on {} **""".format(
+ time.strftime("%m/%d/%Y, %H:%M:%S", time.localtime()))
+
+ def generate_cloud_init(self):
+ """
+ **Creates the cloud-init content**
+
+ :returns: cloud-init content
+ """
+ return "---\n#cloud-config"
+
+ def create_files(self, files, file_content, package_type):
+ """
+ **Creates the files given the file list and type**
+
+ :params:
+ - files: is the list of files structure
+ - file_content: is the content of the descriptor rendered by the template
+ - package_type: is the type of package to filter the creation structure
+
+ :return: None
+ """
+ for file_item, file_package, file_type in files:
+ if package_type == file_package:
+ if file_type == "descriptor":
+ self.save_file(file_item, file_content)
+ elif file_type == "readme":
+ self.save_file(file_item, self.generate_readme())
+ elif file_type == "cloud_init":
+ self.save_file(file_item, self.generate_cloud_init())
+
+ def check_files_folders(self, path_list, override):
+ """
+ **Find files and folders missing given a directory structure {"folders": [], "files": []}**
+
+ :params:
+ - path_list: is the list of files and folders to be created
+ - override: is the flag used to indicate the creation of the list even if the file exist to override it
+
+ :return: Missing paths Dict
+ """
+ missing_paths = {}
+ folders = []
+ files = []
+ for folder in path_list.get("folders"):
+ if not os.path.exists(folder[0]):
+ folders.append(folder)
+ missing_paths["folders"] = folders
+
+ for file_item in path_list.get("files"):
+ if not os.path.exists(file_item[0]) or override is True:
+ files.append(file_item)
+ missing_paths["files"] = files
+
+ return missing_paths
+
+ def discover_folder_structure(self, base_directory, name, override):
+ """
+ **Discover files and folders structure for OSM descriptors given a base_directory and name**
+
+ :params:
+ - base_directory: is the location of the package to be created
+ - name: is the name of the package
+ - override: is the flag used to indicate the creation of the list even if the file exist to override it
+ :return: Files and Folders not found. In case of override, it will return all file list
+ """
+ prefix = "{}/{}".format(base_directory, name)
+ files_folders = {"folders": [("{}_ns".format(prefix), "ns"),
+ ("{}_ns/icons".format(prefix), "ns"),
+ ("{}_ns/charms".format(prefix), "ns"),
+ ("{}_vnf".format(name), "vnf"),
+ ("{}_vnf/charms".format(prefix), "vnf"),
+ ("{}_vnf/cloud_init".format(prefix), "vnf"),
+ ("{}_vnf/images".format(prefix), "vnf"),
+ ("{}_vnf/icons".format(prefix), "vnf"),
+ ("{}_vnf/scripts".format(prefix), "vnf"),
+ ("{}_nst".format(prefix), "nst"),
+ ("{}_nst/icons".format(prefix), "nst")
+ ],
+ "files": [("{}_ns/{}_nsd.yaml".format(prefix, name), "ns", "descriptor"),
+ ("{}_ns/README.md".format(prefix), "ns", "readme"),
+ ("{}_vnf/{}_vnfd.yaml".format(prefix, name), "vnf", "descriptor"),
+ ("{}_vnf/cloud_init/cloud-config.txt".format(prefix), "vnf", "cloud_init"),
+ ("{}_vnf/README.md".format(prefix), "vnf", "readme"),
+ ("{}_nst/{}_nst.yaml".format(prefix, name), "nst", "descriptor"),
+ ("{}_nst/README.md".format(prefix), "nst", "readme")
+ ]
+ }
+ missing_files_folders = self.check_files_folders(files_folders, override)
+ # print("Missing files and folders: {}".format(missing_files_folders))
+ return missing_files_folders
table.align = 'l'
print(table)
+
+@cli.command(name='package-create',
+ short_help='Create a package descriptor')
+@click.argument('package-type')
+@click.argument('package-name')
+@click.option('--base-directory',
+ default='.',
+ help=('(NS/VNF/NST) Set the location for package creation. Default: "."'))
+@click.option('--image',
+ default="image-name",
+ help='(VNF) Set the name of the vdu image. Default "image-name"')
+@click.option('--vdus',
+ default=1,
+ help='(VNF) Set the number of vdus in a VNF. Default 1')
+@click.option('--vcpu',
+ default=1,
+ help='(VNF) Set the number of virtual CPUs in a vdu. Default 1')
+@click.option('--memory',
+ default=1024,
+ help='(VNF) Set the memory size (MB) of the vdu. Default 1024')
+@click.option('--storage',
+ default=10,
+ help='(VNF) Set the disk size (GB) of the vdu. Default 10')
+@click.option('--interfaces',
+ default=0,
+ help='(VNF) Set the number of additional interfaces apart from the management interface. Default 0')
+@click.option('--vendor',
+ default="OSM",
+ help='(NS/VNF) Set the descriptor vendor. Default "OSM"')
+@click.option('--override',
+ default=False,
+ is_flag=True,
+ help='(NS/VNF/NST) Flag for overriding the package if exists.')
+@click.option('--detailed',
+ is_flag=True,
+ default=False,
+ help='(NS/VNF/NST) Flag for generating descriptor .yaml with all possible commented options')
+@click.option('--netslice-subnets',
+ default=1,
+ help='(NST) Number of netslice subnets. Default 1')
+@click.option('--netslice-vlds',
+ default=1,
+ help='(NST) Number of netslice vlds. Default 1')
+@click.pass_context
+def package_create(ctx,
+ package_type,
+ base_directory,
+ package_name,
+ override,
+ image,
+ vdus,
+ vcpu,
+ memory,
+ storage,
+ interfaces,
+ vendor,
+ detailed,
+ netslice_subnets,
+ netslice_vlds):
+ """
+ Creates an OSM NS, VNF, NST package
+
+ \b
+ PACKAGE_TYPE: Package to be created: NS, VNF or NST.
+ PACKAGE_NAME: Name of the package to create the folder with the content.
+ """
+
+ try:
+ check_client_version(ctx.obj, ctx.command.name)
+ print("Creating the {} structure: {}/{}".format(package_type.upper(), base_directory, package_name))
+ resp = ctx.obj.package_tool.create(package_type,
+ base_directory,
+ package_name,
+ override=override,
+ image=image,
+ vdus=vdus,
+ vcpu=vcpu,
+ memory=memory,
+ storage=storage,
+ interfaces=interfaces,
+ vendor=vendor,
+ detailed=detailed,
+ netslice_subnets=netslice_subnets,
+ netslice_vlds=netslice_vlds)
+ print(resp)
+ except ClientException as inst:
+ print("ERROR: {}".format(inst))
+ exit(1)
+
+@cli.command(name='package-validate',
+ short_help='Validate a package descriptor')
+@click.argument('base-directory',
+ default=".",
+ required=False)
+@click.pass_context
+def package_validate(ctx,
+ base_directory):
+ """
+ Validate descriptors given a base directory.
+
+ \b
+ BASE_DIRECTORY: Stub folder for NS, VNF or NST package.
+ """
+ try:
+ check_client_version(ctx.obj, ctx.command.name)
+ results = ctx.obj.package_tool.validate(base_directory)
+ table = PrettyTable()
+ table.field_names = ["TYPE", "PATH", "VALID", "ERROR"]
+ # Print the dictionary generated by the validation function
+ for result in results:
+ table.add_row([result["type"], result["path"], result["valid"], result["error"]])
+ table.sortby = "VALID"
+ table.align["PATH"] = "l"
+ table.align["TYPE"] = "l"
+ table.align["ERROR"] = "l"
+ print(table)
+ except ClientException as inst:
+ print("ERROR: {}".format(inst))
+ exit(1)
+
+@cli.command(name='package-build',
+ short_help='Build the tar.gz of the package')
+@click.argument('package-folder')
+@click.option('--skip-validation',
+ default=False,
+ is_flag=True,
+ help='skip package validation')
+@click.pass_context
+def package_build(ctx,
+ package_folder,
+ skip_validation):
+ """
+ Build the package NS, VNF given the package_folder.
+
+ \b
+ PACKAGE_FOLDER: Folder of the NS, VNF or NST to be packaged
+ """
+ try:
+ check_client_version(ctx.obj, ctx.command.name)
+ results = ctx.obj.package_tool.build(package_folder, skip_validation)
+ print(results)
+ except ClientException as inst:
+ print("ERROR: {}".format(inst))
+ exit(1)
+
+
if __name__ == '__main__':
try:
cli()
from osmclient.sol005 import role
from osmclient.sol005 import pdud
from osmclient.common.exceptions import ClientException
+from osmclient.common import package_tool
import json
self.user = usermodule.User(self._http_client, client=self)
self.role = role.Role(self._http_client, client=self)
self.pdu = pdud.Pdu(self._http_client, client=self)
+
'''
self.vca = vca.Vca(http_client, client=self, **kwargs)
self.utils = utils.Utils(http_client, **kwargs)
'''
+ self.package_tool = package_tool.PackageTool(client=self)
def get_token(self):
if self._token is None:
--- /dev/null
+# Copyright 2019 ETSI OSM
+#
+# 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.
+
+nsd-catalog:
+ schema-version: "v3.0"
+ nsd:
+ - id: {{ name }}_nsd
+ name: {{ name }}_nsd
+ short-name: {{ name }}_nsd
+ vendor: {{ vendor }}
+ description: Generated by OSM package generator
+ version: '1.0'
+ {%- if detailed is sameas true %}
+
+ # Place the logo as png in icons directory and provide the name here
+ # logo: <update, optional> Example: icons/logo.png
+ {%- endif %}
+
+ # Specify the VNFDs that are part of this NSD
+ constituent-vnfd:
+ # The member-vnf-index needs to be unique, starting from 1
+ # vnfd-id-ref is the id of the VNFD
+ # Multiple constituent VNFDs can be specified
+ - member-vnf-index: "1"
+ vnfd-id-ref: {{ name }}_vnfd
+ {%- if detailed is sameas true %}
+ # start-by-default: True
+ {%- endif %}
+
+ # Networks for the VNFs
+ vld:
+ - id: {{ name }}_nsd_vld0
+ name: mgmt
+ short-name: mgmt
+ type: ELAN
+ mgmt-network: true
+ {%- if detailed is sameas true %}
+ # description: <update>
+ # vim-network-name: <update> Name of network in VIM account
+ # ip-profile-ref: <update> Name of reference of IP profile object
+ # provider-network:
+ # physical-network: <update> Name of the physical network on which provider network is built
+ # segmentation_id: <update> ID of segregated virtual network
+ {%- endif %}
+
+ # Specify the constituent VNFs
+ # member-vnf-index-ref - entry from constituent vnf
+ # vnfd-id-ref - VNFD id
+ # vnfd-connection-point-ref - connection point name in the VNFD
+ vnfd-connection-point-ref:
+ - member-vnf-index-ref: "1"
+ vnfd-id-ref: {{ name }}_vnfd
+ # NOTE: Validate the entry below
+ vnfd-connection-point-ref: vnf-cp0
+ {%- if detailed is sameas true %}
+ # ip-address: <update> IP address of the connection point
+ {%- endif %}
+
+ {%- for x in range(1, interfaces + 1 ) %}
+ - member-vnf-index-ref: "1"
+ vnfd-id-ref: {{ name }}_vnfd
+ # NOTE: Validate the entry below
+ vnfd-connection-point-ref: vnf-cp{{ x }}
+ {%- if detailed is sameas true %}
+ # ip-address: <update> IP address of the connection point
+ {%- endif %}
+ {%- endfor %}
+
+ {%- if detailed is sameas true %}
+ # List of IP Profiles.
+ # IP Profile describes the IP characteristics for the Virtual-Link
+ #ip-profiles
+ #- name: <update>
+ # description: <update>
+ # ip-profile-params:
+ # - ip-version:
+ # subnet-address: <update>
+ # gateway-address: <update>
+ # security-group: <update>
+ # subnet-prefix-pool: <update>
+ # dns-server:
+ # - address: <update>
+ # dhcp-params:
+ # - enabled: <update>
+ # start-address: <update>
+ # count: <update>
+
+ # Information about NS configuration
+ #ns-configuration:
+ # juju:
+ # charm: <update>
+ # proxy: <update>
+ # vca-relationships:
+ # relation:
+ # - requires: <update>
+ # provides: <update>
+
+ # # List of config primitives supported by the
+ # # configuration agent for this NS.
+ # config-primitive:
+ # - name: <update>
+ # parameter:
+ # - name: <update>
+ # data-type: <update>
+ # mandatory: <update>
+ # default-value: <update>
+ # parameter-pool: <update>
+ # read-only: <update>
+ # hidden: <update>
+
+ # # Initial set of configuration primitives.
+ # initial-config-primitive:
+ # - seq: <update>
+ # name: <update>
+ # parameter:
+ # - name: <update>
+ # data-type: <update>
+ # value: <update>
+
+ # # Terminate set of configuration primitives.
+ # terminate-config-primitive:
+ # - seq: <update>
+ # name: <update>
+ # parameter:
+ # - name: <update>
+ # data-type: <update>
+ # value: <update>
+
+ # # List of VCA related metric
+ # metrics:
+ # - name: <update>
+
+ # Used to configure the list of public keys to be injected as part
+ # of ns instantiation
+ #key-pair:
+ #- name: <update>
+ # key: <update>
+
+ # List of users to be added through cloud-config
+ #user:
+ #- name: <update>
+ # user-info: <update>
+ # key-pair:
+ # - name: <update>
+ # key: <update>
+
+ # List of VNF Forwarding Graph Descriptors (VNFFGD)
+ #vnffgd:
+ #- id: <update>
+ # name: <update>
+ # short-name: <update>
+ # vendor: <update>
+ # description: <update>
+ # version: <update>
+ # # List of Rendered Service Paths
+ # rsp:
+ # - id: <update>
+ # name: <update>
+ # vnfd-connection-point-ref:
+ # - member-vnf-index-ref: <update>
+ # order: <update>
+ # vnfd-id-ref: <update>
+ # vnfd-ingress-connection-point-ref: <update>
+ # vnfd-egress-connection-point-ref: <update>
+ # # List of classifier rules
+ # classifier:
+ # - id: <update>
+ # name: <update>
+ # rsp-id-ref: <update>
+ # member-vnf-index-ref: <update>
+ # vnfd-id-ref: <update>
+ # vnfd-connection-point-ref: <update>
+ # match-attributes:
+ # - id: <update>
+ # ip-proto: <update>
+ # source-ip-address: <update>
+ # destination-ip-address: <update>
+ # source-port: <update>
+ # destination-port: <update>
+ {%- endif %}
--- /dev/null
+# Copyright 2019 ETSI OSM
+#
+# 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.
+nst:
+- id: {{ name }}_nst
+ name: {{ name }}_nst
+
+ # Slice Service Type [eMBB, mMTC, URLLC]
+ SNSSAI-identifier:
+ slice-service-type: eMBB
+ {%- if detailed is sameas true %}
+ #slice-differentiator: <update, optional>
+ {%- endif %}
+
+ # Quality of service identifier
+ quality-of-service:
+ id: 1
+ {%- if detailed is sameas true %}
+ #resource-type: <update, optional>
+ #priority-level: <update, optional>
+ #packet-delay-budget: <update, optional>
+ #packet-error-rate: <update, optional>
+ #default-max-data-burst: <update, optional>
+ {%- endif %}
+
+ # Netslice subnets (Network services)
+ netslice-subnet:
+ {%- for x in range(1, netslice_subnets + 1 ) %}
+ - id: {{ name }}_nsd_{{ x }}
+ is-shared-nss: 'false'
+ description: NetSlice Subnet (service) {{ name }}_nsd_{{ x }}
+ nsd-ref: {{ name }}_nsd
+ {%- endfor %}
+
+ # Netslice virtual links
+ netslice-vld:
+ # Additional netslice-vld can be created by copying the
+ # vld descriptor below
+ - id: {{ name }}_slice_vld_mgmt
+ name: {{ name }}_slice_vld_mgmt
+ type: ELAN
+ mgmt-network: 'true'
+ {%- if detailed is sameas true %}
+ #short-name: <update, optional>
+ #description: <update, optional>
+ {%- endif %}
+ nss-connection-point-ref:
+ # Specify the connection points
+ # Multiple connection points can be defined
+ - nss-ref: {{ name }}_nsd_1
+ nsd-connection-point-ref: {{ name }}_nsd_cp_mgmt
+ {%- if detailed is sameas true %}
+ #ip-address: <update>
+ {%- endif %}
+
+ {%- for x in range(1, netslice_vlds + 1 ) %}
+ - id: {{ name }}_slice_vld_data{{ x }}
+ name: {{ name }}_slice_vld_data{{ x }}
+ type: ELAN
+ {%- if detailed is sameas true %}
+ #mgmt-network: <update>
+ #short-name: <update, optional>
+ #description: <update, optional>
+ #type: <update, optional>
+ {%- endif %}
+ nss-connection-point-ref:
+ # Specify the connection points
+ # Multiple connection points can be defined
+ - nss-ref: {{ name }}_nsd
+ nsd-connection-point-ref: {{ name }}_nsd_cp_data{{ x }}
+ {%- if detailed is sameas true %}
+ #ip-address: <update>
+ {%- endif %}
+ {%- endfor %}
+
+ {%- if detailed is sameas true %}
+ #netslice-connection-point:
+ #- name:
+ # floating-ip-required: <update>
+ # # Choice connection | netslice-vld-ref / nsd-connection-point-ref
+ # netslice-vld-id-ref: <update, optional>
+ # #
+ # nsd-id-ref: <update, optional>
+ # nsd-connection-point-ref: <update, optional>
+
+ #netslicefgd:
+ #- id: <update>
+ # name: <update, optional>
+ # short-name: <update, optional>
+ # vendor: <update, optional>
+ # description: <update, optional>
+ # version: <update, optional>
+ # rsp:
+ # - id: <update>
+ # name: <update, optional>
+ # nsd-connection-point-ref:
+ # - nsd-ref: <update>
+ # order: <update, optional>
+ # nsd-connection-point-ref: <update, optional>
+ # classifier:
+ # - id: <update>
+ # name: <update, optional>
+ # rsp-id-ref: <update, optional>
+ # match-attributes:
+ # - id: <update>
+ # ip-proto: <update, optional>
+ # source-ip-address: <update, optional>
+ # destination-ip-address: <update, optional>
+ # source-port: <update, optional>
+ # destination-port: <update, optional>
+ # nsd-ref: <update, optional>
+ # nsd-connection-point-ref: <update, optional>
+ {%- endif %}
--- /dev/null
+# Copyright 2019 ETSI OSM
+#
+# 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.
+
+vnfd-catalog:
+ schema-version: "v3.0"
+ vnfd:
+ - id: {{ name }}_vnfd
+ name: {{ name }}_vnfd
+ short-name: {{ name }}_vnfd
+ description: Generated by OSM package generator
+ vendor: OSM
+ version: '1.0'
+
+ {%- if detailed is sameas true %}
+ #Place the logo as png in icons directory and provide the name here
+ #logo: <update, optional>
+
+ {%- endif %}
+
+ # Management interface
+ mgmt-interface:
+ cp: vnf-cp0
+
+ # At least one VDU need to be specified
+ vdu:
+ # Additional VDUs can be created by copying the
+ # VDU descriptor below
+ - id: {{ name }}_vnfd-VM
+ name: {{ name }}_vnfd-VM
+ description: {{ name }}_vnfd-VM
+ count: 1
+ {%- if detailed is sameas true %}
+ #pdu-type: <update, optional>
+ #mgmt-vpci: <update, optional>
+ {%- endif %}
+
+ # Flavour of the VM to be instantiated for the VDU
+ vm-flavor:
+ vcpu-count: {{ vcpu }}
+ memory-mb: {{ memory }}
+ storage-gb: {{ storage }}
+
+ # Image including the full path
+ image: "{{ image }}"
+ {%- if detailed is sameas true %}
+ #image-checksum: <update, optional>
+ {%- endif %}
+
+ interface:
+ # Specify the external interfaces
+ # There can be multiple interfaces defined
+ - name: eth0
+ type: EXTERNAL
+ virtual-interface:
+ type: PARAVIRT
+ {%- if detailed is sameas true %}
+ #vpci: <update, optional>
+ #bandwidth: <update, optional>
+ {%- endif %}
+ external-connection-point-ref: vnf-cp0
+ {%- if detailed is sameas true %}
+ #internal-connection-point-ref: <update, optional>
+ #mac-address <update, optional>
+ #mgmt-interface: <update, optional>
+ {%- endif %}
+
+ {%- for x in range(1, interfaces + 1 ) %}
+ - name: eth{{ x }}
+ type: EXTERNAL
+ virtual-interface:
+ type: PARAVIRT
+ {%- if detailed is sameas true %}
+ #vpci: <update, optional>
+ #bandwidth: <update, optional>
+ {%- endif %}
+ external-connection-point-ref: vnf-cp{{ x }}
+ {%- if detailed is sameas true %}
+ #internal-connection-point-ref: <update, optional>
+ #mac-address <update, optional>
+ #mgmt-interface: <update, optional>
+ {%- endif %}
+ {%- endfor %}
+
+ {%- if detailed is sameas true %}
+ #guest-epa:
+ # mempage-size: <update, optional>
+ # # Choice cpu-pinning / cpu-quota
+ # cpu-pinning-policy: <update, optional> [DEDICATED, SHARED, ANY]
+ # cpu-thread-pinning-policy: <update, optional> [AVOID, SEPARATED, ISOLATE, PREFER]
+ # cpu-quota:
+ # limit: <update, optional>
+ # reserve: <update, optional>
+ # shares: <update, optional>
+ # mem-quota:
+ # limit: <update, optional>
+ # reserve: <update, optional>
+ # shares: <update, optional>
+ # disk-io-quota:
+ # limit: <update, optional>
+ # reserve: <update, optional>
+ # shares: <update, optional>
+ # vif-quota:
+ # limit: <update, optional>
+ # reserve: <update, optional>
+ # shares: <update, optional>
+
+ #alarm:
+ #- alarm-id: <update>
+ # vnf-monitoring-param-ref: <update, optional>
+ # operation: <update, optional>
+ # value: <update, optional>
+ # actions:
+ # ok:
+ # - url: <update>
+ # insufficient-data:
+ # - url: <update>
+ # alarm:
+ # - url: <update>
+ #
+ #alternative-images:
+ #- vim-type: <update>
+ # image: <update, optional>
+ # image-checksum: <update, optional>
+ #
+ #vdu-configuration:
+ # # Configure the VNF or VDU through Juju.
+ # juju:
+ # charm: <update, optional>
+ # proxy: <update, optional>
+ # vca-relationships:
+ # relation:
+ # - requires: <update>
+ # provides: <update>
+ # config-primitive:
+ # - name: <update>
+ # parameter:
+ # - name: <update>
+ # data-type: <update, optional>
+ # mandatory: <update, optional>
+ # default-value: <update, optional>
+ # parameter-pool: <update, optional>
+ # read-only: <update, optional>
+ # hidden: <update, optional>
+ # initial-config-primitive:
+ # - seq: <update>
+ # name: <update, optional>
+ # parameter:
+ # - name: <update>
+ # data-type: <update, optional>
+ # value: <update, optional>
+ # terminate-config-primitive:
+ # - seq: <update>
+ # name: <update, optional>
+ # parameter:
+ # - name: <update>
+ # data-type: <update, optional>
+ # value: <update, optional>
+ # metrics:
+ # - name: <update>
+ # config-access:
+ # ssh-access:
+ # required: <update, optional>
+ # default-user: <update, optional>
+ #
+ #monitoring-param:
+ #- id: <update>
+ # nfvi-metric: <update, optional>
+ # interface-name-ref: <update, optional>
+ #
+ ## Choice cloud-init / cloud-init-file
+ #cloud-init: <update, optional>
+ #cloud-init-file: <update, optional>
+ #supplemental-boot-data:
+ # boot-data-drive: <update, optional>
+ #
+ #internal-connection-point:
+ #- id: <update>
+ # name: <update, optional>
+ # short-name: <update, optional>
+ # type: <update, optional>
+ # port-security-enabled: <update, optional>
+ # internal-vld-ref: <update, optional>
+ #
+ #interface:
+ #- name: <update>
+ # position: <update, optional>
+ # mgmt-interface: <update, optional>
+ # type: <update, optional>
+ # mac-address: <update, optional>
+ # # Choice: connection-point-type | internal-connection-point-ref / external-connection-point-ref
+ # internal-connection-point-ref: <update, optional>
+ # external-connection-point-ref: <update, optional>
+ # virtual-interface:
+ # type: <update, optional> # PARAVIRT,OM-MGMT,PCI-PASSTHROUGH,SR-IOV,VIRTIO,E1000,RTL8139,PCNET
+ # vpci: <update, optional>
+ # bandwidth: <update, optional>
+ #
+ #volumes:
+ #- name: <update>
+ # description: <update, optional>
+ # size: <update, optional>
+ # device-bus: <update, optional> # ide, usb, virtio, iscsi
+ # device-type: <update, optional> # disk, cdrom, floopy, lun
+ # # Choice volume-source | ephemeral / image
+ # ephemeral: <update, optional>
+ # image: <update, optional>
+ # image-checksum: <update, optional>
+
+ #scaling-group-descriptor:
+ #- name: <update>
+ # min-instance-count: <update, optional>
+ # max-instance-count: <update, optional>
+ # scaling-policy:
+ # - name: <update>
+ # scaling-type: <update, optional>
+ # enabled: <update, optional>
+ # scale-in-operator-type: <update, optional>
+ # scale-out-operator-type: <update, optional>
+ # threshold-time: <update, optional>
+ # cooldown-time: <update, optional>
+ # scaling-criteria: <update, optional>
+ # - name: <update>
+ # scale-in-threshold: <update, optional>
+ # scale-in-relational-operation: <update, optional>
+ # scale-out-threshold: <update, optional>
+ # scale-out-relational-operation: <update, optional>
+ # vnf-monitoring-param-ref: <update, optional>
+ # vdu:
+ # - vdu-id-ref: <update>
+ # count: <update, optional>
+ # scaling-config-action:
+ # - trigger: <update>
+ # vnf-config-primitive-name-ref: <update, optional>
+
+ # List of monitoring params at NS level
+ #monitoring-param:
+ #- id: <update>
+ # name: <update, optional>
+ # aggregation-type: <update, optional>
+ # # Choice monitoring-type | vdu-monitoring-param / vnf-metric / vdu-metric
+ # vdu-monitoring-param:
+ # vdu-ref: <update, optional>
+ # vdu-monitoring-param-ref: <update, optional>
+ # vnf-metric:
+ # vnfm-metric-name-ref: <update, optional>
+ # vdu-metric:
+ # vdu-ref: <update, optional>
+ # vdu-metric-name-ref: <update, optional>
+ #
+ # Placement groups at VNF Level
+ #placement-groups:
+ #- name: <update>
+ # requirement: <update, optional>
+ # strategy: <update, optional> # COLOCATION, ISOLATION
+ # member-vdus:
+ # - member-vdu-ref: <update>
+ {%- endif %}
+ {%- if vdus > 1 %}
+ {% for y in range(1, vdus ) %}
+ - id: {{ name }}_vnfd{{y}}-VM
+ name: {{ name }}_vnfd{{y}}-VM
+ description: {{ name }}_vnfd{{y}}-VM
+ count: 1
+ {%- if detailed is sameas true %}
+ #pdu-type: <update, optional>
+ #mgmt-vpci: <update, optional>
+ {%- endif %}
+
+ # Flavour of the VM to be instantiated for the VDU
+ vm-flavor:
+ vcpu-count: {{ vcpu }}
+ memory-mb: {{ memory }}
+ storage-gb: {{ storage }}
+
+ # Image including the full path
+ image: "{{ image }}"
+ {%- if detailed is sameas true %}
+ #image-checksum: <update, optional>
+ {%- endif %}
+
+ interface:
+ # Specify the external interfaces
+ # There can be multiple interfaces defined
+ - name: eth0
+ type: EXTERNAL
+ virtual-interface:
+ type: PARAVIRT
+ {%- if detailed is sameas true %}
+ #vpci: <update, optional>
+ #bandwidth: <update, optional>
+ {%- endif %}
+ external-connection-point-ref: vnf-cp0
+ {%- if detailed is sameas true %}
+ #internal-connection-point-ref: <update, optional>
+ #mac-address <update, optional>
+ #mgmt-interface: <update, optional>
+ {%- endif %}
+
+ {%- for z in range(1, interfaces + 1 ) %}
+ - name: eth{{ z }}
+ type: EXTERNAL
+ virtual-interface:
+ type: PARAVIRT
+ {%- if detailed is sameas true %}
+ #vpci: <update, optional>
+ #bandwidth: <update, optional>
+ {%- endif %}
+ external-connection-point-ref: vnf-cp{{ z }}
+ {%- if detailed is sameas true %}
+ #internal-connection-point-ref: <update, optional>
+ #mac-address <update, optional>
+ #mgmt-interface: <update, optional>
+ {%- endif %}
+ {%- endfor %}
+ {%- endfor %}
+ {%- endif %}
+ connection-point:
+ - name: vnf-cp0
+ {%- for x in range(1, interfaces + 1 ) %}
+ - name: vnf-cp{{ x }}
+ {%- endfor %}
\ No newline at end of file
from osmclient.v1 import vca
from osmclient.v1 import utils
from osmclient.common import http
+from osmclient.common import package_tool
class Client(object):
**kwargs)
self.vca = vca.Vca(http_client, client=self, **kwargs)
self.utils = utils.Utils(http_client, **kwargs)
+ self.package_tool = package_tool.PackageTool(client=self)
@property
def so_rbac_project_path(self):
#
+# 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
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-#
from setuptools import setup, find_packages
setup(
packages=find_packages(),
include_package_data=True,
install_requires=[
- 'Click', 'prettytable', 'pyyaml', 'pycurl', 'python-magic'
+ 'Click', 'prettytable', 'pyyaml', 'pycurl', 'python-magic',
+ 'jinja2', 'osm-im'
+ ],
+ dependency_links=[
+ 'git+https://osm.etsi.org/gerrit/osm/IM.git#egg=osm-im',
],
setup_requires=['setuptools-version-command'],
test_suite='nose.collector',
--- /dev/null
+# Copyright 2019 ETSI OSM
+#
+# 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.
+
+nose
+mock
+git+https://osm.etsi.org/gerrit/osm/IM.git#egg=osm-im
\ No newline at end of file
+# Copyright 2019 ETSI OSM
+#
+# 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
#
[tox]
envlist = py27,py35,flake8,pyflakes
-toxworkdir={homedir}/.tox
+toxworkdir={toxinidir}/.tox
[testenv]
-deps = nose
- mock
-commands =
- nosetests
+deps = -r{toxinidir}/test-requirements.txt
+commands=nosetests
+install_command = python -m pip install -r test-requirements.txt -U {opts} {packages}
[testenv:flake8]
-basepython = python
+basepython = python3
deps = flake8
commands =
flake8 setup.py