v0.4.49 allow IP parameters for networks, and network types in RO
authorgarciadeblas <gerardo.garciadeblas@telefonica.com>
Mon, 5 Sep 2016 03:02:59 +0000 (05:02 +0200)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Mon, 5 Sep 2016 03:02:59 +0000 (05:02 +0200)
Change-Id: I01ac9b0d006b7069555566bac7ba23d84de55312
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
16 files changed:
database_utils/migrate_mano_db.sh
httpserver.py
instance-scenarios/examples/instance-creation-complex4.yaml [new file with mode: 0644]
nfvo.py
nfvo_db.py
openmano_schemas.py
openmanod.py
scenarios/examples/complex3.yaml [new file with mode: 0644]
scenarios/examples/complex4.yaml [new file with mode: 0644]
test/basictest.sh
test/test_vimconn.sh
vimconn.py
vimconn_openstack.py
vimconn_openvim.py
vnfs/examples/dataplaneVNF_2VMs_v02.yaml [new file with mode: 0644]
vnfs/examples/linux_2VMs_v02.yaml [new file with mode: 0644]

index b98a39b..5a18567 100755 (executable)
@@ -571,7 +571,6 @@ function upgrade_to_12(){
        ip_version ENUM('IPv4','IPv6') NOT NULL DEFAULT 'IPv4',
        subnet_address VARCHAR(64) NULL DEFAULT NULL,
        gateway_address VARCHAR(64) NULL DEFAULT NULL,
-       security_group VARCHAR(255) NULL DEFAULT NULL,
        dns_address VARCHAR(64) NULL DEFAULT NULL,
        dhcp_enabled ENUM('true','false') NOT NULL DEFAULT 'true',
        dhcp_start_address VARCHAR(64) NULL DEFAULT NULL,
@@ -585,7 +584,7 @@ function upgrade_to_12(){
         ENGINE=InnoDB;"  | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
     echo "ALTER TABLE interfaces ADD COLUMN ip_address VARCHAR(64) NULL DEFAULT NULL AFTER mac;"  | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
     echo "ALTER TABLE sce_interfaces ADD COLUMN ip_address VARCHAR(64) NULL DEFAULT NULL AFTER interface_id;"  | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
-    echo "INSERT INTO schema_version (version_int, version, openmano_ver, comments, date) VALUES (12, '0.12', '0.4.46', 'create ip_profiles table, with foreign keys to all nets tables, and add ip_address column to interfaces and sce_interfaces', '2016-07-18');" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+    echo "INSERT INTO schema_version (version_int, version, openmano_ver, comments, date) VALUES (12, '0.12', '0.4.46', 'create ip_profiles table, with foreign keys to all nets tables, and add ip_address column to interfaces and sce_interfaces', '2016-08-29');" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
 }
 function downgrade_from_12(){
     echo "    downgrade database from version 0.12 to version 0.11"
index ce164f3..9d1f204 100644 (file)
@@ -38,7 +38,7 @@ import logging
 
 from jsonschema import validate as js_v, exceptions as js_e
 from openmano_schemas import vnfd_schema_v01, vnfd_schema_v02, \
-                            nsd_schema_v01, nsd_schema_v02, scenario_edit_schema, \
+                            nsd_schema_v01, nsd_schema_v02, nsd_schema_v03, scenario_edit_schema, \
                             scenario_action_schema, instance_scenario_action_schema, instance_scenario_create_schema_v01, \
                             tenant_schema, tenant_edit_schema,\
                             datacenter_schema, datacenter_edit_schema, datacenter_action_schema, datacenter_associate_schema,\
@@ -212,6 +212,7 @@ def format_in(default_schema, version_fields=None, version_dict_schema=None):
         #    bottle.abort(HTTP_Bad_Request, "Content error, empty")
         #    return
 
+        #logger.debug('client-data: %s', client_data)
         #look for the client provider version
         error_text = "Invalid content "
         client_version = None
@@ -741,11 +742,17 @@ def http_post_vnfs(tenant_id):
     #print "Parsing the YAML file of the VNF"
     #parse input data
     logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    http_content, used_schema = format_in( vnfd_schema_v01, ("version",), {"v0.2": vnfd_schema_v02})
+    http_content, used_schema = format_in( vnfd_schema_v01, ("schema_version",), {"0.2": vnfd_schema_v02})
     r = utils.remove_extra_items(http_content, used_schema)
     if r is not None: print "http_post_vnfs: Warning: remove extra items ", r
     try:
-        vnf_id = nfvo.new_vnf(mydb,tenant_id,http_content)
+        if http_content.get("schema_version") == None:
+            vnf_id = nfvo.new_vnf(mydb,tenant_id,http_content)
+        elif http_content.get("schema_version") == "0.2":
+            vnf_id = nfvo.new_vnf_v02(mydb,tenant_id,http_content)
+        else:
+            logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
+            bottle.abort(HTTP_Bad_Request, "Invalid schema version")
         return http_get_vnf_id(tenant_id, vnf_id)
     except (nfvo.NfvoException, db_base_Exception) as e:
         logger.error("http_post_vnfs error {}: {}".format(e.http_code, str(e)))
@@ -779,14 +786,14 @@ def http_get_hosts(tenant_id, datacenter):
             result, data = nfvo.get_hosts_info(mydb, tenant_id) #, datacenter)
         
         if result < 0:
-            print "http_post_vnfs error %d %s" % (-result, data)
+            print "http_get_hosts error %d %s" % (-result, data)
             bottle.abort(-result, data)
         else:
             convert_datetime2str(data)
             print json.dumps(data, indent=4)
             return format_out(data)
     except (nfvo.NfvoException, db_base_Exception) as e:
-        logger.error("http_post_vnfs error {}: {}".format(e.http_code, str(e)))
+        logger.error("http_get_hosts error {}: {}".format(e.http_code, str(e)))
         bottle.abort(e.http_code, str(e))
 
 
@@ -837,15 +844,20 @@ def http_post_verify(tenant_id):
 def http_post_scenarios(tenant_id):
     '''add a scenario into the catalogue. Creates the scenario and its internal structure in the OPENMANO DB'''
     logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
-    http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02})
+    http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02, "0.3": nsd_schema_v03})
     #r = utils.remove_extra_items(http_content, used_schema)
     #if r is not None: print "http_post_scenarios: Warning: remove extra items ", r
     #print "http_post_scenarios input: ",  http_content
     try:
         if http_content.get("schema_version") == None:
             scenario_id = nfvo.new_scenario(mydb, tenant_id, http_content)
-        else:
+        elif str(http_content.get("schema_version")) == "2":
             scenario_id = nfvo.new_scenario_v02(mydb, tenant_id, http_content)
+        elif http_content.get("schema_version") == "0.3":
+            scenario_id = nfvo.new_scenario_v03(mydb, tenant_id, http_content)
+        else:
+            logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
+            bottle.abort(HTTP_Bad_Request, "Invalid schema version")
         #print json.dumps(data, indent=4)
         #return format_out(data)
         return http_get_scenario_id(tenant_id, scenario_id)
diff --git a/instance-scenarios/examples/instance-creation-complex4.yaml b/instance-scenarios/examples/instance-creation-complex4.yaml
new file mode 100644 (file)
index 0000000..8f20e4b
--- /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
+##
+---
+schema_version:  "0.1"
+instance:
+  name:          complex4-instance
+  description:   Example of IP parameters in networks
+  scenario:      complex4
+  networks: 
+    dataconn1:
+      ip-profile:
+        ip-version:       IPv4
+        subnet-address:   10.11.1.0/24
+        gateway-address:  10.11.1.1
+        dns-address:      8.8.8.8
+        dhcp:
+          enabled:       true
+          start-address: 10.11.1.100
+          count:         150
+      interfaces:
+      -   vnf:           VNF1
+          vnf_interface: in
+          ip_address:    10.11.1.2
+      -   vnf:           VNF2
+          vnf_interface: in
+          ip_address:    10.11.1.3
+    dataconn2:
+      ip-profile:
+        ip-version:       IPv4
+        subnet-address:   10.11.2.0/24
+        gateway-address:  10.11.2.1
+        dns-address:      8.8.8.8
+        dhcp:
+          enabled:       true
+          start-address: 10.11.2.100
+          count:         150
+      interfaces:
+      -   vnf:           VNF1
+          vnf_interface: out
+          ip_address:    10.11.2.2
+      -   vnf:           VNF2
+          vnf_interface: out
+          ip_address:    10.11.2.3
+
+
diff --git a/nfvo.py b/nfvo.py
index 59c2dca..ce3a07d 100644 (file)
--- a/nfvo.py
+++ b/nfvo.py
@@ -36,6 +36,7 @@ from db_base import HTTP_Unauthorized, HTTP_Bad_Request, HTTP_Internal_Server_Er
 import console_proxy_thread as cli
 import vimconn
 import logging
+import collections
 from db_base import db_base_Exception
 
 global global_config
@@ -160,7 +161,7 @@ def rollback(mydb,  vims, rollback_list):
                     mydb.delete_row(FROM="datacenters_images", WHERE={"datacenter_id": vim["id"], "vim_id":item["uuid"]})
                 elif item["what"]=="flavor":
                     vim.delete_flavor(item["uuid"])
-                    mydb.delete_row(FROM="datacenters_flavos", WHERE={"datacenter_id": vim["id"], "vim_id":item["uuid"]})
+                    mydb.delete_row(FROM="datacenters_flavors", WHERE={"datacenter_id": vim["id"], "vim_id":item["uuid"]})
                 elif item["what"]=="network":
                     vim.delete_network(item["uuid"])
                 elif item["what"]=="vm":
@@ -551,6 +552,139 @@ def new_vnf(mydb, tenant_id, vnf_descriptor):
         #logger.error("start_scenario %s", error_text)
         raise NfvoException(error_text, e.http_code)
         
