From: kbsub Date: Thu, 17 Oct 2019 16:30:32 +0000 (+0000) Subject: VCD feature 7193-provider_nerwork X-Git-Tag: v7.0.0rc1~14 X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FRO.git;a=commitdiff_plain;h=a85c54de5c5d1f951b27082a21e5654e15712529 VCD feature 7193-provider_nerwork Change-Id: I72c64fe451831e20eb60e2629f998aba0130bfdf Signed-off-by: kbsub --- diff --git a/osm_ro/nfvo.py b/osm_ro/nfvo.py index 9cf115e0..86372455 100644 --- a/osm_ro/nfvo.py +++ b/osm_ro/nfvo.py @@ -2675,11 +2675,12 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc myNetDict["type"] = myNetType myNetDict["tenant_id"] = myvim_tenant myNetIPProfile = sce_net.get('ip_profile', None) + myProviderNetwork = sce_net.get('provider_network', None) #TODO: #We should use the dictionary as input parameter for new_network #print myNetDict if not sce_net["external"]: - network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile) + network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile, provider_network_profile=myProviderNetwork) #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id) sce_net['vim_id'] = network_id auxNetDict['scenario'][sce_net['uuid']] = network_id @@ -2709,10 +2710,11 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc myNetDict["type"] = myNetType myNetDict["tenant_id"] = myvim_tenant myNetIPProfile = net.get('ip_profile', None) + myProviderNetwork = sce_net.get('provider_network', None) #print myNetDict #TODO: #We should use the dictionary as input parameter for new_network - network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile) + network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile, provider_network_profile=myProviderNetwork) #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id) net['vim_id'] = network_id if sce_vnf['uuid'] not in auxNetDict: @@ -3037,6 +3039,7 @@ def update(d, u): def create_instance(mydb, tenant_id, instance_dict): # print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id" # logger.debug("Creating instance...") + scenario = instance_dict["scenario"] # find main datacenter @@ -3186,6 +3189,13 @@ def create_instance(mydb, tenant_id, instance_dict): else: update(scenario_net['ip_profile'], ipprofile_db) + if 'provider-network' in net_instance_desc: + provider_network_db = net_instance_desc['provider-network'] + if 'provider-network' not in scenario_net: + scenario_net['provider-network'] = provider_network_db + else: + update(scenario_net['provider-network'], provider_network_db) + for vdu_id, vdu_instance_desc in vnf_instance_desc.get("vdus", {}).iteritems(): for scenario_vm in scenario_vnf['vms']: if vdu_id == scenario_vm['osm_id'] or vdu_id == scenario_vm["name"]: @@ -3208,6 +3218,7 @@ def create_instance(mydb, tenant_id, instance_dict): # Ideally, the operation should be as simple as: update(scenarioDict,instance_dict) # However, this is not possible yet. for net_name, net_instance_desc in instance_dict.get("networks", {}).iteritems(): + for scenario_net in scenarioDict['nets']: if net_name == scenario_net.get("name") or net_name == scenario_net.get("osm_id") or net_name == scenario_net.get("uuid"): if "wim_account" in net_instance_desc and net_instance_desc["wim_account"] is not None: @@ -3218,6 +3229,14 @@ def create_instance(mydb, tenant_id, instance_dict): scenario_net['ip_profile'] = ipprofile_db else: update(scenario_net['ip_profile'], ipprofile_db) + if 'provider-network' in net_instance_desc: + provider_network_db = net_instance_desc['provider-network'] + + if 'provider-network' not in scenario_net: + scenario_net['provider_network'] = provider_network_db + else: + update(scenario_net['provider-network'], provider_network_db) + for interface in net_instance_desc.get('interfaces', ()): if 'ip_address' in interface: for vnf in scenarioDict['vnfs']: @@ -3230,10 +3249,12 @@ def create_instance(mydb, tenant_id, instance_dict): # logger.debug("Creating instance scenario-dict MERGED:\n%s", # yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)) + # 1. Creating new nets (sce_nets) in the VIM" number_mgmt_networks = 0 db_instance_nets = [] for sce_net in scenarioDict['nets']: + sce_net_uuid = sce_net.get('uuid', sce_net["name"]) # get involved datacenters where this network need to be created involved_datacenters = [] @@ -3384,7 +3405,8 @@ def create_instance(mydb, tenant_id, instance_dict): task_extra = {} if create_network: task_action = "CREATE" - task_extra["params"] = (net_vim_name, net_type, sce_net.get('ip_profile', None), wim_account_name) + task_extra["params"] = (net_vim_name, net_type, sce_net.get('ip_profile', None), None, sce_net.get('provider_network', None), wim_account_name) + if lookfor_network: task_extra["find"] = (lookfor_filter,) elif lookfor_network: @@ -4804,10 +4826,9 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): action_dict['add_public_key'], password=password, ro_key=priv_RO_key) vm_result[ vm['uuid'] ] = {"vim_result": 200, - "description": "Public key injected", - "name":vm['name'] + "description": "Public key injected", + "name":vm['name'] } - except KeyError: raise NfvoException("Unable to inject ssh key in vm: {} - Aborting".format(vm['uuid']), httperrors.Internal_Server_Error) @@ -5573,7 +5594,10 @@ def vim_action_create(mydb, tenant_id, datacenter, item, descriptor): net_public = net.pop("shared", False) net_ipprofile = net.pop("ip_profile", None) net_vlan = net.pop("vlan", None) - content, _ = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, vlan=net_vlan) #, **net) + net_provider_network_profile = None + if net_vlan: + net_provider_network_profile = {"segmentation-id": net_vlan} + content, _ = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, provider_network_profile=net_provider_network_profile) #, **net) #If the datacenter has a SDN controller defined and the network is of dataplane type, then create the sdn network if get_sdn_controller_id(mydb, datacenter) != None and (net_type == 'data' or net_type == 'ptp'): diff --git a/osm_ro/vim_thread.py b/osm_ro/vim_thread.py index 38a73d12..733dfc24 100644 --- a/osm_ro/vim_thread.py +++ b/osm_ro/vim_thread.py @@ -958,13 +958,14 @@ class vim_thread(threading.Thread): # CREATE params = task["params"] action_text = "creating VIM" - vim_net_id, created_items = self.vim.new_network(*params[0:3]) + + vim_net_id, created_items = self.vim.new_network(*params[0:5]) net_name = params[0] net_type = params[1] wim_account_name = None - if len(params) >= 4: - wim_account_name = params[3] + if len(params) >= 5: + wim_account_name = params[5] sdn_controller = self.vim.config.get('sdn-controller') if sdn_controller and (net_type == "data" or net_type == "ptp"): diff --git a/osm_ro/vimconn.py b/osm_ro/vimconn.py index 957c4107..14068e90 100644 --- a/osm_ro/vimconn.py +++ b/osm_ro/vimconn.py @@ -326,7 +326,7 @@ class vimconnector(): """ raise vimconnNotImplemented("Should have implemented this") - def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None): + def new_network(self, net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): """Adds a tenant network to VIM Params: 'net_name': name of the network @@ -343,7 +343,7 @@ class vimconnector(): 'dhcp_start_address': ip_schema, first IP to grant 'dhcp_count': number of IPs to grant. 'shared': if this network can be seen/use by other tenants/organization - 'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network + 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk} Returns a tuple with the network identifier and created_items, or raises an exception on error created_items can be None or a dictionary where this method can include key-values that will be passed to the method delete_network. Can be used to store created segments, created l2gw connections, etc. diff --git a/osm_ro/vimconn_aws.py b/osm_ro/vimconn_aws.py index bcd8cbc8..40530f6b 100644 --- a/osm_ro/vimconn_aws.py +++ b/osm_ro/vimconn_aws.py @@ -280,7 +280,7 @@ class vimconnector(vimconn.vimconnector): return map(str, subnets) - def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None): + def new_network(self, net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): """Adds a tenant network to VIM Params: 'net_name': name of the network @@ -298,7 +298,6 @@ class vimconnector(vimconn.vimconnector): 'start-address': ip_schema, first IP to grant 'count': number of IPs to grant. 'shared': if this network can be seen/use by other tenants/organization - 'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network Returns a tuple with the network identifier and created_items, or raises an exception on error created_items can be None or a dictionary where this method can include key-values that will be passed to the method delete_network. Can be used to store created segments, created l2gw connections, etc. diff --git a/osm_ro/vimconn_azure.py b/osm_ro/vimconn_azure.py index ad96da1a..7f2b2ea3 100755 --- a/osm_ro/vimconn_azure.py +++ b/osm_ro/vimconn_azure.py @@ -261,7 +261,7 @@ class vimconnector(vimconn.vimconnector): except Exception as e: self._format_vimconn_exception(e) - def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None): + def new_network(self, net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): """ Adds a tenant network to VIM :param net_name: name of the network @@ -276,7 +276,7 @@ class vimconnector(vimconn.vimconnector): 'start-address': ip_schema, first IP to grant 'count': number of IPs to grant. :param shared: Not allowed for Azure Connector - :param vlan: VLAN tagging is not allowed for Azure + :param provider_network_profile: (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk} :return: a tuple with the network identifier and created_items, or raises an exception on error created_items can be None or a dictionary where this method can include key-values that will be passed to the method delete_network. Can be used to store created segments, created l2gw connections, etc. diff --git a/osm_ro/vimconn_fos.py b/osm_ro/vimconn_fos.py index ca550f27..d101d461 100644 --- a/osm_ro/vimconn_fos.py +++ b/osm_ro/vimconn_fos.py @@ -110,7 +110,7 @@ class vimconnector(vimconn.vimconnector): except Exception as e: raise vimconn.vimconnConnectionException("VIM not reachable. Error {}".format(e)) - def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None): + def new_network(self, net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): """Adds a tenant network to VIM Params: 'net_name': name of the network @@ -127,7 +127,6 @@ class vimconnector(vimconn.vimconnector): 'dhcp_start_address': ip_schema, first IP to grant 'dhcp_count': number of IPs to grant. 'shared': if this network can be seen/use by other tenants/organization - 'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network Returns the network identifier on success or raises and exception on failure """ self.logger.debug('new_network: {}'.format(locals())) diff --git a/osm_ro/vimconn_opennebula.py b/osm_ro/vimconn_opennebula.py index cf1a8fbc..56aabe70 100644 --- a/osm_ro/vimconn_opennebula.py +++ b/osm_ro/vimconn_opennebula.py @@ -154,7 +154,7 @@ class vimconnector(vimconn.vimconnector): '.format(self.user, self.passwd, (str(id_user)), (str(id_group))) requests.post(self.url, params) - def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None): # , **vim_specific): + def new_network(self, net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): # , **vim_specific): """Adds a tenant network to VIM Params: 'net_name': name of the network @@ -171,7 +171,7 @@ class vimconnector(vimconn.vimconnector): 'dhcp_start_address': ip_schema, first IP to grant 'dhcp_count': number of IPs to grant. 'shared': if this network can be seen/use by other tenants/organization - 'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network + 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk} Returns a tuple with the network identifier and created_items, or raises an exception on error created_items can be None or a dictionary where this method can include key-values that will be passed to the method delete_network. Can be used to store created segments, created l2gw connections, etc. @@ -181,6 +181,9 @@ class vimconnector(vimconn.vimconnector): # oca library method cannot be used in this case (problem with cluster parameters) try: + vlan = None + if provider_network_profile: + vlan = provider_network_profile.get("segmentation-id") created_items = {} one = self._new_one_connection() size = "254" diff --git a/osm_ro/vimconn_openstack.py b/osm_ro/vimconn_openstack.py index 4a897a36..8d87b7f7 100644 --- a/osm_ro/vimconn_openstack.py +++ b/osm_ro/vimconn_openstack.py @@ -503,7 +503,7 @@ class vimconnector(vimconn.vimconnector): except (ksExceptions.ConnectionError, ksExceptions.ClientException, ksExceptions.NotFound, ConnectionError) as e: self._format_exception(e) - def new_network(self,net_name, net_type, ip_profile=None, shared=False, vlan=None): + def new_network(self,net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): """Adds a tenant network to VIM Params: 'net_name': name of the network @@ -520,7 +520,7 @@ class vimconnector(vimconn.vimconnector): 'dhcp_start_address': ip_schema, first IP to grant 'dhcp_count': number of IPs to grant. 'shared': if this network can be seen/use by other tenants/organization - 'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network + 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk} Returns a tuple with the network identifier and created_items, or raises an exception on error created_items can be None or a dictionary where this method can include key-values that will be passed to the method delete_network. Can be used to store created segments, created l2gw connections, etc. @@ -529,7 +529,11 @@ class vimconnector(vimconn.vimconnector): """ self.logger.debug("Adding a new network to VIM name '%s', type '%s'", net_name, net_type) # self.logger.debug(">>>>>>>>>>>>>>>>>> IP profile %s", str(ip_profile)) + try: + vlan = None + if provider_network_profile: + vlan = provider_network_profile.get("segmentation-id") new_net = None created_items = {} self._reload_connection() diff --git a/osm_ro/vimconn_openvim.py b/osm_ro/vimconn_openvim.py index 6f584c5e..7d1deb44 100644 --- a/osm_ro/vimconn_openvim.py +++ b/osm_ro/vimconn_openvim.py @@ -484,7 +484,7 @@ class vimconnector(vimconn.vimconnector): except requests.exceptions.RequestException as e: self._format_request_exception(e) - def new_network(self,net_name, net_type, ip_profile=None, shared=False, vlan=None): #, **vim_specific): + def new_network(self,net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): #, **vim_specific): """Adds a tenant network to VIM Params: 'net_name': name of the network @@ -501,7 +501,7 @@ class vimconnector(vimconn.vimconnector): 'dhcp_start_address': ip_schema, first IP to grant 'dhcp_count': number of IPs to grant. 'shared': if this network can be seen/use by other tenants/organization - 'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network + 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk} Returns a tuple with the network identifier and created_items, or raises an exception on error created_items can be None or a dictionary where this method can include key-values that will be passed to the method delete_network. Can be used to store created segments, created l2gw connections, etc. @@ -509,6 +509,9 @@ class vimconnector(vimconn.vimconnector): as not present. """ try: + vlan = None + if provider_network_profile: + vlan = provider_network_profile.get("segmentation-id") created_items = {} self._get_my_tenant() if net_type=="bridge": diff --git a/osm_ro/vimconn_vmware.py b/osm_ro/vimconn_vmware.py index f343eeac..7f915b52 100644 --- a/osm_ro/vimconn_vmware.py +++ b/osm_ro/vimconn_vmware.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ## -# Copyright 2016-2017 VMware Inc. +# Copyright 2016-2019 VMware Inc. # This file is part of ETSI OSM # All Rights Reserved. # @@ -503,7 +503,7 @@ class vimconnector(vimconn.vimconnector): return vdclist - def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None): + def new_network(self, net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): """Adds a tenant network to VIM Params: 'net_name': name of the network @@ -520,7 +520,7 @@ class vimconnector(vimconn.vimconnector): 'dhcp_start_address': ip_schema, first IP to grant 'dhcp_count': number of IPs to grant. 'shared': if this network can be seen/use by other tenants/organization - 'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network + 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk} Returns a tuple with the network identifier and created_items, or raises an exception on error created_items can be None or a dictionary where this method can include key-values that will be passed to the method delete_network. Can be used to store created segments, created l2gw connections, etc. @@ -528,8 +528,11 @@ class vimconnector(vimconn.vimconnector): as not present. """ - self.logger.debug("new_network tenant {} net_type {} ip_profile {} shared {}" - .format(net_name, net_type, ip_profile, shared)) + self.logger.debug("new_network tenant {} net_type {} ip_profile {} shared {} provider_network_profile {}" + .format(net_name, net_type, ip_profile, shared, provider_network_profile)) + vlan = None + if provider_network_profile: + vlan = provider_network_profile.get("segmentation-id") created_items = {} isshared = 'false' @@ -541,9 +544,19 @@ class vimconnector(vimconn.vimconnector): # if self.config.get('dv_switch_name') == None: # raise vimconn.vimconnConflictException("You must provide 'dv_switch_name' at config value") # network_uuid = self.create_dvPort_group(net_name) + parent_network_uuid = None + + import traceback + traceback.print_stack() + + if provider_network_profile is not None: + for k, v in provider_network_profile.items(): + if k == 'physical_network': + parent_network_uuid = self.get_physical_network_by_name(v) network_uuid = self.create_network(network_name=net_name, net_type=net_type, - ip_profile=ip_profile, isshared=isshared) + ip_profile=ip_profile, isshared=isshared, + parent_network_uuid=parent_network_uuid) if network_uuid is not None: return network_uuid, created_items else: @@ -3285,7 +3298,6 @@ class vimconnector(vimconn.vimconnector): The return network uuid. network_uuid: network_id """ - if not network_name: self.logger.debug("get_network_id_by_name() : Network name is empty") return None @@ -3295,8 +3307,6 @@ class vimconnector(vimconn.vimconnector): if org_dict and 'networks' in org_dict: org_network_dict = org_dict['networks'] for net_uuid,net_name in org_network_dict.iteritems(): - #For python3 - #for net_uuid,net_name in org_network_dict.items(): if net_name == network_name: return net_uuid @@ -3305,6 +3315,81 @@ class vimconnector(vimconn.vimconnector): return None + def get_physical_network_by_name(self, physical_network_name): + ''' + Methos returns uuid of physical network which passed + Args: + physical_network_name: physical network name + Returns: + UUID of physical_network_name + ''' + try: + client_as_admin = self.connect_as_admin() + if not client_as_admin: + raise vimconn.vimconnConnectionException("Failed to connect vCD.") + url_list = [self.url, '/api/admin/vdc/', self.tenant_id] + vm_list_rest_call = ''.join(url_list) + + if client_as_admin._session: + headers = {'Accept':'application/*+xml;version=' + API_VERSION, + 'x-vcloud-authorization': client_as_admin._session.headers['x-vcloud-authorization']} + + response = self.perform_request(req_type='GET', + url=vm_list_rest_call, + headers=headers) + + provider_network = None + available_network = None + add_vdc_rest_url = None + + if response.status_code != requests.codes.ok: + self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call, + response.status_code)) + return None + else: + try: + vm_list_xmlroot = XmlElementTree.fromstring(response.content) + for child in vm_list_xmlroot: + + if child.tag.split("}")[1] == 'ProviderVdcReference': + provider_network = child.attrib.get('href') + # application/vnd.vmware.admin.providervdc+xml + if child.tag.split("}")[1] == 'Link': + if child.attrib.get('type') == 'application/vnd.vmware.vcloud.orgVdcNetwork+xml' \ + and child.attrib.get('rel') == 'add': + add_vdc_rest_url = child.attrib.get('href') + except: + self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call)) + self.logger.debug("Respond body {}".format(response.content)) + return None + + # find pvdc provided available network + response = self.perform_request(req_type='GET', + url=provider_network, + headers=headers) + + if response.status_code != requests.codes.ok: + self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call, + response.status_code)) + return None + + try: + vm_list_xmlroot = XmlElementTree.fromstring(response.content) + for child in vm_list_xmlroot.iter(): + if child.tag.split("}")[1] == 'AvailableNetworks': + for networks in child.iter(): + if networks.attrib.get('href') is not None and networks.attrib.get('name') is not None: + if networks.attrib.get('name') == physical_network_name: + network_url = networks.attrib.get('href') + available_network = network_url[network_url.rindex('/')+1:] + break + except Exception as e: + return None + + return available_network + except Exception as e: + self.logger.error("Error while getting physical network: {}".format(e)) + def list_org_action(self): """ Method leverages vCloud director and query for available organization for particular user @@ -3789,6 +3874,7 @@ class vimconnector(vimconn.vimconnector): try: vm_list_xmlroot = XmlElementTree.fromstring(response.content) for child in vm_list_xmlroot: + if child.tag.split("}")[1] == 'ProviderVdcReference': provider_network = child.attrib.get('href') # application/vnd.vmware.admin.providervdc+xml @@ -3805,6 +3891,7 @@ class vimconnector(vimconn.vimconnector): response = self.perform_request(req_type='GET', url=provider_network, headers=headers) + if response.status_code != requests.codes.ok: self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call, response.status_code)) @@ -3890,31 +3977,61 @@ class vimconnector(vimconn.vimconnector): dns2_text = "" if len(dns_list) >= 2: dns2_text = "\n {}\n".format(dns_list[1]) - data = """ - Openmano created - - - - {1:s} - {2:s} - {3:s} - {4:s}{5:s} - {6:s} - - - {7:s} - {8:s} - - - - - {9:s} - - {10:s} - """.format(escape(network_name), is_inherited, gateway_address, - subnet_address, dns1, dns2_text, dhcp_enabled, - dhcp_start_address, dhcp_end_address, - fence_mode, isshared) + if net_type == "isolated": + fence_mode="isolated" + data = """ + Openmano created + + + + {1:s} + {2:s} + {3:s} + {4:s}{5:s} + {6:s} + + + {7:s} + {8:s} + + + + + {9:s} + + {10:s} + """.format(escape(network_name), is_inherited, gateway_address, + subnet_address, dns1, dns2_text, dhcp_enabled, + dhcp_start_address, dhcp_end_address, + fence_mode, isshared) + else: + fence_mode = "bridged" + data = """ + Openmano created + + + + {1:s} + {2:s} + {3:s} + {4:s}{5:s} + {6:s} + + + {7:s} + {8:s} + + + + + + {10:s} + + {11:s} + """.format(escape(network_name), is_inherited, gateway_address, + subnet_address, dns1, dns2_text, dhcp_enabled, + dhcp_start_address, dhcp_end_address, available_networks, + fence_mode, isshared) headers['Content-Type'] = 'application/vnd.vmware.vcloud.orgVdcNetwork+xml' try: