Merge branch 'v1.0' 33/933/1
authorgarciadeblas <gerardo.garciadeblas@telefonica.com>
Thu, 12 Jan 2017 14:03:58 +0000 (15:03 +0100)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Thu, 12 Jan 2017 14:03:58 +0000 (15:03 +0100)
16 files changed:
.gitignore-common
database_utils/migrate_mano_db.sh
db_base.py
nfvo.py
nfvo_db.py
openmano
openmano_schemas.py
openmanod.py
scenarios/examples/scenario_vnf_floating_ip.yaml [new file with mode: 0644]
scenarios/examples/scenario_vnf_no_port_security.yaml [new file with mode: 0644]
scripts/install-openmano.sh
test/test_openmanoclient.py [new file with mode: 0755]
vimconn_openstack.py
vimconn_openvim.py
vnfs/examples/vnf_floating_ip.yaml [new file with mode: 0644]
vnfs/examples/vnf_no_port_security.yaml [new file with mode: 0644]

index c71eced..77f6798 100644 (file)
@@ -22,7 +22,8 @@
 # This is a template with common files to be igonored, after clone make a copy to .gitignore
 # cp .gitignore-common .gitignore
 
-*.pyc         
+*.pyc
+*.pyo
 
 #auto-ignore
 .gitignore
index 208ec7d..9fc4966 100755 (executable)
@@ -185,6 +185,7 @@ DATABASE_TARGET_VER_NUM=0
 [ $OPENMANO_VER_NUM -ge 4059 ] && DATABASE_TARGET_VER_NUM=15  #0.4.59=>  15
 [ $OPENMANO_VER_NUM -ge 5002 ] && DATABASE_TARGET_VER_NUM=16  #0.5.2 =>  16
 [ $OPENMANO_VER_NUM -ge 5003 ] && DATABASE_TARGET_VER_NUM=17  #0.5.3 =>  17
+[ $OPENMANO_VER_NUM -ge 5004 ] && DATABASE_TARGET_VER_NUM=18  #0.5.4 =>  18
 #TODO ... put next versions here
 
 
@@ -696,6 +697,25 @@ function downgrade_from_17(){
     echo "DELETE FROM schema_version WHERE version_int='17';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
 }
 