+def new_vnf_v02(mydb, tenant_id, vnf_descriptor):
+    global global_config
+    
+    # Step 1. Check the VNF descriptor
+    check_vnf_descriptor(vnf_descriptor)
+    # Step 2. Check tenant exist
+    if tenant_id != "any":
+        check_tenant(mydb, tenant_id) 
+        if "tenant_id" in vnf_descriptor["vnf"]:
+            if vnf_descriptor["vnf"]["tenant_id"] != tenant_id:
+                raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor["vnf"]["tenant_id"], tenant_id),
+                                    HTTP_Unauthorized)
+        else:
+            vnf_descriptor['vnf']['tenant_id'] = tenant_id
+        # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
+        vims = get_vim(mydb, tenant_id)
+    else:
+        vims={}
+
+    # Step 4. Review the descriptor and add missing  fields
+    #print vnf_descriptor
+    #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
+    vnf_name = vnf_descriptor['vnf']['name']
+    vnf_descriptor['vnf']['description'] = vnf_descriptor['vnf'].get("description", vnf_name)
+    if "physical" in vnf_descriptor['vnf']:
+        del vnf_descriptor['vnf']['physical']
+    #print vnf_descriptor
+    # Step 5. Check internal connections
+    # TODO: to be moved to step 1????
+    internal_connections=vnf_descriptor['vnf'].get('internal_connections',[])
+    for ic in internal_connections:
+        if len(ic['elements'])>2 and ic['type']=='e-line':
+            raise NfvoException("Mismatch 'type':'e-line' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'e-lan'".format(len(ic), ic['name']), 
+                                HTTP_Bad_Request)
+        
+    # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM 
+    logger.debug('BEGIN creation of VNF "%s"' % vnf_name)
+    logger.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name,len(vnf_descriptor['vnf']['VNFC'])))
+    
+    #For each VNFC, we add it to the VNFCDict and we  create a flavor.
+    VNFCDict = {}     # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
+    rollback_list = []    # It will contain the new images created in mano. It is used for rollback
+    try:
+        logger.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
+        for vnfc in vnf_descriptor['vnf']['VNFC']:
+            VNFCitem={}
+            VNFCitem["name"] = vnfc['name']
+            VNFCitem["description"] = vnfc.get("description", 'VM %s of the VNF %s' %(vnfc['name'],vnf_name))
+            
+            #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
+            
+            myflavorDict = {}
+            myflavorDict["name"] = vnfc['name']+"-flv"
+            myflavorDict["description"] = VNFCitem["description"]
+            myflavorDict["ram"] = vnfc.get("ram", 0)
+            myflavorDict["vcpus"] = vnfc.get("vcpus", 0)
+            myflavorDict["disk"] = vnfc.get("disk", 1)
+            myflavorDict["extended"] = {}
+            
+            devices = vnfc.get("devices")
+            if devices != None:
+                myflavorDict["extended"]["devices"] = devices
+            
+            # TODO:
+            # Mapping from processor models to rankings should be available somehow in the NFVO. They could be taken from VIM or directly from a new database table
+            # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host 
+            
+            # Previous code has been commented
+            #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
+            #    myflavorDict["flavor"]['extended']['processor_ranking'] = 200
+            #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
+            #    myflavorDict["flavor"]['extended']['processor_ranking'] = 300
+            #else:
+            #    result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
+            #    if result2:
+            #        print "Error creating flavor: unknown processor model. Rollback successful."
+            #        return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
+            #    else:
+            #        return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
+            myflavorDict['extended']['processor_ranking'] = 100  #Hardcoded value, while we decide when the mapping is done
+     
+            if 'numas' in vnfc and len(vnfc['numas'])>0:
+                myflavorDict['extended']['numas'] = vnfc['numas']
+
+            #print myflavorDict
+    
+            # Step 6.2 New flavors are created in the VIM
+            flavor_id = create_or_use_flavor(mydb, vims, myflavorDict, rollback_list)
+
+            #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
+            VNFCitem["flavor_id"] = flavor_id
+            VNFCDict[vnfc['name']] = VNFCitem
+            
+        logger.debug("Creating new images in the VIM for each VNFC")
+        # Step 6.3 New images are created in the VIM
+        #For each VNFC, we must create the appropriate image.
+        #This "for" loop might be integrated with the previous one 
+        #In case this integration is made, the VNFCDict might become a VNFClist.
+        for vnfc in vnf_descriptor['vnf']['VNFC']:
+            #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
+            image_dict={'location':vnfc['VNFC image'], 'name':vnfc['name']+"-img", 'description':VNFCDict[vnfc['name']]['description']}
+            image_metadata_dict = vnfc.get('image metadata', None)
+            image_metadata_str = None
+            if image_metadata_dict is not None: 
+                image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
+            image_dict['metadata']=image_metadata_str
+            #print "create_or_use_image", mydb, vims, image_dict, rollback_list
+            image_id = create_or_use_image(mydb, vims, image_dict, rollback_list)
+            #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
+            VNFCDict[vnfc['name']]["image_id"] = image_id
+            VNFCDict[vnfc['name']]["image_path"] = vnfc['VNFC image']
+
+            
+        # Step 7. Storing the VNF descriptor in the repository
+        if "descriptor" not in vnf_descriptor["vnf"]:
+            vnf_descriptor["vnf"]["descriptor"] = yaml.safe_dump(vnf_descriptor, indent=4, explicit_start=True, default_flow_style=False)
+    
+        # Step 8. Adding the VNF to the NFVO DB
+        vnf_id = mydb.new_vnf_as_a_whole2(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
+        return vnf_id
+    except (db_base_Exception, vimconn.vimconnException, KeyError) as e:
+        _, message = rollback(mydb, vims, rollback_list)
+        if isinstance(e, db_base_Exception):
+            error_text = "Exception at database"
+        elif isinstance(e, KeyError):
+            error_text = "KeyError exception "
+            e.http_code = HTTP_Internal_Server_Error
+        else:
+            error_text = "Exception at VIM"
+        error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
+        #logger.error("start_scenario %s", error_text)
+        raise NfvoException(error_text, e.http_code)
+
 def get_vnf_id(mydb, tenant_id, vnf_id):
     #check valid tenant_id
     check_tenant(mydb, tenant_id) 
@@ -574,12 +708,28 @@ def get_vnf_id(mydb, tenant_id, vnf_id):
         raise NfvoException("vnf '{}' not found".format(vnf_id), HTTP_Not_Found)
 
     data['vnf']['VNFC'] = content
+    #TODO: GET all the information from a VNFC and include it in the output.
+    
     #GET NET
     content = mydb.get_rows(FROM='vnfs join nets on vnfs.uuid=nets.vnf_id', 
                                     SELECT=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
                                     WHERE={'vnfs.uuid': vnf_id} )
     data['vnf']['nets'] = content
-    #GET Interfaces
+
+    #GET ip-profile for each net
+    for net in data['vnf']['nets']:
+        ipprofiles = mydb.get_rows(FROM='ip_profiles',
+                                   SELECT=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
+                                   WHERE={'net_id': net["uuid"]} )
+        if len(ipprofiles)==1:
+            net["ip_profile"] = ipprofiles[0]
+        elif len(ipprofiles)>1:
+            raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net['uuid']), HTTP_Bad_Request)
+        
+    
+    #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
+     
+    #GET External Interfaces
     content = mydb.get_rows(FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
                                     SELECT=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
                                             'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
@@ -587,6 +737,7 @@ def get_vnf_id(mydb, tenant_id, vnf_id):
                                     WHERE_NOT={'interfaces.external_name': None} )
     #print content
     data['vnf']['external-connections'] = content
+    
     return data
 
 
@@ -1155,11 +1306,12 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc
             myNetDict["name"] = myNetName
             myNetDict["type"] = myNetType
             myNetDict["tenant_id"] = myvim_tenant
+            myNetIPProfile = sce_net.get('ip_profile', None)
             #TODO:
             #We should use the dictionary as input parameter for new_network
             #print myNetDict
             if not sce_net["external"]:
-                network_id = myvim.new_network(myNetName, myNetType)
+                network_id = myvim.new_network(myNetName, myNetType, myNetIPProfile)
                 #print "New VIM network created for scenario %s. Network id:  %s" % (scenarioDict['name'],network_id)
                 sce_net['vim_id'] = network_id
                 auxNetDict['scenario'][sce_net['uuid']] = network_id
@@ -1186,10 +1338,11 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc
                 myNetDict["name"] = myNetName
                 myNetDict["type"] = myNetType
                 myNetDict["tenant_id"] = myvim_tenant
+                myNetIPProfile = net.get('ip_profile', None)
                 #print myNetDict
                 #TODO:
                 #We should use the dictionary as input parameter for new_network
-                network_id = myvim.new_network(myNetName, myNetType)
+                network_id = myvim.new_network(myNetName, myNetType, myNetIPProfile)
                 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
                 net['vim_id'] = network_id
                 if sce_vnf['uuid'] not in auxNetDict:
@@ -1315,7 +1468,6 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc
         #logger.error("start_scenario %s", error_text)
         raise NfvoException(error_text, e.http_code)
 
-
 def unify_cloud_config(cloud_config):
     index_to_delete = []
     users = cloud_config.get("users", [])
@@ -1352,6 +1504,129 @@ def get_datacenter_by_name_uuid(mydb, tenant_id, datacenter_id_name=None):
         raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict)
     return vims.keys()[0], vims.values()[0]
 
