Implemented basic test for RO. It runs basic RO functionality tests as well as scenar... 92/1192/2
authorPablo Montes Moreno <pablo.montesmoreno@telefonica.com>
Mon, 27 Feb 2017 11:33:10 +0000 (12:33 +0100)
committerPablo Montes Moreno <pablo.montesmoreno@telefonica.com>
Mon, 27 Feb 2017 14:48:36 +0000 (15:48 +0100)
Change-Id: I3217da96e1ae7e42942b6f5a4e127fab7ed25635
Signed-off-by: Pablo Montes Moreno <pablo.montesmoreno@telefonica.com>
16 files changed:
openmanoclient.py
test/RO_tests/empy_volume/scenario_additional_disk_empty_volume.yaml [new file with mode: 0644]
test/RO_tests/empy_volume/vnfd_additional_disk_empty_volume.yaml [new file with mode: 0644]
test/RO_tests/floating_ip/scenario_floating_ip.yaml [new file with mode: 0644]
test/RO_tests/floating_ip/vnfd_floating_ip.yaml [new file with mode: 0644]
test/RO_tests/image_based_volume/scenario_additional_disk_based_image.yaml [new file with mode: 0644]
test/RO_tests/image_based_volume/vnfd_additional_disk_based_image.yaml [new file with mode: 0644]
test/RO_tests/no_port_security/scenario_vnf_no_port_security.yaml [new file with mode: 0644]
test/RO_tests/no_port_security/vnfd_no_port_security.yaml [new file with mode: 0644]
test/RO_tests/simple_cloud_init/scenario_simple-cloud-init.yaml [new file with mode: 0644]
test/RO_tests/simple_cloud_init/vnfd_linux-cloud-init.yaml [new file with mode: 0644]
test/RO_tests/simple_linux/scenario_simple_linux.yaml [new file with mode: 0644]
test/RO_tests/simple_linux/vnfd_linux.yaml [new file with mode: 0644]
test/RO_tests/simple_multi_vnfc/scenario_multi_vnfc.yaml [new file with mode: 0644]
test/RO_tests/simple_multi_vnfc/vnfd_linux_2VMs_v02.yaml [new file with mode: 0644]
test/test_RO.py [new file with mode: 0755]

index 0d9aa4a..c11f747 100644 (file)
@@ -74,7 +74,7 @@ class openmanoclient():
         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)
         
@@ -424,7 +424,10 @@ class openmanoclient():
         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):
@@ -832,9 +835,14 @@ class openmanoclient():
         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:
diff --git a/test/RO_tests/empy_volume/scenario_additional_disk_empty_volume.yaml b/test/RO_tests/empy_volume/scenario_additional_disk_empty_volume.yaml
new file mode 100644 (file)
index 0000000..61f5f38
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# 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
+
diff --git a/test/RO_tests/empy_volume/vnfd_additional_disk_empty_volume.yaml b/test/RO_tests/empy_volume/vnfd_additional_disk_empty_volume.yaml
new file mode 100644 (file)
index 0000000..0e0f3eb
--- /dev/null
@@ -0,0 +1,63 @@
+##
+# 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
+
diff --git a/test/RO_tests/floating_ip/scenario_floating_ip.yaml b/test/RO_tests/floating_ip/scenario_floating_ip.yaml
new file mode 100644 (file)
index 0000000..4847050
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# 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
+
diff --git a/test/RO_tests/floating_ip/vnfd_floating_ip.yaml b/test/RO_tests/floating_ip/vnfd_floating_ip.yaml
new file mode 100644 (file)
index 0000000..47c73ba
--- /dev/null
@@ -0,0 +1,59 @@
+##
+# 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
+
diff --git a/test/RO_tests/image_based_volume/scenario_additional_disk_based_image.yaml b/test/RO_tests/image_based_volume/scenario_additional_disk_based_image.yaml
new file mode 100644 (file)
index 0000000..20f28cb
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# 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
+
diff --git a/test/RO_tests/image_based_volume/vnfd_additional_disk_based_image.yaml b/test/RO_tests/image_based_volume/vnfd_additional_disk_based_image.yaml
new file mode 100644 (file)
index 0000000..5789831
--- /dev/null
@@ -0,0 +1,64 @@
+##
+# 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
+
diff --git a/test/RO_tests/no_port_security/scenario_vnf_no_port_security.yaml b/test/RO_tests/no_port_security/scenario_vnf_no_port_security.yaml
new file mode 100644 (file)
index 0000000..07c85ab
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# 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
+
diff --git a/test/RO_tests/no_port_security/vnfd_no_port_security.yaml b/test/RO_tests/no_port_security/vnfd_no_port_security.yaml
new file mode 100644 (file)
index 0000000..4815298
--- /dev/null
@@ -0,0 +1,59 @@
+##
+# 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
+
diff --git a/test/RO_tests/simple_cloud_init/scenario_simple-cloud-init.yaml b/test/RO_tests/simple_cloud_init/scenario_simple-cloud-init.yaml
new file mode 100644 (file)
index 0000000..18ed3e9
--- /dev/null
@@ -0,0 +1,34 @@
+##
+# 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
+
diff --git a/test/RO_tests/simple_cloud_init/vnfd_linux-cloud-init.yaml b/test/RO_tests/simple_cloud_init/vnfd_linux-cloud-init.yaml
new file mode 100644 (file)
index 0000000..92e14fb
--- /dev/null
@@ -0,0 +1,67 @@
+##
+# 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
+
diff --git a/test/RO_tests/simple_linux/scenario_simple_linux.yaml b/test/RO_tests/simple_linux/scenario_simple_linux.yaml
new file mode 100644 (file)
index 0000000..a7c2087
--- /dev/null
@@ -0,0 +1,34 @@
+##
+# 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
+
diff --git a/test/RO_tests/simple_linux/vnfd_linux.yaml b/test/RO_tests/simple_linux/vnfd_linux.yaml
new file mode 100644 (file)
index 0000000..47c8498
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# 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: []
diff --git a/test/RO_tests/simple_multi_vnfc/scenario_multi_vnfc.yaml b/test/RO_tests/simple_multi_vnfc/scenario_multi_vnfc.yaml
new file mode 100644 (file)
index 0000000..8de7993
--- /dev/null
@@ -0,0 +1,34 @@
+##
+# 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
+
diff --git a/test/RO_tests/simple_multi_vnfc/vnfd_linux_2VMs_v02.yaml b/test/RO_tests/simple_multi_vnfc/vnfd_linux_2VMs_v02.yaml
new file mode 100644 (file)
index 0000000..3a09672
--- /dev/null
@@ -0,0 +1,104 @@
+##
+# 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
+
diff --git a/test/test_RO.py b/test/test_RO.py
new file mode 100755 (executable)
index 0000000..d666755
--- /dev/null
@@ -0,0 +1,623 @@
+#!/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