self.datacenter_id = kwargs.get("datacenter_id")
self.datacenter_name = kwargs.get("datacenter_name")
self.datacenter = None
- self.logger = logging.getLogger('manoclient')
+ self.logger = logging.getLogger(kwargs.get('logger','manoclient'))
if kwargs.get("debug"):
self.logger.setLevel(logging.DEBUG)
Return: Raises an exception on error, not found, found several, not free
Obtain a dictionary with format {'result': text indicating deleted}
'''
- return self._del_item("datacenters", uuid, name, all_tenants=True)
+ if not uuid:
+ # check that exist
+ uuid = self._get_item_uuid("datacenters", uuid, name, all_tenants=True)
+ return self._del_item("datacenters", uuid, name, all_tenants=None)
def create_datacenter(self, descriptor=None, descriptor_format=None, name=None, vim_url=None, **kwargs):
#, type="openvim", public=False, description=None):
Return: Raises an exception on error
Obtain a dictionary with format {'tenant':{new_tenant_info}}
'''
- if item not in ("tenants", "networks"):
- raise OpenmanoBadParamsException("Unknown value for item '{}', must be 'tenants' or 'nets'".format(str(item)))
-
+ if item not in ("tenants", "networks", "images"):
+ raise OpenmanoBadParamsException("Unknown value for item '{}', must be 'tenants', 'nets' or "
+ "images".format(str(item)))
+
+ image_actions = ['list','get','show','delete']
+ if item == "images" and action not in image_actions:
+ raise OpenmanoBadParamsException("Only available actions for item '{}' are {}\n"
+ "Requested action was '{}'".format(item, ', '.join(image_actions), action))
if all_tenants:
tenant_text = "/any"
else:
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+schema_version: 2
+scenario:
+ name: vnf_additional_disk_empty_volume
+ description: Just deploy vnf_2_disks
+ public: false # if available for other tenants
+ vnfs:
+ vnf_2_disks: # vnf name in the scenario
+ #identify an already openmano uploaded VNF either by vnf_id (uuid, prefered) or vnf_name
+ #vnf_id: 0c0dcc20-c5d5-11e6-a9fb-fa163e2ae06e #prefered id method
+ vnf_name: vnf_additional_disk_empty_volume #can fail if several vnfs matches this name
+ #graph: {"y":399,"x":332,"ifaces":{"left":[["xe0","d"],["xe1","d"]],"bottom":[["eth0","v"],["eth1","m"]]}}
+ networks:
+ mgmt:
+ # Connections based on external networks (datacenter nets) must include the external network in the list of nodes
+ type: bridge
+ external: true #this will be connected outside
+ interfaces:
+ - vnf_2_disks: mgmt0
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+vnf:
+ name: vnf_additional_disk_empty_volume
+ description: VNF with additional volume based on image
+ # class: parent # Optional. Used to organize VNFs
+ external-connections:
+ - name: mgmt0
+ type: mgmt # "mgmt" (autoconnect to management net), "bridge", "data"
+ VNFC: TEMPLATE-VM # Virtual Machine this interface belongs to
+ local_iface_name: mgmt0 # interface name inside this Virtual Machine (must be defined in the VNFC section)
+ description: Management interface
+ VNFC: # Virtual machine array
+ - name: TEMPLATE-VM # name of Virtual Machine
+ description: TEMPLATE description
+ image name: ubuntu16.04
+ # image metadata: {"bus":"ide", "os_type":"windows", "use_incremental": "no" } #Optional
+ # processor: #Optional
+ # model: Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz
+ # features: ["64b", "iommu", "lps", "tlbps", "hwsv", "dioc", "ht"]
+ # hypervisor: #Optional
+ # type: QEMU-kvm
+ # version: "10002|12001|2.6.32-358.el6.x86_64"
+ vcpus: 1 # Only for traditional cloud VMs. Number of virtual CPUs (oversubscription is allowed).
+ ram: 1000 # Only for traditional cloud VMs. Memory in MBytes (not from hugepages, oversubscription is allowed)
+ disk: 5 # disk size in GiB, by default 1
+ #numas:
+ #- paired-threads: 5 # "cores", "paired-threads", "threads"
+ # paired-threads-id: [ [0,1], [2,3], [4,5], [6,7], [8,9] ] # By default follows incremental order
+ # memory: 14 # GBytes
+ # interfaces: []
+ bridge-ifaces:
+ - name: mgmt0
+ vpci: "0000:00:0a.0" # Optional. Virtual PCI address
+ bandwidth: 1 Mbps # Optional. Informative only
+ # mac_address: '20:33:45:56:77:46' #avoid this option if possible
+ # model: 'virtio' # ("virtio","e1000","ne2k_pci","pcnet","rtl8139") By default, it is automatically filled by libvirt
+ devices: # Optional, order determines device letter asignation (hda, hdb, ...)
+ - type: disk # "disk","cdrom","xml"
+ size: 1
+ # image metadata: {"bus":"ide", "os_type":"windows", "use_incremental": "no" }
+ # vpci: "0000:00:03.0" # Optional, not for disk or cdrom
+ # Additional Virtual Machines would be included here
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+schema_version: 2
+scenario:
+ name: vnf_floating_ip
+ description: vnf_floating_ip
+ public: false # if available for other tenants
+ vnfs:
+ vnf_floating_ip: # vnf name in the scenario
+ #identify an already openmano uploaded VNF either by vnf_id (uuid, prefered) or vnf_name
+ #vnf_id: 0c0dcc20-c5d5-11e6-a9fb-fa163e2ae06e #prefered id method
+ vnf_name: vnf_floating_ip #can fail if several vnfs matches this name
+ #graph: {"y":399,"x":332,"ifaces":{"left":[["xe0","d"],["xe1","d"]],"bottom":[["eth0","v"],["eth1","m"]]}}
+ networks:
+ mgmt:
+ # Connections based on external networks (datacenter nets) must include the external network in the list of nodes
+ type: bridge
+ external: true #this will be connected outside
+ interfaces:
+ - vnf_floating_ip: mgmt0
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+vnf:
+ name: vnf_floating_ip
+ description: VNF disabling port_security option in mgmt interface
+ # class: parent # Optional. Used to organize VNFs
+ external-connections:
+ - name: mgmt0
+ type: mgmt # "mgmt" (autoconnect to management net), "bridge", "data"
+ VNFC: vnf_floating_ip # Virtual Machine this interface belongs to
+ local_iface_name: mgmt0 # interface name inside this Virtual Machine (must be defined in the VNFC section)
+ description: Management interface
+ VNFC: # Virtual machine array
+ - name: vnf_floating_ip # name of Virtual Machine
+ description: vnf_floating_ip
+ image name: ubuntu16.04
+ # image metadata: {"bus":"ide", "os_type":"windows", "use_incremental": "no" } #Optional
+ # processor: #Optional
+ # model: Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz
+ # features: ["64b", "iommu", "lps", "tlbps", "hwsv", "dioc", "ht"]
+ # hypervisor: #Optional
+ # type: QEMU-kvm
+ # version: "10002|12001|2.6.32-358.el6.x86_64"
+ vcpus: 1 # Only for traditional cloud VMs. Number of virtual CPUs (oversubscription is allowed).
+ ram: 1000 # Only for traditional cloud VMs. Memory in MBytes (not from hugepages, oversubscription is allowed)
+ disk: 5 # disk size in GiB, by default 1
+ #numas:
+ #- paired-threads: 5 # "cores", "paired-threads", "threads"
+ # paired-threads-id: [ [0,1], [2,3], [4,5], [6,7], [8,9] ] # By default follows incremental order
+ # memory: 14 # GBytes
+ # interfaces: []
+ bridge-ifaces:
+ - name: mgmt0
+ vpci: "0000:00:0a.0" # Optional. Virtual PCI address
+ bandwidth: 1 Mbps # Optional. Informative only
+ floating-ip: True
+ # mac_address: '20:33:45:56:77:46' #avoid this option if possible
+ # model: 'virtio' # ("virtio","e1000","ne2k_pci","pcnet","rtl8139") By default, it is automatically filled by libvirt
+ # Additional Virtual Machines would be included here
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+schema_version: 2
+scenario:
+ name: vnf_additional_disk_based_image
+ description: Just deploy vnf_2_disks
+ public: false # if available for other tenants
+ vnfs:
+ vnf_2_disks: # vnf name in the scenario
+ #identify an already openmano uploaded VNF either by vnf_id (uuid, prefered) or vnf_name
+ #vnf_id: 0c0dcc20-c5d5-11e6-a9fb-fa163e2ae06e #prefered id method
+ vnf_name: vnf_additional_disk_based_image #can fail if several vnfs matches this name
+ #graph: {"y":399,"x":332,"ifaces":{"left":[["xe0","d"],["xe1","d"]],"bottom":[["eth0","v"],["eth1","m"]]}}
+ networks:
+ mgmt:
+ # Connections based on external networks (datacenter nets) must include the external network in the list of nodes
+ type: bridge
+ external: true #this will be connected outside
+ interfaces:
+ - vnf_2_disks: mgmt0
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+vnf:
+ name: vnf_additional_disk_based_image
+ description: VNF with additional volume based on image
+ # class: parent # Optional. Used to organize VNFs
+ external-connections:
+ - name: mgmt0
+ type: mgmt # "mgmt" (autoconnect to management net), "bridge", "data"
+ VNFC: TEMPLATE-VM # Virtual Machine this interface belongs to
+ local_iface_name: mgmt0 # interface name inside this Virtual Machine (must be defined in the VNFC section)
+ description: Management interface
+ VNFC: # Virtual machine array
+ - name: TEMPLATE-VM # name of Virtual Machine
+ description: TEMPLATE description
+ image name: image_name.qcow2
+ # image metadata: {"bus":"ide", "os_type":"windows", "use_incremental": "no" } #Optional
+ # processor: #Optional
+ # model: Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz
+ # features: ["64b", "iommu", "lps", "tlbps", "hwsv", "dioc", "ht"]
+ # hypervisor: #Optional
+ # type: QEMU-kvm
+ # version: "10002|12001|2.6.32-358.el6.x86_64"
+ vcpus: 1 # Only for traditional cloud VMs. Number of virtual CPUs (oversubscription is allowed).
+ ram: 1000 # Only for traditional cloud VMs. Memory in MBytes (not from hugepages, oversubscription is allowed)
+ disk: 5 # disk size in GiB, by default 1
+ #numas:
+ #- paired-threads: 5 # "cores", "paired-threads", "threads"
+ # paired-threads-id: [ [0,1], [2,3], [4,5], [6,7], [8,9] ] # By default follows incremental order
+ # memory: 14 # GBytes
+ # interfaces: []
+ bridge-ifaces:
+ - name: mgmt0
+ vpci: "0000:00:0a.0" # Optional. Virtual PCI address
+ bandwidth: 1 Mbps # Optional. Informative only
+ # mac_address: '20:33:45:56:77:46' #avoid this option if possible
+ # model: 'virtio' # ("virtio","e1000","ne2k_pci","pcnet","rtl8139") By default, it is automatically filled by libvirt
+ devices: # Optional, order determines device letter asignation (hda, hdb, ...)
+ - type: disk # "disk","cdrom","xml"
+ image name: image_name.qcow2
+ size: 2
+ # image metadata: {"bus":"ide", "os_type":"windows", "use_incremental": "no" }
+ # vpci: "0000:00:03.0" # Optional, not for disk or cdrom
+ # Additional Virtual Machines would be included here
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+schema_version: 2
+scenario:
+ name: vnf_no_port_security
+ description: vnf_no_port_security
+ public: false # if available for other tenants
+ vnfs:
+ vnf_no_port_security: # vnf name in the scenario
+ #identify an already openmano uploaded VNF either by vnf_id (uuid, prefered) or vnf_name
+ #vnf_id: 0c0dcc20-c5d5-11e6-a9fb-fa163e2ae06e #prefered id method
+ vnf_name: vnf_no_port_security #can fail if several vnfs matches this name
+ #graph: {"y":399,"x":332,"ifaces":{"left":[["xe0","d"],["xe1","d"]],"bottom":[["eth0","v"],["eth1","m"]]}}
+ networks:
+ mgmt:
+ # Connections based on external networks (datacenter nets) must include the external network in the list of nodes
+ type: bridge
+ external: true #this will be connected outside
+ interfaces:
+ - vnf_no_port_security: mgmt0
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+vnf:
+ name: vnf_no_port_security
+ description: VNF disabling port_security option in mgmt interface
+ # class: parent # Optional. Used to organize VNFs
+ external-connections:
+ - name: mgmt0
+ type: mgmt # "mgmt" (autoconnect to management net), "bridge", "data"
+ VNFC: vnf_no_port_security # Virtual Machine this interface belongs to
+ local_iface_name: mgmt0 # interface name inside this Virtual Machine (must be defined in the VNFC section)
+ description: Management interface
+ VNFC: # Virtual machine array
+ - name: vnf_no_port_security # name of Virtual Machine
+ description: vnf_no_port_security
+ image name: ubuntu16.04
+ # image metadata: {"bus":"ide", "os_type":"windows", "use_incremental": "no" } #Optional
+ # processor: #Optional
+ # model: Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz
+ # features: ["64b", "iommu", "lps", "tlbps", "hwsv", "dioc", "ht"]
+ # hypervisor: #Optional
+ # type: QEMU-kvm
+ # version: "10002|12001|2.6.32-358.el6.x86_64"
+ vcpus: 1 # Only for traditional cloud VMs. Number of virtual CPUs (oversubscription is allowed).
+ ram: 1000 # Only for traditional cloud VMs. Memory in MBytes (not from hugepages, oversubscription is allowed)
+ disk: 5 # disk size in GiB, by default 1
+ #numas:
+ #- paired-threads: 5 # "cores", "paired-threads", "threads"
+ # paired-threads-id: [ [0,1], [2,3], [4,5], [6,7], [8,9] ] # By default follows incremental order
+ # memory: 14 # GBytes
+ # interfaces: []
+ bridge-ifaces:
+ - name: mgmt0
+ vpci: "0000:00:0a.0" # Optional. Virtual PCI address
+ bandwidth: 1 Mbps # Optional. Informative only
+ port-security: False
+ # mac_address: '20:33:45:56:77:46' #avoid this option if possible
+ # model: 'virtio' # ("virtio","e1000","ne2k_pci","pcnet","rtl8139") By default, it is automatically filled by libvirt
+ # Additional Virtual Machines would be included here
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+schema_version: 2
+scenario:
+ name: simple-cloud-init
+ description: Simple network scenario consisting of a single VNF connected to an external network
+ vnfs:
+ linux1: # vnf/net name in the scenario
+ vnf_name: linux-cloud-init # VNF name as introduced in OPENMANO DB
+ networks:
+ mgmt: # provide a name for this net or connection
+ external: true
+ interfaces:
+ - linux1: eth0 # Node and its interface
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+---
+schema_version: "0.2"
+vnf:
+ name: linux-cloud-init
+ description: Single-VM VNF with a traditional cloud VM based on generic Linux OS
+ external-connections:
+ - name: eth0
+ type: mgmt
+ description: General purpose interface
+ VNFC: linux-VM
+ local_iface_name: eth0
+ VNFC:
+ - name: linux-VM
+ description: Generic Linux Virtual Machine
+ #Copy the image to a compute path and edit this path
+ image name: ubuntu16.04
+ vcpus: 1 # Only for traditional cloud VMs. Number of virtual CPUs (oversubscription is allowed).
+ ram: 2048 # Only for traditional cloud VMs. Memory in MBytes (not from hugepages, oversubscription is allowed)
+ disk: 20
+ bridge-ifaces:
+ - name: eth0
+ vpci: "0000:00:11.0"
+ numas: []
+ boot-data:
+ key-pairs:
+ - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCy2w9GHMKKNkpCmrDK2ovc3XBYDETuLWwaW24S+feHhLBQiZlzh3gSQoINlA+2ycM9zYbxl4BGzEzpTVyCQFZv5PidG4m6ox7LR+KYkDcITMyjsVuQJKDvt6oZvRt6KbChcCi0n2JJD/oUiJbBFagDBlRslbaFI2mmqmhLlJ5TLDtmYxzBLpjuX4m4tv+pdmQVfg7DYHsoy0hllhjtcDlt1nn05WgWYRTu7mfQTWfVTavu+OjIX3e0WN6NW7yIBWZcE/Q9lC0II3W7PZDE3QaT55se4SPIO2JTdqsx6XGbekdG1n6adlduOI27sOU5m4doiyJ8554yVbuDB/z5lRBD alfonso.tiernosepulveda@telefonica.com
+ users:
+ - name: atierno
+ key-pairs:
+ - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCy2w9GHMKKNkpCmrDK2ovc3XBYDETuLWwaW24S+feHhLBQiZlzh3gSQoINlA+2ycM9zYbxl4BGzEzpTVyCQFZv5PidG4m6ox7LR+KYkDcITMyjsVuQJKDvt6oZvRt6KbChcCi0n2JJD/oUiJbBFagDBlRslbaFI2mmqmhLlJ5TLDtmYxzBLpjuX4m4tv+pdmQVfg7DYHsoy0hllhjtcDlt1nn05WgWYRTu7mfQTWfVTavu+OjIX3e0WN6NW7yIBWZcE/Q9lC0II3W7PZDE3QaT55se4SPIO2JTdqsx6XGbekdG1n6adlduOI27sOU5m4doiyJ8554yVbuDB/z5lRBD alfonso.tiernosepulveda@telefonica.com
+ boot-data-drive: true
+ config-files:
+ - content: |
+ auto enp0s3
+ iface enp0s3 inet dhcp
+ dest: /etc/network/interfaces.d/enp0s3.cfg
+ permissions: '0644'
+ owner: root:root
+ - content: |
+ #! /bin/bash
+ ls -al >> /var/log/osm.log
+ dest: /etc/rc.local
+ permissions: '0755'
+ - content: "file content"
+ dest: /etc/test_delete
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+schema_version: 2
+scenario:
+ name: simple
+ description: Simple network scenario consisting of a single VNF connected to an external network
+ vnfs:
+ linux1: # vnf/net name in the scenario
+ vnf_name: linux # VNF name as introduced in OPENMANO DB
+ networks:
+ mgmt: # provide a name for this net or connection
+ external: true
+ interfaces:
+ - linux1: eth0 # Node and its interface
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+vnf:
+ name: linux
+ description: Single-VM VNF with a traditional cloud VM based on generic Linux OS
+ external-connections:
+ - name: eth0
+ type: bridge
+ VNFC: linux-VM
+ local_iface_name: eth0
+ description: General purpose interface
+ VNFC:
+ - name: linux-VM
+ description: Generic Linux Virtual Machine
+ #Copy the image to a compute path and edit this path
+ image name: image_name.qcow2
+ vcpus: 1 # Only for traditional cloud VMs. Number of virtual CPUs (oversubscription is allowed).
+ ram: 1024 # Only for traditional cloud VMs. Memory in MBytes (not from hugepages, oversubscription is allowed)
+ disk: 10
+ bridge-ifaces:
+ - name: eth0
+ vpci: "0000:00:11.0"
+ numas: []
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+schema_version: 2
+scenario:
+ name: simple_multi_vnfc
+ description: Simple network scenario consisting of a multi VNFC VNF connected to an external network
+ vnfs:
+ linux1: # vnf/net name in the scenario
+ vnf_name: linux_2VMs_v02 # VNF name as introduced in OPENMANO DB
+ networks:
+ mgmt: # provide a name for this net or connection
+ external: true
+ interfaces:
+ - linux1: control0 # Node and its interface
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+schema_version: "0.2"
+vnf:
+ name: linux_2VMs_v02
+ description: "Example of a linux VNF consisting of two VMs with one internal network"
+ # class: parent # Optional. Used to organize VNFs
+ internal-connections:
+ - name: internalnet
+ description: internalnet
+ type: e-lan
+ implementation: overlay
+ ip-profile:
+ ip-version: IPv4
+ subnet-address: 192.168.1.0/24
+ gateway-address: 192.168.1.1
+ dns-address: 8.8.8.8
+ dhcp:
+ enabled: true
+ start-address: 192.168.1.100
+ count: 100
+ elements:
+ - VNFC: linux_2VMs-VM1
+ local_iface_name: xe0
+ ip_address: 192.168.1.2
+ - VNFC: linux_2VMs-VM2
+ local_iface_name: xe0
+ ip_address: 192.168.1.3
+ external-connections:
+ - name: control0
+ type: mgmt
+ VNFC: linux_2VMs-VM1
+ local_iface_name: eth0
+ description: control interface VM1
+ - name: control1
+ type: mgmt
+ VNFC: linux_2VMs-VM2
+ local_iface_name: eth0
+ description: control interface VM2
+ - name: in
+ type: bridge
+ VNFC: linux_2VMs-VM1
+ local_iface_name: xe1
+ description: data interface input
+ - name: out
+ type: bridge
+ VNFC: linux_2VMs-VM2
+ local_iface_name: xe1
+ description: data interface output
+ VNFC:
+ - name: linux_2VMs-VM1
+ description: "Linux VM1 with 4 CPUs, 2 GB RAM and 3 bridge interfaces"
+ #Copy the image to a compute path and edit this path
+ image name: TestVM
+ disk: 10
+ vcpus: 4
+ ram: 2048
+ bridge-ifaces:
+ - name: eth0
+ vpci: "0000:00:09.0"
+ bandwidth: 1 Mbps # Optional, informative only
+ - name: xe0
+ vpci: "0000:00:11.0"
+ bandwidth: 1 Mbps
+ - name: xe1
+ vpci: "0000:00:12.0"
+ bandwidth: 1 Mbps
+ - name: linux_2VMs-VM2
+ description: "Linux VM2 with 2 CPUs, 2 GB RAM and 3 bridge interfaces"
+ #Copy the image to a compute path and edit this path
+ image name: TestVM
+ disk: 10
+ vcpus: 2
+ ram: 2048
+ bridge-ifaces:
+ - name: eth0
+ vpci: "0000:00:09.0"
+ bandwidth: 1 Mbps # Optional, informative only
+ - name: xe0
+ vpci: "0000:00:11.0"
+ bandwidth: 1 Mbps
+ - name: xe1
+ vpci: "0000:00:12.0"
+ bandwidth: 1 Mbps
+
--- /dev/null
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+'''
+Module for testing openmano functionality. It uses openmanoclient.py for invoking openmano
+'''
+__author__="Pablo Montes"
+__date__ ="$16-Feb-2017 17:08:16$"
+__version__="0.0.1"
+version_date="Feb 2017"
+
+import logging
+import imp
+import os
+from optparse import OptionParser
+import unittest
+import string
+import inspect
+import random
+import traceback
+import glob
+import yaml
+import sys
+import time
+
+global test_number
+global test_directory
+global scenario_test_folder
+global test_image_name
+global management_network
+
+'''
+IMPORTANT NOTE
+All unittest classes for code based tests must have prefix 'test_' in order to be taken into account for tests
+'''
+class test_tenant_operations(unittest.TestCase):
+ test_index = 1
+ tenant_name = None
+ test_text = None
+
+ @classmethod
+ def setUpClass(cls):
+ logger.info("{}. {}".format(test_number, cls.__name__))
+
+ @classmethod
+ def tearDownClass(cls):
+ globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+
+ def tearDown(self):
+ exec_info = sys.exc_info()
+ if exec_info == (None, None, None):
+ logger.info(self.__class__.test_text+" -> TEST OK")
+ else:
+ logger.warning(self.__class__.test_text+" -> TEST NOK")
+ error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
+ msg = ""
+ for line in error_trace:
+ msg = msg + line
+ logger.critical("{}".format(msg))
+
+ def test_000_create_RO_tenant(self):
+ self.__class__.tenant_name = _get_random_string(20)
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+ self.__class__.test_index += 1
+ tenant = client.create_tenant(name=self.__class__.tenant_name, description=self.__class__.tenant_name)
+ logger.debug("{}".format(tenant))
+ self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.tenant_name)
+
+ def test_010_list_RO_tenant(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+ self.__class__.test_index += 1
+ tenant = client.get_tenant(name=self.__class__.tenant_name)
+ logger.debug("{}".format(tenant))
+ self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.tenant_name)
+
+ def test_020_delete_RO_tenant(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+ self.__class__.test_index += 1
+ tenant = client.delete_tenant(name=self.__class__.tenant_name)
+ logger.debug("{}".format(tenant))
+ assert('deleted' in tenant.get('result',""))
+
+class test_datacenter_operations(unittest.TestCase):
+ test_index = 1
+ datacenter_name = None
+ test_text = None
+
+ @classmethod
+ def setUpClass(cls):
+ logger.info("{}. {}".format(test_number, cls.__name__))
+
+ @classmethod
+ def tearDownClass(cls):
+ globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+
+ def tearDown(self):
+ exec_info = sys.exc_info()
+ if exec_info == (None, None, None):
+ logger.info(self.__class__.test_text+" -> TEST OK")
+ else:
+ logger.warning(self.__class__.test_text+" -> TEST NOK")
+ error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
+ msg = ""
+ for line in error_trace:
+ msg = msg + line
+ logger.critical("{}".format(msg))
+
+ def test_000_create_datacenter(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+ self.__class__.datacenter_name = _get_random_string(20)
+ self.__class__.test_index += 1
+ self.datacenter = client.create_datacenter(name=self.__class__.datacenter_name, vim_url="http://fakeurl/fake")
+ logger.debug("{}".format(self.datacenter))
+ self.assertEqual (self.datacenter.get('datacenter', {}).get('name',''), self.__class__.datacenter_name)
+
+ def test_010_list_datacenter(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+
+ self.__class__.test_index += 1
+ self.datacenter = client.get_datacenter(all_tenants=True, name=self.__class__.datacenter_name)
+ logger.debug("{}".format(self.datacenter))
+ self.assertEqual (self.datacenter.get('datacenter', {}).get('name', ''), self.__class__.datacenter_name)
+
+ def test_020_attach_datacenter(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+
+ self.__class__.test_index += 1
+ self.datacenter = client.attach_datacenter(name=self.__class__.datacenter_name, vim_tenant_name='fake')
+ logger.debug("{}".format(self.datacenter))
+ assert ('vim_tenants' in self.datacenter.get('datacenter', {}))
+
+ def test_030_list_attached_datacenter(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+
+ self.__class__.test_index += 1
+ self.datacenter = client.get_datacenter(all_tenants=False, name=self.__class__.datacenter_name)
+ logger.debug("{}".format(self.datacenter))
+ self.assertEqual (self.datacenter.get('datacenter', {}).get('name', ''), self.__class__.datacenter_name)
+
+ def test_040_detach_datacenter(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+
+ self.__class__.test_index += 1
+ self.datacenter = client.detach_datacenter(name=self.__class__.datacenter_name)
+ logger.debug("{}".format(self.datacenter))
+ assert ('detached' in self.datacenter.get('result', ""))
+
+ def test_050_delete_datacenter(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+
+ self.__class__.test_index += 1
+ self.datacenter = client.delete_datacenter(name=self.__class__.datacenter_name)
+ logger.debug("{}".format(self.datacenter))
+ assert('deleted' in self.datacenter.get('result',""))
+
+class test_VIM_network_operations(unittest.TestCase):
+ test_index = 1
+ vim_network_name = None
+ test_text = None
+ vim_network_uuid = None
+
+ @classmethod
+ def setUpClass(cls):
+ logger.info("{}. {}".format(test_number, cls.__name__))
+
+ @classmethod
+ def tearDownClass(cls):
+ globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+
+ def tearDown(self):
+ exec_info = sys.exc_info()
+ if exec_info == (None, None, None):
+ logger.info(self.__class__.test_text + " -> TEST OK")
+ else:
+ logger.warning(self.__class__.test_text + " -> TEST NOK")
+ error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
+ msg = ""
+ for line in error_trace:
+ msg = msg + line
+ logger.critical("{}".format(msg))
+
+ def test_000_create_VIM_network(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+ self.__class__.vim_network_name = _get_random_string(20)
+ self.__class__.test_index += 1
+ network = client.vim_action("create", "networks", name=self.__class__.vim_network_name)
+ logger.debug("{}".format(network))
+ self.__class__.vim_network_uuid = network["network"]["id"]
+ self.assertEqual(network.get('network', {}).get('name', ''), self.__class__.vim_network_name)
+
+ def test_010_list_VIM_networks(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+ self.__class__.test_index += 1
+ networks = client.vim_action("list", "networks")
+ logger.debug("{}".format(networks))
+
+ def test_020_get_VIM_network_by_uuid(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+
+ self.__class__.test_index += 1
+ network = client.vim_action("show", "networks", uuid=self.__class__.vim_network_uuid)
+ logger.debug("{}".format(network))
+ self.assertEqual(network.get('network', {}).get('name', ''), self.__class__.vim_network_name)
+
+ def test_030_delete_VIM_network_by_uuid(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+
+ self.__class__.test_index += 1
+ network = client.vim_action("delete", "networks", uuid=self.__class__.vim_network_uuid)
+ logger.debug("{}".format(network))
+ assert ('deleted' in network.get('result', ""))
+
+class test_VIM_image_operations(unittest.TestCase):
+ test_index = 1
+ test_text = None
+
+ @classmethod
+ def setUpClass(cls):
+ logger.info("{}. {}".format(test_number, cls.__name__))
+
+ @classmethod
+ def tearDownClass(cls):
+ globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+
+ def tearDown(self):
+ exec_info = sys.exc_info()
+ if exec_info == (None, None, None):
+ logger.info(self.__class__.test_text + " -> TEST OK")
+ else:
+ logger.warning(self.__class__.test_text + " -> TEST NOK")
+ error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
+ msg = ""
+ for line in error_trace:
+ msg = msg + line
+ logger.critical("{}".format(msg))
+
+ def test_000_list_VIM_images(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+ self.__class__.test_index += 1
+ images = client.vim_action("list", "images")
+ logger.debug("{}".format(images))
+
+'''
+The following is a non critical test that will fail most of the times.
+In case of OpenStack datacenter these tests will only success if RO has access to the admin endpoint
+This test will only be executed in case it is specifically requested by the user
+'''
+class test_VIM_tenant_operations(unittest.TestCase):
+ test_index = 1
+ vim_tenant_name = None
+ test_text = None
+ vim_tenant_uuid = None
+
+ @classmethod
+ def setUpClass(cls):
+ logger.info("{}. {}".format(test_number, cls.__name__))
+ logger.warning("In case of OpenStack datacenter these tests will only success "
+ "if RO has access to the admin endpoint")
+
+ @classmethod
+ def tearDownClass(cls):
+ globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+
+ def tearDown(self):
+ exec_info = sys.exc_info()
+ if exec_info == (None, None, None):
+ logger.info(self.__class__.test_text + " -> TEST OK")
+ else:
+ logger.warning(self.__class__.test_text + " -> TEST NOK")
+ error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
+ msg = ""
+ for line in error_trace:
+ msg = msg + line
+ logger.critical("{}".format(msg))
+
+ def test_000_create_VIM_tenant(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+ self.__class__.vim_tenant_name = _get_random_string(20)
+ self.__class__.test_index += 1
+ tenant = client.vim_action("create", "tenants", name=self.__class__.vim_tenant_name)
+ logger.debug("{}".format(tenant))
+ self.__class__.vim_tenant_uuid = tenant["tenant"]["id"]
+ self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.vim_tenant_name)
+
+ def test_010_list_VIM_tenants(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+ self.__class__.test_index += 1
+ tenants = client.vim_action("list", "tenants")
+ logger.debug("{}".format(tenants))
+
+ def test_020_get_VIM_tenant_by_uuid(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+
+ self.__class__.test_index += 1
+ tenant = client.vim_action("show", "tenants", uuid=self.__class__.vim_tenant_uuid)
+ logger.debug("{}".format(tenant))
+ self.assertEqual(tenant.get('tenant', {}).get('name', ''), self.__class__.vim_tenant_name)
+
+ def test_030_delete_VIM_tenant_by_uuid(self):
+ self.__class__.test_text = "{}.{}. TEST {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name)
+
+ self.__class__.test_index += 1
+ tenant = client.vim_action("delete", "tenants", uuid=self.__class__.vim_tenant_uuid)
+ logger.debug("{}".format(tenant))
+ assert ('deleted' in tenant.get('result', ""))
+
+'''
+IMPORTANT NOTE
+The following unittest class does not have the 'test_' on purpose. This test is the one used for the
+scenario based tests.
+'''
+class descriptor_based_scenario_test(unittest.TestCase):
+ test_index = 0
+ test_text = None
+ scenario_test_path = None
+ scenario_uuid = None
+ instance_scenario_uuid = None
+ to_delete_list = []
+
+ @classmethod
+ def setUpClass(cls):
+ cls.test_index = 1
+ cls.to_delete_list = []
+ cls.scenario_test_path = test_directory + '/' + scenario_test_folder
+ logger.info("{}. {} {}".format(test_number, cls.__name__, scenario_test_folder))
+
+ @classmethod
+ def tearDownClass(cls):
+ globals().__setitem__('test_number', globals().__getitem__('test_number') + 1)
+
+ def tearDown(self):
+ exec_info = sys.exc_info()
+ if exec_info == (None, None, None):
+ logger.info(self.__class__.test_text + " -> TEST OK")
+ else:
+ logger.warning(self.__class__.test_text + " -> TEST NOK")
+ error_trace = traceback.format_exception(exec_info[0], exec_info[1], exec_info[2])
+ msg = ""
+ for line in error_trace:
+ msg = msg + line
+ logger.critical("{}".format(msg))
+
+
+ def test_000_load_scenario(self):
+ self.__class__.test_text = "{}.{}. TEST {} {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name,
+ scenario_test_folder)
+ self.__class__.test_index += 1
+ vnfd_files = glob.glob(self.__class__.scenario_test_path+'/vnfd_*.yaml')
+ scenario_file = glob.glob(self.__class__.scenario_test_path + '/scenario_*.yaml')
+ if len(vnfd_files) == 0 or len(scenario_file) > 1:
+ raise Exception('Test '+scenario_test_folder+' not valid. It must contain an scenario file and at least one'
+ ' vnfd file')
+
+ #load all vnfd
+ for vnfd in vnfd_files:
+ with open(vnfd, 'r') as stream:
+ vnf_descriptor = yaml.load(stream)
+
+ vnfc_list = vnf_descriptor['vnf']['VNFC']
+ for vnfc in vnfc_list:
+ vnfc['image name'] = test_image_name
+ devices = vnfc.get('devices',[])
+ for device in devices:
+ if device['type'] == 'disk' and 'image name' in device:
+ device['image name'] = test_image_name
+
+ logger.debug("VNF descriptor: {}".format(vnf_descriptor))
+ vnf = client.create_vnf(descriptor=vnf_descriptor)
+ logger.debug(vnf)
+ self.__class__.to_delete_list.insert(0, {"item": "vnf", "function": client.delete_vnf,
+ "params": {"uuid": vnf['vnf']['uuid']}})
+
+ #load the scenario definition
+ with open(scenario_file[0], 'r') as stream:
+ scenario_descriptor = yaml.load(stream)
+ networks = scenario_descriptor['scenario']['networks']
+ networks[management_network] = networks.pop('mgmt')
+ logger.debug("Scenario descriptor: {}".format(scenario_descriptor))
+ scenario = client.create_scenario(descriptor=scenario_descriptor)
+ logger.debug(scenario)
+ self.__class__.to_delete_list.insert(0,{"item": "scenario", "function": client.delete_scenario,
+ "params":{"uuid": scenario['scenario']['uuid']} })
+ self.__class__.scenario_uuid = scenario['scenario']['uuid']
+
+ def test_010_instantiate_scenario(self):
+ self.__class__.test_text = "{}.{}. TEST {} {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name,
+ scenario_test_folder)
+ self.__class__.test_index += 1
+
+ instance = client.create_instance(scenario_id=self.__class__.scenario_uuid, name=self.__class__.test_text)
+ logger.debug(instance)
+ self.__class__.to_delete_list.insert(0, {"item": "instance", "function": client.delete_instance,
+ "params": {"uuid": instance['uuid']}})
+
+ def test_020_clean_deployment(self):
+ self.__class__.test_text = "{}.{}. TEST {} {}".format(test_number, self.__class__.test_index,
+ inspect.currentframe().f_code.co_name,
+ scenario_test_folder)
+ self.__class__.test_index += 1
+ #At the moment if you delete an scenario right after creating it, in openstack datacenters
+ #sometimes scenario ports get orphaned. This sleep is just a dirty workaround
+ time.sleep(5)
+ for item in self.__class__.to_delete_list:
+ response = item["function"](**item["params"])
+ logger.debug(response)
+
+def _get_random_string(maxLength):
+ '''generates a string with random characters string.letters and string.digits
+ with a random length up to maxLength characters. If maxLength is <15 it will be changed automatically to 15
+ '''
+ prefix = 'testing_'
+ min_string = 15
+ minLength = min_string - len(prefix)
+ if maxLength < min_string: maxLength = min_string
+ maxLength -= len(prefix)
+ length = random.randint(minLength,maxLength)
+ return 'testing_'+"".join([random.choice(string.letters+string.digits) for i in xrange(length)])
+
+if __name__=="__main__":
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+ import openmanoclient
+
+ parser = OptionParser()
+
+ #Optional arguments
+ parser.add_option("-v",'--version', help='Show current version', dest='version', action="store_true", default=False)
+ parser.add_option('--debug', help='Set logs to debug level', dest='debug', action="store_true", default=False)
+ parser.add_option('--failed', help='Set logs to show only failed tests. --debug disables this option',
+ dest='failed', action="store_true", default=False)
+ parser.add_option('-u', '--url', dest='endpoint_url', help='Set the openmano server url. By default '
+ 'http://localhost:9090/openmano',
+ default='http://localhost:9090/openmano')
+ default_logger_file = os.path.dirname(__file__)+'/'+os.path.splitext(os.path.basename(__file__))[0]+'.log'
+ parser.add_option('--logger_file', dest='logger_file', help='Set the logger file. By default '+default_logger_file,
+ default=default_logger_file)
+ parser.add_option('--list-tests', help='List all available tests', dest='list-tests', action="store_true",
+ default=False)
+ parser.add_option('--test', '--tests', help='Specify the tests to run', dest='tests', default=None)
+
+ #Mandatory arguments
+ parser.add_option("-t", '--tenant', dest='tenant_name', help='MANDATORY. Set the tenant name to test')
+ parser.add_option('-d', '--datacenter', dest='datacenter_name', help='MANDATORY, Set the datacenter name to test')
+ parser.add_option("-i", '--image-name', dest='image-name', help='MANDATORY. Image name of an Ubuntu 16.04 image '
+ 'that will be used for testing available in the '
+ 'datacenter.')
+ parser.add_option("-n", '--mgmt-net-name', dest='mgmt-net', help='MANDATORY. Set the tenant name to test')
+
+ (options, args) = parser.parse_args()
+
+ # default logger level is INFO. Options --debug and --failed override this, being --debug prioritary
+ logger_level = 'INFO'
+ if options.__dict__['debug']:
+ logger_level = 'DEBUG'
+ elif options.__dict__['failed']:
+ logger_level = 'WARNING'
+ logger_name = os.path.basename(__file__)
+ logger = logging.getLogger(logger_name)
+ logger.setLevel(logger_level)
+
+ # Configure a logging handler to store in a logging file
+ fileHandler = logging.FileHandler(options.__dict__['logger_file'])
+ formatter_fileHandler = logging.Formatter('%(asctime)s %(name)s %(levelname)s: %(message)s')
+ fileHandler.setFormatter(formatter_fileHandler)
+ logger.addHandler(fileHandler)
+
+ # Configure a handler to print to stdout
+ consoleHandler = logging.StreamHandler(sys.stdout)
+ formatter_consoleHandler = logging.Formatter('%(message)s')
+ consoleHandler.setFormatter(formatter_consoleHandler)
+ logger.addHandler(consoleHandler)
+
+ logger.debug('Program started with the following arguments: ' + str(options.__dict__))
+
+ #If version is required print it and exit
+ if options.__dict__['version']:
+ logger.info("{}".format((sys.argv[0], __version__+" version", version_date)))
+ logger.info ("(c) Copyright Telefonica")
+ sys.exit(0)
+
+ test_directory = os.path.dirname(__file__) + "/RO_tests"
+ test_directory_content = os.listdir(test_directory)
+ clsmembers = inspect.getmembers(sys.modules[__name__], inspect.isclass)
+
+ # If only want to obtain a tests list print it and exit
+ if options.__dict__['list-tests']:
+ tests_names = []
+ for cls in clsmembers:
+ if cls[0].startswith('test_'):
+ tests_names.append(cls[0])
+
+ msg = "The code based tests are:\n\t" + ', '.join(sorted(tests_names))+'\n'+\
+ "The descriptor based tests are:\n\t"+ ', '.join(sorted(test_directory_content))+'\n'+\
+ "NOTE: The test test_VIM_tenant_operations will fail in case the used datacenter is type OpenStack " \
+ "unless RO has access to the admin endpoint. Therefore this test is excluded by default"
+
+ logger.info(msg)
+ sys.exit(0)
+
+ #Make sure required arguments are present
+ required = "tenant_name datacenter_name image-name mgmt-net".split()
+ error = False
+ for r in required:
+ if options.__dict__[r] is None:
+ print "ERROR: parameter "+r+" is required"
+ error = True
+ if error:
+ parser.print_help()
+ sys.exit(1)
+
+ # set test image name and management network
+ test_image_name = options.__dict__['image-name']
+ management_network = options.__dict__['mgmt-net']
+
+ #Create the list of tests to be run
+ descriptor_based_tests = []
+ code_based_tests = []
+ if options.__dict__['tests'] != None:
+ tests = sorted(options.__dict__['tests'].split(','))
+ for test in tests:
+ matches_code_based_tests = [item for item in clsmembers if item[0] == test]
+ if test in test_directory_content:
+ descriptor_based_tests.append(test)
+ elif len(matches_code_based_tests) > 0:
+ code_based_tests.append(matches_code_based_tests[0][1])
+ else:
+ logger.critical("Test {} is not among the possible ones".format(test))
+ sys.exit(1)
+ else:
+ #include all tests
+ descriptor_based_tests = test_directory_content
+ for cls in clsmembers:
+ #We exclude 'test_VIM_tenant_operations' unless it is specifically requested by the user
+ if cls[0].startswith('test_') and cls[0] != 'test_VIM_tenant_operations':
+ code_based_tests.append(cls[1])
+
+ logger.debug("descriptor_based_tests to be executed: {}".format(descriptor_based_tests))
+ logger.debug("code_based_tests to be executed: {}".format(code_based_tests))
+
+ # import openmanoclient from relative path
+ client = openmanoclient.openmanoclient(
+ endpoint_url=options.__dict__['endpoint_url'],
+ tenant_name=options.__dict__['tenant_name'],
+ datacenter_name = options.__dict__['datacenter_name'],
+ debug = options.__dict__['debug'], logger = logger_name)
+
+ # TextTestRunner stream is set to /dev/null in order to avoid the method to directly print the result of tests.
+ # This is handled in the tests using logging.
+ stream = open('/dev/null', 'w')
+ test_number=1
+ executed = 0
+ failed = 0
+
+ #Run code based tests
+ basic_tests_suite = unittest.TestSuite()
+ for test in code_based_tests:
+ basic_tests_suite.addTest(unittest.makeSuite(test))
+ result = unittest.TextTestRunner(stream=stream).run(basic_tests_suite)
+ executed += result.testsRun
+ failed += len(result.failures) + len(result.errors)
+ if len(result.failures) > 0:
+ logger.debug("failures : {}".format(result.failures))
+ if len(result.errors) > 0:
+ logger.debug("errors : {}".format(result.errors))
+
+ # Additionally to the previous tests, scenario based tests will be executed.
+ # This scenario based tests are defined as directories inside the directory defined in 'test_directory'
+ for test in descriptor_based_tests:
+ scenario_test_folder = test
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(unittest.makeSuite(descriptor_based_scenario_test))
+ result = unittest.TextTestRunner(stream=stream).run(test_suite)
+ executed += result.testsRun
+ failed += len(result.failures) + len(result.errors)
+ if len(result.failures) > 0:
+ logger.debug("failures : {}".format(result.failures))
+ if len(result.errors) > 0:
+ logger.debug("errors : {}".format(result.errors))
+
+ #Log summary
+ logger.warning("Total number of tests: {}; Total number of failures/errors: {}".format(executed, failed))
+
+ sys.exit(0)
\ No newline at end of file