+def new_scenario_v03(mydb, tenant_id, scenario_dict):
+    scenario = scenario_dict["scenario"]
+    if tenant_id != "any":
+        check_tenant(mydb, tenant_id) 
+        if "tenant_id" in scenario:
+            if scenario["tenant_id"] != tenant_id:
+                logger("Tenant '%s' not found", tenant_id)
+                raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
+                                                    scenario["tenant_id"], tenant_id), HTTP_Unauthorized)
+    else:
+        tenant_id=None
+
+#1: Check that VNF are present at database table vnfs and update content into scenario dict
+    for name,vnf in scenario["vnfs"].iteritems():
+        where={}
+        where_or={"tenant_id": tenant_id, 'public': "true"}
+        error_text = ""
+        error_pos = "'topology':'nodes':'" + name + "'"
+        if 'vnf_id' in vnf:
+            error_text += " 'vnf_id' " +  vnf['vnf_id']
+            where['uuid'] = vnf['vnf_id']
+        if 'vnf_name' in vnf:
+            error_text += " 'vnf_name' " +  vnf['vnf_name']
+            where['name'] = vnf['vnf_name']
+        if len(where) == 0:
+            raise NfvoException("Needed a 'vnf_id' or 'VNF model' at " + error_pos, HTTP_Bad_Request)
+        vnf_db = mydb.get_rows(SELECT=('uuid','name','description'),
+                               FROM='vnfs',
+                               WHERE=where,
+                               WHERE_OR=where_or,
+                               WHERE_AND_OR="AND")
+        if len(vnf_db)==0:
+            raise NfvoException("Unknown" + error_text + " at " + error_pos, HTTP_Not_Found)
+        elif len(vnf_db)>1:
+            raise NfvoException("More than one" + error_text + " at " + error_pos + " Concrete with 'vnf_id'", HTTP_Conflict)
+        vnf['uuid']=vnf_db[0]['uuid']
+        vnf['description']=vnf_db[0]['description']
+        vnf['ifaces'] = {}
+        # get external interfaces
+        ext_ifaces = mydb.get_rows(SELECT=('external_name as name','i.uuid as iface_uuid', 'i.type as type'), 
+            FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id', 
+            WHERE={'vnfs.uuid':vnf['uuid']}, WHERE_NOT={'external_name':None} )
+        for ext_iface in ext_ifaces:
+            vnf['ifaces'][ ext_iface['name'] ] = {'uuid':ext_iface['iface_uuid'], 'type':ext_iface['type']}
+        
+        # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly 
+
+#2: Insert net_key and ip_address at every vnf interface
+    for net_name,net in scenario["networks"].iteritems():
+        net_type_bridge=False
+        net_type_data=False
+        for iface_dict in net["interfaces"]:
+            logger.debug("Iface_dict %s", iface_dict)
+            vnf = iface_dict["vnf"]
+            iface = iface_dict["vnf_interface"]
+            if vnf not in scenario["vnfs"]:
+                error_text = "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name, vnf)
+                #logger.debug(error_text)
+                raise NfvoException(error_text, HTTP_Not_Found)
+            if iface not in scenario["vnfs"][vnf]['ifaces']:
+                error_text = "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name, iface)
+                #logger.debug(error_text)
+                raise NfvoException(error_text, HTTP_Bad_Request)
+            if "net_key" in scenario["vnfs"][vnf]['ifaces'][iface]:
+                error_text = "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
+                                % (net_name, iface,scenario["vnfs"][vnf]['ifaces'][iface]['net_key'])
+                #logger.debug(error_text)
+                raise NfvoException(error_text, HTTP_Bad_Request)
+            scenario["vnfs"][vnf]['ifaces'][ iface ]['net_key'] = net_name
+            scenario["vnfs"][vnf]['ifaces'][ iface ]['ip_address'] = iface_dict.get('ip_address',None)
+            iface_type = scenario["vnfs"][vnf]['ifaces'][iface]['type']
+            if iface_type=='mgmt' or iface_type=='bridge':
+                net_type_bridge = True
+            else:
+                net_type_data = True
+        if net_type_bridge and net_type_data:
+            error_text = "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name)
+            #logger.debug(error_text)
+            raise NfvoException(error_text, HTTP_Bad_Request)
+        elif net_type_bridge:
+            type_='bridge'
+        else:
+            type_='data' if len(net["interfaces"])>2 else 'ptp'
+        
+        if ("implementation" in net):
+            if (type_ == "bridge" and net["implementation"] == "underlay"):
+                error_text = "Error connecting interfaces of data type to a network declared as 'underlay' at 'network':'%s'" % (net_name)
+                #logger.debug(error_text)
+                raise NfvoException(error_text, HTTP_Bad_Request)
+            elif (type_ <> "bridge" and net["implementation"] == "overlay"):
+                error_text = "Error connecting interfaces of data type to a network declared as 'overlay' at 'network':'%s'" % (net_name)
+                #logger.debug(error_text)
+                raise NfvoException(error_text, HTTP_Bad_Request)
+            net.pop("implementation")
+        if ("type" in net):
+            if (type_ == "data" and net["type"] == "e-line"):
+                error_text = "Error connecting more than 2 interfaces of data type to a network declared as type 'e-line' at 'network':'%s'" % (net_name)
+                #logger.debug(error_text)
+                raise NfvoException(error_text, HTTP_Bad_Request)
+            elif (type_ == "ptp" and net["type"] == "e-lan"):
+                type_ = "data"
+
+        net['type'] = type_
+        net['name'] = net_name
+        net['external'] = net.get('external', False)
+
+#3: insert at database
+    scenario["nets"] = scenario["networks"]
+    scenario['tenant_id'] = tenant_id
+    scenario_id = mydb.new_scenario2(scenario)
+    return scenario_id
+
+def update(d, u):
+    '''Takes dict d and updates it with the values in dict u.'''
+    '''It merges all depth levels'''
+    for k, v in u.iteritems():
+        if isinstance(v, collections.Mapping):
+            r = update(d.get(k, {}), v)
+            d[k] = r
+        else:
+            d[k] = u[k]
+    return d
+
 def create_instance(mydb, tenant_id, instance_dict):
     #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
     logger.debug("Creating instance...")
@@ -1364,18 +1639,23 @@ def create_instance(mydb, tenant_id, instance_dict):
     myvims[default_datacenter_id] = vim
     #myvim_tenant = myvim['tenant_id']
 #    default_datacenter_name = vim['name']
-    default_datacenter_tenant_id = vim['config']['datacenter_tenant_id']    #TODO revisar
+    default_datacenter_tenant_id = vim['config']['datacenter_tenant_id']    #TODO review
     rollbackList=[]
     
     #print "Checking that the scenario exists and getting the scenario dictionary"
     scenarioDict = mydb.get_scenario(scenario, tenant_id, default_datacenter_id)
+    
+    #logger.debug("Dictionaries before merging")
+    #logger.debug("InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
+    #logger.debug("ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
+    
     scenarioDict['datacenter_tenant_id'] = default_datacenter_tenant_id
     scenarioDict['datacenter_id'] = default_datacenter_id
-   
+
     auxNetDict = {}   #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
     auxNetDict['scenario'] = {}
     
-    print "scenario dict: ",yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)  #TODO quitar 
+    logger.debug("scenario dict: {}".format(yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)))  #TODO remove 
     instance_name = instance_dict["name"]
     instance_description = instance_dict.get("description")
     try:
@@ -1427,6 +1707,36 @@ def create_instance(mydb, tenant_id, instance_dict):
         else:
             scenarioDict["cloud-config"] = cloud_config
             unify_cloud_config(cloud_config)
+
+    #0.2 merge instance information into scenario
+        #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
+        #However, this is not possible yet.
+        for net_name, net_instance_desc in instance_dict.get("networks",{}).iteritems():
+            for scenario_net in scenarioDict['nets']:
+                if net_name == scenario_net["name"]:
+                    if 'ip-profile' in net_instance_desc:
+                        ipprofile = net_instance_desc['ip-profile']
+                        ipprofile['subnet_address'] = ipprofile.pop('subnet-address',None)
+                        ipprofile['ip_version'] = ipprofile.pop('ip-version','IPv4')
+                        ipprofile['gateway_address'] = ipprofile.pop('gateway-address',None)
+                        ipprofile['dns_address'] = ipprofile.pop('dns-address',None)
+                        if 'dhcp' in ipprofile:
+                            ipprofile['dhcp_start_address'] = ipprofile['dhcp'].get('start-address',None)
+                            ipprofile['dhcp_enabled'] = ipprofile['dhcp'].get('enabled',True)
+                            ipprofile['dhcp_count'] = ipprofile['dhcp'].get('count',None)
+                            del ipprofile['dhcp']
+                        update(scenario_net['ip_profile'],ipprofile)
+            for interface in net_instance_desc['interfaces']:
+                if 'ip_address' in interface:
+                    for vnf in scenarioDict['vnfs']:
+                        if interface['vnf'] == vnf['name']:
+                            for vnf_interface in vnf['interfaces']:
+                                if interface['vnf_interface'] == vnf_interface['external_name']:
+                                    vnf_interface['ip_address']=interface['ip_address']
+
+        logger.debug("Merged dictionary")
+        logger.debug("ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
+
         
     #1. Creating new nets (sce_nets) in the VIM"
         for sce_net in scenarioDict['nets']:
@@ -1502,7 +1812,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                         create_network = False
                 if create_network:
                     #if network is not external
-                    network_id = vim.new_network(net_vim_name, net_type)
+                    network_id = vim.new_network(net_vim_name, net_type, sce_net.get('ip_profile',None))
                     sce_net["vim_id_sites"][datacenter_id] = network_id
                     auxNetDict['scenario'][sce_net['uuid']][datacenter_id] = network_id
                     rollbackList.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id, 'uuid':network_id})
@@ -1523,7 +1833,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                     net_name = "%s.%s" %(instance_name, net["name"])
                     net_name = net_name[:255]     #limit length
                 net_type = net['type']
-                network_id = vim.new_network(net_name, net_type)
+                network_id = vim.new_network(net_name, net_type, net.get('ip_profile',None))
                 net['vim_id'] = network_id
                 if sce_vnf['uuid'] not in auxNetDict:
                     auxNetDict[sce_vnf['uuid']] = {}
@@ -2332,8 +2642,9 @@ def vim_action_create(mydb, tenant_id, datacenter, item, descriptor):
             net = descriptor["network"]
             net_name = net.pop("name")
             net_type = net.pop("type", "bridge")
-            net_public=net.pop("shared", False)
-            content = myvim.new_network(net_name, net_type, net_public, **net)
+            net_public = net.pop("shared", False)
+            net_ipprofile = net.pop("ip_profile", None)
+            content = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, **net)
         elif item=="tenants":
             tenant = descriptor["tenant"]
             content = myvim.new_tenant(tenant["name"], tenant.get("description"))