+function upgrade_to_18(){
+    echo "    upgrade database from version 0.17 to version 0.18"
+    echo "      add columns 'floating_ip' and 'port_security' at tables 'interfaces' and 'instance_interfaces'"
+    echo "ALTER TABLE interfaces ADD floating_ip BOOL DEFAULT 0 NOT NULL COMMENT 'Indicates if a floating_ip must be associated to this interface';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+    echo "ALTER TABLE interfaces ADD port_security BOOL DEFAULT 1 NOT NULL COMMENT 'Indicates if port security must be enabled or disabled. By default it is enabled';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+    echo "ALTER TABLE instance_interfaces ADD floating_ip BOOL DEFAULT 0 NOT NULL COMMENT 'Indicates if a floating_ip must be associated to this interface';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+    echo "ALTER TABLE instance_interfaces ADD port_security BOOL DEFAULT 1 NOT NULL COMMENT 'Indicates if port security must be enabled or disabled. By default it is enabled';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+    echo "INSERT INTO schema_version (version_int, version, openmano_ver, comments, date) VALUES (18, '0.18', '0.5.4', 'Add columns \'floating_ip\' and \'port_security\' at tables \'interfaces\' and \'instance_interfaces\'', '2017-01-09');" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+}
+function downgrade_from_18(){
+    echo "    downgrade database from version 0.18 to version 0.17"
+    echo "      remove columns 'floating_ip' and 'port_security' from tables 'interfaces' and 'instance_interfaces'"
+    echo "ALTER TABLE interfaces DROP COLUMN floating_ip;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+    echo "ALTER TABLE interfaces DROP COLUMN port_security;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+    echo "ALTER TABLE instance_interfaces DROP COLUMN floating_ip;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+    echo "ALTER TABLE instance_interfaces DROP COLUMN port_security;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+    echo "DELETE FROM schema_version WHERE version_int='18';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+}
+
 function upgrade_to_X(){
     echo "      change 'datacenter_nets'"
     echo "ALTER TABLE datacenter_nets ADD COLUMN vim_tenant_id VARCHAR(36) NOT NULL AFTER datacenter_id, DROP INDEX name_datacenter_id, ADD UNIQUE INDEX name_datacenter_id (name, datacenter_id, vim_tenant_id);" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
index 807c73d..10f9404 100644 (file)
@@ -125,8 +125,11 @@ def _convert_str2boolean(data, items):
                 _convert_str2boolean(data[k], items)
             if k in items:
                 if type(data[k]) is str:
-                    if   data[k]=="false" or data[k]=="False": data[k]=False
-                    elif data[k]=="true"  or data[k]=="True":  data[k]=True
+                    if   data[k]=="false" or data[k]=="False" or data[k]=="0": data[k]=False
+                    elif data[k]=="true"  or data[k]=="True" or data[k]=="1":  data[k]=True
+                elif type(data[k]) is int:
+                    if   data[k]==0: data[k]=False
+                    elif  data[k]==1:  data[k]=True
     if type(data) is tuple or type(data) is list:
         for k in data:
             if type(k) is dict or type(k) is tuple or type(k) is list:
diff --git a/nfvo.py b/nfvo.py
index 4958762..9a2dd05 100644 (file)
--- a/nfvo.py
+++ b/nfvo.py
@@ -1493,6 +1493,10 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc
                         netDict['vpci'] = iface['vpci']
                     if "mac" in iface and iface["mac"] is not None:
                         netDict['mac_address'] = iface['mac']
+                    if "port-security" in iface and iface["port-security"] is not None:
+                        netDict['port_security'] = iface['port-security']
+                    if "floating-ip" in iface and iface["floating-ip"] is not None:
+                        netDict['floating_ip'] = iface['floating-ip']
                     netDict['name'] = iface['internal_name']
                     if iface['net_id'] is None:
                         for vnf_iface in sce_vnf["interfaces"]:
@@ -2014,6 +2018,10 @@ def create_instance(mydb, tenant_id, instance_dict):
                         netDict['vpci'] = iface['vpci']
                     if "mac" in iface and iface["mac"] is not None:
                         netDict['mac_address'] = iface['mac']
+                    if "port-security" in iface and iface["port-security"] is not None:
+                        netDict['port_security'] = iface['port-security']
+                    if "floating-ip" in iface and iface["floating-ip"] is not None:
+                        netDict['floating_ip'] = iface['floating-ip']
                     netDict['name'] = iface['internal_name']
                     if iface['net_id'] is None:
                         for vnf_iface in sce_vnf["interfaces"]:
index 6ab73e9..5e51c3b 100644 (file)
@@ -93,12 +93,20 @@ class nfvo_db(db_base.db_base):
                         if 'bridge-ifaces' in  vm:
                             bridgeInterfacesDict[vm['name']] = {}
                             for bridgeiface in vm['bridge-ifaces']:
+                                if 'port-security' in bridgeiface:
+                                    bridgeiface['port_security'] = bridgeiface.pop('port-security')
+                                if 'floating-ip' in bridgeiface:
+                                    bridgeiface['floating_ip'] = bridgeiface.pop('floating-ip')
                                 db_base._convert_bandwidth(bridgeiface, logger=self.logger)
                                 bridgeInterfacesDict[vm['name']][bridgeiface['name']] = {}
                                 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['vpci'] = bridgeiface.get('vpci',None)
                                 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['mac'] = bridgeiface.get('mac_address',None)
                                 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['bw'] = bridgeiface.get('bandwidth', None)
                                 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['model'] = bridgeiface.get('model', None)
+                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['port_security'] = \
+                                    int(bridgeiface.get('port_security', True))
+                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['floating_ip'] = \
+                                    int(bridgeiface.get('floating_ip', False))
                     
                     #For each internal connection, we add it to the interfaceDict and we  create the appropriate net in the NFVO database.
                     #print "Adding new nets (VNF internal nets) to the NFVO database (if any)"
@@ -133,6 +141,10 @@ class nfvo_db(db_base.db_base):
                                     ifaceItem["mac"] =  bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['mac_address']
                                     ifaceItem["bw"] =    bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['bw']
                                     ifaceItem["model"] = bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['model']
+                                    ifaceItem["port_security"] = \
+                                    bridgeInterfacesDict[element['VNFC']][element['local_iface_name']]['port_security']
+                                    ifaceItem["floating_ip"] = \
+                                    bridgeInterfacesDict[element['VNFC']][element['local_iface_name']]['floating_ip']
                                 internalconnList.append(ifaceItem)
                             #print "Internal net id in NFVO DB: %s" % net_id
                     
@@ -161,6 +173,10 @@ class nfvo_db(db_base.db_base):
                             myIfaceDict["bw"]    = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['bw']
                             myIfaceDict["model"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['model']
                             myIfaceDict["mac"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['mac']
+                            myIfaceDict["port_security"] = \
+                                bridgeInterfacesDict[iface['VNFC']][iface['local_iface_name']]['port_security']
+                            myIfaceDict["floating_ip"] = \
+                                bridgeInterfacesDict[iface['VNFC']][iface['local_iface_name']]['floating_ip']
                         print "Iface name: %s" % iface['name']
                         created_time += 0.00001
                         iface_id = self._new_row_internal('interfaces', myIfaceDict, add_uuid=True, root_uuid=vnf_id, created_time=created_time)
@@ -222,11 +238,19 @@ class nfvo_db(db_base.db_base):
                             bridgeInterfacesDict[vm['name']] = {}
                             for bridgeiface in vm['bridge-ifaces']:
                                 db_base._convert_bandwidth(bridgeiface, logger=self.logger)
+                                if 'port-security' in bridgeiface:
+                                    bridgeiface['port_security'] = bridgeiface.pop('port-security')
+                                if 'floating-ip' in bridgeiface:
+                                    bridgeiface['floating_ip'] = bridgeiface.pop('floating-ip')
                                 bridgeInterfacesDict[vm['name']][bridgeiface['name']] = {}
                                 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['vpci'] = bridgeiface.get('vpci',None)
                                 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['mac'] = bridgeiface.get('mac_address',None)
                                 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['bw'] = bridgeiface.get('bandwidth', None)
                                 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['model'] = bridgeiface.get('model', None)
+                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['port_security'] = \
+                                    int(bridgeiface.get('port_security', True))
+                                bridgeInterfacesDict[vm['name']][bridgeiface['name']]['floating_ip'] = \
+                                    int(bridgeiface.get('floating_ip', False))
                     
                     #For each internal connection, we add it to the interfaceDict and we  create the appropriate net in the NFVO database.
                     #print "Adding new nets (VNF internal nets) to the NFVO database (if any)"
@@ -287,6 +311,10 @@ class nfvo_db(db_base.db_base):
                                     ifaceItem["mac"] =  bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['mac']
                                     ifaceItem["bw"] =    bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['bw']
                                     ifaceItem["model"] = bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['model']
+                                    ifaceItem["port_security"] = \
+                                    bridgeInterfacesDict[element['VNFC']][element['local_iface_name']]['port_security']
+                                    ifaceItem["floating_ip"] = \
+                                    bridgeInterfacesDict[element['VNFC']][element['local_iface_name']]['floating_ip']
                                 internalconnList.append(ifaceItem)
                             #print "Internal net id in NFVO DB: %s" % net_id
                     
@@ -315,6 +343,10 @@ class nfvo_db(db_base.db_base):
                             myIfaceDict["bw"]    = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['bw']
                             myIfaceDict["model"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['model']
                             myIfaceDict["mac"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['mac']
+                            myIfaceDict["port_security"] = \
+                                bridgeInterfacesDict[iface['VNFC']][iface['local_iface_name']]['port_security']
+                            myIfaceDict["floating_ip"] = \
+                                bridgeInterfacesDict[iface['VNFC']][iface['local_iface_name']]['floating_ip']
                         print "Iface name: %s" % iface['name']
                         created_time += 0.00001
                         iface_id = self._new_row_internal('interfaces', myIfaceDict, add_uuid=True, root_uuid=vnf_id, created_time=created_time)
@@ -643,13 +675,17 @@ class nfvo_db(db_base.db_base):
                                     vm['vim_flavor_id']=vim_flavor_dict['vim_id']
                                 
                             #interfaces
-                            cmd = "SELECT uuid,internal_name,external_name,net_id,type,vpci,mac,bw,model,ip_address" \
+                            cmd = "SELECT uuid,internal_name,external_name,net_id,type,vpci,mac,bw,model,ip_address," \
+                                  "floating_ip, port_security" \
                                     " FROM interfaces" \
                                     " WHERE vm_id='{}'" \
                                     " ORDER BY created_at".format(vm['uuid'])
                             self.logger.debug(cmd)
                             self.cur.execute(cmd)
                             vm['interfaces'] = self.cur.fetchall()
+                            for index in range(0,len(vm['interfaces'])):
+                                vm['interfaces'][index]['port-security'] = vm['interfaces'][index].pop("port_security")
+                                vm['interfaces'][index]['floating-ip'] = vm['interfaces'][index].pop("floating_ip")
                         #nets    every net of a vms
                         cmd = "SELECT uuid,name,type,description FROM nets WHERE vnf_id='{}'".format(vnf['vnf_id'])  
                         self.logger.debug(cmd)
@@ -700,7 +736,7 @@ class nfvo_db(db_base.db_base):
                             net['vim_id']=d_net['vim_net_id']
                     
                     db_base._convert_datetime2str(scenario_dict)
-                    db_base._convert_str2boolean(scenario_dict, ('public','shared','external') )
+                    db_base._convert_str2boolean(scenario_dict, ('public','shared','external','port-security','floating-ip') )
                     return scenario_dict
             except (mdb.Error, AttributeError) as e:
                 self._format_error(e, tries)
@@ -846,7 +882,8 @@ class nfvo_db(db_base.db_base):
                                 interface_type='external' if interface['external_name'] is not None else 'internal'
                                 INSERT_={'instance_vm_id': instance_vm_uuid,  'instance_net_id': net_scene2instance[net_id][datacenter_site_id],
                                     'interface_id': interface['uuid'], 'vim_interface_id': interface.get('vim_id'), 'type':  interface_type,
-                                    'ip_address': interface.get('ip_address')  }
+                                    'ip_address': interface.get('ip_address'), 'floating_ip': int(interface.get('floating-ip',False)),
+                                    'port_security': int(interface.get('port-security',True))}
                                 #created_time += 0.00001
                                 interface_uuid =  self._new_row_internal('instance_interfaces', INSERT_, True, instance_uuid) #, created_time)
                                 interface['uuid'] = interface_uuid  #overwrite scnario uuid by instance uuid
index 11cc726..59fd7e8 100755 (executable)
--- a/openmano
+++ b/openmano
@@ -591,7 +591,7 @@ def instance_create(args):
     if args.scenario != None:
         scenario = args.scenario
     if not scenario:
-        print "you must provide an scenario in the file descriptor or with --scenario"
+        print "you must provide a scenario in the file descriptor or with --scenario"
         return -1
     myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant)
     if args.netmap_use:
index 013234f..a8c92a0 100644 (file)
@@ -450,7 +450,9 @@ bridge_interfaces_schema={
             "bandwidth":bandwidth_schema,
             "vpci":pci_schema,
             "mac_address": mac_schema,
-            "model": {"type":"string", "enum":["virtio","e1000","ne2k_pci","pcnet","rtl8139"]}
+            "model": {"type":"string", "enum":["virtio","e1000","ne2k_pci","pcnet","rtl8139"]},
+            "port-security": {"type" : "boolean"},
+            "floating-ip": {"type" : "boolean"}
         },
         "additionalProperties": False,
         "required": ["name"]
index b50ca9d..d00f618 100755 (executable)
@@ -33,9 +33,9 @@ It loads the configuration file and launches the http_server thread that will li
 '''
 __author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
 __date__ ="$26-aug-2014 11:09:29$"
-__version__="0.5.3-r511"
-version_date="Dec 2016"
-database_version="0.17"      #expected database schema version
+__version__="0.5.4-r512"
+version_date="Jan 2017"
+database_version="0.18"      #expected database schema version
 
 import httpserver
 import time
diff --git a/scenarios/examples/scenario_vnf_floating_ip.yaml b/scenarios/examples/scenario_vnf_floating_ip.yaml
new file mode 100644 (file)
index 0000000..61da9e7
--- /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:                
+    internal:
+      # 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/scenarios/examples/scenario_vnf_no_port_security.yaml b/scenarios/examples/scenario_vnf_no_port_security.yaml
new file mode 100644 (file)
index 0000000..df0a53b
--- /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:                
+    internal:
+      # 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
+
index f141076..9e76b0d 100755 (executable)
@@ -273,8 +273,8 @@ sudo pip install pyvmomi
 [ "$_DISTRO" == "CentOS" -o "$_DISTRO" == "Red" ] && easy_install -U bottle
 
 #install openstack client needed for using openstack as a VIM
-[ "$_DISTRO" == "Ubuntu" ] && install_packages "python-novaclient python-keystoneclient python-glanceclient python-neutronclient"
-[ "$_DISTRO" == "CentOS" -o "$_DISTRO" == "Red" ] && install_packages "python-devel" && easy_install python-novaclient python-keystoneclient python-glanceclient python-neutronclient #TODO revise if gcc python-pip is needed
+[ "$_DISTRO" == "Ubuntu" ] && install_packages "python-novaclient python-keystoneclient python-glanceclient python-neutronclient python-cinderclient"
+[ "$_DISTRO" == "CentOS" -o "$_DISTRO" == "Red" ] && install_packages "python-devel" && easy_install python-novaclient python-keystoneclient python-glanceclient python-neutronclient python-cinderclient #TODO revise if gcc python-pip is needed
 fi  #[[ -z "$NO_PACKAGES" ]]
 
 if [[ -z $NOCLONE ]]; then
diff --git a/test/test_openmanoclient.py b/test/test_openmanoclient.py
new file mode 100755 (executable)
index 0000000..5e8876b
--- /dev/null
@@ -0,0 +1,432 @@
+#!/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 to test openmanoclient class and indirectly the whole openmano
+It allows both python 2 and python 3
+'''
+__author__="Alfonso Tierno"
+__date__ ="$09-Mar-2016 09:09:48$"
+__version__="0.0.2"
+version_date="May 2016"
+
+import logging
+import imp 
+        
+
+
+def _get_random_name(maxLength):
+    '''generates a string with random craracters from space (ASCCI 32) to ~(ASCCI 126)
+    with a random length up to maxLength
+    '''
+    long_name = "testing up to {} size name: ".format(maxLength) 
+    #long_name += ''.join(chr(random.randint(32,126)) for _ in range(random.randint(20, maxLength-len(long_name))))
+    long_name += ''.join(random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ') for _ in range(20, maxLength-len(long_name)))
+    return long_name
+
+
+if __name__=="__main__":
+    import getopt
+    #import os
+    import sys
+    
+
+
+    usage =\
+    """Make a test against an openmano server.\nUsage: test_openmanoclient [options]
+    -v|--verbose: prints more info in the test
+    --version:    shows current version
+    -h|--help:    shows this help
+    -d|--debug:   set logs to debug level
+    -t|--tenant:  set the tenant name to test. By default creates one
+    --datacenter: set the datacenter name to test. By default creates one at http://localhost:9080/openvim
+    -u|--url:     set the openmano server url. By default 'http://localhost:9090/openmano'
+    --image:      use this image path for testing a VNF. By default a fake one is generated, valid for VIM in test mode'
+    """
+
+    #import openmanoclient from relative path
+    module_info = imp.find_module("openmanoclient", [".."] )
+    Client = imp.load_module("Client", *module_info)
+    
+    streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
+    logging.basicConfig(format=streamformat)
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "t:u:dhv", ["url=", "tenant=", "debug", "help", "version", "verbose", "datacenter=", "image="])
+    except getopt.GetoptError as err:
+        print ("Error: {}\n Try '{} --help' for more information".format(str(err), sys.argv[0]))
+        sys.exit(2)
+
+    debug = False
+    verbose = False
+    url = "http://localhost:9090/openmano"
+    to_delete_list=[]
+    test_tenant = None
+    test_datacenter = None
+    test_vim_tenant = None
+    test_image = None
+    for o, a in opts:
+        if o in ("-v", "--verbose"):
+            verbose = True
+        elif o in ("--version"):
+            print ("{} version".format(sys.argv[0]), __version__, version_date)
+            print ("(c) Copyright Telefonica")
+            sys.exit()
+        elif o in ("-h", "--help"):
+            print(usage)
+            sys.exit()
+        elif o in ("-d", "--debug"):
+            debug = True
+        elif o in ("-u", "--url"):
+            url = a
+        elif o in ("-t", "--tenant"):
+            test_tenant = a 
+        elif o in ("--datacenter"):
+            test_datacenter = a 
+        elif o in ("--image"):
+            test_image = a 
+        else:
+            assert False, "Unhandled option"
+
+    
+    
+    client = Client.openmanoclient(
+                            endpoint_url=url, 
+                            tenant_name=test_tenant,
+                            datacenter_name = test_datacenter,
+                            debug = debug)
+
+    import random
+    test_number=1
+    
+    #TENANTS
+    print("  {}. TEST create_tenant".format(test_number))
+    test_number += 1
+    long_name = _get_random_name(60)
+
+    tenant = client.create_tenant(name=long_name, description=long_name)
+    if verbose: print(tenant)
+
+    print("  {}. TEST list_tenants".format(test_number))
+    test_number += 1
+    tenants = client.list_tenants()
+    if verbose: print(tenants)
+    
+    print("  {}. TEST list_tenans filter by name".format(test_number))
+    test_number += 1
+    tenants_ = client.list_tenants(name=long_name)
+    if not tenants_["tenants"]:
+        raise Exception("Text error, no TENANT found with name")
+    if verbose: print(tenants_)
+    
+    print("  {}. TEST get_tenant by UUID".format(test_number))
+    test_number += 1
+    tenant = client.get_tenant(uuid=tenants_["tenants"][0]["uuid"])
+    if verbose: print(tenant)
+        
+    print("  {}. TEST delete_tenant by name".format(test_number))
+    test_number += 1
+    tenant = client.delete_tenant(name = long_name)
+    if verbose: print(tenant)
+    
+    if not test_tenant:
+        print("  {}. TEST create_tenant for remaining tests".format(test_number))
+        test_number += 1
+        test_tenant = "test-tenant "+\
+        ''.join(random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(40))
+        tenant = client.create_tenant(name = test_tenant)
+        if verbose: print(tenant)
+        client["tenant_name"] = test_tenant
+        
+        to_delete_list.insert(0,{"item": "tenant", "function": client.delete_tenant, "params":{"name": test_tenant} })
+
+    #DATACENTERS
+    print("  {}. TEST create_datacenter".format(test_number))
+    test_number += 1
+    long_name = _get_random_name(60)
+
+    datacenter = client.create_datacenter(name=long_name, vim_url="http://fakeurl/fake")
+    if verbose: print(datacenter)
+
+    print("  {}. TEST list_datacenters".format(test_number))
+    test_number += 1
+    datacenters = client.list_datacenters(all_tenants=True)
+    if verbose: print(datacenters)
+    
+    print("  {}. TEST list_tenans filter by name".format(test_number))
+    test_number += 1
+    datacenters_ = client.list_datacenters(all_tenants=True, name=long_name)
+    if not datacenters_["datacenters"]:
+        raise Exception("Text error, no TENANT found with name")
+    if verbose: print(datacenters_)
+    
+    print("  {}. TEST get_datacenter by UUID".format(test_number))
+    test_number += 1
+    datacenter = client.get_datacenter(uuid=datacenters_["datacenters"][0]["uuid"], all_tenants=True)
+    if verbose: print(datacenter)
+        
+    print("  {}. TEST delete_datacenter by name".format(test_number))
+    test_number += 1
+    datacenter = client.delete_datacenter(name=long_name)
+    if verbose: print(datacenter)
+    
+    if not test_datacenter:
+        print("  {}. TEST create_datacenter for remaining tests".format(test_number))
+        test_number += 1
+        test_datacenter = "test-datacenter "+\
+        ''.join(random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(40))
+        datacenter = client.create_datacenter(name=test_datacenter, vim_url="http://127.0.0.1:9080/openvim")
+        if verbose: print(datacenter)
+        client["datacenter_name"] = test_datacenter
+        to_delete_list.insert(0,{"item": "datacenter", "function": client.delete_datacenter,
+                                  "params":{
+                                        "name": test_datacenter
+                                    } 
+                                 })
+
+        print("  {}. TEST datacenter new tenenat".format(test_number))
+        test_number += 1
+        test_vim_tenant = "test-vimtenant "+\
+        ''.join(random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(40))
+        vim_tenant = client.vim_action("create", "tenants", datacenter_name=test_datacenter, all_tenants=True, name=test_vim_tenant)
+        if verbose: print(vim_tenant)
+        client["datacenter_name"] = test_datacenter
+        to_delete_list.insert(0,{"item": "vim_tenant", 
+                                 "function": client.vim_action,
+                                  "params":{
+                                            "action":"delete",
+                                            "item":"tenants",
+                                            "datacenter_name": test_datacenter,
+                                            "all_tenants": True,
+                                            "uuid": vim_tenant["tenant"]["id"]
+                                            }
+                                 })
+
+        print("  {}. TEST datacenter attach".format(test_number))
+        test_number += 1
+        datacenter = client.attach_datacenter(name=test_datacenter, vim_tenant_name=test_vim_tenant)
+        if verbose: print(datacenter)
+        client["datacenter_name"] = test_datacenter
+        to_delete_list.insert(0,{"item": "datacenter-detach", "function": client.detach_datacenter, "params":{"name": test_datacenter} })
+
+        client["datacenter_name"] = test_datacenter
+        
+    
+    #VIM_ACTIONS
+    print("  {}. TEST create_VIM_tenant".format(test_number))
+    test_number += 1
+    long_name = _get_random_name(60)
+
+    tenant = client.vim_action("create", "tenants", name=long_name)
+    if verbose: print(tenant)
+    tenant_uuid = tenant["tenant"]["id"] 
+
+    print("  {}. TEST list_VIM_tenants".format(test_number))
+    test_number += 1
+    tenants = client.vim_action("list", "tenants")
+    if verbose: print(tenants)
+    
+    print("  {}. TEST get_VIM_tenant by UUID".format(test_number))
+    test_number += 1
+    tenant = client.vim_action("show", "tenants", uuid=tenant_uuid)
+    if verbose: print(tenant)
+        
+    print("  {}. TEST delete_VIM_tenant by id".format(test_number))
+    test_number += 1
+    tenant = client.vim_action("delete", "tenants", uuid = tenant_uuid)
+    if verbose: print(tenant)
+    
+    print("  {}. TEST create_VIM_network".format(test_number))
+    test_number += 1
+    long_name = _get_random_name(60)
+
+    network = client.vim_action("create", "networks", name=long_name)
+    if verbose: print(network)
+    network_uuid = network["network"]["id"] 
+
+    print("  {}. TEST list_VIM_networks".format(test_number))
+    test_number += 1
+    networks = client.vim_action("list", "networks")
+    if verbose: print(networks)
+    
+    print("  {}. TEST get_VIM_network by UUID".format(test_number))
+    test_number += 1
+    network = client.vim_action("show", "networks", uuid=network_uuid)
+    if verbose: print(network)
+        
+    print("  {}. TEST delete_VIM_network by id".format(test_number))
+    test_number += 1
+    network = client.vim_action("delete", "networks", uuid = network_uuid)
+    if verbose: print(network)
+    #VNFS
+    print("  {}. TEST create_vnf".format(test_number))
+    test_number += 1
+    test_vnf_name = _get_random_name(255)
+    if test_image:
+        test_vnf_path = test_image
+    else:
+        test_vnf_path = "/random/path/" + "".join(random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ') for _ in range(20))
+    
+    vnf_descriptor={'vnf': {'name': test_vnf_name, 
+                                'VNFC': [{'description': _get_random_name(255),
+                                          'name': 'linux-VM',
+                                          'VNFC image': test_vnf_path,
+                                          'ram': 1024,
+                                          'vcpus': 1,
+                                          'bridge-ifaces': [{'name': 'eth0'}]
+                                        }],
+                                'description': _get_random_name(255),
+                                'nets': [], 
+                                'external-connections': [{'name': 'eth0', 
+                                                          'local_iface_name': 'eth0',
+                                                          'VNFC': 'linux-VM',
+                                                          'type': 'bridge'}], 
+                                'public': False}}
+
+    vnf = client.create_vnf(descriptor=vnf_descriptor)
+    if verbose: print(vnf)
+    to_delete_list.insert(0,{"item": "vnf", "function": client.delete_vnf, "params":{"name": test_vnf_name} })
+
+    print("  {}. TEST list_vnfs".format(test_number))
+    test_number += 1
+    vnfs = client.list_vnfs()
+    if verbose: print(vnfs)
+    
+    print("  {}. TEST list_vnfs filter by name".format(test_number))
+    test_number += 1
+    vnfs_ = client.list_vnfs(name=test_vnf_name)
+    if not vnfs_["vnfs"]:
+        raise Exception("Text error, no VNF found with name")
+    if verbose: print(vnfs_)
+    
+    print("  {}. TEST get_vnf by UUID".format(test_number))
+    test_number += 1
+    vnf = client.get_vnf(uuid=vnfs_["vnfs"][0]["uuid"])
+    if verbose: print(vnf)
+
+    #SCENARIOS
+    print("  {}. TEST create_scenario".format(test_number))
+    test_number += 1
+    test_scenario_name = _get_random_name(255)
+    
+    scenario_descriptor={   'schema_version': 2,
+                            'scenario': {
+                                'name': test_scenario_name, 
+                                'description': _get_random_name(255),
+                                'public': True,
+                                'vnfs':{
+                                    'vnf1': {
+                                        'vnf_name': test_vnf_name
+                                    }
+                                },
+                                'networks':{
+                                    'net1':{
+                                        'external': True,
+                                        'interfaces': [
+                                            {'vnf1': 'eth0'}
+                                        ]
+                                    }
+                                }
+                            }
+                        }
+
+    scenario = client.create_scenario(descriptor=scenario_descriptor)
+    if verbose: print(scenario)
+    to_delete_list.insert(0,{"item": "scenario", "function": client.delete_scenario, "params":{"name": test_scenario_name} })
+
+    print("  {}. TEST list_scenarios".format(test_number))
+    test_number += 1
+    scenarios = client.list_scenarios()
+    if verbose: print(scenarios)
+    
+    print("  {}. TEST list_scenarios filter by name".format(test_number))
+    test_number += 1
+    scenarios_ = client.list_scenarios(name=test_scenario_name)
+    if not scenarios_["scenarios"]:
+        raise Exception("Text error, no VNF found with name")
+    if verbose: print(scenarios_)
+    
+    print("  {}. TEST get_scenario by UUID".format(test_number))
+    test_number += 1
+    scenario = client.get_scenario(uuid=scenarios_["scenarios"][0]["uuid"])
+    if verbose: print(scenario)
+
+
+
+    #INSTANCES
+    print("  {}. TEST create_instance".format(test_number))
+    test_number += 1
+    test_instance_name = _get_random_name(255)
+    
+    instance_descriptor={   'schema_version': 2,
+                            'instance': {
+                                'name': test_instance_name, 
+                                'description': _get_random_name(255),
+                                'public': True,
+                                'vnfs':{
+                                    'vnf1': {
+                                        'vnf_name': test_vnf_name
+                                    }
+                                },
+                                'networks':{
+                                    'net1':{
+                                        'external': True,
+                                        'interfaces': [
+                                            {'vnf1': 'eth0'}
+                                        ]
+                                    }
+                                }
+                            }
+                        }
+
+    instance = client.create_instance(scenario_name=test_scenario_name, name=test_instance_name )
+    if verbose: print(instance)
+    to_delete_list.insert(0,{"item": "instance", "function": client.delete_instance, "params":{"name": test_instance_name} })
+
+    print("  {}. TEST list_instances".format(test_number))
+    test_number += 1
+    instances = client.list_instances()
+    if verbose: print(instances)
+    
+    print("  {}. TEST list_instances filter by name".format(test_number))
+    test_number += 1
+    instances_ = client.list_instances(name=test_instance_name)
+    if not instances_["instances"]:
+        raise Exception("Text error, no VNF found with name")
+    if verbose: print(instances_)
+    
+    print("  {}. TEST get_instance by UUID".format(test_number))
+    test_number += 1
+    instance = client.get_instance(uuid=instances_["instances"][0]["uuid"])
+    if verbose: print(instance)
+
+
+
+
+    #DELETE Create things
+    for item in to_delete_list:
+        print("  {}. TEST delete_{}".format(test_number, item["item"]))
+        test_number += 1
+        response = item["function"](**item["params"]) 
+        if verbose: print(response)
+    
index 999acee..96d89e3 100644 (file)
@@ -62,6 +62,7 @@ netStatus2manoFormat={'ACTIVE':'ACTIVE','PAUSED':'PAUSED','INACTIVE':'INACTIVE',
 
 #global var to have a timeout creating and deleting volumes
 volume_timeout = 60
+server_timeout = 60
 
 class vimconnector(vimconn.vimconnector):
     def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None, config={}):
@@ -95,6 +96,9 @@ class vimconnector(vimconn.vimconnector):
         if self.osc_api_version == 'v3.3':
             self.k_creds['project_name'] = tenant_name
             self.k_creds['project_id'] = tenant_id
+        if config.get('region_name'):
+            self.k_creds['region_name'] = config.get('region_name')
+            self.n_creds['region_name'] = config.get('region_name')
 
         self.reload_client       = True
         self.logger = logging.getLogger('openmano.vim.openstack')
@@ -705,6 +709,8 @@ class vimconnector(vimconn.vimconnector):
                         port_dict["name"]=name
                     if net.get("mac_address"):
                         port_dict["mac_address"]=net["mac_address"]
+                    if net.get("port_security") == False:
+                        port_dict["port_security_enabled"]=net["port_security"]
                     new_port = self.neutron.create_port({"port": port_dict })
                     net["mac_adress"] = new_port["port"]["mac_address"]
                     net["vim_id"] = new_port["port"]["id"]
@@ -787,7 +793,7 @@ class vimconnector(vimconn.vimconnector):
                     #delete ports we just created
                     for net_item  in net_list_vim:
                         if 'port-id' in net_item:
-                            self.neutron.delete_port(net_item['port_id'])
+                            self.neutron.delete_port(net_item['port-id'])
 
                     raise vimconn.vimconnException('Timeout creating volumes for instance ' + name,
                                                    http_code=vimconn.HTTP_Request_Timeout)
@@ -800,15 +806,29 @@ class vimconnector(vimconn.vimconnector):
                                               block_device_mapping = block_device_mapping
                                               )  # , description=description)
             #print "DONE :-)", server
-            
             pool_id = None
             floating_ips = self.neutron.list_floatingips().get("floatingips", ())
             for floating_network in external_network:
+                # wait until vm is active
+                elapsed_time = 0
+                while elapsed_time < server_timeout:
+                    status = self.nova.servers.get(server.id).status
+                    if status == 'ACTIVE':
+                        break
+                    time.sleep(1)
+                    elapsed_time += 1
+
+                #if we exceeded the timeout rollback
+                if elapsed_time >= server_timeout:
+                    self.delete_vminstance(server.id)
+                    raise vimconn.vimconnException('Timeout creating instance ' + name,
+                                                   http_code=vimconn.HTTP_Request_Timeout)
+
                 assigned = False
                 while(assigned == False):
                     if floating_ips:
                         ip = floating_ips.pop(0)
-                        if not ip.get("port_id", False):
+                        if not ip.get("port_id", False) and ip.get('tenant_id') == server.tenant_id:
                             free_floating_ip = ip.get("floating_ip_address")
                             try:
                                 fix_ip = floating_network.get('ip')
@@ -818,8 +838,25 @@ class vimconnector(vimconn.vimconnector):
                                 self.delete_vminstance(server.id)
                                 raise vimconn.vimconnException(type(e).__name__ + ": Cannot create floating_ip "+  str(e), http_code=vimconn.HTTP_Conflict)
                     else:
-                        pool_id = floating_network.get('net_id')
-                        param = {'floatingip': {'floating_network_id': pool_id}}
+                        #Find the external network
+                        external_nets = list()
+                        for net in self.neutron.list_networks()['networks']:
+                            if net['router:external']:
+                                    external_nets.append(net)
+
+                        if len(external_nets) == 0:
+                            self.delete_vminstance(server.id)
+                            raise vimconn.vimconnException("Cannot create floating_ip automatically since no external "
+                                                           "network is present",
+                                                            http_code=vimconn.HTTP_Conflict)
+                        if len(external_nets) > 1:
+                            self.delete_vminstance(server.id)
+                            raise vimconn.vimconnException("Cannot create floating_ip automatically since multiple "
+                                                           "external networks are present",
+                                                           http_code=vimconn.HTTP_Conflict)
+
+                        pool_id = external_nets[0].get('id')
+                        param = {'floatingip': {'floating_network_id': pool_id, 'tenant_id': server.tenant_id}}
                         try:
                             #self.logger.debug("Creating floating IP")
                             new_floating_ip = self.neutron.create_floatingip(param)
@@ -837,6 +874,15 @@ class vimconnector(vimconn.vimconnector):
 #            error_text= "vm instance %s not found" % vm_id
         except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError
                 ) as e:
+            # delete the volumes we just created
+            if block_device_mapping != None:
+                for volume_id in block_device_mapping.itervalues():
+                    self.cinder.volumes.delete(volume_id)
+
+            # delete ports we just created
+            for net_item in net_list_vim:
+                if 'port-id' in net_item:
+                    self.neutron.delete_port(net_item['port-id'])
             self._format_exception(e)
         except TypeError as e:
             raise vimconn.vimconnException(type(e).__name__ + ": "+  str(e), http_code=vimconn.HTTP_Bad_Request)
index 241f63d..62c1677 100644 (file)
@@ -591,8 +591,10 @@ class vimconnector(vimconn.vimconnector):
         '''Adds a tenant flavor to VIM'''
         '''Returns the flavor identifier'''
         try:
+            new_flavor_dict = flavor_data.copy()
+            new_flavor_dict["name"] = flavor_data["name"][:64]
             self._get_my_tenant()
-            payload_req = json.dumps({'flavor': flavor_data})
+            payload_req = json.dumps({'flavor': new_flavor_dict})
             url = self.url+'/'+self.tenant+'/flavors'
             self.logger.info("Adding a new VIM flavor POST %s", url)
             vim_response = requests.post(url, headers = self.headers_req, data=payload_req)
@@ -647,7 +649,7 @@ class vimconnector(vimconn.vimconnector):
         ''' Adds a tenant image to VIM, returns image_id'''
         try:
             self._get_my_tenant()
-            new_image_dict={'name': image_dict['name']}
+            new_image_dict={'name': image_dict['name'][:64]}
             if image_dict.get('description'):
                 new_image_dict['description'] = image_dict['description']
             if image_dict.get('metadata'):
@@ -811,7 +813,7 @@ class vimconnector(vimconn.vimconnector):
                 if net.get("model"):       net_dict["model"] = net["model"]
                 if net.get("mac_address"): net_dict["mac_address"] = net["mac_address"]
                 virtio_net_list.append(net_dict)
-            payload_dict={  "name":        name,
+            payload_dict={  "name":        name[:64],
                             "description": description,
                             "imageRef":    image_id,
                             "flavorRef":   flavor_id,
diff --git a/vnfs/examples/vnf_floating_ip.yaml b/vnfs/examples/vnf_floating_ip.yaml
new file mode 100644 (file)
index 0000000..b8fe82a
--- /dev/null
@@ -0,0 +1,61 @@
+##
+# 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
+#        VNFC image: /path/to/imagefolder/TEMPLATE-VM.qcow2
+        image name: ubuntu16.04
+        image checksum: 7373edba82a31eedd182d29237b746cf
+        # 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/vnfs/examples/vnf_no_port_security.yaml b/vnfs/examples/vnf_no_port_security.yaml
new file mode 100644 (file)
index 0000000..1c26c24
--- /dev/null
@@ -0,0 +1,61 @@
+##
+# 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
+#        VNFC image: /path/to/imagefolder/TEMPLATE-VM.qcow2
+        image name: ubuntu16.04
+        image checksum: 7373edba82a31eedd182d29237b746cf
+        # 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
+