From: tierno Date: Fri, 13 May 2016 10:28:55 +0000 (+0200) Subject: v0.4.38 new openmanoclient.py library; new version2 for scenario descriptor X-Git-Tag: v1.0.0~78^2 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=392f28583d8750e7e2c2c5f2341688ec5acdf824;p=osm%2FRO.git v0.4.38 new openmanoclient.py library; new version2 for scenario descriptor Signed-off-by: tierno --- diff --git a/auxiliary_functions.py b/auxiliary_functions.py old mode 100755 new mode 100644 diff --git a/console_proxy_thread.py b/console_proxy_thread.py old mode 100755 new mode 100644 diff --git a/database_utils/dump_db.sh b/database_utils/dump_db.sh index dfd5bbf9..3c94d318 100755 --- a/database_utils/dump_db.sh +++ b/database_utils/dump_db.sh @@ -22,6 +22,28 @@ ## +LICENSE_HEAD='/** +* 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 +**/ +' + DBUSER="mano" DBPASS="" DBHOST="localhost" @@ -105,18 +127,20 @@ do echo done - #echo structure, including the content of schema_version -mysqldump $DBHOST_ $DBPORT_ $DBUSER_ $DBPASS_ --no-data --add-drop-table --add-drop-database --routines --databases $DBNAME > ${DIRNAME}/${DBNAME}_structure.sql +echo "$LICENSE_HEAD" > ${DIRNAME}/${DBNAME}_structure.sql +mysqldump $DBHOST_ $DBPORT_ $DBUSER_ $DBPASS_ --no-data --add-drop-table --add-drop-database --routines --databases $DBNAME >> ${DIRNAME}/${DBNAME}_structure.sql echo -e "\n\n\n\n" >> ${DIRNAME}/${DBNAME}_structure.sql mysqldump $DBHOST_ $DBPORT_ $DBUSER_ $DBPASS_ --no-create-info $DBNAME --tables schema_version 2>/dev/null >> ${DIRNAME}/${DBNAME}_structure.sql echo " ${DIRNAME}/${DBNAME}_structure.sql" #echo only data -mysqldump $DBHOST_ $DBPORT_ $DBUSER_ $DBPASS_ --no-create-info $DBNAME > ${DIRNAME}/${DBNAME}_data.sql +echo "$LICENSE_HEAD" > ${DIRNAME}/${DBNAME}_data.sql #copy my own header +mysqldump $DBHOST_ $DBPORT_ $DBUSER_ $DBPASS_ --no-create-info $DBNAME >> ${DIRNAME}/${DBNAME}_data.sql echo " ${DIRNAME}/${DBNAME}_data.sql" #echo all -mysqldump $DBHOST_ $DBPORT_ $DBUSER_ $DBPASS_ --add-drop-table --add-drop-database --routines --databases $DBNAME > ${DIRNAME}/${DBNAME}_all.sql +echo "$LICENSE_HEAD" > ${DIRNAME}/${DBNAME}_all.sql #copy my own header +mysqldump $DBHOST_ $DBPORT_ $DBUSER_ $DBPASS_ --add-drop-table --add-drop-database --routines --databases $DBNAME >> ${DIRNAME}/${DBNAME}_all.sql echo " ${DIRNAME}/${DBNAME}_all.sql" diff --git a/database_utils/mano_db_structure.sql b/database_utils/mano_db_structure.sql index cea38f4d..aca07aa0 100644 --- a/database_utils/mano_db_structure.sql +++ b/database_utils/mano_db_structure.sql @@ -18,11 +18,12 @@ * For those usages not covered by the Apache License, Version 2.0 please * contact with: nfvlabs@tid.es **/ --- MySQL dump 10.13 Distrib 5.5.35, for debian-linux-gnu (x86_64) + +-- MySQL dump 10.13 Distrib 5.5.43, for debian-linux-gnu (x86_64) -- -- Host: localhost Database: mano_db -- ------------------------------------------------------ --- Server version 5.5.35-1ubuntu1 +-- Server version 5.5.43-0ubuntu0.14.04.1 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; @@ -54,15 +55,15 @@ DROP TABLE IF EXISTS `datacenter_nets`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `datacenter_nets` ( `uuid` varchar(36) NOT NULL, - `name` varchar(36) NOT NULL COMMENT 'To match with sce_nets', + `name` varchar(255) NOT NULL, `vim_net_id` varchar(36) NOT NULL, `datacenter_id` varchar(36) NOT NULL, `type` enum('bridge','data','ptp') NOT NULL DEFAULT 'data' COMMENT 'Type of network', `multipoint` enum('true','false') NOT NULL DEFAULT 'true', `shared` enum('true','false') NOT NULL DEFAULT 'false' COMMENT 'If can be shared with serveral scenarios', - `description` varchar(100) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, PRIMARY KEY (`uuid`), UNIQUE KEY `name_datacenter_id` (`name`,`datacenter_id`), KEY `FK_datacenter_nets_datacenters` (`datacenter_id`), @@ -70,6 +71,29 @@ CREATE TABLE `datacenter_nets` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Contain the external nets of a datacenter'; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `datacenter_tenants` +-- + +DROP TABLE IF EXISTS `datacenter_tenants`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `datacenter_tenants` ( + `uuid` varchar(36) NOT NULL, + `datacenter_id` varchar(36) NOT NULL COMMENT 'Datacenter of this tenant', + `vim_tenant_name` varchar(64) DEFAULT NULL, + `vim_tenant_id` varchar(36) DEFAULT NULL COMMENT 'Tenant ID at VIM', + `created` enum('true','false') NOT NULL DEFAULT 'false' COMMENT 'Indicates if this tenant has been created by openmano, or it existed on VIM', + `user` varchar(64) DEFAULT NULL, + `passwd` varchar(64) DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, + PRIMARY KEY (`uuid`), + KEY `FK_vim_tenants_datacenters` (`datacenter_id`), + CONSTRAINT `FK_vim_tenants_datacenters` FOREIGN KEY (`datacenter_id`) REFERENCES `datacenters` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Scenarios defined by the user'; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `datacenters` -- @@ -79,18 +103,98 @@ DROP TABLE IF EXISTS `datacenters`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `datacenters` ( `uuid` varchar(36) NOT NULL, - `name` varchar(36) NOT NULL, - `description` varchar(100) DEFAULT NULL, - `type` enum('openvim','openstack') NOT NULL DEFAULT 'openvim', + `name` varchar(255) NOT NULL, + `description` varchar(255) DEFAULT NULL, + `type` varchar(36) NOT NULL DEFAULT 'openvim', `vim_url` varchar(150) NOT NULL COMMENT 'URL of the VIM for the REST API', `vim_url_admin` varchar(150) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `config` varchar(4000) DEFAULT NULL COMMENT 'extra config information in json', + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, PRIMARY KEY (`uuid`), UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Datacenters managed by the NFVO.'; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `datacenters_flavors` +-- + +DROP TABLE IF EXISTS `datacenters_flavors`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `datacenters_flavors` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `flavor_id` varchar(36) NOT NULL, + `datacenter_id` varchar(36) NOT NULL, + `vim_id` varchar(36) NOT NULL, + `created` enum('true','false') NOT NULL DEFAULT 'false' COMMENT 'Indicates if it has been created by openmano, or already existed', + PRIMARY KEY (`id`), + KEY `FK__flavors` (`flavor_id`), + KEY `FK__datacenters_f` (`datacenter_id`), + CONSTRAINT `FK__datacenters_f` FOREIGN KEY (`datacenter_id`) REFERENCES `datacenters` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `FK__flavors` FOREIGN KEY (`flavor_id`) REFERENCES `flavors` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `datacenters_images` +-- + +DROP TABLE IF EXISTS `datacenters_images`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `datacenters_images` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `image_id` varchar(36) NOT NULL, + `datacenter_id` varchar(36) NOT NULL, + `vim_id` varchar(36) NOT NULL, + `created` enum('true','false') NOT NULL DEFAULT 'false' COMMENT 'Indicates if it has been created by openmano, or already existed', + PRIMARY KEY (`id`), + KEY `FK__images` (`image_id`), + KEY `FK__datacenters_i` (`datacenter_id`), + CONSTRAINT `FK__datacenters_i` FOREIGN KEY (`datacenter_id`) REFERENCES `datacenters` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `FK__images` FOREIGN KEY (`image_id`) REFERENCES `images` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `flavors` +-- + +DROP TABLE IF EXISTS `flavors`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `flavors` ( + `uuid` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, + `description` varchar(255) DEFAULT NULL, + `disk` smallint(5) unsigned DEFAULT NULL, + `ram` smallint(5) unsigned DEFAULT NULL, + `vcpus` smallint(5) unsigned DEFAULT NULL, + `extended` varchar(2000) DEFAULT NULL COMMENT 'Extra description json format of needed resources and pining, orginized in sets per numa', + PRIMARY KEY (`uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `images` +-- + +DROP TABLE IF EXISTS `images`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `images` ( + `uuid` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, + `location` varchar(200) NOT NULL, + `description` varchar(255) DEFAULT NULL, + `metadata` varchar(2000) DEFAULT NULL, + PRIMARY KEY (`uuid`), + UNIQUE KEY `location` (`location`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `instance_interfaces` -- @@ -103,7 +207,10 @@ CREATE TABLE `instance_interfaces` ( `instance_vm_id` varchar(36) NOT NULL, `instance_net_id` varchar(36) NOT NULL, `interface_id` varchar(36) NOT NULL, - `vim_interface_id` varchar(36) NOT NULL COMMENT 'vim identity for that interface', + `vim_interface_id` varchar(36) DEFAULT NULL COMMENT 'vim identity for that interface', + `mac_address` varchar(32) DEFAULT NULL, + `ip_address` varchar(64) DEFAULT NULL, + `vim_info` text, `type` enum('internal','external') NOT NULL COMMENT 'Indicates if this interface is external to a vnf, or internal', PRIMARY KEY (`uuid`), KEY `FK_instance_vms` (`instance_vm_id`), @@ -126,15 +233,29 @@ CREATE TABLE `instance_nets` ( `uuid` varchar(36) NOT NULL, `vim_net_id` varchar(36) NOT NULL COMMENT 'Network ID in the VIM DB', `instance_scenario_id` varchar(36) NOT NULL, - `status` enum('ACTIVE','DOWN','BUILD','ERROR') NOT NULL DEFAULT 'BUILD', + `sce_net_id` varchar(36) DEFAULT NULL, + `net_id` varchar(36) DEFAULT NULL, + `datacenter_id` varchar(36) DEFAULT NULL, + `datacenter_tenant_id` varchar(36) NOT NULL, + `status` enum('ACTIVE','DOWN','BUILD','ERROR','VIM_ERROR','INACTIVE','DELETED') NOT NULL DEFAULT 'BUILD', + `error_msg` varchar(1024) DEFAULT NULL, + `vim_info` text, `multipoint` enum('true','false') NOT NULL DEFAULT 'true', `external` enum('true','false') NOT NULL DEFAULT 'false' COMMENT 'If external, means that it already exists at VIM', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, PRIMARY KEY (`uuid`), UNIQUE KEY `vim_net_id_instance_scenario_id` (`vim_net_id`,`instance_scenario_id`), KEY `FK_instance_nets_instance_scenarios` (`instance_scenario_id`), - CONSTRAINT `FK_instance_nets_instance_scenarios` FOREIGN KEY (`instance_scenario_id`) REFERENCES `instance_scenarios` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE + KEY `FK_instance_nets_sce_nets` (`sce_net_id`), + KEY `FK_instance_nets_nets` (`net_id`), + KEY `FK_instance_nets_datacenters` (`datacenter_id`), + KEY `FK_instance_nets_datacenter_tenants` (`datacenter_tenant_id`), + CONSTRAINT `FK_instance_nets_datacenter_tenants` FOREIGN KEY (`datacenter_tenant_id`) REFERENCES `datacenter_tenants` (`uuid`), + CONSTRAINT `FK_instance_nets_datacenters` FOREIGN KEY (`datacenter_id`) REFERENCES `datacenters` (`uuid`), + CONSTRAINT `FK_instance_nets_instance_scenarios` FOREIGN KEY (`instance_scenario_id`) REFERENCES `instance_scenarios` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `FK_instance_nets_nets` FOREIGN KEY (`net_id`) REFERENCES `nets` (`uuid`) ON DELETE SET NULL ON UPDATE CASCADE, + CONSTRAINT `FK_instance_nets_sce_nets` FOREIGN KEY (`sce_net_id`) REFERENCES `sce_nets` (`uuid`) ON DELETE SET NULL ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Instances of networks'; /*!40101 SET character_set_client = @saved_cs_client */; @@ -147,24 +268,24 @@ DROP TABLE IF EXISTS `instance_scenarios`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `instance_scenarios` ( `uuid` varchar(36) NOT NULL, - `name` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, + `tenant_id` varchar(36) DEFAULT NULL, `scenario_id` varchar(36) NOT NULL, - `nfvo_tenant_id` varchar(36) NOT NULL, - `vim_tenant_id` varchar(36) NOT NULL, `datacenter_id` varchar(36) NOT NULL, - `description` varchar(100) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `datacenter_tenant_id` varchar(36) NOT NULL, + `description` varchar(255) DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, PRIMARY KEY (`uuid`), UNIQUE KEY `name` (`name`), - KEY `FK_scenarios_nfvo_tenants` (`nfvo_tenant_id`), - KEY `FK_instance_scenarios_vim_tenants` (`vim_tenant_id`), + KEY `FK_scenarios_nfvo_tenants` (`tenant_id`), + KEY `FK_instance_scenarios_vim_tenants` (`datacenter_tenant_id`), KEY `FK_instance_scenarios_datacenters` (`datacenter_id`), KEY `FK_instance_scenarios_scenarios` (`scenario_id`), + CONSTRAINT `FK_instance_scenarios_datacenter_tenants` FOREIGN KEY (`datacenter_tenant_id`) REFERENCES `datacenter_tenants` (`uuid`), CONSTRAINT `FK_instance_scenarios_datacenters` FOREIGN KEY (`datacenter_id`) REFERENCES `datacenters` (`uuid`), - CONSTRAINT `FK_instance_scenarios_nfvo_tenants` FOREIGN KEY (`nfvo_tenant_id`) REFERENCES `nfvo_tenants` (`uuid`), - CONSTRAINT `FK_instance_scenarios_scenarios` FOREIGN KEY (`scenario_id`) REFERENCES `scenarios` (`uuid`), - CONSTRAINT `FK_instance_scenarios_vim_tenants` FOREIGN KEY (`vim_tenant_id`) REFERENCES `vim_tenants` (`uuid`) + CONSTRAINT `FK_instance_scenarios_nfvo_tenants` FOREIGN KEY (`tenant_id`) REFERENCES `nfvo_tenants` (`uuid`), + CONSTRAINT `FK_instance_scenarios_scenarios` FOREIGN KEY (`scenario_id`) REFERENCES `scenarios` (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Instances of scenarios defined by the user'; /*!40101 SET character_set_client = @saved_cs_client */; @@ -180,9 +301,11 @@ CREATE TABLE `instance_vms` ( `instance_vnf_id` varchar(36) NOT NULL, `vm_id` varchar(36) NOT NULL, `vim_vm_id` varchar(36) NOT NULL COMMENT 'VM ID in the VIM DB', - `status` enum('ACTIVE','PAUSED','INACTIVE','CREATING','ERROR','DELETING') NOT NULL DEFAULT 'CREATING', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `status` enum('ACTIVE:NoMgmtIP','ACTIVE','INACTIVE','BUILD','ERROR','VIM_ERROR','PAUSED','SUSPENDED','DELETED') NOT NULL DEFAULT 'BUILD', + `error_msg` varchar(1024) DEFAULT NULL, + `vim_info` text, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, PRIMARY KEY (`uuid`), UNIQUE KEY `vim_vm_id` (`vim_vm_id`), KEY `FK_instance_vms_vms` (`vm_id`), @@ -203,12 +326,21 @@ CREATE TABLE `instance_vnfs` ( `uuid` varchar(36) NOT NULL, `instance_scenario_id` varchar(36) NOT NULL, `vnf_id` varchar(36) NOT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `sce_vnf_id` varchar(36) DEFAULT NULL, + `datacenter_id` varchar(36) DEFAULT NULL, + `datacenter_tenant_id` varchar(36) DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, PRIMARY KEY (`uuid`), KEY `FK_instance_vnfs_vnfs` (`vnf_id`), KEY `FK_instance_vnfs_instance_scenarios` (`instance_scenario_id`), + KEY `FK_instance_vnfs_sce_vnfs` (`sce_vnf_id`), + KEY `FK_instance_vnfs_datacenters` (`datacenter_id`), + KEY `FK_instance_vnfs_datacenter_tenants` (`datacenter_tenant_id`), + CONSTRAINT `FK_instance_vnfs_datacenter_tenants` FOREIGN KEY (`datacenter_tenant_id`) REFERENCES `datacenter_tenants` (`uuid`), + CONSTRAINT `FK_instance_vnfs_datacenters` FOREIGN KEY (`datacenter_id`) REFERENCES `datacenters` (`uuid`), CONSTRAINT `FK_instance_vnfs_instance_scenarios` FOREIGN KEY (`instance_scenario_id`) REFERENCES `instance_scenarios` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `FK_instance_vnfs_sce_vnfs` FOREIGN KEY (`sce_vnf_id`) REFERENCES `sce_vnfs` (`uuid`) ON DELETE SET NULL ON UPDATE CASCADE, CONSTRAINT `FK_instance_vnfs_vnfs` FOREIGN KEY (`vnf_id`) REFERENCES `vnfs` (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Instances of VNFs as part of a scenario'; /*!40101 SET character_set_client = @saved_cs_client */; @@ -222,16 +354,17 @@ DROP TABLE IF EXISTS `interfaces`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `interfaces` ( `uuid` varchar(36) NOT NULL, - `internal_name` varchar(25) NOT NULL, - `external_name` varchar(25) DEFAULT NULL COMMENT 'NULL if the interface is not an external interface', + `internal_name` varchar(255) NOT NULL, + `external_name` varchar(255) DEFAULT NULL, `vm_id` varchar(36) NOT NULL, `net_id` varchar(36) DEFAULT NULL, `type` enum('mgmt','bridge','data') NOT NULL DEFAULT 'data' COMMENT 'Type of network', `vpci` char(12) DEFAULT NULL, `bw` mediumint(8) unsigned DEFAULT NULL COMMENT 'BW expressed in Mbits/s. Maybe this field is not necessary.', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, `model` varchar(12) DEFAULT NULL, + `mac` char(18) DEFAULT NULL, PRIMARY KEY (`uuid`), UNIQUE KEY `internal_name_vm_id` (`internal_name`,`vm_id`), KEY `FK_interfaces_vms` (`vm_id`), @@ -252,12 +385,12 @@ CREATE TABLE `logs` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `nfvo_tenant_id` varchar(36) DEFAULT NULL, - `related` enum('nfvo_tenants','datacenters','vim_tenants','tenants_datacenters','vnfs','vms','interfaces','nets','scenarios','sce_vnfs','sce_interfaces','sce_nets','instance_scenarios','instance_vnfs','instance_vms','instance_nets','instance_interfaces') NOT NULL COMMENT 'Relevant element for the log', + `related` varchar(36) NOT NULL COMMENT 'Relevant element for the log', `uuid` varchar(36) DEFAULT NULL COMMENT 'Uuid of vnf, scenario, etc. that log relates to', `level` enum('panic','error','info','debug','verbose') NOT NULL, `description` varchar(200) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=3286 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; +) ENGINE=InnoDB AUTO_INCREMENT=3423 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -270,12 +403,12 @@ DROP TABLE IF EXISTS `nets`; CREATE TABLE `nets` ( `uuid` varchar(36) NOT NULL, `vnf_id` varchar(36) NOT NULL, - `name` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, `type` enum('bridge','data','ptp') NOT NULL DEFAULT 'data' COMMENT 'Type of network', `multipoint` enum('true','false') NOT NULL DEFAULT 'false', - `description` varchar(100) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, PRIMARY KEY (`uuid`), UNIQUE KEY `vnf_id_name` (`vnf_id`,`name`), CONSTRAINT `FK_nets_vnfs` FOREIGN KEY (`vnf_id`) REFERENCES `vnfs` (`uuid`) ON DELETE CASCADE @@ -291,10 +424,10 @@ DROP TABLE IF EXISTS `nfvo_tenants`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `nfvo_tenants` ( `uuid` varchar(36) NOT NULL, - `name` varchar(36) NOT NULL, - `description` varchar(100) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `name` varchar(255) NOT NULL, + `description` varchar(255) DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, PRIMARY KEY (`uuid`), UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Scenarios defined by the user'; @@ -312,8 +445,8 @@ CREATE TABLE `sce_interfaces` ( `sce_vnf_id` varchar(36) NOT NULL, `sce_net_id` varchar(36) DEFAULT NULL, `interface_id` varchar(36) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, PRIMARY KEY (`uuid`), KEY `FK_sce_interfaces_sce_vnfs` (`sce_vnf_id`), KEY `FK_sce_interfaces_sce_nets` (`sce_net_id`), @@ -333,15 +466,15 @@ DROP TABLE IF EXISTS `sce_nets`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `sce_nets` ( `uuid` varchar(36) NOT NULL, - `name` varchar(36) DEFAULT NULL, + `name` varchar(255) NOT NULL, `scenario_id` varchar(36) DEFAULT NULL COMMENT 'NULL if net is matched to several scenarios', `type` enum('bridge','data','ptp') NOT NULL DEFAULT 'data' COMMENT 'Type of network', `multipoint` enum('true','false') NOT NULL DEFAULT 'true', `external` enum('true','false') NOT NULL DEFAULT 'false' COMMENT 'If external, net is already present at VIM', - `description` varchar(100) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, - `graph` varchar(200) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, + `graph` varchar(2000) DEFAULT NULL, PRIMARY KEY (`uuid`), KEY `FK_sce_nets_scenarios` (`scenario_id`), CONSTRAINT `FK_sce_nets_scenarios` FOREIGN KEY (`scenario_id`) REFERENCES `scenarios` (`uuid`) ON DELETE CASCADE ON UPDATE CASCADE @@ -357,13 +490,13 @@ DROP TABLE IF EXISTS `sce_vnfs`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `sce_vnfs` ( `uuid` varchar(36) NOT NULL, - `name` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, `scenario_id` varchar(36) NOT NULL, `vnf_id` varchar(36) NOT NULL, - `description` varchar(100) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, - `graph` varchar(200) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, + `graph` varchar(2000) DEFAULT NULL, PRIMARY KEY (`uuid`), UNIQUE KEY `name_scenario_id` (`name`,`scenario_id`), KEY `FK_sce_vnfs_scenarios` (`scenario_id`), @@ -382,19 +515,37 @@ DROP TABLE IF EXISTS `scenarios`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `scenarios` ( `uuid` varchar(36) NOT NULL, - `name` varchar(36) NOT NULL, - `nfvo_tenant_id` varchar(36) DEFAULT NULL, - `description` varchar(100) DEFAULT NULL, + `name` varchar(255) NOT NULL, + `tenant_id` varchar(36) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, `public` enum('true','false') NOT NULL DEFAULT 'false', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, + `descriptor` text COMMENT 'Original text descriptor used for create the scenario', PRIMARY KEY (`uuid`), UNIQUE KEY `name` (`name`), - KEY `FK_scenarios_nfvo_tenants` (`nfvo_tenant_id`), - CONSTRAINT `FK_scenarios_nfvo_tenants` FOREIGN KEY (`nfvo_tenant_id`) REFERENCES `nfvo_tenants` (`uuid`) + KEY `FK_scenarios_nfvo_tenants` (`tenant_id`), + CONSTRAINT `FK_scenarios_nfvo_tenants` FOREIGN KEY (`tenant_id`) REFERENCES `nfvo_tenants` (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Scenarios defined by the user'; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `schema_version` +-- + +DROP TABLE IF EXISTS `schema_version`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `schema_version` ( + `version_int` int(11) NOT NULL COMMENT 'version as a number. Must not contain gaps', + `version` varchar(20) NOT NULL COMMENT 'version as a text', + `openmano_ver` varchar(20) NOT NULL COMMENT 'openmano version', + `comments` varchar(2000) DEFAULT NULL COMMENT 'changes to database', + `date` date DEFAULT NULL, + PRIMARY KEY (`version_int`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='database schema control version'; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `tenants_datacenters` -- @@ -406,18 +557,18 @@ CREATE TABLE `tenants_datacenters` ( `id` int(11) NOT NULL AUTO_INCREMENT, `nfvo_tenant_id` varchar(36) NOT NULL, `datacenter_id` varchar(36) NOT NULL, - `vim_tenant_id` varchar(36) NOT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `datacenter_tenant_id` varchar(36) NOT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `datacenter_nfvo_tenant` (`datacenter_id`,`nfvo_tenant_id`), KEY `FK_nfvo_tenants_datacenters` (`datacenter_id`), - KEY `FK_nfvo_tenants_vim_tenants` (`vim_tenant_id`), + KEY `FK_nfvo_tenants_vim_tenants` (`datacenter_tenant_id`), KEY `FK_tenants_datacenters_nfvo_tenants` (`nfvo_tenant_id`), + CONSTRAINT `FK_tenants_datacenters_datacenter_tenants` FOREIGN KEY (`datacenter_tenant_id`) REFERENCES `datacenter_tenants` (`uuid`), CONSTRAINT `FK_tenants_datacenters_datacenters` FOREIGN KEY (`datacenter_id`) REFERENCES `datacenters` (`uuid`), - CONSTRAINT `FK_tenants_datacenters_nfvo_tenants` FOREIGN KEY (`nfvo_tenant_id`) REFERENCES `nfvo_tenants` (`uuid`), - CONSTRAINT `FK_tenants_datacenters_vim_tenants` FOREIGN KEY (`vim_tenant_id`) REFERENCES `vim_tenants` (`uuid`) -) ENGINE=InnoDB AUTO_INCREMENT=85 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Scenarios defined by the user'; + CONSTRAINT `FK_tenants_datacenters_nfvo_tenants` FOREIGN KEY (`nfvo_tenant_id`) REFERENCES `nfvo_tenants` (`uuid`) +) ENGINE=InnoDB AUTO_INCREMENT=86 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Scenarios defined by the user'; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -430,32 +581,12 @@ DROP TABLE IF EXISTS `uuids`; CREATE TABLE `uuids` ( `uuid` varchar(36) NOT NULL, `root_uuid` varchar(36) DEFAULT NULL COMMENT 'Some related UUIDs can be grouped by this field, so that they can be deleted at once', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `used_at` enum('nfvo_tenants','datacenters','vim_tenants','vnfs','vms','interfaces','nets','scenarios','sce_vnfs','sce_interfaces','sce_nets','instance_scenarios','instance_vnfs','instance_vms','instance_nets','instance_interfaces') DEFAULT NULL COMMENT 'Table that uses this UUID', + `created_at` double NOT NULL, + `used_at` varchar(36) DEFAULT NULL COMMENT 'Table that uses this UUID', PRIMARY KEY (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Table with all unique IDs used to avoid UUID repetitions among different elements'; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Table structure for table `vim_tenants` --- - -DROP TABLE IF EXISTS `vim_tenants`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `vim_tenants` ( - `uuid` varchar(36) NOT NULL, - `name` varchar(36) NOT NULL, - `vim_tenant_id` varchar(36) NOT NULL COMMENT 'Tenant ID in the VIM DB', - `created` enum('true','false') NOT NULL DEFAULT 'false' COMMENT 'Indicates if this tenant has been created by openmano, or it existed on VIM', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, - PRIMARY KEY (`uuid`), - UNIQUE KEY `name` (`name`), - UNIQUE KEY `vim_tenant_id` (`vim_tenant_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Scenarios defined by the user'; -/*!40101 SET character_set_client = @saved_cs_client */; - -- -- Table structure for table `vms` -- @@ -465,17 +596,21 @@ DROP TABLE IF EXISTS `vms`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `vms` ( `uuid` varchar(36) NOT NULL, - `name` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, `vnf_id` varchar(36) NOT NULL, - `vim_flavor_id` varchar(36) NOT NULL COMMENT 'Flavor ID in the VIM DB', - `vim_image_id` varchar(36) NOT NULL COMMENT 'Image ID in the VIM DB', + `flavor_id` varchar(36) NOT NULL COMMENT 'Link to flavor table', + `image_id` varchar(36) NOT NULL COMMENT 'Link to image table', `image_path` varchar(100) NOT NULL COMMENT 'Path where the image of the VM is located', - `description` varchar(100) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, PRIMARY KEY (`uuid`), UNIQUE KEY `name_vnf_id` (`name`,`vnf_id`), KEY `FK_vms_vnfs` (`vnf_id`), + KEY `FK_vms_images` (`image_id`), + KEY `FK_vms_flavors` (`flavor_id`), + CONSTRAINT `FK_vms_flavors` FOREIGN KEY (`flavor_id`) REFERENCES `flavors` (`uuid`), + CONSTRAINT `FK_vms_images` FOREIGN KEY (`image_id`) REFERENCES `images` (`uuid`), CONSTRAINT `FK_vms_vnfs` FOREIGN KEY (`vnf_id`) REFERENCES `vnfs` (`uuid`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='VM definitions. It contains the set of VMs used by the VNF definitions.'; /*!40101 SET character_set_client = @saved_cs_client */; @@ -489,17 +624,18 @@ DROP TABLE IF EXISTS `vnfs`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `vnfs` ( `uuid` varchar(36) NOT NULL, - `name` varchar(36) NOT NULL, - `path` varchar(100) DEFAULT NULL COMMENT 'Path where the YAML descriptor of the VNF can be found. NULL if it is a physical network function.', + `name` varchar(255) NOT NULL, + `tenant_id` varchar(36) DEFAULT NULL, `physical` enum('true','false') NOT NULL DEFAULT 'false', - `public` enum('true','false') NOT NULL DEFAULT 'true', - `description` varchar(100) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `modified_at` timestamp NULL DEFAULT NULL, + `public` enum('true','false') NOT NULL DEFAULT 'false', + `description` varchar(255) DEFAULT NULL, + `created_at` double NOT NULL, + `modified_at` double DEFAULT NULL, `class` varchar(36) DEFAULT 'MISC', + `descriptor` text COMMENT 'Original text descriptor used for create the VNF', PRIMARY KEY (`uuid`), - UNIQUE KEY `name` (`name`), - UNIQUE KEY `path` (`path`) + KEY `FK_vnfs_nfvo_tenants` (`tenant_id`), + CONSTRAINT `FK_vnfs_nfvo_tenants` FOREIGN KEY (`tenant_id`) REFERENCES `nfvo_tenants` (`uuid`) ON DELETE SET NULL ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='VNF definitions. This is the catalogue of VNFs. It also includes Physical Network Functions or Physical Elements.\r\n'; /*!40101 SET character_set_client = @saved_cs_client */; @@ -516,4 +652,46 @@ CREATE TABLE `vnfs` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2015-03-11 17:34:28 +-- Dump completed on 2016-05-13 12:23:52 + + + + + +-- MySQL dump 10.13 Distrib 5.5.43, for debian-linux-gnu (x86_64) +-- +-- Host: localhost Database: mano_db +-- ------------------------------------------------------ +-- Server version 5.5.43-0ubuntu0.14.04.1 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Dumping data for table `schema_version` +-- + +LOCK TABLES `schema_version` WRITE; +/*!40000 ALTER TABLE `schema_version` DISABLE KEYS */; +INSERT INTO `schema_version` VALUES (1,'0.1','0.2.2','insert schema_version','2015-05-08'),(2,'0.2','0.2.5','new tables images,flavors','2015-07-13'),(3,'0.3','0.3.3','alter vim_tenant tables','2015-07-28'),(4,'0.4','0.3.5','enlarge graph field at sce_vnfs/nets','2015-10-20'),(5,'0.5','0.4.1','Add mac address for bridge interfaces','2015-12-14'),(6,'0.6','0.4.2','Adding VIM status info','2015-12-22'),(7,'0.7','0.4.3','Changing created_at time at database','2016-01-25'),(8,'0.8','0.4.32','Enlarging name at database','2016-02-01'),(9,'0.9','0.4.33','Add ACTIVE:NoMgmtIP to instance_vms table','2016-02-05'),(10,'0.10','0.4.36','tenant management of vnfs,scenarios','2016-03-08'); +/*!40000 ALTER TABLE `schema_version` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2016-05-13 12:23:52 diff --git a/httpserver.py b/httpserver.py old mode 100755 new mode 100644 index 29af42dc..0e60b3d2 --- a/httpserver.py +++ b/httpserver.py @@ -783,7 +783,7 @@ def http_post_deploy(tenant_id): '''post topology deploy.''' print "http_post_deploy by tenant " + tenant_id - http_content, used_schema = format_in( nsd_schema_v01, ("version",), {"v0.2": nsd_schema_v02}) + http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02}) #r = af.remove_extra_items(http_content, used_schema) #if r is not None: print "http_post_deploy: Warning: remove extra items ", r print "http_post_deploy input: ", http_content @@ -816,7 +816,7 @@ 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''' print "http_post_scenarios by tenant " + tenant_id - http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {"0.2": nsd_schema_v02}) + http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02}) #r = af.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 diff --git a/nfvo.py b/nfvo.py index 1c76984e..1a97fa2d 100644 --- a/nfvo.py +++ b/nfvo.py @@ -140,14 +140,11 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, vi return -HTTP_Bad_Request, "Unknown vim type %s" % vim["type"] try: - tenant=vim.get('vim_tenant_id') - if not tenant: - tenant=vim.get('vim_tenant_name') #if not tenant: # return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM %s" % ( vim["type"]) vim_dict[ vim['datacenter_id'] ] = vimconn_imported[ vim["type"] ].vimconnector( uuid=vim['datacenter_id'], name=vim['datacenter_name'], - tenant=tenant, + tenant_id=vim.get('vim_tenant_id'), tenant_name=vim.get('vim_tenant_name'), url=vim['vim_url'], url_admin=vim['vim_url_admin'], user=vim.get('user'), passwd=vim.get('passwd'), config=extra @@ -1094,12 +1091,15 @@ def new_scenario(mydb, tenant_id, topo): #2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets r,c = mydb.new_scenario( { 'vnfs':vnfs, 'nets':net_list, - 'tenant_id':tenant_id, 'name':topo['name'], 'description':topo.get('description',topo['name']) } ) + 'tenant_id':tenant_id, 'name':topo['name'], + 'description':topo.get('description',topo['name']), + 'public': topo.get('public', False) + }) return r,c -def new_scenario_v02(mydb, tenant_id, scenario): - +def new_scenario_v02(mydb, tenant_id, scenario_dict): + scenario = scenario_dict["scenario"] if tenant_id != "any": if not check_tenant(mydb, tenant_id): print 'nfvo.new_scenario_v02() tenant %s not found' % tenant_id @@ -1119,9 +1119,9 @@ def new_scenario_v02(mydb, tenant_id, scenario): if 'vnf_id' in vnf: error_text += " 'vnf_id' " + vnf['vnf_id'] WHERE_['uuid'] = vnf['vnf_id'] - if 'vnf_model' in vnf: - error_text += " 'vnf_model' " + vnf['vnf_model'] - WHERE_['name'] = vnf['vnf_model'] + if 'vnf_name' in vnf: + error_text += " 'vnf_name' " + vnf['vnf_name'] + WHERE_['name'] = vnf['vnf_name'] if len(WHERE_) == 0: return -HTTP_Bad_Request, "needed a 'vnf_id' or 'VNF model' at " + error_pos r,vnf_db = mydb.get_table(SELECT=('uuid','name','description'), FROM='vnfs', WHERE=WHERE_) @@ -1215,7 +1215,7 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc print "start_scenario error. Several datacenters available, you must concrete" return -HTTP_Bad_Request, "Several datacenters available, you must concrete" myvim = vims.values()[0] - myvim_tenant = myvim['tenant'] + myvim_tenant = myvim['tenant_id'] datacenter_id = myvim['id'] datacenter_name = myvim['name'] datacenter_tenant_id = myvim['config']['datacenter_tenant_id'] @@ -1460,7 +1460,7 @@ def create_instance(mydb, tenant_id, instance_dict): print "start_scenario error. Several datacenters available, you must concrete" return -HTTP_Bad_Request, "Several datacenters available, you must concrete" myvim = vims.values()[0] - #myvim_tenant = myvim['tenant'] + #myvim_tenant = myvim['tenant_id'] datacenter_id = myvim['id'] datacenter_name = myvim['name'] datacenter_tenant_id = myvim['config']['datacenter_tenant_id'] @@ -2294,8 +2294,8 @@ def datacenter_new_netmap(mydb, tenant_id, datacenter, action_dict=None): filter_dict["shared"] = True result, content = myvim.get_network_list(filter_dict=filter_dict) - print content - if result != 200: + print result, content + if result <0: print " Not possible to get_network_list from VIM: %s " % (content) return -HTTP_Internal_Server_Error, content elif len(content)>1 and action_dict: @@ -2348,7 +2348,7 @@ def vim_action_get(mydb, tenant_id, datacenter, item, name): else: filter_dict["name"] = name if item=="networks": - filter_dict['tenant_id'] = myvim["tenant"] + #filter_dict['tenant_id'] = myvim['tenant_id'] result, content = myvim.get_network_list(filter_dict=filter_dict) elif item=="tenants": result, content = myvim.get_tenant_list(filter_dict=filter_dict) @@ -2367,6 +2367,9 @@ def vim_action_get(mydb, tenant_id, datacenter, item, name): def vim_action_delete(mydb, tenant_id, datacenter, item, name): #get datacenter info + if tenant_id == "any": + tenant_id=None + if af.check_valid_uuid(datacenter): result, vims = get_vim(mydb, nfvo_tenant=tenant_id, datacenter_id=datacenter) else: @@ -2381,20 +2384,19 @@ def vim_action_delete(mydb, tenant_id, datacenter, item, name): return -HTTP_Conflict, "More than one datacenters found, try to identify with uuid" datacenter_id=vims.keys()[0] myvim=vims[datacenter_id] - #get uuid - if not af.check_valid_uuid(name): - result, content = vim_action_get(mydb, tenant_id, datacenter, item, name) - print content - if result < 0: - return result, content - items = content.values()[0] - if type(items)==list and len(items)==0: - return -HTTP_Not_Found, "Not found " + item - elif type(items)==list and len(items)>1: - return -HTTP_Not_Found, "Found more than one %s with this name. Use uuid." % item - else: # it is a dict - item_id = items["id"] - item_name = str(items.get("name")) + #get uuid name + result, content = vim_action_get(mydb, tenant_id, datacenter, item, name) + print content + if result < 0: + return result, content + items = content.values()[0] + if type(items)==list and len(items)==0: + return -HTTP_Not_Found, "Not found " + item + elif type(items)==list and len(items)>1: + return -HTTP_Not_Found, "Found more than one %s with this name. Use uuid." % item + else: # it is a dict + item_id = items["id"] + item_name = str(items.get("name")) if item=="networks": result, content = myvim.delete_tenant_network(item_id) @@ -2410,6 +2412,9 @@ def vim_action_delete(mydb, tenant_id, datacenter, item, name): def vim_action_create(mydb, tenant_id, datacenter, item, descriptor): #get datacenter info print "vim_action_create descriptor", descriptor + if tenant_id == "any": + tenant_id=None + if af.check_valid_uuid(datacenter): result, vims = get_vim(mydb, nfvo_tenant=tenant_id, datacenter_id=datacenter) else: diff --git a/nfvo_db.py b/nfvo_db.py index 7104ca8b..1bf3e4bc 100644 --- a/nfvo_db.py +++ b/nfvo_db.py @@ -730,7 +730,9 @@ class nfvo_db(): tenant_id = scenario_dict.get('tenant_id') #scenario INSERT_={'tenant_id': tenant_id, - 'name': scenario_dict['name'],'description': scenario_dict['description']} + 'name': scenario_dict['name'], + 'description': scenario_dict['description'], + 'public': scenario_dict.get('public', "false")} r,scenario_uuid = self._new_row_internal('scenarios', INSERT_, tenant_id, True, None, True,created_time) if r<0: diff --git a/openmano b/openmano index 938d13da..b207d291 100755 --- a/openmano +++ b/openmano @@ -766,7 +766,7 @@ def tenant_create(args): def tenant_list(args): #print "tenant-list",args if args.name: - toshow = _get_item_uuid("vnfs", args.name) + toshow = _get_item_uuid("tenants", args.name) URLrequest = "http://%s:%s/openmano/tenants/%s" %(mano_host, mano_port, toshow) else: URLrequest = "http://%s:%s/openmano/tenants" %(mano_host, mano_port) diff --git a/openmano_schemas.py b/openmano_schemas.py index 8ab251bf..a563b1a9 100644 --- a/openmano_schemas.py +++ b/openmano_schemas.py @@ -28,6 +28,7 @@ __author__="Alfonso Tierno, Gerardo Garcia" __date__ ="$09-oct-2014 09:09:48$" #Basis schemas +patern_name="^[ -~]+$" passwd_schema={"type" : "string", "minLength":1, "maxLength":60} nameshort_schema={"type" : "string", "minLength":1, "maxLength":60, "pattern" : "^[^,;()'\"]+$"} name_schema={"type" : "string", "minLength":1, "maxLength":255, "pattern" : "^[^,;()'\"]+$"} @@ -41,7 +42,7 @@ bandwidth_schema={"type":"string", "pattern" : "^[0-9]+ *([MG]bps)?$"} memory_schema={"type":"string", "pattern" : "^[0-9]+ *([MG]i?[Bb])?$"} integer0_schema={"type":"integer","minimum":0} integer1_schema={"type":"integer","minimum":1} -path_schema={"type":"string", "pattern":"^(\.(\.?))?(/[^/"":{}\ \(\)]+)+$"} +path_schema={"type":"string", "pattern":"^(\.){0,2}(/[^/\"':{}\(\)]+)+$"} vlan_schema={"type":"integer","minimum":1,"maximum":4095} vlan1000_schema={"type":"integer","minimum":1000,"maximum":4095} mac_schema={"type":"string", "pattern":"^[0-9a-fA-F][02468aceACE](:[0-9a-fA-F]{2}){5}$"} #must be unicast LSB bit of MSB byte ==0 @@ -49,6 +50,7 @@ mac_schema={"type":"string", "pattern":"^[0-9a-fA-F][02468aceACE](:[0-9a-fA-F]{2 ip_schema={"type":"string","pattern":"^([0-9]{1,3}.){3}[0-9]{1,3}$"} port_schema={"type":"integer","minimum":1,"maximum":65534} object_schema={"type":"object"} +schema_version_2={"type":"integer","minimum":2,"maximum":2} metadata_schema={ "type":"object", @@ -433,7 +435,7 @@ vnfd_schema_v02 = { "$schema": "http://json-schema.org/draft-04/schema#", "type":"object", "properties":{ - "version": {"type": "string", "pattern":"^v0.2$"}, + "schema_version": schema_version_2, "vnf":{ "type":"object", "properties":{ @@ -443,7 +445,7 @@ vnfd_schema_v02 = { "additionalProperties": True } }, - "required": ["vnf", "version"], + "required": ["vnf", "schema_version"], "additionalProperties": False } @@ -481,6 +483,7 @@ nsd_schema_v01 = { "name":name_schema, "description": description_schema, "tenant_id": id_schema, #only valid for admin + "public": {"type": "boolean"}, "topology":{ "type":"object", "properties":{ @@ -530,40 +533,50 @@ nsd_schema_v02 = { "$schema": "http://json-schema.org/draft-04/schema#", "type":"object", "properties":{ - "schema_version": {"type": "string", "enum": ["0.2"]}, - "name":name_schema, - "description": description_schema, - "tenant_id": id_schema, #only valid for admin - "vnfs": { - "type":"object", - "patternProperties":{ - ".": { - "type": "object", - "properties":{ - "vnf_id": id_schema, - "graph": graph_schema, - "vnf_model": name_schema, - }, - } - }, - "minProperties": 1 - }, - "networks": { + "schema_version": schema_version_2, + "scenario":{ "type":"object", - "patternProperties":{ - ".": { - "type": "object", - "properties":{ - "interfaces":{"type":"array", "minLength":1}, - "type": {"type": "string", "enum":["link", "external_network", "dataplane_net", "bridge_net"]}, - "graph": graph_schema + "properties":{ + "name":name_schema, + "description": description_schema, + "tenant_id": id_schema, #only valid for admin + "public": {"type": "boolean"}, + "vnfs": { + "type":"object", + "patternProperties":{ + ".": { + "type": "object", + "properties":{ + "vnf_id": id_schema, + "graph": graph_schema, + "vnf_name": name_schema, + }, + } }, - "required": ["interfaces"] + "minProperties": 1 }, - } - }, + "networks": { + "type":"object", + "patternProperties":{ + ".": { + "type": "object", + "properties":{ + "interfaces":{"type":"array", "minLength":1}, + "type": {"type": "string", "enum":["dataplane", "bridge"]}, + "external" : {"type": "boolean"}, + "graph": graph_schema + }, + "required": ["interfaces"] + }, + } + }, + + }, + "required": ["vnfs", "networks","name"], + "additionalProperties": False + } }, - "required": ["vnfs", "networks","name", "schema_version"], + "required": ["scenario","schema_version"], "additionalProperties": False } diff --git a/openmanoclient.py b/openmanoclient.py new file mode 100644 index 00000000..0d9aa4ae --- /dev/null +++ b/openmanoclient.py @@ -0,0 +1,908 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# This file is part of openmano +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact with: nfvlabs@tid.es +## + +''' +openmano python client used to interact with openmano-server +''' +__author__="Alfonso Tierno" +__date__ ="$09-Mar-2016 09:09:48$" +__version__="0.0.1-r467" +version_date="Mar 2016" + +import requests +import json +import yaml +import logging +import sys +if sys.version_info.major == 3: + from urllib.parse import quote +elif sys.version_info.major == 2: + from urllib import quote + +class OpenmanoException(Exception): + '''Common Exception for all openmano client exceptions''' + +class OpenmanoBadParamsException(OpenmanoException): + '''Bad or missing input parameters''' + +class OpenmanoResponseException(OpenmanoException): + '''Unexpected response from openmano server''' + +class OpenmanoNotFoundException(OpenmanoException): + '''Not found at server''' + +# class vnf(): +# def __init__(self, message): +# print "Error: %s" %message +# print +# self.print_usage() +# #self.print_help() +# print +# print "Type 'openmano -h' for help" + +class openmanoclient(): + headers_req = {'Accept': 'application/yaml', 'content-type': 'application/yaml'} + + def __init__(self, **kwargs): + self.username = kwargs.get("username") + self.password = kwargs.get("password") + self.endpoint_url = kwargs.get("endpoint_url") + self.tenant_id = kwargs.get("tenant_id") + self.tenant_name = kwargs.get("tenant_name") + self.tenant = None + self.datacenter_id = kwargs.get("datacenter_id") + self.datacenter_name = kwargs.get("datacenter_name") + self.datacenter = None + self.logger = logging.getLogger('manoclient') + if kwargs.get("debug"): + self.logger.setLevel(logging.DEBUG) + + def __getitem__(self, index): + if index=='tenant_name': + return self.tenant_name + elif index=='tenant_id': + return self.tenant_id + elif index=='datacenter_name': + return self.datacenter_name + elif index=='datacenter_id': + return self.datacenter_id + elif index=='username': + return self.username + elif index=='password': + return self.password + elif index=='endpoint_url': + return self.endpoint_url + else: + raise KeyError("Invalid key '%s'" %str(index)) + + def __setitem__(self,index, value): + if index=='tenant_name': + self.tenant_name = value + elif index=='tenant_id': + self.tenant_id = value + elif index=='datacenter_name': + self.datacenter_name = value + elif index=='datacenter_id': + self.datacenter_id = value + elif index=='username': + self.username = value + elif index=='password': + self.password = value + elif index=='endpoint_url': + self.endpoint_url = value + else: + raise KeyError("Invalid key '%s'" %str(index)) + self.tenant = None # force to reload tenant with different credentials + self.datacenter = None # force to reload datacenter with different credentials + + def _parse(self, descriptor, descriptor_format, response=False): + #try yaml + if descriptor_format and descriptor_format != "json" and descriptor_format != "yaml": + raise OpenmanoBadParamsException("'descriptor_format' must be a 'json' or 'yaml' text") + if descriptor_format != "json": + try: + return yaml.load(descriptor) + except yaml.YAMLError as exc: + error_pos = "" + if hasattr(exc, 'problem_mark'): + mark = exc.problem_mark + error_pos = " at line:{} column:{}s".format(mark.line+1, mark.column+1) + error_text = "yaml format error" + error_pos + elif descriptor_format != "yaml": + try: + return json.loads(descriptor) + except Exception as e: + if response: + error_text = "json format error" + str(e) + + if response: + raise OpenmanoResponseException(error_text) + raise OpenmanoBadParamsException(error_text) + + def _parse_yaml(self, descriptor, response=False): + try: + return yaml.load(descriptor) + except yaml.YAMLError as exc: + error_pos = "" + if hasattr(exc, 'problem_mark'): + mark = exc.problem_mark + error_pos = " at line:{} column:{}s".format(mark.line+1, mark.column+1) + error_text = "yaml format error" + error_pos + if response: + raise OpenmanoResponseException(error_text) + raise OpenmanoBadParamsException(error_text) + + + def _get_item_uuid(self, item, item_id=None, item_name=None, all_tenants=False): + if all_tenants == None: + tenant_text = "" + elif all_tenants == False: + tenant_text = "/" + self.tenant + else: + tenant_text = "/any" + URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item) + self.logger.debug("GET %s", URLrequest ) + mano_response = requests.get(URLrequest, headers=self.headers_req) + self.logger.debug("openmano response: %s", mano_response.text ) + content = self._parse_yaml(mano_response.text, response=True) + #print content + found = 0 + if not item_id and not item_name: + raise OpenmanoResponseException("Missing either {0}_name or {0}_id".format(item[:-1])) + for i in content[item]: + if item_id and i["uuid"] == item_id: + return item_id + elif item_name and i["name"] == item_name: + uuid = i["uuid"] + found += 1 + + if found == 0: + if item_id: + raise OpenmanoNotFoundException("No {} found with id '{}'".format(item[:-1], item_id)) + else: + #print(item, item_name) + raise OpenmanoNotFoundException("No {} found with name '{}'".format(item[:-1], item_name) ) + elif found > 1: + raise OpenmanoNotFoundException("{} {} found with name '{}'. uuid must be used".format(found, item, item_name)) + return uuid + + def _get_item(self, item, uuid=None, name=None, all_tenants=False): + if all_tenants: + tenant_text = "/any" + elif all_tenants==None: + tenant_text = "" + else: + tenant_text = "/"+self._get_tenant() + if not uuid: + #check that exist + uuid = self._get_item_uuid(item, uuid, name, all_tenants) + + URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid) + self.logger.debug("GET %s", URLrequest ) + mano_response = requests.get(URLrequest, headers=self.headers_req) + self.logger.debug("openmano response: %s", mano_response.text ) + + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code==200: + return content + else: + raise OpenmanoResponseException(str(content)) + + def _get_tenant(self): + if not self.tenant: + self.tenant = self._get_item_uuid("tenants", self.tenant_id, self.tenant_name, None) + return self.tenant + + def _get_datacenter(self): + if not self.tenant: + self._get_tenant() + if not self.datacenter: + self.datacenter = self._get_item_uuid("datacenters", self.datacenter_id, self.datacenter_name, False) + return self.datacenter + + def _create_item(self, item, descriptor, all_tenants=False): + if all_tenants: + tenant_text = "/any" + elif all_tenants==None: + tenant_text = "" + else: + tenant_text = "/"+self._get_tenant() + payload_req = yaml.safe_dump(descriptor) + + #print payload_req + + URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item) + self.logger.debug("openmano POST %s %s", URLrequest, payload_req) + mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req) + self.logger.debug("openmano response: %s", mano_response.text ) + + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code==200: + return content + else: + raise OpenmanoResponseException(str(content)) + + def _del_item(self, item, uuid=None, name=None, all_tenants=False): + if all_tenants: + tenant_text = "/any" + elif all_tenants==None: + tenant_text = "" + else: + tenant_text = "/"+self._get_tenant() + if not uuid: + #check that exist + uuid = self._get_item_uuid(item, uuid, name, all_tenants) + + URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid) + self.logger.debug("DELETE %s", URLrequest ) + mano_response = requests.delete(URLrequest, headers = self.headers_req) + self.logger.debug("openmano response: %s", mano_response.text ) + + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code==200: + return content + else: + raise OpenmanoResponseException(str(content)) + + def _list_item(self, item, all_tenants=False, filter_dict=None): + if all_tenants: + tenant_text = "/any" + elif all_tenants==None: + tenant_text = "" + else: + tenant_text = "/"+self._get_tenant() + + URLrequest = "{}{}/{}".format(self.endpoint_url, tenant_text, item) + separator="?" + if filter_dict: + for k in filter_dict: + URLrequest += separator + quote(str(k)) + "=" + quote(str(filter_dict[k])) + separator = "&" + self.logger.debug("openmano GET %s", URLrequest) + mano_response = requests.get(URLrequest, headers=self.headers_req) + self.logger.debug("openmano response: %s", mano_response.text ) + + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code==200: + return content + else: + raise OpenmanoResponseException(str(content)) + + def _edit_item(self, item, descriptor, uuid=None, name=None, all_tenants=False): + if all_tenants: + tenant_text = "/any" + elif all_tenants==None: + tenant_text = "" + else: + tenant_text = "/"+self._get_tenant() + + if not uuid: + #check that exist + uuid = self._get_item_uuid("tenants", uuid, name, all_tenants) + + payload_req = yaml.safe_dump(descriptor) + + #print payload_req + + URLrequest = "{}{}/{}/{}".format(self.endpoint_url, tenant_text, item, uuid) + self.logger.debug("openmano PUT %s %s", URLrequest, payload_req) + mano_response = requests.put(URLrequest, headers = self.headers_req, data=payload_req) + self.logger.debug("openmano response: %s", mano_response.text ) + + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code==200: + return content + else: + raise OpenmanoResponseException(str(content)) + + #TENANTS + def list_tenants(self, **kwargs): + '''Obtain a list of tenants + Params: can be filtered by 'uuid','name','description' + Return: Raises an exception on error + Obtain a dictionary with format {'tenants':[{tenant1_info},{tenant2_info},...]}} + ''' + return self._list_item("tenants", all_tenants=None, filter_dict=kwargs) + + def get_tenant(self, uuid=None, name=None): + '''Obtain the information of a tenant + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several + Obtain a dictionary with format {'tenant':{tenant_info}} + ''' + return self._get_item("tenants", uuid, name, all_tenants=None) + + def delete_tenant(self, uuid=None, name=None): + '''Delete a tenant + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several + Obtain a dictionary with format {'result': text indicating deleted} + ''' + return self._del_item("tenants", uuid, name, all_tenants=None) + + def create_tenant(self, descriptor=None, descriptor_format=None, name=None, description=None): + '''Creates a tenant + Params: must supply a descriptor or/and just a name + descriptor: with format {'tenant':{new_tenant_info}} + newtenant_info must contain 'name', and optionally 'description' + must be a dictionary or a json/yaml text. + name: the tenant name. Overwrite descriptor name if any + description: tenant descriptor.. Overwrite descriptor description if any + Return: Raises an exception on error + Obtain a dictionary with format {'tenant':{new_tenant_info}} + ''' + if isinstance(descriptor, str): + descriptor = self._parse(descriptor, descriptor_format) + elif descriptor: + pass + elif name: + descriptor={"tenant": {"name": name}} + else: + raise OpenmanoBadParamsException("Missing descriptor") + + if 'tenant' not in descriptor or len(descriptor)!=1: + raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field") + if name: + descriptor['tenant']['name'] = name + if description: + descriptor['tenant']['description'] = description + + return self._create_item("tenants", descriptor, all_tenants=None) + + def edit_tenant(self, uuid=None, name=None, descriptor=None, descriptor_format=None, new_name=None, new_description=None): + '''Edit the parameters of a tenant + Params: must supply a descriptor or/and a new_name or new_description + uuid or/and name. If only name is supplied, there must be only one or an exception is raised + descriptor: with format {'tenant':{params to change info}} + must be a dictionary or a json/yaml text. + name: the tenant name. Overwrite descriptor name if any + description: tenant descriptor.. Overwrite descriptor description if any + Return: Raises an exception on error, not found or found several + Obtain a dictionary with format {'tenant':{newtenant_info}} + ''' + + if isinstance(descriptor, str): + descriptor = self.parse(descriptor, descriptor_format) + elif descriptor: + pass + elif new_name or new_description: + descriptor={"tenant": {}} + else: + raise OpenmanoBadParamsException("Missing descriptor") + + if 'tenant' not in descriptor or len(descriptor)!=1: + raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field") + if new_name: + descriptor['tenant']['name'] = new_name + if new_description: + descriptor['tenant']['description'] = new_description + + return self._edit_item("tenants", descriptor, uuid, name, all_tenants=None) + + #DATACENTERS + + def list_datacenters(self, all_tenants=False, **kwargs): + '''Obtain a list of datacenters, that are the VIM information at openmano + Params: can be filtered by 'uuid','name','vim_url','type' + Return: Raises an exception on error + Obtain a dictionary with format {'datacenters':[{datacenter1_info},{datacenter2_info},...]}} + ''' + return self._list_item("datacenters", all_tenants, filter_dict=kwargs) + + def get_datacenter(self, uuid=None, name=None, all_tenants=False): + '''Obtain the information of a datacenter + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several + Obtain a dictionary with format {'datacenter':{datacenter_info}} + ''' + return self._get_item("datacenters", uuid, name, all_tenants) + + def delete_datacenter(self, uuid=None, name=None): + '''Delete a datacenter + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several, not free + Obtain a dictionary with format {'result': text indicating deleted} + ''' + return self._del_item("datacenters", uuid, name, all_tenants=True) + + def create_datacenter(self, descriptor=None, descriptor_format=None, name=None, vim_url=None, **kwargs): +#, type="openvim", public=False, description=None): + '''Creates a datacenter + Params: must supply a descriptor or/and just a name and vim_url + descriptor: with format {'datacenter':{new_datacenter_info}} + newdatacenter_info must contain 'name', 'vim_url', and optionally 'description' + must be a dictionary or a json/yaml text. + name: the datacenter name. Overwrite descriptor name if any + vim_url: the datacenter URL. Overwrite descriptor vim_url if any + vim_url_admin: the datacenter URL for administrative issues. Overwrite descriptor vim_url if any + vim_type: the datacenter type, can be openstack or openvim. Overwrite descriptor type if any + public: boolean, by default not public + description: datacenter description. Overwrite descriptor description if any + config: dictionary with extra configuration for the concrete datacenter + Return: Raises an exception on error + Obtain a dictionary with format {'datacenter':{new_datacenter_info}} + ''' + if isinstance(descriptor, str): + descriptor = self.parse(descriptor, descriptor_format) + elif descriptor: + pass + elif name and vim_url: + descriptor={"datacenter": {"name": name, "vim_url": vim_url}} + else: + raise OpenmanoBadParamsException("Missing descriptor, or name and vim_url") + + if 'datacenter' not in descriptor or len(descriptor)!=1: + raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field") + if name: + descriptor['datacenter']['name'] = name + if vim_url: + descriptor['datacenter']['vim_url'] = vim_url + for param in kwargs: + descriptor['datacenter'][param] = kwargs[param] + + return self._create_item("datacenters", descriptor, all_tenants=None) + + def edit_datacenter(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs): + '''Edit the parameters of a datacenter + Params: must supply a descriptor or/and a parameter to change + uuid or/and name. If only name is supplied, there must be only one or an exception is raised + descriptor: with format {'datacenter':{params to change info}} + must be a dictionary or a json/yaml text. + parameters to change can be supplyied by the descriptor or as parameters: + new_name: the datacenter name + vim_url: the datacenter URL + vim_url_admin: the datacenter URL for administrative issues + vim_type: the datacenter type, can be openstack or openvim. + public: boolean, available to other tenants + description: datacenter description + Return: Raises an exception on error, not found or found several + Obtain a dictionary with format {'datacenter':{new_datacenter_info}} + ''' + + if isinstance(descriptor, str): + descriptor = self.parse(descriptor, descriptor_format) + elif descriptor: + pass + elif kwargs: + descriptor={"datacenter": {}} + else: + raise OpenmanoBadParamsException("Missing descriptor") + + if 'datacenter' not in descriptor or len(descriptor)!=1: + raise OpenmanoBadParamsException("Descriptor must contain only one 'datacenter' field") + for param in kwargs: + if param=='new_name': + descriptor['datacenter']['name'] = kwargs[param] + else: + descriptor['datacenter'][param] = kwargs[param] + return self._edit_item("datacenters", descriptor, uuid, name, all_tenants=None) + + def attach_datacenter(self, uuid=None, name=None, descriptor=None, descriptor_format=None, vim_user=None, vim_password=None, vim_tenant_name=None, vim_tenant_id=None): + #check that exist + uuid = self._get_item_uuid("datacenters", uuid, name, all_tenants=True) + tenant_text = "/"+self._get_tenant() + + if isinstance(descriptor, str): + descriptor = self.parse(descriptor, descriptor_format) + elif descriptor: + pass + elif vim_user or vim_password or vim_tenant_name or vim_tenant_id: + descriptor={"datacenter": {}} + else: + raise OpenmanoBadParamsException("Missing descriptor or params") + + if vim_user or vim_password or vim_tenant_name or vim_tenant_id: + #print args.name + try: + if vim_user: + descriptor['datacenter']['vim_user'] = vim_user + if vim_password: + descriptor['datacenter']['vim_password'] = vim_password + if vim_tenant_name: + descriptor['datacenter']['vim_tenant_name'] = vim_tenant_name + if vim_tenant_id: + descriptor['datacenter']['vim_tenant'] = vim_tenant_id + except (KeyError, TypeError) as e: + if str(e)=='datacenter': error_pos= "missing field 'datacenter'" + else: error_pos="wrong format" + raise OpenmanoBadParamsException("Wrong datacenter descriptor: " + error_pos) + + payload_req = yaml.safe_dump(descriptor) + #print payload_req + URLrequest = "{}{}/datacenters/{}".format(self.endpoint_url, tenant_text, uuid) + self.logger.debug("openmano POST %s %s", URLrequest, payload_req) + mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req) + self.logger.debug("openmano response: %s", mano_response.text ) + + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code==200: + return content + else: + raise OpenmanoResponseException(str(content)) + + def detach_datacenter(self, uuid=None, name=None): + if not uuid: + #check that exist + uuid = self._get_item_uuid("datacenters", uuid, name, all_tenants=False) + tenant_text = "/"+self._get_tenant() + URLrequest = "{}{}/datacenters/{}".format(self.endpoint_url, tenant_text, uuid) + self.logger.debug("openmano DELETE %s", URLrequest) + mano_response = requests.delete(URLrequest, headers = self.headers_req) + self.logger.debug("openmano response: %s", mano_response.text ) + + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code==200: + return content + else: + raise OpenmanoResponseException(str(content)) + + #VNFS + def list_vnfs(self, all_tenants=False, **kwargs): + '''Obtain a list of vnfs + Params: can be filtered by 'uuid','name','description','public', "tenant_id" + Return: Raises an exception on error + Obtain a dictionary with format {'vnfs':[{vnf1_info},{vnf2_info},...]}} + ''' + return self._list_item("vnfs", all_tenants, kwargs) + + def get_vnf(self, uuid=None, name=None, all_tenants=False): + '''Obtain the information of a vnf + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several + Obtain a dictionary with format {'vnf':{vnf_info}} + ''' + return self._get_item("vnfs", uuid, name, all_tenants) + + def delete_vnf(self, uuid=None, name=None, all_tenants=False): + '''Delete a vnf + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several, not free + Obtain a dictionary with format {'result': text indicating deleted} + ''' + return self._del_item("vnfs", uuid, name, all_tenants) + + def create_vnf(self, descriptor=None, descriptor_format=None, **kwargs): + '''Creates a vnf + Params: must supply a descriptor + descriptor: with format {'vnf':{new_vnf_info}} + must be a dictionary or a json/yaml text. + must be a dictionary or a json/yaml text. + Other parameters can be: + name: the vnf name. Overwrite descriptor name if any + image_path: Can be a string or a string list. Overwrite the image_path at descriptor + description: vnf descriptor.. Overwrite descriptor description if any + public: boolean, available to other tenants + class: user text for vnf classification + tenant_id: Propietary tenant + ... + Return: Raises an exception on error + Obtain a dictionary with format {'vnf':{new_vnf_info}} + ''' + if isinstance(descriptor, str): + descriptor = self.parse(descriptor, descriptor_format) + elif descriptor: + pass + else: + raise OpenmanoBadParamsException("Missing descriptor") + + if 'vnf' not in descriptor or len(descriptor)>2: + raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field, and an optional version") + for param in kwargs: + if param == 'image_path': + #print args.name + try: + if isinstance(kwargs[param], str): + descriptor['vnf']['VNFC'][0]['VNFC image']=kwargs[param] + elif isinstance(kwargs[param], tuple) or isinstance(kwargs[param], list): + index=0 + for image_path_ in kwargs[param]: + #print "image-path", image_path_ + descriptor['vnf']['VNFC'][index]['VNFC image']=image_path_ + index=index+1 + else: + raise OpenmanoBadParamsException("Wrong image_path type. Expected text or a text list") + except (KeyError, TypeError) as e: + if str(e)=='vnf': error_pos= "missing field 'vnf'" + elif str(e)=='VNFC': error_pos= "missing field 'vnf':'VNFC'" + elif str(e)==str(index): error_pos= "field 'vnf':'VNFC' must be an array" + elif str(e)=='VNFC image': error_pos= "missing field 'vnf':'VNFC'['VNFC image']" + else: error_pos="wrong format" + raise OpenmanoBadParamsException("Wrong VNF descriptor: " + error_pos) + else: + descriptor['vnf'][param] = kwargs[param] + return self._create_item("vnfs", descriptor) + +# def edit_vnf(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs): +# '''Edit the parameters of a vnf +# Params: must supply a descriptor or/and a parameters to change +# uuid or/and name. If only name is supplied, there must be only one or an exception is raised +# descriptor: with format {'vnf':{params to change info}} +# parameters to change can be supplyied by the descriptor or as parameters: +# new_name: the vnf name +# vim_url: the vnf URL +# vim_url_admin: the vnf URL for administrative issues +# vim_type: the vnf type, can be openstack or openvim. +# public: boolean, available to other tenants +# description: vnf description +# Return: Raises an exception on error, not found or found several +# Obtain a dictionary with format {'vnf':{new_vnf_info}} +# ''' +# +# if isinstance(descriptor, str): +# descriptor = self.parse(descriptor, descriptor_format) +# elif descriptor: +# pass +# elif kwargs: +# descriptor={"vnf": {}} +# else: +# raise OpenmanoBadParamsException("Missing descriptor") +# +# if 'vnf' not in descriptor or len(descriptor)>2: +# raise OpenmanoBadParamsException("Descriptor must contain only one 'vnf' field") +# for param in kwargs: +# if param=='new_name': +# descriptor['vnf']['name'] = kwargs[param] +# else: +# descriptor['vnf'][param] = kwargs[param] +# return self._edit_item("vnfs", descriptor, uuid, name, all_tenants=None) + + #SCENARIOS + def list_scenarios(self, all_tenants=False, **kwargs): + '''Obtain a list of scenarios + Params: can be filtered by 'uuid','name','description','public', "tenant_id" + Return: Raises an exception on error + Obtain a dictionary with format {'scenarios':[{scenario1_info},{scenario2_info},...]}} + ''' + return self._list_item("scenarios", all_tenants, kwargs) + + def get_scenario(self, uuid=None, name=None, all_tenants=False): + '''Obtain the information of a scenario + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several + Obtain a dictionary with format {'scenario':{scenario_info}} + ''' + return self._get_item("scenarios", uuid, name, all_tenants) + + def delete_scenario(self, uuid=None, name=None, all_tenants=False): + '''Delete a scenario + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several, not free + Obtain a dictionary with format {'result': text indicating deleted} + ''' + return self._del_item("scenarios", uuid, name, all_tenants) + + def create_scenario(self, descriptor=None, descriptor_format=None, **kwargs): + '''Creates a scenario + Params: must supply a descriptor + descriptor: with format {'scenario':{new_scenario_info}} + must be a dictionary or a json/yaml text. + Other parameters can be: + name: the scenario name. Overwrite descriptor name if any + description: scenario descriptor.. Overwrite descriptor description if any + public: boolean, available to other tenants + tenant_id. Propietary tenant + Return: Raises an exception on error + Obtain a dictionary with format {'scenario':{new_scenario_info}} + ''' + if isinstance(descriptor, str): + descriptor = self.parse(descriptor, descriptor_format) + elif descriptor: + pass + else: + raise OpenmanoBadParamsException("Missing descriptor") + + if 'scenario' not in descriptor or len(descriptor)>2: + raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field, and an optional version") + for param in kwargs: + descriptor['scenario'][param] = kwargs[param] + return self._create_item("scenarios", descriptor) + + def edit_scenario(self, uuid=None, name=None, descriptor=None, descriptor_format=None, all_tenants=False, **kwargs): + '''Edit the parameters of a scenario + Params: must supply a descriptor or/and a parameters to change + uuid or/and name. If only name is supplied, there must be only one or an exception is raised + descriptor: with format {'scenario':{params to change info}} + must be a dictionary or a json/yaml text. + parameters to change can be supplyied by the descriptor or as parameters: + new_name: the scenario name + public: boolean, available to other tenants + description: scenario description + tenant_id. Propietary tenant + Return: Raises an exception on error, not found or found several + Obtain a dictionary with format {'scenario':{new_scenario_info}} + ''' + + if isinstance(descriptor, str): + descriptor = self.parse(descriptor, descriptor_format) + elif descriptor: + pass + elif kwargs: + descriptor={"scenario": {}} + else: + raise OpenmanoBadParamsException("Missing descriptor") + + if 'scenario' not in descriptor or len(descriptor)>2: + raise OpenmanoBadParamsException("Descriptor must contain only one 'scenario' field") + for param in kwargs: + if param=='new_name': + descriptor['scenario']['name'] = kwargs[param] + else: + descriptor['scenario'][param] = kwargs[param] + return self._edit_item("scenarios", descriptor, uuid, name, all_tenants=None) + + + #INSTANCE-SCENARIOS + def list_instances(self, all_tenants=False, **kwargs): + '''Obtain a list of instances + Params: can be filtered by 'uuid','name','description','scenario_id', "tenant_id" + Return: Raises an exception on error + Obtain a dictionary with format {'instances':[{instance1_info},{instance2_info},...]}} + ''' + return self._list_item("instances", all_tenants, kwargs) + + def get_instance(self, uuid=None, name=None, all_tenants=False): + '''Obtain the information of a instance + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several + Obtain a dictionary with format {'instance':{instance_info}} + ''' + return self._get_item("instances", uuid, name, all_tenants) + + def delete_instance(self, uuid=None, name=None, all_tenants=False): + '''Delete a instance + Params: uuid or/and name. If only name is supplied, there must be only one or an exception is raised + Return: Raises an exception on error, not found, found several, not free + Obtain a dictionary with format {'result': text indicating deleted} + ''' + return self._del_item("instances", uuid, name, all_tenants) + + def create_instance(self, descriptor=None, descriptor_format=None, name=None, **kwargs): + '''Creates a instance + Params: must supply a descriptor or/and a name and scenario + descriptor: with format {'instance':{new_instance_info}} + must be a dictionary or a json/yaml text. + name: the instance name. Overwrite descriptor name if any + Other parameters can be: + description: instance descriptor.. Overwrite descriptor description if any + datacenter_name, datacenter_id: datacenter where to be deployed + scenario_name, scenario_id: Scenario this instance is based on + Return: Raises an exception on error + Obtain a dictionary with format {'instance':{new_instance_info}} + ''' + if isinstance(descriptor, str): + descriptor = self.parse(descriptor, descriptor_format) + elif descriptor: + pass + elif name and ("scenario_name" in kwargs or "scenario_id" in kwargs): + descriptor = {"instance":{"name": name}} + else: + raise OpenmanoBadParamsException("Missing descriptor") + + if 'instance' not in descriptor or len(descriptor)>2: + raise OpenmanoBadParamsException("Descriptor must contain only one 'instance' field, and an optional version") + if name: + descriptor['instance']["name"] = name + if "scenario_name" in kwargs or "scenario_id" in kwargs: + descriptor['instance']["scenario"] = self._get_item_uuid("scenarios", kwargs.get("scenario_id"), kwargs.get("scenario_name")) + if "datacenter_name" in kwargs or "datacenter_id" in kwargs: + descriptor['instance']["datacenter"] = self._get_item_uuid("datacenters", kwargs.get("datacenter_id"), kwargs.get("datacenter_name")) + if "description" in kwargs: + descriptor['instance']["description"] = kwargs.get("description") + #for param in kwargs: + # descriptor['instance'][param] = kwargs[param] + if "datacenter" not in descriptor['instance']: + descriptor['instance']["datacenter"] = self._get_datacenter() + return self._create_item("instances", descriptor) + + #VIM ACTIONS + def vim_action(self, action, item, uuid=None, all_tenants=False, **kwargs): + '''Perform an action over a vim + Params: + action: can be 'list', 'get'/'show', 'delete' or 'create' + item: can be 'tenants' or 'networks' + uuid: uuid of the tenant/net to show or to delete. Ignore otherwise + other parameters: + datacenter_name, datacenter_id: datacenters to act on, if missing uses classes store datacenter + descriptor, descriptor_format: descriptor needed on creation, can be a dict or a yaml/json str + must be a dictionary or a json/yaml text. + name: for created tenant/net Overwrite descriptor name if any + description: tenant descriptor. Overwrite descriptor description if any + + Return: Raises an exception on error + Obtain a dictionary with format {'tenant':{new_tenant_info}} + ''' + if item not in ("tenants", "networks"): + raise OpenmanoBadParamsException("Unknown value for item '{}', must be 'tenants' or 'nets'".format(str(item))) + + if all_tenants: + tenant_text = "/any" + else: + tenant_text = "/"+self._get_tenant() + + if "datacenter_id" in kwargs or "datacenter_name" in kwargs: + datacenter = self._get_item_uuid("datacenters", kwargs.get("datacenter_id"), kwargs.get("datacenter_name"), all_tenants=all_tenants) + else: + datacenter = self._get_datacenter() + + if action=="list": + URLrequest = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item) + self.logger.debug("GET %s", URLrequest ) + mano_response = requests.get(URLrequest, headers=self.headers_req) + self.logger.debug("openmano response: %s", mano_response.text ) + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code==200: + return content + else: + raise OpenmanoResponseException(str(content)) + elif action=="get" or action=="show": + URLrequest = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid) + self.logger.debug("GET %s", URLrequest ) + mano_response = requests.get(URLrequest, headers=self.headers_req) + self.logger.debug("openmano response: %s", mano_response.text ) + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code==200: + return content + else: + raise OpenmanoResponseException(str(content)) + elif action=="delete": + URLrequest = "{}{}/vim/{}/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item, uuid) + self.logger.debug("DELETE %s", URLrequest ) + mano_response = requests.delete(URLrequest, headers=self.headers_req) + self.logger.debug("openmano response: %s", mano_response.text ) + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code==200: + return content + else: + raise OpenmanoResponseException(str(content)) + elif action=="create": + if "descriptor" in kwargs: + if isinstance(kwargs["descriptor"], str): + descriptor = self._parse(kwargs["descriptor"], kwargs.get("descriptor_format") ) + else: + descriptor = kwargs["descriptor"] + elif "name" in kwargs: + descriptor={item[:-1]: {"name": kwargs["name"]}} + else: + raise OpenmanoResponseException("Missing descriptor") + + if item[:-1] not in descriptor or len(descriptor)!=1: + raise OpenmanoBadParamsException("Descriptor must contain only one 'tenant' field") + if "name" in kwargs: + descriptor[ item[:-1] ]['name'] = kwargs["name"] + if "description" in kwargs: + descriptor[ item[:-1] ]['description'] = kwargs["description"] + payload_req = yaml.safe_dump(descriptor) + #print payload_req + URLrequest = "{}{}/vim/{}/{}".format(self.endpoint_url, tenant_text, datacenter, item) + self.logger.debug("openmano POST %s %s", URLrequest, payload_req) + mano_response = requests.post(URLrequest, headers = self.headers_req, data=payload_req) + self.logger.debug("openmano response: %s", mano_response.text ) + content = self._parse_yaml(mano_response.text, response=True) + if mano_response.status_code==200: + return content + else: + raise OpenmanoResponseException(str(content)) + else: + raise OpenmanoBadParamsException("Unknown value for action '{}".format(str(action))) + diff --git a/scenarios/scenario-template2.yaml b/scenarios/scenario-template2.yaml new file mode 100644 index 00000000..9612802e --- /dev/null +++ b/scenarios/scenario-template2.yaml @@ -0,0 +1,35 @@ +--- +schema_version: 2 +scenario: + name: insert a name for the scenario + description: insert a description for the scenario + public: false # if available for other tenants + vnfs: + vnf1: # vnf name in the scenario + #identify an already openmano uploaded VNF either by vnf_id (uuid, prefered) or vnf_name + vnf_id: fb356022-f664-11e5-a1e7-0800273e724c #prefered id method + #vnf_name: openmano_vnf_name #can fail if several vnfs matches this name + #graph: {"y":399,"x":332,"ifaces":{"left":[["xe0","d"],["xe1","d"]],"bottom":[["eth0","v"],["eth1","m"]]}} + vnf2: + vnf_name: vnf_name_2 # can fail if several vnfs matches this name + graph: {"y":399,"x":632,"ifaces":{"left":[["xe0","d"],["xe1","d"]],"bottom":[["eth0","v"],["eth1","m"]]}} + networks: + net1: # network name in the scenario + #optional type, deduced from interfaces + type: dataplane # "dataplane", "bridge" + #graph: {} + interfaces: # nodes that will be connected: one or several vnfs + - vnf1: xe0 # First node and its interface to be connected (interfaces must match to one in the VNF descriptor) + - vnf2: xe0 # Second node and its interface + control net: + # Control plane connections must include a bridge network in the list of nodes + interfaces: + - vnf1: eth1 + - vnf2: eth1 + out: + # Connections based on external networks (datacenter nets) must include the external network in the list of nodes + type: dataplane + external: true #this will be connected outside + interfaces: + - vnf1: xe1 + diff --git a/vimconn.py b/vimconn.py old mode 100755 new mode 100644 index 6702c5f8..7ae33592 --- a/vimconn.py +++ b/vimconn.py @@ -38,26 +38,31 @@ HTTP_Conflict = 409 HTTP_Service_Unavailable = 503 HTTP_Internal_Server_Error = 500 +class vimconnectorException(Exception): + pass class vimconnector(): '''Abstract base class for all the VIM connector plugins These plugins must implement a vimconnector class deribed from this and all these methods ''' - def __init__(self, uuid, name, tenant, url, url_admin=None, user=None, passwd=None,debug=True,config={}): + def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None,debug=True,config={}): self.id = uuid self.name = name self.url = url self.url_admin = url_admin - self.tenant = tenant + self.tenant_id = tenant_id + self.tenant_name = tenant_name self.user = user self.passwd = passwd self.config = config self.debug = debug def __getitem__(self,index): - if index=='tenant': - return self.tenant + if index=='tenant_id': + return self.tenant_id + if index=='tenant_name': + return self.tenant_name elif index=='id': return self.id elif index=='name': @@ -76,8 +81,10 @@ class vimconnector(): raise KeyError("Invalid key '%s'" %str(index)) def __setitem__(self,index, value): - if index=='tenant': - self.tenant = value + if index=='tenant_id': + self.tenant_id = value + if index=='tenant_name': + self.tenant_name = value elif index=='id': self.id = value elif index=='name': diff --git a/vimconn_openstack.py b/vimconn_openstack.py index 3a323a83..242acb75 100644 --- a/vimconn_openstack.py +++ b/vimconn_openstack.py @@ -54,12 +54,12 @@ netStatus2manoFormat={'ACTIVE':'ACTIVE','PAUSED':'PAUSED','INACTIVE':'INACTIVE', } class vimconnector(vimconn.vimconnector): - def __init__(self, uuid, name, tenant, url, url_admin=None, user=None, passwd=None, debug=True, config={}): + def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, debug=True, config={}): '''using common constructor parameters. In this case 'url' is the keystone authorization url, 'url_admin' is not use ''' - vimconn.vimconnector.__init__(self, uuid, name, tenant, url, url_admin, user, passwd, debug, config) + vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, debug, config) self.k_creds={} self.n_creds={} @@ -67,9 +67,12 @@ class vimconnector(vimconn.vimconnector): raise TypeError, 'url param can not be NoneType' self.k_creds['auth_url'] = url self.n_creds['auth_url'] = url - if tenant: - self.k_creds['tenant_name'] = tenant - self.n_creds['project_id'] = tenant + if tenant_name: + self.k_creds['tenant_name'] = tenant_name + self.n_creds['project_id'] = tenant_name + if tenant_id: + self.k_creds['tenant_id'] = tenant_id + self.n_creds['tenant_id'] = tenant_id if user: self.k_creds['username'] = user self.n_creds['username'] = user @@ -82,9 +85,18 @@ class vimconnector(vimconn.vimconnector): '''Set individuals parameters Throw TypeError, KeyError ''' - if index=='tenant': + if index=='tenant_id': + self.reload_client=True + self.tenant_id = value + if value: + self.k_creds['tenant_id'] = value + self.n_creds['tenant_id'] = value + else: + del self.k_creds['tenant_name'] + del self.n_creds['project_id'] + elif index=='tenant_name': self.reload_client=True - self.tenant = value + self.tenant_name = value if value: self.k_creds['tenant_name'] = value self.n_creds['project_id'] = value @@ -258,7 +270,7 @@ class vimconnector(vimconn.vimconnector): '''Adds a tenant network to VIM''' '''Returns the network identifier''' if self.debug: - print "osconnector: Adding a new tenant network to VIM (tenant: " + self.tenant + ", type: " + net_type + "): "+ net_name + print "osconnector: Adding a new tenant network to VIM (tenant: " + str(self.tenant_name) + ", type: " + net_type + "): "+ net_name try: self._reload_connection() network_dict = {'name': net_name, 'admin_state_up': True} @@ -359,7 +371,7 @@ class vimconnector(vimconn.vimconnector): '''Deletes a tenant network from VIM''' '''Returns the network identifier''' if self.debug: - print "osconnector: Deleting a new tenant network from VIM tenant: " + self.tenant + ", id: " + net_id + print "osconnector: Deleting a new tenant network from VIM tenant: " + str(self.tenant_name) + ", id: " + net_id try: self._reload_connection() #delete VM ports attached to this networks before the network diff --git a/vimconn_openvim.py b/vimconn_openvim.py old mode 100755 new mode 100644 index 6dfd474c..e253b4e4 --- a/vimconn_openvim.py +++ b/vimconn_openvim.py @@ -306,9 +306,40 @@ get_processor_rankings_response_schema = { } class vimconnector(vimconn.vimconnector): - def __init__(self, uuid, name, tenant, url, url_admin=None, user=None, passwd=None,debug=True,config={}): - vimconn.vimconnector.__init__(self, uuid, name, tenant, url, url_admin, user, passwd, debug, config) - + def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None,debug=True,config={}): + vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, debug, config) + self.tenant = None + self.headers_req = {'content-type': 'application/json'} + if tenant_id: + self.tenant = tenant_id + + def __setitem__(self,index, value): + '''Set individuals parameters + Throw TypeError, KeyError + ''' + if index=='tenant_id': + self.tenant = value + elif index=='tenant_name': + self.tenant = None + vimconn.vimconnector.__setitem__(self,index, value) + + def _get_my_tenant(self): + '''Obtain uuid of my tenant from name + ''' + if self.tenant: + return self.tenant + + vim_response = requests.get(self.url+'/tenants?name='+ self.tenant_name, headers = self.headers_req) + if vim_response.status_code != 200: + raise vimconn.vimconnectorException ("_get_my_tenant response " + str(vim_response.status_code)) + tenant_list = vim_response.json()["tenants"] + if len(tenant_list) == 0: + raise vimconn.vimconnectorException ("No tenant found for name '%s'" % str(self.tenant_name)) + elif len(tenant_list) > 1: + raise vimconn.vimconnectorException ("More that one tenant found for name '%s'" % str(self.tenant_name)) + self.tenant = tenant_list[0]["id"] + return self.tenant + def _format_jsonerror(self,http_response): try: data = http_response.json() @@ -348,10 +379,9 @@ class vimconnector(vimconn.vimconnector): '''Adds a new host to VIM''' '''Returns status code of the VIM response''' print "VIMConnector: Adding a new host" - headers_req = {'content-type': 'application/json'} payload_req = host_data try: - vim_response = requests.post(self.url_admin+'/hosts', headers = headers_req, data=payload_req) + vim_response = requests.post(self.url_admin+'/hosts', headers = self.headers_req, data=payload_req) except requests.exceptions.RequestException, e: print "new_host Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -381,10 +411,9 @@ class vimconnector(vimconn.vimconnector): '''Adds a external port to VIM''' '''Returns the port identifier''' print "VIMConnector: Adding a new external port" - headers_req = {'content-type': 'application/json'} payload_req = port_data try: - vim_response = requests.post(self.url_admin+'/ports', headers = headers_req, data=payload_req) + vim_response = requests.post(self.url_admin+'/ports', headers = self.headers_req, data=payload_req) except requests.exceptions.RequestException, e: print "new_external_port Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -415,10 +444,9 @@ class vimconnector(vimconn.vimconnector): '''Returns the network identifier''' print "VIMConnector: Adding external shared network to VIM (type " + net_type + "): "+ net_name - headers_req = {'content-type': 'application/json'} payload_req = '{"network":{"name": "' + net_name + '","shared":true,"type": "' + net_type + '"}}' try: - vim_response = requests.post(self.url+'/networks', headers = headers_req, data=payload_req) + vim_response = requests.post(self.url+'/networks', headers = self.headers_req, data=payload_req) except requests.exceptions.RequestException, e: print "new_external_network Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -449,7 +477,6 @@ class vimconnector(vimconn.vimconnector): '''Returns status code of the VIM response''' print "VIMConnector: Connecting external port to network" - headers_req = {'content-type': 'application/json'} payload_req = '{"port":{"network_id":"' + network_id + '"}}' if admin: if self.url_admin==None: @@ -458,7 +485,7 @@ class vimconnector(vimconn.vimconnector): else: url= self.url try: - vim_response = requests.put(url +'/ports/'+port_id, headers = headers_req, data=payload_req) + vim_response = requests.put(url +'/ports/'+port_id, headers = self.headers_req, data=payload_req) except requests.exceptions.RequestException, e: print "connect_port_network Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -488,13 +515,12 @@ class vimconnector(vimconn.vimconnector): '''Adds a new tenant to VIM''' '''Returns the tenant identifier''' print "VIMConnector: Adding a new tenant to VIM" - headers_req = {'content-type': 'application/json'} payload_dict = {"tenant": {"name":tenant_name,"description": tenant_description, "enabled": True}} payload_req = json.dumps(payload_dict) #print payload_req try: - vim_response = requests.post(self.url+'/tenants', headers = headers_req, data=payload_req) + vim_response = requests.post(self.url+'/tenants', headers = self.headers_req, data=payload_req) except requests.exceptions.RequestException, e: print "new_tenant Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -523,9 +549,8 @@ class vimconnector(vimconn.vimconnector): '''Delete a tenant from VIM''' '''Returns the tenant identifier''' print "VIMConnector: Deleting a tenant from VIM" - headers_req = {'content-type': 'application/json'} try: - vim_response = requests.delete(self.url+'/tenants/'+tenant_id, headers = headers_req) + vim_response = requests.delete(self.url+'/tenants/'+tenant_id, headers = self.headers_req) except requests.exceptions.RequestException, e: print "delete_tenant Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -542,16 +567,19 @@ class vimconnector(vimconn.vimconnector): def new_tenant_network(self,net_name,net_type,public=False, **vim_specific): '''Adds a tenant network to VIM''' '''Returns the network identifier''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "vim_specific", vim_specific if net_type=="bridge": net_type="bridge_data" - print "VIMConnector: Adding a new tenant network to VIM (tenant: " + self.tenant + ", type: " + net_type + "): "+ net_name + print "VIMConnector: Adding a new tenant network to VIM (tenant: " + str(self.tenant) + ", type: " + net_type + "): "+ net_name - headers_req = {'content-type': 'application/json'} payload_req = {"name": net_name, "type": net_type, "tenant_id": self.tenant, "shared": public} payload_req.update(vim_specific) try: - vim_response = requests.post(self.url+'/networks', headers = headers_req, data=json.dumps({"network": payload_req}) ) + vim_response = requests.post(self.url+'/networks', headers = self.headers_req, data=json.dumps({"network": payload_req}) ) except requests.exceptions.RequestException, e: print "new_tenant_network Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -591,10 +619,9 @@ class vimconnector(vimconn.vimconnector): filterquery.append(str(k)+'='+str(v)) if len(filterquery)>0: filterquery_text='?'+ '&'.join(filterquery) - headers_req = {'content-type': 'application/json'} try: print self.url+'/tenants'+filterquery_text - vim_response = requests.get(self.url+'/tenants'+filterquery_text, headers = headers_req) + vim_response = requests.get(self.url+'/tenants'+filterquery_text, headers = self.headers_req) except requests.exceptions.RequestException, e: print "get_tenant_list Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -624,6 +651,8 @@ class vimconnector(vimconn.vimconnector): status: 'ACTIVE' Returns the network list of dictionaries ''' + + filter_dict["tenant_id"] = self._get_my_tenant() print "VIMConnector.get_network_list: Getting tenant network from VIM (filter: " + str(filter_dict) + "): " filterquery=[] filterquery_text='' @@ -631,10 +660,9 @@ class vimconnector(vimconn.vimconnector): filterquery.append(str(k)+'='+str(v)) if len(filterquery)>0: filterquery_text='?'+ '&'.join(filterquery) - headers_req = {'content-type': 'application/json'} try: print self.url+'/networks'+filterquery_text - vim_response = requests.get(self.url+'/networks'+filterquery_text, headers = headers_req) + vim_response = requests.get(self.url+'/networks'+filterquery_text, headers = self.headers_req) except requests.exceptions.RequestException, e: print "get_network_list Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -673,11 +701,14 @@ class vimconnector(vimconn.vimconnector): def delete_tenant_network(self, net_id): '''Deletes a tenant network from VIM''' '''Returns the network identifier''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "VIMConnector: Deleting a new tenant network from VIM tenant: " + self.tenant + ", id: " + net_id - headers_req = {'content-type': 'application/json'} try: - vim_response = requests.delete(self.url+'/networks/'+net_id, headers=headers_req) + vim_response = requests.delete(self.url+'/networks/'+net_id, headers=self.headers_req) except requests.exceptions.RequestException, e: print "delete_tenant_network Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -703,13 +734,16 @@ class vimconnector(vimconn.vimconnector): '''Obtain flavor details from the VIM Returns the flavor dict details ''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "VIMConnector: Getting flavor from VIM" #print "VIM URL:",self.url #print "Tenant id:",self.tenant #print "Flavor:",flavor_data - headers_req = {'content-type': 'application/json'} try: - vim_response = requests.get(self.url+'/'+self.tenant+'/flavors/'+flavor_id, headers = headers_req) + vim_response = requests.get(self.url+'/'+self.tenant+'/flavors/'+flavor_id, headers = self.headers_req) except requests.exceptions.RequestException, e: print "get_tenant_flavor Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -739,14 +773,17 @@ class vimconnector(vimconn.vimconnector): def new_tenant_flavor(self, flavor_data): '''Adds a tenant flavor to VIM''' '''Returns the flavor identifier''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "VIMConnector: Adding a new flavor to VIM" #print "VIM URL:",self.url #print "Tenant id:",self.tenant #print "Flavor:",flavor_data - headers_req = {'content-type': 'application/json'} payload_req = json.dumps({'flavor': flavor_data}) try: - vim_response = requests.post(self.url+'/'+self.tenant+'/flavors', headers = headers_req, data=payload_req) + vim_response = requests.post(self.url+'/'+self.tenant+'/flavors', headers = self.headers_req, data=payload_req) except requests.exceptions.RequestException, e: print "new_tenant_flavor Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -776,11 +813,14 @@ class vimconnector(vimconn.vimconnector): def delete_tenant_flavor(self,flavor_id): '''Deletes a tenant flavor from VIM''' '''Returns the HTTP response code and a message indicating details of the success or fail''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "VIMConnector: Deleting a flavor from VIM" print "VIM URL:",self.url print "Tenant id:",self.tenant print "Flavor id:",flavor_id - #headers_req = {'content-type': 'application/json'} #payload_req = flavor_data try: vim_response = requests.delete(self.url+'/'+self.tenant+'/flavors/'+flavor_id) @@ -806,8 +846,11 @@ class vimconnector(vimconn.vimconnector): 200, image-id if the image is created <0, message if there is an error ''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "VIMConnector: Adding a new image to VIM", image_dict['location'] - headers_req = {'content-type': 'application/json'} new_image_dict={'name': image_dict['name']} if 'description' in image_dict and image_dict['description'] != None: new_image_dict['description'] = image_dict['description'] @@ -818,7 +861,7 @@ class vimconnector(vimconn.vimconnector): payload_req = json.dumps({"image":new_image_dict}) url=self.url + '/' + self.tenant + '/images' try: - vim_response = requests.post(url, headers = headers_req, data=payload_req) + vim_response = requests.post(url, headers = self.headers_req, data=payload_req) except requests.exceptions.RequestException, e: print "new_tenant_image Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -847,8 +890,11 @@ class vimconnector(vimconn.vimconnector): def delete_tenant_image(self, image_id): '''Deletes a tenant image from VIM''' '''Returns the HTTP response code and a message indicating details of the success or fail''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "VIMConnector: Deleting an image from VIM" - #headers_req = {'content-type': 'application/json'} #payload_req = flavor_data url=self.url + '/'+ self.tenant +'/images/'+image_id try: @@ -871,11 +917,14 @@ class vimconnector(vimconn.vimconnector): def new_tenant_vminstancefromJSON(self, vm_data): '''Adds a VM instance to VIM''' '''Returns the instance identifier''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "VIMConnector: Adding a new VM instance from JSON to VIM" - headers_req = {'content-type': 'application/json'} payload_req = vm_data try: - vim_response = requests.post(self.url+'/'+self.tenant+'/servers', headers = headers_req, data=payload_req) + vim_response = requests.post(self.url+'/'+self.tenant+'/servers', headers = self.headers_req, data=payload_req) except requests.exceptions.RequestException, e: print "new_tenant_vminstancefromJSON Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -919,8 +968,11 @@ class vimconnector(vimconn.vimconnector): Returns >=0, the instance identifier <0, error_text ''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "VIMConnector: Adding a new VM instance to VIM" - headers_req = {'content-type': 'application/json'} # net_list = [] # for k,v in net_dict.items(): @@ -949,7 +1001,7 @@ class vimconnector(vimconn.vimconnector): payload_req = json.dumps({"server": payload_dict}) print self.url+'/'+self.tenant+'/servers'+payload_req try: - vim_response = requests.post(self.url+'/'+self.tenant+'/servers', headers = headers_req, data=payload_req) + vim_response = requests.post(self.url+'/'+self.tenant+'/servers', headers = self.headers_req, data=payload_req) except requests.exceptions.RequestException, e: print "new_tenant_vminstance Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -1007,13 +1059,16 @@ class vimconnector(vimconn.vimconnector): def get_tenant_vminstance(self,vm_id): '''Returns the VM instance information from VIM''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "VIMConnector: Getting tenant VM instance information from VIM" - headers_req = {'content-type': 'application/json'} url = self.url+'/'+self.tenant+'/servers/'+vm_id print url try: - vim_response = requests.get(url, headers = headers_req) + vim_response = requests.get(url, headers = self.headers_req) except requests.exceptions.RequestException, e: print "get_tenant_vminstance Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -1038,11 +1093,14 @@ class vimconnector(vimconn.vimconnector): def delete_tenant_vminstance(self, vm_id): '''Removes a VM instance from VIM''' '''Returns the instance identifier''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "VIMConnector: Delete a VM instance from VIM " + vm_id - headers_req = {'content-type': 'application/json'} try: - vim_response = requests.delete(self.url+'/'+self.tenant+'/servers/'+vm_id, headers = headers_req) + vim_response = requests.delete(self.url+'/'+self.tenant+'/servers/'+vm_id, headers = self.headers_req) except requests.exceptions.RequestException, e: print "delete_tenant_vminstance Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -1066,6 +1124,10 @@ class vimconnector(vimconn.vimconnector): <0 if error (foreseen) - error_msg: text with reference to possible errors ''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) #vms_refreshed = [] #nets_refreshed = [] vms_unrefreshed = [] @@ -1073,12 +1135,11 @@ class vimconnector(vimconn.vimconnector): for vm_id in vmDict: vmDict[vm_id]={'error_msg':None, 'vim_info':None} print "VIMConnector refresh_tenant_vms and nets: Getting tenant VM instance information from VIM" - headers_req = {'content-type': 'application/json'} url = self.url+'/'+self.tenant+'/servers/'+ vm_id print url try: - vim_response = requests.get(url, headers = headers_req) + vim_response = requests.get(url, headers = self.headers_req) except requests.exceptions.RequestException, e: print "VIMConnector refresh_tenant_elements. Exception: ", e.args vmDict[vm_id]['status'] = "VIM_ERROR" @@ -1102,7 +1163,7 @@ class vimconnector(vimconn.vimconnector): #get interfaces info url2 = self.url+'/ports?device_id='+ vm_id try: - vim_response2 = requests.get(url2, headers = headers_req) + vim_response2 = requests.get(url2, headers = self.headers_req) if vim_response.status_code == 200: client_data = vim_response2.json() for port in client_data.get("ports"): @@ -1148,7 +1209,6 @@ class vimconnector(vimconn.vimconnector): for net_id in netDict: netDict[net_id] = {'error_msg':None, 'vim_info':None} print "VIMConnector refresh_tenant_vms_and_nets: Getting tenant network from VIM (tenant: " + str(self.tenant) + "): " - headers_req = {'content-type': 'application/json'} r,c = self.get_tenant_network(net_id) if r<0: print "VIMconnector refresh_tenant_network. Error getting net_id '%s' status: %s" % (net_id, c) @@ -1185,14 +1245,17 @@ class vimconnector(vimconn.vimconnector): def action_tenant_vminstance(self, vm_id, action_dict): '''Send and action over a VM instance from VIM''' '''Returns the status''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) print "VIMConnector: Action over VM instance from VIM " + vm_id - headers_req = {'content-type': 'application/json'} try: if "console" in action_dict: return -vimconn.HTTP_Service_Unavailable, "getting console is not available at openvim" - vim_response = requests.post(self.url+'/'+self.tenant+'/servers/'+vm_id+"/action", headers = headers_req, data=json.dumps(action_dict) ) + vim_response = requests.post(self.url+'/'+self.tenant+'/servers/'+vm_id+"/action", headers = self.headers_req, data=json.dumps(action_dict) ) except requests.exceptions.RequestException, e: print "action_tenant_vminstance Exception: ", e.args return -vimconn.HTTP_Not_Found, str(e.args[0]) @@ -1358,6 +1421,10 @@ class vimconnector(vimconn.vimconnector): 1,image-id if there is one image with that path <0,message if there was an error (Image not found, error contacting VIM, more than 1 image with that path, etc.) ''' + try: + self._get_my_tenant() + except Exception as e: + return -vimconn.HTTP_Not_Found, str(e) url=self.url + '/' + self.tenant + '/images?path='+path try: vim_response = requests.get(url)