index 09da2a9..a729aa2 100644 (file)
@@ -32,7 +32,7 @@ import MySQLdb as mdb
 import json
 import yaml
 import time
-
+import sys, os
 
 tables_with_createdat_field=["datacenters","instance_nets","instance_scenarios","instance_vms","instance_vnfs",
                            "interfaces","nets","nfvo_tenants","scenarios","sce_interfaces","sce_nets",
@@ -173,6 +173,164 @@ class nfvo_db(db_base.db_base):
                 self._format_error(e, tries)
             tries -= 1
         
+    def new_vnf_as_a_whole2(self,nfvo_tenant,vnf_name,vnf_descriptor,VNFCDict):
+        self.logger.debug("Adding new vnf to the NFVO database")
+        tries = 2
+        while tries:
+            created_time = time.time()
+            try:
+                with self.con:
+                     
+                    myVNFDict = {}
+                    myVNFDict["name"] = vnf_name
+                    myVNFDict["descriptor"] = vnf_descriptor['vnf'].get('descriptor')
+                    myVNFDict["public"] = vnf_descriptor['vnf'].get('public', "false")
+                    myVNFDict["description"] = vnf_descriptor['vnf']['description']
+                    myVNFDict["class"] = vnf_descriptor['vnf'].get('class',"MISC")
+                    myVNFDict["tenant_id"] = vnf_descriptor['vnf'].get("tenant_id")
+                    
+                    vnf_id = self._new_row_internal('vnfs', myVNFDict, add_uuid=True, root_uuid=None, created_time=created_time)
+                    #print "Adding new vms to the NFVO database"
+                    #For each vm, we must create the appropriate vm in the NFVO database.
+                    vmDict = {}
+                    for _,vm in VNFCDict.iteritems():
+                        #This code could make the name of the vms grow and grow.
+                        #If we agree to follow this convention, we should check with a regex that the vnfc name is not including yet the vnf name  
+                        #vm['name'] = "%s-%s" % (vnf_name,vm['name'])
+                        #print "VM name: %s. Description: %s" % (vm['name'], vm['description'])
+                        vm["vnf_id"] = vnf_id
+                        created_time += 0.00001
+                        vm_id = self._new_row_internal('vms', vm, add_uuid=True, root_uuid=vnf_id, created_time=created_time) 
+                        #print "Internal vm id in NFVO DB: %s" % vm_id
+                        vmDict[vm['name']] = vm_id
+                     
+                    #Collect the data interfaces of each VM/VNFC under the 'numas' field
+                    dataifacesDict = {}
+                    for vm in vnf_descriptor['vnf']['VNFC']:
+                        dataifacesDict[vm['name']] = {}
+                        for numa in vm.get('numas', []):
+                            for dataiface in numa.get('interfaces',[]):
+                                db_base._convert_bandwidth(dataiface)
+                                dataifacesDict[vm['name']][dataiface['name']] = {}
+                                dataifacesDict[vm['name']][dataiface['name']]['vpci'] = dataiface['vpci']
+                                dataifacesDict[vm['name']][dataiface['name']]['bw'] = dataiface['bandwidth']
+                                dataifacesDict[vm['name']][dataiface['name']]['model'] = "PF" if dataiface['dedicated']=="yes" else ("VF"  if dataiface['dedicated']=="no" else "VFnotShared")
+                    
+                    #Collect the bridge interfaces of each VM/VNFC under the 'bridge-ifaces' field
+                    bridgeInterfacesDict = {}
+                    for vm in vnf_descriptor['vnf']['VNFC']:
+                        if 'bridge-ifaces' in  vm:
+                            bridgeInterfacesDict[vm['name']] = {}
+                            for bridgeiface in vm['bridge-ifaces']:
+                                db_base._convert_bandwidth(bridgeiface)
+                                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)
+                    
+                    #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)"
+                    internalconnList = []
+                    if 'internal-connections' in vnf_descriptor['vnf']:
+                        for net in vnf_descriptor['vnf']['internal-connections']:
+                            #print "Net name: %s. Description: %s" % (net['name'], net['description'])
+                            
+                            myNetDict = {}
+                            myNetDict["name"] = net['name']
+                            myNetDict["description"] = net['description']
+                            if (net["implementation"] == "overlay"):
+                                net["type"] = "bridge"
+                                #It should give an error if the type is e-line. For the moment, we consider it as a bridge 
+                            elif (net["implementation"] == "underlay"):
+                                if (net["type"] == "e-line"):
+                                    net["type"] = "ptp"
+                                elif (net["type"] == "e-lan"):
+                                    net["type"] = "data"
+                            net.pop("implementation")
+                            myNetDict["type"] = net['type']
+                            myNetDict["vnf_id"] = vnf_id
+                            
+                            created_time += 0.00001
+                            net_id = self._new_row_internal('nets', myNetDict, add_uuid=True, root_uuid=vnf_id, created_time=created_time)
+                            
+                            if "ip-profile" in net:
+                                ip_profile = net["ip-profile"]
+                                myIPProfileDict = {}
+                                myIPProfileDict["net_id"] = net_id
+                                myIPProfileDict["ip_version"] = ip_profile.get('ip-version',"IPv4")
+                                myIPProfileDict["subnet_address"] = ip_profile.get('subnet-address',None)
+                                myIPProfileDict["gateway_address"] = ip_profile.get('gateway-address',None)
+                                myIPProfileDict["dns_address"] = ip_profile.get('dns-address',None)
+                                if ("dhcp" in ip_profile):
+                                    myIPProfileDict["dhcp_enabled"] = ip_profile["dhcp"].get('enabled',"true")
+                                    myIPProfileDict["dhcp_start_address"] = ip_profile["dhcp"].get('start-address',None)
+                                    myIPProfileDict["dhcp_count"] = ip_profile["dhcp"].get('count',None)
+                                
+                                created_time += 0.00001
+                                ip_profile_id = self._new_row_internal('ip_profiles', myIPProfileDict)
+                                
+                            for element in net['elements']:
+                                ifaceItem = {}
+                                #ifaceItem["internal_name"] = "%s-%s-%s" % (net['name'],element['VNFC'], element['local_iface_name'])  
+                                ifaceItem["internal_name"] = element['local_iface_name']
+                                #ifaceItem["vm_id"] = vmDict["%s-%s" % (vnf_name,element['VNFC'])]
+                                ifaceItem["vm_id"] = vmDict[element['VNFC']]
+                                ifaceItem["net_id"] = net_id
+                                ifaceItem["type"] = net['type']
+                                ifaceItem["ip_address"] = element.get('ip_address',None)
+                                if ifaceItem ["type"] == "data":
+                                    ifaceItem["vpci"] =  dataifacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['vpci'] 
+                                    ifaceItem["bw"] =    dataifacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['bw']
+                                    ifaceItem["model"] = dataifacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['model']
+                                else:
+                                    ifaceItem["vpci"] =  bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['vpci']
+                                    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']
+                                internalconnList.append(ifaceItem)
+                            #print "Internal net id in NFVO DB: %s" % net_id
+                    
+                    #print "Adding internal interfaces to the NFVO database (if any)"
+                    for iface in internalconnList:
+                        print "Iface name: %s" % iface['internal_name']
+                        created_time += 0.00001
+                        iface_id = self._new_row_internal('interfaces', iface, add_uuid=True, root_uuid=vnf_id, created_time=created_time)
+                        #print "Iface id in NFVO DB: %s" % iface_id
+                    
+                    #print "Adding external interfaces to the NFVO database"
+                    for iface in vnf_descriptor['vnf']['external-connections']:
+                        myIfaceDict = {}
+                        #myIfaceDict["internal_name"] = "%s-%s-%s" % (vnf_name,iface['VNFC'], iface['local_iface_name'])  
+                        myIfaceDict["internal_name"] = iface['local_iface_name']
+                        #myIfaceDict["vm_id"] = vmDict["%s-%s" % (vnf_name,iface['VNFC'])]
+                        myIfaceDict["vm_id"] = vmDict[iface['VNFC']]
+                        myIfaceDict["external_name"] = iface['name']
+                        myIfaceDict["type"] = iface['type']
+                        if iface["type"] == "data":
+                            myIfaceDict["vpci"]  = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['vpci']
+                            myIfaceDict["bw"]    = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['bw']
+                            myIfaceDict["model"] = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['model']
+                        else:
+                            myIfaceDict["vpci"]  = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['vpci']
+                            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']
+                        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)
+                        #print "Iface id in NFVO DB: %s" % iface_id
+                    
+                    return vnf_id
+                
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+#             except KeyError as e2:
+#                 exc_type, exc_obj, exc_tb = sys.exc_info()
+#                 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
+#                 self.logger.debug("Exception type: %s; Filename: %s; Line number: %s", exc_type, fname, exc_tb.tb_lineno)
+#                 raise KeyError
+            tries -= 1
 
     def new_scenario(self, scenario_dict):
         tries = 2
@@ -237,6 +395,92 @@ class nfvo_db(db_base.db_base):
                 self._format_error(e, tries)
             tries -= 1
 
+    def new_scenario2(self, scenario_dict):
+        tries = 2
+        while tries:
+            created_time = time.time()
+            try:
+                with self.con:
+                    self.cur = self.con.cursor()
+                    tenant_id = scenario_dict.get('tenant_id')
+                    #scenario
+                    INSERT_={'tenant_id': tenant_id,
+                             'name': scenario_dict['name'],
+                             'description': scenario_dict['description'],
+                             'public': scenario_dict.get('public', "false")}
+                    
+                    scenario_uuid =  self._new_row_internal('scenarios', INSERT_, add_uuid=True, root_uuid=None, created_time=created_time)
+                    #sce_nets
+                    for net in scenario_dict['nets'].values():
+                        net_dict={'scenario_id': scenario_uuid}
+                        net_dict["name"] = net["name"]
+                        net_dict["type"] = net["type"]
+                        net_dict["description"] = net.get("description")
+                        net_dict["external"] = net.get("external", False)
+                        if "graph" in net:
+                            #net["graph"]=yaml.safe_dump(net["graph"],default_flow_style=True,width=256)
+                            #TODO, must be json because of the GUI, change to yaml
+                            net_dict["graph"]=json.dumps(net["graph"])
+                        created_time += 0.00001
+                        net_uuid =  self._new_row_internal('sce_nets', net_dict, add_uuid=True, root_uuid=scenario_uuid, created_time=created_time)
+                        net['uuid']=net_uuid
+                        
+                        if "ip-profile" in net:
+                            ip_profile = net["ip-profile"]
+                            myIPProfileDict = {}
+                            myIPProfileDict["sce_net_id"] = net_uuid
+                            myIPProfileDict["ip_version"] = ip_profile.get('ip-version',"IPv4")
+                            myIPProfileDict["subnet_address"] = ip_profile.get('subnet-address',None)
+                            myIPProfileDict["gateway_address"] = ip_profile.get('gateway-address',None)
+                            myIPProfileDict["dns_address"] = ip_profile.get('dns-address',None)
+                            if ("dhcp" in ip_profile):
+                                myIPProfileDict["dhcp_enabled"] = ip_profile["dhcp"].get('enabled',"true")
+                                myIPProfileDict["dhcp_start_address"] = ip_profile["dhcp"].get('start-address',None)
+                                myIPProfileDict["dhcp_count"] = ip_profile["dhcp"].get('count',None)
+                            
+                            created_time += 0.00001
+                            ip_profile_id = self._new_row_internal('ip_profiles', myIPProfileDict)
+
+                    #sce_vnfs
+                    for k,vnf in scenario_dict['vnfs'].items():
+                        INSERT_={'scenario_id': scenario_uuid,
+                                'name': k,
+                                'vnf_id': vnf['uuid'],
+                                #'description': scenario_dict['name']
+                                'description': vnf['description']
+                            }
+                        if "graph" in vnf:
+                            #INSERT_["graph"]=yaml.safe_dump(vnf["graph"],default_flow_style=True,width=256)
+                            #TODO, must be json because of the GUI, change to yaml
+                            INSERT_["graph"]=json.dumps(vnf["graph"])
+                        created_time += 0.00001
+                        scn_vnf_uuid =  self._new_row_internal('sce_vnfs', INSERT_, add_uuid=True, root_uuid=scenario_uuid, created_time=created_time)
+                        vnf['scn_vnf_uuid']=scn_vnf_uuid
+                        #sce_interfaces
+                        for iface in vnf['ifaces'].values():
+                            #print 'iface', iface
+                            if 'net_key' not in iface:
+                                continue
+                            iface['net_id'] = scenario_dict['nets'][ iface['net_key'] ]['uuid']
+                            INSERT_={'sce_vnf_id': scn_vnf_uuid,
+                                'sce_net_id': iface['net_id'],
+                                'interface_id': iface['uuid'],
+                                'ip_address': iface['ip_address']
+                            }
+                            created_time += 0.00001
+                            iface_uuid =  self._new_row_internal('sce_interfaces', INSERT_, add_uuid=True, root_uuid=scenario_uuid, created_time=created_time)
+                            
+                    return scenario_uuid
+                    
+            except (mdb.Error, AttributeError) as e:
+                self._format_error(e, tries)
+#             except KeyError as e2:
+#                 exc_type, exc_obj, exc_tb = sys.exc_info()
+#                 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
+#                 self.logger.debug("Exception type: %s; Filename: %s; Line number: %s", exc_type, fname, exc_tb.tb_lineno)
+#                 raise KeyError
+            tries -= 1
+
     def edit_scenario(self, scenario_dict):
         tries = 2
         while tries:
@@ -372,7 +616,7 @@ class nfvo_db(db_base.db_base):
                     scenario_dict['vnfs'] = self.cur.fetchall()
                     for vnf in scenario_dict['vnfs']:
                         #sce_interfaces
-                        cmd = "SELECT uuid,sce_net_id,interface_id FROM sce_interfaces WHERE sce_vnf_id='{}' ORDER BY created_at".format(vnf['uuid'])
+                        cmd = "SELECT scei.uuid,scei.sce_net_id,scei.interface_id,i.external_name,scei.ip_address FROM sce_interfaces as scei join interfaces as i on scei.interface_id=i.uuid WHERE scei.sce_vnf_id='{}' ORDER BY scei.created_at".format(vnf['uuid'])
                         self.logger.debug(cmd)
                         self.cur.execute(cmd)
                         vnf['interfaces'] = self.cur.fetchall()
@@ -400,7 +644,7 @@ 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" \
+                            cmd = "SELECT uuid,internal_name,external_name,net_id,type,vpci,mac,bw,model,ip_address" \
                                     " FROM interfaces" \
                                     " WHERE vm_id='{}'" \
                                     " ORDER BY created_at".format(vm['uuid'])
@@ -412,6 +656,17 @@ class nfvo_db(db_base.db_base):
                         self.logger.debug(cmd)
                         self.cur.execute(cmd)
                         vnf['nets'] = self.cur.fetchall()
+                        for vnf_net in vnf['nets']:
+                            SELECT_ = "ip_version,subnet_address,gateway_address,dns_address,dhcp_enabled,dhcp_start_address,dhcp_count"
+                            cmd = "SELECT {} FROM ip_profiles WHERE net_id='{}'".format(SELECT_,vnf_net['uuid'])  
+                            self.logger.debug(cmd)
+                            self.cur.execute(cmd)
+                            ipprofiles = self.cur.fetchall()
+                            if self.cur.rowcount==1:
+                                vnf_net["ip_profile"] = ipprofiles[0]
+                            elif self.cur.rowcount>1:
+                                raise db_base.db_base_Exception("More than one ip-profile found with this criteria: net_id='{}'".format(vnf_net['uuid']), db_base.HTTP_Bad_Request)
+                            
                     #sce_nets
                     cmd = "SELECT uuid,name,type,external,description" \
                           " FROM sce_nets  WHERE scenario_id='{}'" \
@@ -422,6 +677,15 @@ class nfvo_db(db_base.db_base):
                     #datacenter_nets
                     for net in scenario_dict['nets']:
                         if str(net['external']) == 'false':
+                            SELECT_ = "ip_version,subnet_address,gateway_address,dns_address,dhcp_enabled,dhcp_start_address,dhcp_count"
+                            cmd = "SELECT {} FROM ip_profiles WHERE sce_net_id='{}'".format(SELECT_,net['uuid'])  
+                            self.logger.debug(cmd)
+                            self.cur.execute(cmd)
+                            ipprofiles = self.cur.fetchall()
+                            if self.cur.rowcount==1:
+                                net["ip_profile"] = ipprofiles[0]
+                            elif self.cur.rowcount>1:
+                                raise db_base.db_base_Exception("More than one ip-profile found with this criteria: sce_net_id='{}'".format(net['uuid']), db_base.HTTP_Bad_Request)
                             continue
                         WHERE_=" WHERE name='{}'".format(net['name'])
                         if datacenter_id!=None:
@@ -521,6 +785,13 @@ class nfvo_db(db_base.db_base):
                             instance_net_uuid =  self._new_row_internal('instance_nets', INSERT_, True, instance_uuid, created_time)
                             net_scene2instance[ sce_net_id ][datacenter_site_id] = instance_net_uuid
                             net['uuid'] = instance_net_uuid  #overwrite scnario uuid by instance uuid
+                        
+                        if 'ip_profile' in net:
+                            net['ip_profile']['net_id'] = None
+                            net['ip_profile']['sce_net_id'] = None
+                            net['ip_profile']['instance_net_id'] = instance_net_uuid
+                            created_time += 0.00001
+                            ip_profile_id = self._new_row_internal('ip_profiles', net['ip_profile'])
                     
                     #instance_vnfs
                     for vnf in scenarioDict['vnfs']:
@@ -547,7 +818,14 @@ class nfvo_db(db_base.db_base):
                             instance_net_uuid =  self._new_row_internal('instance_nets', INSERT_, True, instance_uuid, created_time)
                             net_scene2instance[ net['uuid'] ][datacenter_site_id] = instance_net_uuid
                             net['uuid'] = instance_net_uuid  #overwrite scnario uuid by instance uuid
-                        
+                            
+                            if 'ip_profile' in net:
+                                net['ip_profile']['net_id'] = None
+                                net['ip_profile']['sce_net_id'] = None
+                                net['ip_profile']['instance_net_id'] = instance_net_uuid
+                                created_time += 0.00001
+                                ip_profile_id = self._new_row_internal('ip_profiles', net['ip_profile'])
+
                         #instance_vms
                         for vm in vnf['vms']:
                             INSERT_={'instance_vnf_id': instance_vnf_uuid,  'vm_id': vm['uuid'], 'vim_vm_id': vm['vim_id']  }
@@ -562,13 +840,16 @@ class nfvo_db(db_base.db_base):
                                     #check if is connected to a inter VNFs net
                                     for iface in vnf['interfaces']:
                                         if iface['interface_id'] == interface['uuid']:
+                                            if 'ip_address' in iface:
+                                                interface['ip_address'] = iface['ip_address']
                                             net_id = iface.get('sce_net_id', None)
                                             break
                                 if net_id is None:
                                     continue
                                 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  }
+                                    'interface_id': interface['uuid'], 'vim_interface_id': interface.get('vim_id'), 'type':  interface_type,
+                                    'ip_address': interface.get('ip_address')  }
                                 #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 5eeee4d..3d95dc7 100644 (file)
