def post(self): data = flask.request.get_json() LOG.info("network_request:" + json.dumps(data, indent=4)) config = flask.current_app.osloconfig neutron = OpenStackClients(config).neutron() name = data['networkResourceName'] network = { 'name': name, 'admin_state_up': True, } # id = data['reservationId'] if data['networkResourceType'] == 'network': if 'metadata' in data: metadata = convert_metadata_array_to_dict(data['metadata']) if "interpop_vlan" in metadata and metadata[ 'interpop_vlan'] != "": physical_network = conf.cfg.CONF.nfvi_pop.inter_pop_physical_network network.update({"provider:network_type": "vlan"}) network.update( {"provider:physical_network": physical_network}) network.update({ "provider:segmentation_id": metadata['interpop_vlan'] }) is_network_exists = check_if_network_exists(neutron, name) if is_network_exists is None: network = neutron.create_network({'network': network}) else: network['network'] = is_network_exists data = NetworkResource(network['network'], 'network', neutron).export() elif data['networkResourceType'] == 'subnet': subnet_data = data.get('typeSubnetData', None) if 'metadata' in subnet_data: metadata = convert_metadata_array_to_dict( subnet_data['metadata']) if 'dns' in metadata.keys(): meta_dns = metadata['dns'] meta_dns = meta_dns.replace("[", "") meta_dns = meta_dns.replace("]", "") meta_dns = meta_dns.replace("\"", "") meta_dns = meta_dns.split(",") elif 'subnet_type' in metadata.keys( ) and metadata['subnet_type'] == 'admin': meta_dns = conf.cfg.CONF.vtep.vtep_dns else: # we are not supposed to reach this case, but just in case meta_dns = [] else: meta_dns = [] #import ipdb; ipdb.set_trace() cidr = subnet_data['cidr'] cttcAddressPool = subnet_data.get('addressPool', None) if self.isCttcFormat(cttcAddressPool): addressPool = self.indexesToAddrPools(cidr, cttcAddressPool) cttcFormat = True else: addressPool = cttcAddressPool cttcFormat = False ip_versions = {'IPv4': 4, 'IPv6': 6} if 'gatewayIp' not in subnet_data.keys( ) or subnet_data['gatewayIp'] == "null": subnet_data['gatewayIp'] = None body_create_subnet = { 'subnet': { 'name': name, 'enable_dhcp': subnet_data['isDhcpEnabled'], 'network_id': subnet_data['networkId'], # 'segment_id': None, # 'project_id': '4fd44f30292945e481c7b8a0c8908869', # 'tenant_id': '4fd44f30292945e481c7b8a0c8908869', 'dns_nameservers': meta_dns, 'allocation_pools': addressPool, 'host_routes': [], 'ip_version': ip_versions[subnet_data['ipVersion']], 'gateway_ip': subnet_data['gatewayIp'], 'cidr': cidr, # 'id': '3b80198d-4f7b-4f77-9ef5-774d54e17126', # 'created_at': '2016-10-10T14:35:47Z', 'description': '', # 'ipv6_address_mode': None, # 'ipv6_ra_mode': None, # 'revision_number': 1, # 'service_types': [], 'subnetpool_id': None, # 'tags': ['tag1,tag2'], # 'updated_at': '2016-10-10T14:35:47Z' } } # network_name = name.replace("subnet-", "") # is_network_exists = check_if_network_exists(neutron, network_name) # if is_network_exists is None: # network = neutron.create_network({'network': network}) # else: # network['network'] = is_network_exists subnets = neutron.list_subnets(network_id=subnet_data['networkId'], name=name) if len(subnets['subnets']) != 0: data = NetworkResource(subnets['subnets'][0], 'subnet', neutron, cttcFormat).export() if cttcFormat == True: data['subnetData']['addressPool'] = cttcAddressPool else: subnet = neutron.create_subnet(body=body_create_subnet) data = NetworkResource(subnet['subnet'], 'subnet', neutron, cttcFormat).export() if cttcFormat == True: data['subnetData']['addressPool'] = cttcAddressPool if metadata and 'router_id' in metadata.keys(): router_id = metadata['router_id'] subnet_object = { 'subnet_id': data['subnetData']['resourceId'] } neutron.add_interface_router(router_id, subnet_object) if metadata and 'ip-floating-required' in metadata.keys(): floating_required = metadata['ip-floating-required'] if floating_required == "True": router_body = { 'router': { 'name': "router_" + name, 'admin_state_up': True } } router = neutron.create_router(router_body) router_id = router['router']['id'] subnet_object = { 'subnet_id': data['subnetData']['resourceId'] } neutron.add_interface_router(router_id, subnet_object) if "external_network" in metadata.keys(): external_network_name = metadata[ 'external_network'] else: external_network_name = conf.cfg.CONF.nfvi_pop.floating_network networks = neutron.list_networks( name=external_network_name)['networks'] if len(networks) > 1: message = "More then one networks with name:" + external_network_name raise Exception(message) if len(networks) == 0: message = "No networks with name:" + external_network_name print(message) raise Exception(message) router_id = router['router']['id'] network_id = networks[0]['id'] router_dict = { 'network_id': network_id, 'enable_snat': True } neutron.add_gateway_router(router_id, router_dict) elif data['networkResourceType'] == 'network-port': port_data = data.get('typeNetworkPortData', None) if 'metadata' in port_data: # floating_ip or vtep metadata = convert_metadata_array_to_dict( port_data['metadata']) if metadata['type'] == "floating_ip": body_create_floatingip = { "floatingip": { "floating_network_id": port_data['networkId'] # external network } } # request a floatingip for this project (on the network external) # this address won't be bind to any interface, it's done when the vm is created floating = neutron.create_floatingip( body=body_create_floatingip) data = NetworkResource(floating['floatingip'], 'float', neutron).export() # add the subnet of the admin network to the project's router body_add_inerface_router = { "subnet_id": metadata['subnet_id'] } # If there is no gateway interface for this subnet, it means that we need to add # this subnet to the router if not subnet_has_gateway_interface( neutron, metadata['subnet_id']): # If there is more than one router for a project, we can ad the name= of the router # in the config file router = neutron.list_routers( project_id=conf.cfg.CONF.DEFAULT.project_id) # TODO store the router_id in the config file ? router_id = router['routers'][0]['id'] neutron.add_interface_router(router_id, body_add_inerface_router) elif metadata['type'] == "vtep": port_data = data.get('typeNetworkPortData', None) nova = OpenStackClients(config).nova() vtep_name = conf.cfg.CONF.vtep.vtep_name vtep_image = conf.cfg.CONF.vtep.vtep_image vtep_flavor = conf.cfg.CONF.vtep.vtep_flavor admin_network_id = metadata['admin_network_id'] internal_ipaddr = metadata['internal_ip'] internal_network_id = metadata['internal_network_id'] # add the network interfaces _nics = [] _nics.append({'net-id': admin_network_id}) _nics.append({ 'net-id': internal_network_id, 'v4-fixed-ip': internal_ipaddr }) # the connection to the vm is done with ssh key and user ubuntu # ssh -i vim-manager-key ubuntu@floating_ip key_name = 'vim-manager-key' # param for cloudinit user_data vlan_id = port_data['segmentId'] remote_floating_ip = metadata['remote_floating_ip'] kwargs = dict( meta=None, files={}, reservation_id=None, min_count=1, max_count=1, security_groups=[], userdata=generate_cloudinit_string( vlan_id, remote_floating_ip, internal_ipaddr), key_name=key_name, availability_zone=None, block_device_mapping_v2=[], nics=_nics, scheduler_hints={}, config_drive=None, ) # create the vm server = nova.servers.create(vtep_name, vtep_image, vtep_flavor, **kwargs) # TODO not the best way, but we need to have the vm up and running to look for the port max_retry = 0 while server.status == 'BUILD': time.sleep(6) # to avoid to access openstack to often # the try is to avoid crash if the server doesn't yet exist just wait try: server = nova.servers.find(name=vtep_name) except Exception: pass max_retry = max_retry + 1 if max_retry > 10: break # get the local admin ip address to bound the floating ip address if data['networkResourceName'] in server.networks.keys(): # the local ip address is always index 0 hence the hardcoded value [0] admin_ipaddr = server.networks[ data['networkResourceName']][0] else: # TODO if we stop we probably need to delete the vtep vm because if we try another time # it won't work as the vm will already exist so we have to think of a way to clean up if # ther is a problem return flask.jsonify( 'Error wrong networkResourceName, expecting: ' + str(server.networks.keys())), OK # get the port_id of the vm_vtp admin interface ip for floating ip mapping ports = neutron.list_ports( network_id=admin_network_id)['ports'] for port in ports: for fixed_ip in port['fixed_ips']: if (fixed_ip['ip_address'] == admin_ipaddr): port_id = port['id'] break body_update_floatingip = { "floatingip": { "port_id": port_id } } # get the id of the floating ip that we want to bind to the the vtep_vm floatingip_id = neutron.list_floatingips( floating_ip_address=metadata['local_floating_ip'] )['floatingips'][0]['id'] # attach the floating ip to the interface of the vm float_update = neutron.update_floatingip( floatingip_id, body=body_update_floatingip) # disable port security for internal port (the MAC address of the the bridge interface # br_vtp is not known by openstack so if the port security is true, the traffic is blocked) # get the internal interface port id ports = neutron.list_ports( network_id=internal_network_id)['ports'] for port in ports: for fixed_ip in port['fixed_ips']: if (fixed_ip['ip_address'] == internal_ipaddr): port_id = port['id'] break body_update_security_port = { "port": { "security_groups": [], # no security group "port_security_enabled": False } } # update port with security disable port_update = neutron.update_port( port_id, body=body_update_security_port) print(port_update) # import ipdb; ipdb.set_trace() data = NetworkResource(float_update['floatingip'], 'float', neutron).export() else: # regular port creation body_create_port = { "port": { 'name': name, "admin_state_up": True, "network_id": port_data['networkId'], } } port = neutron.create_port(body=body_create_port) data = NetworkResource(port['port'], 'port', neutron).export() elif data['networkResourceType'] == 'router': body_router_create = { 'router': { 'name': name, 'admin_state_up': True } } router = neutron.create_router(body_router_create) if 'metadata' in data: metadata = convert_metadata_array_to_dict(data['metadata']) if 'external_network' in metadata.keys(): network_name = metadata['external_network'] networks = neutron.list_networks( name=network_name)['networks'] if len(networks) > 1: message = "More then one networks with name:" + network_name raise Exception(message) if len(networks) == 0: message = "No networks with name:" + network_name print(message) raise Exception(message) router_id = router['router']['id'] network_id = networks[0]['id'] router_dict = { 'network_id': network_id, 'enable_snat': True } neutron.add_gateway_router(router_id, router_dict) data = NetworkResource(router['router'], 'router', neutron).export() return flask.jsonify(data), CREATED
def delete(self): ids = flask.request.args.getlist('networkResourceId') config = flask.current_app.osloconfig neutron = OpenStackClients(config).neutron() deleted_ids = [] for id in ids: if neutron.list_networks(id=id)['networks']: try: neutron.delete_network(id) deleted_ids.append(id) except Exception: pass if neutron.list_subnets(id=id)['subnets']: # import ipdb; ipdb.set_trace() # -- Identifying an admin interface # An admin interface is a special interface, when you delete it, you need to delete the vtep vm if there is # one and release the floating ip used to access it # Check if the subnet has a gateway interface, that means it's an admin subnet if subnet_has_gateway_interface(neutron, id): address = None # check if there is a vtep vm to delete nova = OpenStackClients(config).nova() vtep_name = conf.cfg.CONF.vtep.vtep_name server_list = nova.servers.findall() try: for server in server_list: if server.name == vtep_name: for key, value in server.addresses.items(): for item in value: if item['OS-EXT-IPS:type'] == 'floating': address = item['addr'] # print ('---> found address: ', address) break # delete server server = nova.servers.delete(server.id) # just to avoid exception check if we have found a floating address if address != None: floatingip_id = neutron.list_floatingips( floating_ip_address=address )['floatingips'][0]['id'] float_delete = neutron.delete_floatingip( floatingip_id) print(float_delete) break except Exception as error_msg: print('-----> exception: ' + str(error_msg)) pass # TODO either I look for the router in the list or to improve speed, I put it in conf file # sometime there is more than one router in the tenant so maybe it would be better to have # the router_id in conf delete_router_interface_and_router(neutron, id) # delete subnet neutron.delete_subnet(id) deleted_ids.append(id) if neutron.list_ports(id=id)['ports']: try: neutron.delete_port(id) deleted_ids.append(id) except Exception: pass if neutron.list_floatingips(id=id)['floatingips']: try: neutron.delete_floatingip(id) deleted_ids.append(id) except Exception: pass # routers = neutron.list_routers(id=id) if neutron.list_routers(id=id)['routers']: try: neutron.delete_router(id) deleted_ids.append(id) except Exception as error_msg: print('-----> exception: ' + str(error_msg)) pass return flask.jsonify(deleted_ids), OK
def post(self): data = flask.request.get_json() config = flask.current_app.osloconfig neutron = OpenStackClients(config).neutron() name = data['networkResourceName'] # id = data['reservationId'] if data['networkResourceType'] == 'network': # network_data = data.get('typeNetworkData', None) network = {'name': name, 'admin_state_up': True} network = neutron.create_network({'network': network}) data = NetworkResource(network['network'], 'network', neutron).export() elif data['networkResourceType'] == 'subnet': subnet_data = data.get('typeSubnetData', None) if 'metadata' in subnet_data: if 'dns' in subnet_data['metadata']: meta_dns = subnet_data['metadata']['dns'] elif 'subnet_type' in subnet_data['metadata'] and subnet_data[ 'metadata']['subnet_type'] == 'admin': meta_dns = conf.cfg.CONF.vtep.vtep_dns else: # we are not supposed to reach this case, but just in case meta_dns = [] else: meta_dns = [] ip_versions = {'IPv4': 4, 'IPv6': 6} body_create_subnet = { 'subnet': { 'name': name, 'enable_dhcp': subnet_data['isDhcpEnabled'], 'network_id': subnet_data['networkId'], # 'segment_id': None, # 'project_id': '4fd44f30292945e481c7b8a0c8908869', # 'tenant_id': '4fd44f30292945e481c7b8a0c8908869', 'dns_nameservers': meta_dns, # 'allocation_pools': [ # { # 'start': '192.168.199.2', # 'end': '192.168.199.254' # } # ], 'host_routes': [], 'ip_version': ip_versions[subnet_data['ipVersion']], 'gateway_ip': subnet_data['gatewayIp'], 'cidr': subnet_data['cidr'], # 'id': '3b80198d-4f7b-4f77-9ef5-774d54e17126', # 'created_at': '2016-10-10T14:35:47Z', 'description': '', # 'ipv6_address_mode': None, # 'ipv6_ra_mode': None, # 'revision_number': 1, # 'service_types': [], 'subnetpool_id': None, # 'tags': ['tag1,tag2'], # 'updated_at': '2016-10-10T14:35:47Z' } } subnet = neutron.create_subnet(body=body_create_subnet) data = NetworkResource(subnet['subnet'], 'subnet', neutron).export() elif data['networkResourceType'] == 'network-port': port_data = data.get('typeNetworkPortData', None) if 'metadata' in port_data: # floating_ip or vtep if port_data['metadata']['type'] == "floating_ip": body_create_floatingip = { "floatingip": { "floating_network_id": port_data['networkId'] # external network } } # request a floatingip for this project (on the network external) # this address won't be bind to any interface, it's done when the vm is created floating = neutron.create_floatingip( body=body_create_floatingip) data = NetworkResource(floating['floatingip'], 'float', neutron).export() # add the subnet of the admin network to the project's router body_add_inerface_router = { "subnet_id": port_data['metadata']['subnet_id'] } # If there is no gateway interface for this subnet, it means that we need to add # this subnet to the router if not subnet_has_gateway_interface( neutron, port_data['metadata']['subnet_id']): # If there is more than one router for a project, we can ad the name= of the router # in the config file router = neutron.list_routers( project_id=conf.cfg.CONF.DEFAULT.project_id) # TODO store the router_id in the config file ? router_id = router['routers'][0]['id'] neutron.add_interface_router(router_id, body_add_inerface_router) elif port_data['metadata']['type'] == "vtep": port_data = data.get('typeNetworkPortData', None) nova = OpenStackClients(config).nova() vtep_name = conf.cfg.CONF.vtep.vtep_name vtep_image = conf.cfg.CONF.vtep.vtep_image vtep_flavor = conf.cfg.CONF.vtep.vtep_flavor admin_network_id = port_data['metadata'][ 'admin_interface']['network_id'] internal_ipaddr = port_data['metadata'][ 'internal_interface']['fixed_ip'] internal_network_id = port_data['metadata'][ 'internal_interface']['network_id'] # add the network interfaces _nics = [] _nics.append({'net-id': admin_network_id}) _nics.append({ 'net-id': internal_network_id, 'v4-fixed-ip': internal_ipaddr }) # the connection to the vm is done with ssh key and user ubuntu # ssh -i vim-manager-key ubuntu@floating_ip key_name = 'vim-manager-key' # param for cloudinit user_data vlan_id = port_data['segmentId'] remote_floating_ip = port_data['metadata'][ 'remote_floating_ip'] kwargs = dict( meta=None, files={}, reservation_id=None, min_count=1, max_count=1, security_groups=[], userdata=generate_cloudinit_string( vlan_id, remote_floating_ip, internal_ipaddr), key_name=key_name, availability_zone=None, block_device_mapping_v2=[], nics=_nics, scheduler_hints={}, config_drive=None, ) # create the vm server = nova.servers.create(vtep_name, vtep_image, vtep_flavor, **kwargs) # TODO not the best way, but we need to have the vm up and running to look for the port max_retry = 0 while server.status == 'BUILD': time.sleep(6) # to avoid to access openstack to often # the try is to avoid crash if the server doesn't yet exist just wait try: server = nova.servers.find(name=vtep_name) except Exception: pass max_retry = max_retry + 1 if max_retry > 10: break # get the local admin ip address to bound the floating ip address if data['networkResourceName'] in server.networks.keys(): # the local ip address is always index 0 hence the hardcoded value [0] admin_ipaddr = server.networks[ data['networkResourceName']][0] else: # TODO if we stop we probably need to delete the vtep vm because if we try another time # it won't work as the vm will already exist so we have to think of a way to clean up if # ther is a problem return flask.jsonify( 'Error wrong networkResourceName, expecting: ' + str(server.networks.keys())), OK # get the port_id of the vm_vtp admin interface ip for floating ip mapping ports = neutron.list_ports( network_id=admin_network_id)['ports'] for port in ports: for fixed_ip in port['fixed_ips']: if (fixed_ip['ip_address'] == admin_ipaddr): port_id = port['id'] break body_update_floatingip = { "floatingip": { "port_id": port_id } } # get the id of the floating ip that we want to bind to the the vtep_vm floatingip_id = neutron.list_floatingips( floating_ip_address=port_data['metadata'] ['local_floating_ip'])['floatingips'][0]['id'] # attach the floating ip to the interface of the vm float_update = neutron.update_floatingip( floatingip_id, body=body_update_floatingip) # disable port security for internal port (the MAC address of the the bridge interface # br_vtp is not known by openstack so if the port security is true, the traffic is blocked) # get the internal interface port id ports = neutron.list_ports( network_id=internal_network_id)['ports'] for port in ports: for fixed_ip in port['fixed_ips']: if (fixed_ip['ip_address'] == internal_ipaddr): port_id = port['id'] break body_update_security_port = { "port": { "security_groups": [], # no security group "port_security_enabled": False } } # update port with security disable port_update = neutron.update_port( port_id, body=body_update_security_port) print(port_update) # import ipdb; ipdb.set_trace() data = NetworkResource(float_update['floatingip'], 'float', neutron).export() else: # regular port creation body_create_port = { "port": { 'name': name, "admin_state_up": True, "network_id": port_data['networkId'], } } port = neutron.create_port(body=body_create_port) data = NetworkResource(port['port'], 'port', neutron).export() return flask.jsonify(data), CREATED