@@ -290,7 +290,8 @@ dhcp_schema = {
         "enabled": {"type": "boolean"},
         "start-address": ip_schema,
         "count": integer1_schema
-    }
+    },
+    "required": ["enabled", "start-address", "count"],
 }
 
 ip_profile_schema = {
@@ -301,7 +302,6 @@ ip_profile_schema = {
         "ip-version": {"type":"string", "enum":["IPv4","IPv6"]},
         "subnet-address": ip_prefix_schema,
         "gateway-address": ip_schema,
-        "security-group": {"type":"string"},
         "dns-address": ip_schema,
         "dhcp": dhcp_schema
     },
@@ -380,11 +380,11 @@ internal_connection_schema_v02 = {
         "name": name_schema,
         "description":description_schema,
         "type": {"type": "string", "enum":["e-line", "e-lan"]},
-        "implementation": {"type": "string", "enum":["virtual", "underlay"]},
+        "implementation": {"type": "string", "enum":["overlay", "underlay"]},
         "ip-profile": ip_profile_schema,
         "elements": {"type" : "array", "items": internal_connection_element_schema_v02, "minItems":2}
     },
-    "required": ["name", "type", "elements"],
+    "required": ["name", "type", "implementation", "elements"],
     "additionalProperties": False
 }
 
@@ -401,15 +401,19 @@ external_connection_schema = {
     "additionalProperties": False
 }
 
+#Not yet used
 external_connection_schema_v02 = {
     "type":"object",
     "properties":{
         "name": name_schema,
+        "mgmt": {"type":"boolean"},
+        "type": {"type": "string", "enum":["e-line", "e-lan"]}, 
+        "implementation": {"type": "string", "enum":["overlay", "underlay"]},
         "VNFC": name_schema,
         "local_iface_name": name_schema ,
         "description":description_schema
     },
-    "required": ["name", "VNFC", "local_iface_name"],
+    "required": ["name", "type", "VNFC", "local_iface_name"],
     "additionalProperties": False
 }
 
@@ -559,7 +563,7 @@ vnfd_schema_v02 = {
                 "public": {"type" : "boolean"},
                 "physical": {"type" : "boolean"},
                 "tenant_id": id_schema, #only valid for admin
-                "external-connections": {"type" : "array", "items": external_connection_schema_v02, "minItems":1},
+                "external-connections": {"type" : "array", "items": external_connection_schema, "minItems":1},
                 "internal-connections": {"type" : "array", "items": internal_connection_schema_v02, "minItems":1},
                 # "cloud-config": cloud_config_schema, #common for all vnfcs
                 "VNFC":{"type" : "array", "items": vnfc_schema, "minItems":1}
@@ -769,15 +773,15 @@ nsd_schema_v03 = {
                                     "items":{
                                         "type":"object",
                                         "properties":{
+                                            "vnf": name_schema,
+                                            "vnf_interface": name_schema,
                                             "ip_address": ip_schema
                                         },
-                                        "patternProperties":{
-                                            ".": {"type": "string"}
-                                        }
+                                        "required": ["vnf", "vnf_interface"],
                                     }
                                 },
                                 "type": {"type": "string", "enum":["e-line", "e-lan"]},
-                                "implementation": {"type": "string", "enum":["virtual", "underlay"]},
+                                "implementation": {"type": "string", "enum":["overlay", "underlay"]},
                                 "external" : {"type": "boolean"},
                                 "graph": graph_schema,
                                 "ip-profile": ip_profile_schema
@@ -966,7 +970,9 @@ instance_scenario_create_schema_v01 = {
                                     "items":{
                                         "type":"object",
                                         "properties":{
-                                            "ip_address": ip_schema
+                                            "ip_address": ip_schema,
+                                            "datacenter": name_schema,
+                                            "vim-network-name": name_schema
                                         },
                                         "patternProperties":{
                                             ".": {"type": "string"}
index 422e3ed..57aa6bd 100755 (executable)
@@ -33,7 +33,7 @@ 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.4.48-r490"
+__version__="0.4.49-r491"
 version_date="Aug 2016"
 database_version="0.13"      #expected database schema version
 
diff --git a/scenarios/examples/complex3.yaml b/scenarios/examples/complex3.yaml
new file mode 100644 (file)
index 0000000..84eb106
--- /dev/null
@@ -0,0 +1,96 @@
+##
+# 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.3"
+scenario:
+  name:          complex3
+  description:   Complex network scenario consisting of 2 VNFs interconnected and IP profiles in the networks
+  public:        false
+  vnfs:
+    VNF2vms:                            # vnf name in the scenario
+      vnf_name:  dataplaneVNF_2VMs_v02  # openmano vnf name
+      internal_connections:
+        datanet:
+          ip-profile: Null
+    VNF3:
+      vnf_name:  dataplaneVNF3
+  networks:
+    dataconn1:
+      type: e-lan
+      implementation: underlay
+      ip-profile:
+        ip-version:       IPv4
+        subnet-address:   10.1.1.0/24
+        gateway-address:  10.1.1.1
+        dns-address:      8.8.8.8
+        dhcp:
+          enabled:       true
+          start-address: 10.1.1.100
+          count:         150
+      interfaces:
+      -   vnf:           VNF2vms
+          vnf_interface: in
+          ip_address:    10.1.1.2
+      -   vnf:           VNF3
+          vnf_interface: data0
+          ip_address:    10.1.1.3
+    dataconn2:
+      type: e-line
+      implementation: underlay
+      ip-profile:
+        ip-version:       IPv4
+        subnet-address:   10.1.2.0/24
+        gateway-address:  10.1.2.1
+        dns-address:      8.8.8.8
+        dhcp:
+          enabled:       true
+          start-address: 10.1.2.100
+          count:         150
+      interfaces:
+      -   vnf:           VNF2vms
+          vnf_interface: out
+          ip_address:    10.1.2.2
+      -   vnf:           VNF3
+          vnf_interface: data1
+          ip_address:    10.1.2.3
+    default:
+      type: e-lan
+      implementation: overlay
+      ip-profile:
+        ip-version:       IPv4
+        subnet-address:   10.1.3.0/24
+        gateway-address:  10.1.3.1
+        dns-address:      8.8.8.8
+        dhcp:
+          enabled:       true
+          start-address: 10.1.3.100
+          count:         150
+      interfaces:
+      -   vnf:           VNF2vms
+          vnf_interface: control0
+          ip_address:    10.1.3.2
+      -   vnf:           VNF2vms
+          vnf_interface: control1
+          ip_address:    10.1.3.3
+      -   vnf:           VNF3
+          vnf_interface: mgmt
+          ip_address:    10.1.3.4
+
diff --git a/scenarios/examples/complex4.yaml b/scenarios/examples/complex4.yaml
new file mode 100644 (file)
index 0000000..7682a71
--- /dev/null
@@ -0,0 +1,99 @@
+##
+# 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.3"
+scenario:
+  name:          complex4
+  description:   Complex network scenario consisting of 2 VNFs interconnected by overlay networks and IP profiles in the networks
+  public:        false
+  vnfs:
+    VNF1:                        # vnf name in the scenario
+      vnf_name:  linux_2VMs_v02         # openmano vnf name
+      internal_connections:
+        datanet:
+          ip-profile: Null
+    VNF2:
+      vnf_name:  linux_2VMs_v02
+  networks:
+    dataconn1:
+      type: e-lan
+      implementation: overlay
+      ip-profile:
+        ip-version:       IPv4
+        subnet-address:   10.1.1.0/24
+        gateway-address:  10.1.1.1
+        dns-address:      8.8.8.8
+        dhcp:
+          enabled:       true
+          start-address: 10.1.1.100
+          count:         150
+      interfaces:
+      -   vnf:           VNF1
+          vnf_interface: in
+          ip_address:    10.1.1.2
+      -   vnf:           VNF2
+          vnf_interface: in
+          ip_address:    10.1.1.3
+    dataconn2:
+      type: e-lan
+      implementation: overlay
+      ip-profile:
+        ip-version:       IPv4
+        subnet-address:   10.1.2.0/24
+        gateway-address:  10.1.2.1
+        dns-address:      8.8.8.8
+        dhcp:
+          enabled:       true
+          start-address: 10.1.2.100
+          count:         150
+      interfaces:
+      -   vnf:           VNF1
+          vnf_interface: out
+          ip_address:    10.1.2.2
+      -   vnf:           VNF2
+          vnf_interface: out
+          ip_address:    10.1.2.3
+    default:
+      type: e-lan
+      implementation: overlay
+      ip-profile:
+        ip-version:       IPv4
+        subnet-address:   10.1.3.0/24
+        gateway-address:  10.1.3.1
+        dns-address:      8.8.8.8
+        dhcp:
+          enabled:       true
+          start-address: 10.1.3.100
+          count:         150
+      interfaces:
+      -   vnf:           VNF1
+          vnf_interface: control0
+          ip_address:    10.1.3.2
+      -   vnf:           VNF1
+          vnf_interface: control1
+          ip_address:    10.1.3.3
+      -   vnf:           VNF2
+          vnf_interface: control0
+          ip_address:    10.1.3.4
+      -   vnf:           VNF2
+          vnf_interface: control1
+          ip_address:    10.1.3.5
+
index 8b25448..61cf44e 100755 (executable)
@@ -141,16 +141,20 @@ then
     ${DIRmano}/openmano instance-scenario-delete -f simple-instance     || echo "fail"
     ${DIRmano}/openmano instance-scenario-delete -f complex-instance    || echo "fail"
     ${DIRmano}/openmano instance-scenario-delete -f complex2-instance   || echo "fail"
-    ${DIRmano}/openmano scenario-delete -f simple       || echo "fail"
-    ${DIRmano}/openmano scenario-delete -f complex      || echo "fail"
-    ${DIRmano}/openmano scenario-delete -f complex2     || echo "fail"
-    ${DIRmano}/openmano vnf-delete -f linux             || echo "fail"
-    ${DIRmano}/openmano vnf-delete -f dataplaneVNF_2VMs || echo "fail"
-    ${DIRmano}/openmano vnf-delete -f dataplaneVNF2     || echo "fail"
-    ${DIRmano}/openmano vnf-delete -f dataplaneVNF3     || echo "fail"
-    ${DIRmano}/openmano datacenter-detach TEST-dc        || echo "fail"
-    ${DIRmano}/openmano datacenter-delete -f TEST-dc     || echo "fail"
-    ${DIRmano}/openmano tenant-delete -f TEST-tenant     || echo "fail"
+    ${DIRmano}/openmano scenario-delete -f simple           || echo "fail"
+    ${DIRmano}/openmano scenario-delete -f complex          || echo "fail"
+    ${DIRmano}/openmano scenario-delete -f complex2         || echo "fail"
+    ${DIRmano}/openmano scenario-delete -f complex3         || echo "fail"
+    ${DIRmano}/openmano scenario-delete -f complex4         || echo "fail"
+    ${DIRmano}/openmano vnf-delete -f linux                 || echo "fail"
+    ${DIRmano}/openmano vnf-delete -f linux_2VMs_v02        || echo "fail"
+    ${DIRmano}/openmano vnf-delete -f dataplaneVNF_2VMs     || echo "fail"
+    ${DIRmano}/openmano vnf-delete -f dataplaneVNF_2VMs_v02 || echo "fail"
+    ${DIRmano}/openmano vnf-delete -f dataplaneVNF2         || echo "fail"
+    ${DIRmano}/openmano vnf-delete -f dataplaneVNF3         || echo "fail"
+    ${DIRmano}/openmano datacenter-detach TEST-dc           || echo "fail"
+    ${DIRmano}/openmano datacenter-delete -f TEST-dc        || echo "fail"
+    ${DIRmano}/openmano tenant-delete -f TEST-tenant        || echo "fail"
     echo
 
 elif [[ $action == "create" ]]
@@ -189,7 +193,7 @@ then
     [[ $? != 0 ]] && echo  "FAIL" && echo "    $result"  && $_exit 1
     echo OK
 
-    for VNF in linux dataplaneVNF1 dataplaneVNF2 dataplaneVNF_2VMs dataplaneVNF3
+    for VNF in linux dataplaneVNF1 dataplaneVNF2 dataplaneVNF_2VMs dataplaneVNF_2VMs_v02 dataplaneVNF3 linux_2VMs_v02
     do    
         printf "%-50s" "Creating VNF '${VNF}': "
         result=`$DIRmano/openmano vnf-create $DIRmano/vnfs/examples/${VNF}.yaml`
@@ -198,7 +202,7 @@ then
         ! is_valid_uuid $vnf && echo FAIL && echo "    $result" &&  $_exit 1
         echo $vnf
     done
-    for NS in simple complex complex2
+    for NS in simple complex complex2 complex3 complex4
     do
         printf "%-50s" "Creating scenario '${NS}':"
         result=`$DIRmano/openmano scenario-create $DIRmano/scenarios/examples/${NS}.yaml`
@@ -207,7 +211,7 @@ then
         echo $scenario
     done
 
-    for IS in simple complex complex2
+    for IS in simple complex complex2 complex3
     do
         printf "%-50s" "Creating instance-scenario '${IS}':"
         result=`$DIRmano/openmano instance-scenario-create  --scenario ${IS} --name ${IS}-instance`
@@ -216,6 +220,12 @@ then
         echo $instance
     done
 
+    printf "%-50s" "Creating instance-scenario 'complex4':"
+    result=`$DIRmano/openmano instance-scenario-create $DIRmano/instance-scenarios/examples/instance-creation-complex4.yaml`
+    instance=`echo $result |gawk '{print $1}'`
+    ! is_valid_uuid $instance && echo FAIL && echo "    $result" &&  $_exit 1
+    echo $instance
+
     echo
     #echo "Check virtual machines are deployed"
     #vms_error=`openvim vm-list | grep ERROR | wc -l`
index 57be314..7b96d86 100755 (executable)
@@ -123,9 +123,13 @@ then
     export OPENMANO_TENANT=$nfvotenant
     openmano instance-scenario-delete -f simple-instance     || echo "fail"
     openmano instance-scenario-delete -f complex2-instance   || echo "fail"
+    openmano instance-scenario-delete -f complex4-instance   || echo "fail"
     openmano scenario-delete -f simple       || echo "fail"
     openmano scenario-delete -f complex2     || echo "fail"
+    openmano scenario-delete -f complex3     || echo "fail"
+    openmano scenario-delete -f complex4     || echo "fail"
     openmano vnf-delete -f linux             || echo "fail"
+    openmano vnf-delete -f linux_2VMs_v02    || echo "fail"
     openmano vnf-delete -f dataplaneVNF_2VMs || echo "fail"
     openmano vnf-delete -f dataplaneVNF3     || echo "fail"
     openmano vnf-delete -f TESTVIM-VNF1          || echo "fail"
@@ -240,7 +244,19 @@ then
     ! is_valid_uuid $vnf && echo FAIL && echo "    $result" && $_exit 1
     echo $vnf
 
-    for sce in simple complex2
+    printf "%-50s" "Creating VNF 'dataplaneVNF_2VMs_v02': "
+    result=`openmano vnf-create $DIRmano/vnfs/examples/dataplaneVNF_2VMs_v02.yaml "--image-path=$VIM_TEST_IMAGE_PATH_NFV,$VIM_TEST_IMAGE_PATH_NFV"`
+    vnf=`echo $result |gawk '{print $1}'`
+    ! is_valid_uuid $vnf && echo FAIL && echo "    $result" && $_exit 1
+    echo $vnf
+
+    printf "%-50s" "Creating VNF 'linux_2VMs_v02': "
+    result=`openmano vnf-create $DIRmano/vnfs/examples/linux_2VMs_v02.yaml "--image-path=$VIM_TEST_IMAGE_PATH_NFV,$VIM_TEST_IMAGE_PATH_NFV"`
+    vnf=`echo $result |gawk '{print $1}'`
+    ! is_valid_uuid $vnf && echo FAIL && echo "    $result" && $_exit 1
+    echo $vnf
+
+    for sce in simple complex2 complex3 complex4
     do
       printf "%-50s" "Creating scenario '$sce':"
       result=`openmano scenario-create $DIRmano/scenarios/examples/${sce}.yaml`
@@ -269,6 +285,13 @@ then
       echo $instance
     done
 
+    #Testing IP parameters in networks
+    printf "%-50s" "Deploying scenario 'complex4' with IP parameters in networks:"
+    result=`openmano instance-scenario-create --scenario complex4 --name complex4-instance $DIRmano/instance-scenarios/examples/instance-creation-complex4.yaml`
+    instance=`echo $result |gawk '{print $1}'`
+    ! is_valid_uuid $instance && echo FAIL && echo "    $result" && $_exit 1
+    echo $instance
+
     echo
     echo DONE
 fi
index 36c3b52..7e82590 100644 (file)
@@ -160,9 +160,11 @@ class vimconnector():
         '''
         raise vimconnNotImplemented( "Should have implemented this" )
 
-    def new_network(self,net_name, net_type, shared=False):
+    def new_network(self,net_name, net_type, ip_profile=None, shared=False):
         '''Adds a tenant network to VIM
-            net_type can be 'bridge','data'.'ptp'.  TODO: this need to be revised 
+            net_name is the name
+            net_type can be 'bridge','data'.'ptp'.  TODO: this need to be revised
+            ip_profile is a dict containing the IP parameters of the network 
             shared is a boolean
         Returns the network identifier'''
         raise vimconnNotImplemented( "Should have implemented this" )
index 6e5f007..314027d 100644 (file)
@@ -31,6 +31,7 @@ import vimconn
 import json
 import yaml
 import logging
+import netaddr
 
 from novaclient import client as nClient, exceptions as nvExceptions
 import keystoneclient.v2_0.client as ksClient
@@ -223,7 +224,7 @@ class vimconnector(vimconn.vimconnector):
         except (ksExceptions.ConnectionError, ksExceptions.ClientException)  as e:
             self._format_exception(e)
         
-    def new_network(self,net_name,net_type, shared=False, cidr=None, vlan=None):
+    def new_network(self,net_name, net_type, ip_profile=None, shared=False, vlan=None):
         '''Adds a tenant network to VIM. Returns the network identifier'''
         self.logger.debug("Adding a new network to VIM name '%s', type '%s'", net_name, net_type)
         try:
@@ -239,14 +240,38 @@ class vimconnector(vimconn.vimconnector):
             network_dict["shared"]=shared
             new_net=self.neutron.create_network({'network':network_dict})
             #print new_net
-            #create fake subnetwork
-            if not cidr:
-                cidr="192.168.111.0/24"
+            #create subnetwork, even if there is no profile
+            if not ip_profile:
+                ip_profile = {}
+            if 'subnet_address' not in ip_profile:
+                #Fake subnet is required 
+                ip_profile['subnet_address'] = "192.168.111.0/24"
+            if 'ip_version' not in ip_profile: 
+                ip_profile['ip_version'] = "IPv4"
             subnet={"name":net_name+"-subnet",
                     "network_id": new_net["network"]["id"],
-                    "ip_version": 4,
-                    "cidr": cidr
+                    "ip_version": 4 if ip_profile['ip_version']=="IPv4" else 6,
+                    "cidr": ip_profile['subnet_address']
                     }
+            if 'gateway_address' in ip_profile:
+                subnet['gateway_ip'] = ip_profile['gateway_address']
+            if 'dns_address' in ip_profile:
+                #TODO: manage dns_address as a list of addresses separated by commas 
+                subnet['dns_nameservers'] = []
+                subnet['dns_nameservers'].append(ip_profile['dns_address'])
+            if 'dhcp_enabled' in ip_profile:
+                subnet['enable_dhcp'] = False if ip_profile['dhcp_enabled']=="false" else True
+            if 'dhcp_start_address' in ip_profile:
+                subnet['allocation_pools']=[]
+                subnet['allocation_pools'].append(dict())
+                subnet['allocation_pools'][0]['start'] = ip_profile['dhcp_start_address']
+            if 'dhcp_count' in ip_profile:
+                #parts = ip_profile['dhcp_start_address'].split('.')
+                #ip_int = (int(parts[0]) << 24) + (int(parts[1]) << 16) + (int(parts[2]) << 8) + int(parts[3])
+                ip_int = int(netaddr.IPAddress(ip_profile['dhcp_start_address']))
+                ip_int += ip_profile['dhcp_count']
+                ip_str = str(netaddr.IPAddress(ip_int))
+                subnet['allocation_pools'][0]['end'] = ip_str
             self.neutron.create_subnet({"subnet": subnet} )
             return new_net["network"]["id"]
         except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException) as e:
index ac02678..ff98d19 100644 (file)
@@ -481,7 +481,7 @@ class vimconnector(vimconn.vimconnector):
         except requests.exceptions.RequestException as e:
             self._format_request_exception(e)
 
-    def new_network(self,net_name,net_type, shared=False, **vim_specific):
+    def new_network(self,net_name, net_type, ip_profile=None, shared=False, **vim_specific):
         '''Adds a tenant network to VIM'''
         '''Returns the network identifier'''
         try:
diff --git a/vnfs/examples/dataplaneVNF_2VMs_v02.yaml b/vnfs/examples/dataplaneVNF_2VMs_v02.yaml
new file mode 100644 (file)
index 0000000..dbd5bd1
--- /dev/null
@@ -0,0 +1,113 @@
+##\r
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.\r
+# This file is part of openmano\r
+# All Rights Reserved.\r
+#\r
+# Licensed under the Apache License, Version 2.0 (the "License"); you may\r
+# not use this file except in compliance with the License. You may obtain\r
+# a copy of the License at\r
+#\r
+#         http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+# Unless required by applicable law or agreed to in writing, software\r
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\r
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\r
+# License for the specific language governing permissions and limitations\r
+# under the License.\r
+#\r
+# For those usages not covered by the Apache License, Version 2.0 please\r
+# contact with: nfvlabs@tid.es\r
+##\r
+---\r
+schema_version: "0.2"\r
+vnf:\r
+    name:        dataplaneVNF_2VMs_v02\r
+    description: "Example of a dataplane VNF consisting of two VMs for data plane workloads with one internal network"\r
+    # class: parent      # Optional. Used to organize VNFs\r
+    internal-connections:\r
+    -   name:        datanet\r
+        description: datanet\r
+        type:        e-lan\r
+        implementation: underlay\r
+        ip-profile:\r
+            ip-version:       IPv4\r
+            subnet-address:   192.168.1.0/24\r
+            gateway-address:  192.168.1.1\r
+            dns-address:      8.8.8.8\r
+            dhcp:\r
+                enabled: true\r
+                start-address: 192.168.1.100\r
+                count: 100\r
+        elements:\r
+        -   VNFC:             VNF_2VMs-VM1\r
+            local_iface_name: xe0\r
+            ip_address:       192.168.1.2\r
+        -   VNFC:             VNF_2VMs-VM2\r
+            local_iface_name: xe0\r
+            ip_address:       192.168.1.3\r
+    external-connections:\r
+    -   name:              control0\r
+        type:              mgmt\r
+        VNFC:              VNF_2VMs-VM1\r
+        local_iface_name:  eth0\r
+        description:       control interface VM1\r
+    -   name:              control1\r
+        type:              mgmt\r
+        VNFC:              VNF_2VMs-VM2\r
+        local_iface_name:  eth0\r
+        description:       control interface VM2\r
+    -   name:              in\r
+        type:              data\r
+        VNFC:              VNF_2VMs-VM1\r
+        local_iface_name:  xe1\r
+        description:       Dataplane interface input\r
+    -   name:              out\r
+        type:              data\r
+        VNFC:              VNF_2VMs-VM2\r
+        local_iface_name:  xe1\r
+        description:       Dataplane interface output\r
+    VNFC:\r
+    -   name:        VNF_2VMs-VM1\r
+        description: "Dataplane VM1 with 4 threads, 2 GB hugepages, 2 SR-IOV interface"\r
+        #Copy the image to a compute path and edit this path\r
+        VNFC image:  /path/to/imagefolder/dataplaneVNF_2VMs.qcow2\r
+        disk: 10\r
+        numas: \r
+        -   paired-threads: 2         # "cores", "paired-threads", "threads"\r
+            memory: 2                 # GBytes\r
+            interfaces:\r
+            -   name:      xe0\r
+                vpci:      "0000:00:11.0"\r
+                dedicated: "no"         # "yes"(passthrough), "no"(sriov with vlan tags), "yes:sriov"(sriovi, but exclusive and without vlan tag)\r
+                bandwidth: 1 Gbps\r
+            -   name:      xe1\r
+                vpci:      "0000:00:12.0"\r
+                dedicated: "no"\r
+                bandwidth: 1 Gbps\r
+        bridge-ifaces:\r
+        -   name:      eth0\r
+            vpci:      "0000:00:09.0"\r
+            bandwidth: 1 Mbps          # Optional, informative only\r
+\r
+    -   name:        VNF_2VMs-VM2\r
+        description: "Dataplane VM1 with 2 threads, 2 GB hugepages, 2 SR-IOV interface"\r
+        #Copy the image to a compute path and edit this path\r
+        VNFC image:  /path/to/imagefolder/dataplaneVNF_2VMs.qcow2\r
+        disk: 10\r
+        numas: \r
+        -   paired-threads: 1         # "cores", "paired-threads", "threads"\r
+            memory: 2                 # GBytes\r
+            interfaces:\r
+            -   name:      xe0\r
+                vpci:      "0000:00:11.0"\r
+                dedicated: "no"         # "yes"(passthrough), "no"(sriov with vlan tags), "yes:sriov"(sriovi, but exclusive and without vlan tag)\r
+                bandwidth: 1 Gbps\r
+            -   name:      xe1\r
+                vpci:      "0000:00:12.0"\r
+                dedicated: "no"\r
+                bandwidth: 1 Gbps\r
+        bridge-ifaces:\r
+        -   name:      eth0\r
+            vpci:      "0000:00:09.0"\r
+            bandwidth: 1 Mbps          # Optional, informative only\r
+\r
diff --git a/vnfs/examples/linux_2VMs_v02.yaml b/vnfs/examples/linux_2VMs_v02.yaml
new file mode 100644 (file)
index 0000000..41b5982
--- /dev/null
@@ -0,0 +1,104 @@
+##\r
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.\r
+# This file is part of openmano\r
+# All Rights Reserved.\r
+#\r
+# Licensed under the Apache License, Version 2.0 (the "License"); you may\r
+# not use this file except in compliance with the License. You may obtain\r
+# a copy of the License at\r
+#\r
+#         http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+# Unless required by applicable law or agreed to in writing, software\r
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\r
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\r
+# License for the specific language governing permissions and limitations\r
+# under the License.\r
+#\r
+# For those usages not covered by the Apache License, Version 2.0 please\r
+# contact with: nfvlabs@tid.es\r
+##\r
+---\r
+schema_version: "0.2"\r
+vnf:\r
+    name:        linux_2VMs_v02\r
+    description: "Example of a linux VNF consisting of two VMs with one internal network"\r
+    # class: parent      # Optional. Used to organize VNFs\r
+    internal-connections:\r
+    -   name:        internalnet\r
+        description: internalnet\r
+        type:        e-lan\r
+        implementation: overlay\r
+        ip-profile:\r
+            ip-version:       IPv4\r
+            subnet-address:   192.168.1.0/24\r
+            gateway-address:  192.168.1.1\r
+            dns-address:      8.8.8.8\r
+            dhcp:\r
+                enabled: true\r
+                start-address: 192.168.1.100\r
+                count: 100\r
+        elements:\r
+        -   VNFC:             linux_2VMs-VM1\r
+            local_iface_name: xe0\r
+            ip_address:       192.168.1.2\r
+        -   VNFC:             linux_2VMs-VM2\r
+            local_iface_name: xe0\r
+            ip_address:       192.168.1.3\r
+    external-connections:\r
+    -   name:              control0\r
+        type:              mgmt\r
+        VNFC:              linux_2VMs-VM1\r
+        local_iface_name:  eth0\r
+        description:       control interface VM1\r
+    -   name:              control1\r
+        type:              mgmt\r
+        VNFC:              linux_2VMs-VM2\r
+        local_iface_name:  eth0\r
+        description:       control interface VM2\r
+    -   name:              in\r
+        type:              bridge\r
+        VNFC:              linux_2VMs-VM1\r
+        local_iface_name:  xe1\r
+        description:       data interface input\r
+    -   name:              out\r
+        type:              bridge\r
+        VNFC:              linux_2VMs-VM2\r
+        local_iface_name:  xe1\r
+        description:       data interface output\r
+    VNFC:\r
+    -   name:        linux_2VMs-VM1\r
+        description: "Linux VM1 with 4 CPUs, 2 GB RAM and 3 bridge interfaces"\r
+        #Copy the image to a compute path and edit this path\r
+        VNFC image:  /path/to/imagefolder/linux_VNF_2VMs.qcow2\r
+        disk: 10\r
+        vcpus: 4\r
+        ram: 2048\r
+        bridge-ifaces:\r
+        -   name:      eth0\r
+            vpci:      "0000:00:09.0"\r
+            bandwidth: 1 Mbps          # Optional, informative only\r
+        -   name: xe0\r
+            vpci:      "0000:00:11.0"\r
+            bandwidth: 1 Mbps\r
+        -   name: xe1\r
+            vpci:      "0000:00:12.0"\r
+            bandwidth: 1 Mbps\r
+    -   name:        linux_2VMs-VM2\r
+        description: "Linux VM2 with 2 CPUs, 2 GB RAM and 3 bridge interfaces"\r
+        #Copy the image to a compute path and edit this path\r
+        VNFC image:  /path/to/imagefolder/linux_VNF_2VMs.qcow2\r
+        disk: 10\r
+        vcpus: 2\r
+        ram: 2048\r
+        bridge-ifaces:\r
+        -   name:      eth0\r
+            vpci:      "0000:00:09.0"\r
+            bandwidth: 1 Mbps          # Optional, informative only\r
+        -   name: xe0\r
+            vpci:      "0000:00:11.0"\r
+            bandwidth: 1 Mbps\r
+        -   name: xe1\r
+            vpci:      "0000:00:12.0"\r
+            bandwidth: 1 Mbps\r
+\r