blob: 384d7533fac8068ba4b8e36774df0d95f9767040 [file] [log] [blame]
# -*- coding: utf-8 -*-
__author__='Sergio Gonzalez'
__date__ ='$18-apr-2019 23:59:59$'
import base64
import vimconn
import logging
import netaddr
from os import getenv
from uuid import uuid4
from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.resource import ResourceManagementClient
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.compute import ComputeManagementClient
from msrestazure.azure_exceptions import CloudError
if getenv('OSMRO_PDB_DEBUG'):
import sys
print(sys.path)
import pdb
pdb.set_trace()
class vimconnector(vimconn.vimconnector):
provision_state2osm = {
"Deleting": "INACTIVE",
"Failed": "ERROR",
"Succeeded": "ACTIVE",
"Updating": "BUILD",
}
def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None,
config={}, persistent_info={}):
vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level,
config, persistent_info)
self.vnet_address_space = None
# LOGGER
self.logger = logging.getLogger('openmano.vim.azure')
if log_level:
logging.basicConfig()
self.logger.setLevel(getattr(logging, log_level))
# CREDENTIALS
self.credentials = ServicePrincipalCredentials(
client_id=user,
secret=passwd,
tenant=(tenant_id or tenant_name)
)
self.tenant=(tenant_id or tenant_name)
# SUBSCRIPTION
if 'subscription_id' in config:
self.subscription_id = config.get('subscription_id')
self.logger.debug('Setting subscription '+str(self.subscription_id))
else:
raise vimconn.vimconnException('Subscription not specified')
# REGION
if 'region_name' in config:
self.region = config.get('region_name')
else:
raise vimconn.vimconnException('Azure region_name is not specified at config')
# RESOURCE_GROUP
if 'resource_group' in config:
self.resource_group = config.get('resource_group')
else:
raise vimconn.vimconnException('Azure resource_group is not specified at config')
# VNET_NAME
if 'vnet_name' in config:
self.vnet_name = config["vnet_name"]
# public ssh key
self.pub_key = config.get('pub_key')
def _reload_connection(self):
"""
Sets connections to work with Azure service APIs
:return:
"""
self.logger.debug('Reloading API Connection')
try:
self.conn = ResourceManagementClient(self.credentials, self.subscription_id)
self.conn_compute = ComputeManagementClient(self.credentials, self.subscription_id)
self.conn_vnet = NetworkManagementClient(self.credentials, self.subscription_id)
self._check_or_create_resource_group()
self._check_or_create_vnet()
except Exception as e:
self.format_vimconn_exception(e)
def _get_resource_name_from_resource_id(self, resource_id):
try:
resource=str(resource_id.split('/')[-1])
return resource
except Exception as e:
raise vimconn.vimconnNotFoundException("Resource name '{}' not found".format(resource_id))
def _get_location_from_resource_group(self, resource_group_name):
try:
location=self.conn.resource_groups.get(resource_group_name).location
return location
except Exception as e:
raise vimconn.vimconnNotFoundException("Location '{}' not found".format(resource_group_name))
def _get_resource_group_name_from_resource_id(self, resource_id):
try:
rg=str(resource_id.split('/')[4])
return rg
except Exception as e:
raise vimconn.vimconnNotFoundException("Resource group '{}' not found".format(resource_id))
def _get_net_name_from_resource_id(self, resource_id):
try:
net_name=str(resource_id.split('/')[8])
return net_name
except Exception as e:
raise vimconn.vimconnNotFoundException("Net name '{}' not found".format(resource_id))
def _check_subnets_for_vm(self, net_list):
# All subnets must belong to the same resource group and vnet
# ERROR
# File "/root/RO/build/osm_ro/vimconn_azure.py", line 110, in <genexpr>
# self._get_resource_name_from_resource_id(net['id']) for net in net_list)) != 1:
#if len(set(self._get_resource_group_name_from_resource_id(net['net_id']) +
# self._get_resource_name_from_resource_id(net['net_id']) for net in net_list)) != 2:
# raise self.format_vimconn_exception('Azure VMs can only attach to subnets in same VNET')
self.logger.debug('Checking subnets for VM')
num_elem_set = len(set(self._get_resource_group_name_from_resource_id(net['net_id']) +
self._get_resource_name_from_resource_id(net['net_id']) for net in net_list))
if ( num_elem_set != 1 ):
raise self.format_vimconn_exception('Azure VMs can only attach to subnets in same VNET')
def format_vimconn_exception(self, e):
"""
Params: an Exception object
:param e:
:return: Raises the proper vimconnException
"""
self.conn = None
self.conn_vnet = None
raise vimconn.vimconnException(type(e).__name__ + ': ' + str(e))
def _check_or_create_resource_group(self):
"""
Creates a resource group in indicated region
:return: None
"""
self.logger.debug('Creating RG {} in location {}'.format(self.resource_group, self.region))
self.conn.resource_groups.create_or_update(self.resource_group, {'location': self.region})
def _check_or_create_vnet(self):
try:
vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name)
self.vnet_address_space = vnet.address_space.address_prefixes[0]
self.vnet_id = vnet.id
return
except CloudError as e:
if e.error.error == "ResourceNotFound":
pass
else:
raise
# if not exist, creates it
try:
vnet_params = {
'location': self.region,
'address_space': {
'address_prefixes': ["10.0.0.0/8"]
},
}
self.vnet_address_space = "10.0.0.0/8"
self.conn_vnet.virtual_networks.create_or_update(self.resource_group, self.vnet_name, vnet_params)
vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name)
self.vnet_id = vnet.id
except Exception as e:
self.format_vimconn_exception(e)
def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None):
"""
Adds a tenant network to VIM
:param net_name: name of the network
:param net_type:
:param ip_profile: is a dict containing the IP parameters of the network (Currently only IPv4 is implemented)
'ip-version': can be one of ['IPv4','IPv6']
'subnet-address': ip_prefix_schema, that is X.X.X.X/Y
'gateway-address': (Optional) ip_schema, that is X.X.X.X
'dns-address': (Optional) ip_schema,
'dhcp': (Optional) dict containing
'enabled': {'type': 'boolean'},
'start-address': ip_schema, first IP to grant
'count': number of IPs to grant.
:param shared:
:param vlan:
: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.
Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
as not present.
"""
return self._new_subnet(net_name, ip_profile)
def _new_subnet(self, net_name, ip_profile):
"""
Adds a tenant network to VIM. It creates a new VNET with a single subnet
:param net_name:
:param ip_profile:
:return:
"""
self.logger.debug('Adding a subnet to VNET '+self.vnet_name)
self._reload_connection()
if ip_profile is None:
# get a non used vnet ip range /24 and allocate automatically inside the range self.vnet_address_space
used_subnets = self.get_network_list()
for ip_range in netaddr.IPNetwork(self.vnet_address_space).subnet(24):
for used_subnet in used_subnets:
subnet_range = netaddr.IPNetwork(used_subnet["cidr_block"])
if subnet_range in ip_range or ip_range in subnet_range:
# this range overlaps with an existing subnet ip range. Breaks and look for another
break
else:
ip_profile = {"subnet_address": str(ip_range)}
self.logger.debug('ip_profile: ' + str(ip_range))
break
else:
vimconn.vimconnException("Cannot find a non-used subnet range in {}".format(self.vnet_address_space))
else:
ip_profile = {"subnet_address": ip_profile['subnet_address']}
try:
#subnet_name = "{}-{}".format(net_name[:24], uuid4())
subnet_name = net_name[:24]
subnet_params= {
'address_prefix': ip_profile['subnet_address']
}
self.logger.debug('subnet_name : {}'.format(subnet_name))
async_creation=self.conn_vnet.subnets.create_or_update(self.resource_group, self.vnet_name, subnet_name, subnet_params)
async_creation.wait()
#return "{}/subnet/{}".format(self.vnet_id, subnet_name), None
return "{}/subnets/{}".format(self.vnet_id, subnet_name), None
except Exception as e:
self.format_vimconn_exception(e)
def _create_nic(self, net, nic_name, static_ip=None):
self._reload_connection()
subnet_id = net['net_id']
location = self._get_location_from_resource_group(self.resource_group)
try:
if static_ip:
async_nic_creation = self.conn_vnet.network_interfaces.create_or_update(
self.resource_group,
nic_name,
{
'location': location,
'ip_configurations': [{
'name': nic_name + '-ipconfiguration',
'privateIPAddress': static_ip,
'privateIPAllocationMethod': 'Static',
'subnet': {
'id': subnet_id
}
}]
}
)
async_nic_creation.wait()
else:
ip_configuration_name = nic_name + '-ipconfiguration'
self.logger.debug('Create NIC')
async_nic_creation = self.conn_vnet.network_interfaces.create_or_update(
self.resource_group,
nic_name,
{
'location': location,
'ip_configurations': [{
'name': ip_configuration_name,
'subnet': {
'id': subnet_id
}
}]
}
)
async_nic_creation.wait()
public_ip = net.get('floating_ip')
if public_ip and public_ip == True:
self.logger.debug('Creating PUBLIC IP')
public_ip_addess_params = {
'location': location,
'public_ip_allocation_method': 'Dynamic'
}
public_ip_name = nic_name + '-public-ip'
public_ip = self.conn_vnet.public_ip_addresses.create_or_update(
self.resource_group,
public_ip_name,
public_ip_addess_params
)
self.logger.debug('Create PUBLIC IP: {}'.format(public_ip.result()))
# Asociate NIC to Public IP
self.logger.debug('Getting NIC DATA')
nic_data = self.conn_vnet.network_interfaces.get(
self.resource_group,
nic_name)
nic_data.ip_configurations[0].public_ip_address = public_ip.result()
self.logger.debug('Updating NIC with public IP')
self.conn_vnet.network_interfaces.create_or_update(
self.resource_group,
nic_name,
nic_data)
except Exception as e:
self.format_vimconn_exception(e)
result = async_nic_creation.result()
return async_nic_creation.result()
def new_flavor(self, flavor_data):
if flavor_data:
flavor_id = self.get_flavor_id_from_data(flavor_data)
if flavor_id != []:
return flavor_id
else:
raise vimconn.vimconnNotFoundException("flavor '{}' not found".format(flavor_data))
else:
vimconn.vimconnException("There is no data in the flavor_data input parameter")
def new_tenant(self,tenant_name,tenant_description):
raise vimconn.vimconnAuthException("It is not possible to create a TENANT in AZURE")
def new_image(self, image_dict):
self._reload_connection()
try:
self.logger.debug('new_image - image_dict - {}'.format(image_dict))
if image_dict.get("name"):
image_name = image_dict.get("name")
else:
raise vimconn.vimconnException("There is no name in the image input data")
if image_dict.get("location"):
params = image_dict["location"].split(":")
if len(params) >= 4:
publisher = params[0]
offer = params[1]
sku = params[2]
version = params[3]
#image_params = {'location': self.region, 'publisher': publisher, 'offer': offer, 'sku': sku, 'version': version }
image_params = {'location': self.region}
self.conn_compute.images.create_or_update()
async_creation=self.conn_compute.images.create_or_update(self.resource_group, image_name, image_params)
image_id = async_creation.result().id
else:
raise vimconn.vimconnException("The image location is not correct: {}".format(image_dict["location"]))
return image_id
except Exception as e:
self.format_vimconn_exception(e)
def get_image_id_from_path(self, path):
"""Get the image id from image path in the VIM database.
Returns the image_id or raises a vimconnNotFoundException
"""
def get_image_list(self, filter_dict={}):
"""Obtain tenant images from VIM
Filter_dict can be:
name: image name
id: image uuid
checksum: image checksum
location: image path
Returns the image list of dictionaries:
[{<the fields at Filter_dict plus some VIM specific>}, ...]
List can be empty
"""
self._reload_connection()
image_list = []
if filter_dict.get("name"):
params = filter_dict["name"].split(":")
if len(params) >= 3:
publisher = params[0]
offer = params[1]
sku = params[2]
version = None
if len(params) == 4:
version = params[3]
images = self.conn_compute.virtual_machine_images.list(self.region, publisher, offer, sku)
for image in images:
if version:
image_version = str(image.id).split("/")[-1]
if image_version != version:
continue
image_list.append({
'id': str(image.id),
'name': self._get_resource_name_from_resource_id(image.id)
})
return image_list
def get_network_list(self, filter_dict={}):
"""Obtain tenant networks of VIM
Filter_dict can be:
name: network name
id: network uuid
shared: boolean
tenant_id: tenant
admin_state_up: boolean
status: 'ACTIVE'
Returns the network list of dictionaries
"""
self.logger.debug('Getting all subnets from VIM')
try:
self._reload_connection()
vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name)
subnet_list = []
for subnet in vnet.subnets:
if filter_dict:
if filter_dict.get("id") and str(subnet.id) != filter_dict["id"]:
continue
if filter_dict.get("name") and \
str(subnet.id) != filter_dict["name"]:
continue
name = self._get_resource_name_from_resource_id(subnet.id)
subnet_list.append({
'id': str(subnet.id),
'name': self._get_resource_name_from_resource_id(subnet.id),
'status' : self.provision_state2osm[subnet.provisioning_state],
'cidr_block': str(subnet.address_prefix),
'type': 'bridge',
'shared': False
}
)
return subnet_list
except Exception as e:
self.format_vimconn_exception(e)
def new_vminstance(self, vm_name, description, start, image_id, flavor_id, net_list, cloud_config=None,
disk_list=None, availability_zone_index=None, availability_zone_list=None):
return self._new_vminstance(vm_name, image_id, flavor_id, net_list)
#def _new_vminstance(self, vm_name, image_id, flavor_id, net_list, cloud_config=None, disk_list=None,
# availability_zone_index=None, availability_zone_list=None):
def new_vminstance(self, name, description, start, image_id, flavor_id, net_list, cloud_config=None,
disk_list=None,
availability_zone_index=None, availability_zone_list=None):
self._check_subnets_for_vm(net_list)
vm_nics = []
for idx, net in enumerate(net_list):
# Fault with subnet_id
# subnet_id=net['subnet_id']
# subnet_id=net['net_id']
nic_name = name + '-nic-'+str(idx)
vm_nic = self._create_nic(net, nic_name)
vm_nics.append({ 'id': str(vm_nic.id)})
try:
# image_id are several fields of the image_id
image_reference = self.get_image_reference(image_id)
# The virtual machine name must have less or 64 characters and it can not have the following
# characters: (~ ! @ # $ % ^ & * ( ) = + _ [ ] { } \ | ; : ' " , < > / ?.)
vm_name_aux = self.check_vm_name(name)
# cloud-init configuration
# cloud config
if cloud_config:
config_drive, userdata = self._create_user_data(cloud_config)
custom_data = base64.b64encode(userdata.encode('utf-8')).decode('latin-1')
os_profile = {
'computer_name': vm_name_aux, # TODO if vm_name cannot be repeated add uuid4() suffix
'admin_username': 'osm', # TODO is it mandatory???
'admin_password': 'Osm-osm', # TODO is it mandatory???
'custom_data': custom_data
}
else:
os_profile = {
'computer_name': vm_name_aux, # TODO if vm_name cannot be repeated add uuid4() suffix
'admin_username': 'osm', # TODO is it mandatory???
'admin_password': 'Osm-osm', # TODO is it mandatory???
}
vm_parameters = {
'location': self.region,
'os_profile': os_profile,
'hardware_profile': {
'vm_size': flavor_id
},
'storage_profile': {
'image_reference': image_reference
},
'network_profile': {
'network_interfaces': [
vm_nics[0]
]
}
}
creation_result = self.conn_compute.virtual_machines.create_or_update(
self.resource_group,
vm_name_aux,
vm_parameters
)
#creation_result.wait()
result = creation_result.result()
for index, subnet in enumerate(net_list):
net_list[index]['vim_id'] = result.id
if start == True:
#self.logger.debug('Arrancamos VM y esperamos')
start_result = self.conn_compute.virtual_machines.start(
self.resource_group,
vm_name_aux)
#start_result.wait()
return result.id, None
#run_command_parameters = {
# 'command_id': 'RunShellScript', # For linux, don't change it
# 'script': [
# 'date > /tmp/test.txt'
# ]
#}
except Exception as e:
#self.logger.debug('AZURE <=== EX: _new_vminstance', exc_info=True)
self.format_vimconn_exception(e)
# It is necesary extract from image_id data to create the VM with this format
# 'image_reference': {
# 'publisher': vm_reference['publisher'],
# 'offer': vm_reference['offer'],
# 'sku': vm_reference['sku'],
# 'version': vm_reference['version']
# },
def get_image_reference(self, imagen):
# The data input format example:
# /Subscriptions/ca3d18ab-d373-4afb-a5d6-7c44f098d16a/Providers/Microsoft.Compute/Locations/westeurope/
# Publishers/Canonical/ArtifactTypes/VMImage/
# Offers/UbuntuServer/
# Skus/18.04-LTS/
# Versions/18.04.201809110
publiser = str(imagen.split('/')[8])
offer = str(imagen.split('/')[12])
sku = str(imagen.split('/')[14])
version = str(imagen.split('/')[16])
return {
'publisher': publiser,
'offer': offer,
'sku': sku,
'version': version
}
# Azure VM names can not have some special characters
def check_vm_name( self, vm_name ):
#chars_not_allowed_list = ['~','!','@','#','$','%','^','&','*','(',')','=','+','_','[',']','{','}','|',';',':','<','>','/','?','.']
chars_not_allowed_list = "~!@#$%^&*()=+_[]{}|;:<>/?."
# First: the VM name max length is 64 characters
vm_name_aux = vm_name[:64]
# Second: replace not allowed characters
for elem in chars_not_allowed_list :
# Check if string is in the main string
if elem in vm_name_aux :
#self.logger.debug('Dentro del IF')
# Replace the string
vm_name_aux = vm_name_aux.replace(elem, '-')
return vm_name_aux
def get_flavor_id_from_data(self, flavor_dict):
self.logger.debug("Getting flavor id from data")
try:
self._reload_connection()
vm_sizes_list = [vm_size.serialize() for vm_size in self.conn_compute.virtual_machine_sizes.list(self.region)]
cpus = flavor_dict['vcpus']
memMB = flavor_dict['ram']
filteredSizes = [size for size in vm_sizes_list if size['numberOfCores'] >= cpus and size['memoryInMB'] >= memMB]
listedFilteredSizes = sorted(filteredSizes, key=lambda k: k['numberOfCores'])
return listedFilteredSizes[0]['name']
except Exception as e:
self.format_vimconn_exception(e)
def _get_flavor_id_from_flavor_name(self, flavor_name):
self.logger.debug("Getting flavor id from falvor name {}".format(flavor_name))
try:
self._reload_connection()
vm_sizes_list = [vm_size.serialize() for vm_size in self.conn_compute.virtual_machine_sizes.list(self.region)]
output_flavor = None
for size in vm_sizes_list:
if size['name'] == flavor_name:
output_flavor = size
return output_flavor
except Exception as e:
self.format_vimconn_exception(e)
def check_vim_connectivity(self):
try:
self._reload_connection()
return True
except Exception as e:
raise vimconn.vimconnException("Connectivity issue with Azure API: {}".format(e))
def get_network(self, net_id):
resName = self._get_resource_name_from_resource_id(net_id)
self._reload_connection()
filter_dict = {'name' : net_id}
network_list = self.get_network_list(filter_dict)
if not network_list:
raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id))
else:
return network_list[0]
# Added created_items because it is neccesary
# self.vim.delete_network(net_vim_id, task["extra"].get("created_items"))
# TypeError: delete_network() takes exactly 2 arguments (3 given)
def delete_network(self, net_id, created_items=None):
self.logger.debug('Deletting network {} - {}'.format(self.resource_group, net_id))
resName = self._get_resource_name_from_resource_id(net_id)
self._reload_connection()
filter_dict = {'name' : net_id}
network_list = self.get_network_list(filter_dict)
if not network_list:
raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id))
try:
# Subnet API fails (CloudError: Azure Error: ResourceNotFound)
# Put the initial virtual_network API
async_delete=self.conn_vnet.subnets.delete(self.resource_group, self.vnet_name, resName)
return net_id
except CloudError as e:
if e.error.error == "ResourceNotFound":
raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id))
else:
raise
except Exception as e:
self.format_vimconn_exception(e)
# Added third parameter because it is necesary
def delete_vminstance(self, vm_id, created_items=None):
self.logger.debug('Deletting VM instance {} - {}'.format(self.resource_group, vm_id))
self._reload_connection()
try:
resName = self._get_resource_name_from_resource_id(vm_id)
vm = self.conn_compute.virtual_machines.get(self.resource_group, resName)
# Shuts down the virtual machine and releases the compute resources
#vm_stop = self.conn_compute.virtual_machines.power_off(self.resource_group, resName)
#vm_stop.wait()
vm_delete = self.conn_compute.virtual_machines.delete(self.resource_group, resName)
vm_delete.wait()
# Delete OS Disk
os_disk_name = vm.storage_profile.os_disk.name
self.logger.debug('Delete OS DISK - ' + os_disk_name)
self.conn_compute.disks.delete(self.resource_group, os_disk_name)
# After deletting VM, it is necessary delete NIC, because if is not deleted delete_network
# does not work because Azure says that is in use the subnet
network_interfaces = vm.network_profile.network_interfaces
for network_interface in network_interfaces:
#self.logger.debug('nic - {}'.format(network_interface))
nic_name = self._get_resource_name_from_resource_id(network_interface.id)
#self.logger.debug('nic_name - {}'.format(nic_name))
nic_data = self.conn_vnet.network_interfaces.get(
self.resource_group,
nic_name)
exist_public_ip = nic_data.ip_configurations[0].public_ip_address
if exist_public_ip:
public_ip_id = nic_data.ip_configurations[0].public_ip_address.id
self.logger.debug('Public ip id - ' + public_ip_id)
self.logger.debug('Delete NIC - ' + nic_name)
nic_delete = self.conn_vnet.network_interfaces.delete(self.resource_group, nic_name)
nic_delete.wait()
# Delete public_ip
public_ip_name = self._get_resource_name_from_resource_id(public_ip_id)
self.logger.debug('Delete PUBLIC IP - ' + public_ip_name)
public_ip = self.conn_vnet.public_ip_addresses.delete(self.resource_group, public_ip_name)
except CloudError as e:
if e.error.error == "ResourceNotFound":
raise vimconn.vimconnNotFoundException("No vminstance found '{}'".format(vm_id))
else:
raise
except Exception as e:
self.format_vimconn_exception(e)
def action_vminstance(self, vm_id, action_dict, created_items={}):
"""Send and action over a VM instance from VIM
Returns the vm_id if the action was successfully sent to the VIM"""
self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict))
try:
self._reload_connection()
resName = self._get_resource_name_from_resource_id(vm_id)
if "start" in action_dict:
self.conn_compute.virtual_machines.start(self.resource_group,resName)
elif "stop" in action_dict or "shutdown" in action_dict or "shutoff" in action_dict:
self.conn_compute.virtual_machines.power_off(self.resource_group,resName)
elif "terminate" in action_dict:
self.conn_compute.virtual_machines.delete(self.resource_group,resName)
elif "reboot" in action_dict:
self.conn_compute.virtual_machines.restart(self.resource_group,resName)
return None
except CloudError as e:
if e.error.error == "ResourceNotFound":
raise vimconn.vimconnNotFoundException("No vm found '{}'".format(vm_id))
else:
raise
except Exception as e:
self.format_vimconn_exception(e)
def delete_flavor(self, flavor_id):
raise vimconn.vimconnAuthException("It is not possible to delete a FLAVOR in AZURE")
def delete_tenant(self,tenant_id,):
raise vimconn.vimconnAuthException("It is not possible to delete a TENANT in AZURE")
def delete_image(self, image_id):
raise vimconn.vimconnAuthException("It is not possible to delete a IMAGE in AZURE")
def get_vminstance(self, vm_id):
self._reload_connection()
try:
resName = self._get_resource_name_from_resource_id(vm_id)
vm=self.conn_compute.virtual_machines.get(self.resource_group, resName)
except CloudError as e:
if e.error.error == "ResourceNotFound":
raise vimconn.vimconnNotFoundException("No vminstance found '{}'".format(vm_id))
else:
raise
except Exception as e:
self.format_vimconn_exception(e)
return vm
def get_flavor(self, flavor_id):
self._reload_connection()
flavor_data = self._get_flavor_id_from_flavor_name(flavor_id)
if flavor_data:
flavor = {
'id': flavor_id,
'name': flavor_id,
'ram': flavor_data['memoryInMB'],
'vcpus': flavor_data['numberOfCores'],
'disk': flavor_data['resourceDiskSizeInMB']
}
return flavor
else:
raise vimconn.vimconnNotFoundException("flavor '{}' not found".format(flavor_id))
def get_tenant_list(self, filter_dict={}):
tenants_azure=[{'name': self.tenant, 'id': self.tenant}]
tenant_list=[]
for tenant_azure in tenants_azure:
if filter_dict:
if filter_dict.get("id") and str(tenant_azure.get("id")) != filter_dict["id"]:
continue
if filter_dict.get("name") and str(tenant_azure.get("name")) != filter_dict["name"]:
continue
tenant_list.append(tenant_azure)
return tenant_list
def refresh_nets_status(self, net_list):
out_nets = {}
self._reload_connection()
for net_id in net_list:
try:
netName = self._get_net_name_from_resource_id(net_id)
resName = self._get_resource_name_from_resource_id(net_id)
net = self.conn_vnet.subnets.get(self.resource_group, netName, resName)
out_nets[net_id] ={
"status": self.provision_state2osm[net.provisioning_state],
"vim_info": str(net)
}
except CloudError as e:
if e.error.error == "ResourceNotFound":
out_nets[net_id] = {
"status": "DELETED",
"error_msg": str(e)
}
else:
raise
except vimconn.vimconnNotFoundException as e:
out_nets[net_id] = {
"status": "DELETED",
"error_msg": str(e)
}
except Exception as e:
# TODO distinguish when it is deleted
out_nets[net_id] = {
"status": "VIM_ERROR",
"error_msg": str(e)
}
return out_nets
def refresh_vms_status(self, vm_list):
out_vms = {}
out_vms_dict = {}
self._reload_connection()
for vm_id in vm_list:
try:
resName = self._get_resource_name_from_resource_id(vm_id)
vm = self.conn_compute.virtual_machines.get(self.resource_group, resName)
out_vms_dict['status'] = self.provision_state2osm[vm.provisioning_state]
out_vms_dict['interfaces'] = []
interface_dict = {}
network_interfaces = vm.network_profile.network_interfaces
for network_interface in network_interfaces:
nic_name = self._get_resource_name_from_resource_id(network_interface.id)
interface_dict['vim_interface_id'] = vm_id
nic_data = self.conn_vnet.network_interfaces.get(
self.resource_group,
nic_name)
private_ip = nic_data.ip_configurations[0].private_ip_address
interface_dict['mac_address'] = nic_data.mac_address
interface_dict['ip_address'] = private_ip
out_vms_dict['interfaces'].append(interface_dict)
except Exception as e:
out_vms_dict['status'] = "DELETED"
out_vms_dict['error_msg'] = str(e)
vm = None
finally:
if vm:
out_vms_dict['vim_info'] = str(vm)
out_vms[vm_id] = out_vms_dict
return out_vms
if __name__ == "__main__":
# Making some basic test
vim_id='azure'
vim_name='azure'
needed_test_params = {
"client_id": "AZURE_CLIENT_ID",
"secret": "AZURE_SECRET",
"tenant": "AZURE_TENANT",
"resource_group": "AZURE_RESOURCE_GROUP",
"subscription_id": "AZURE_SUBSCRIPTION_ID",
"vnet_name": "AZURE_VNET_NAME",
}
test_params = {}
for param, env_var in needed_test_params.items():
value = getenv(env_var)
if not value:
raise Exception("Provide a valid value for env '{}'".format(env_var))
test_params[param] = value
config = {
'region_name': getenv("AZURE_REGION_NAME", 'westeurope'),
'resource_group': getenv("AZURE_RESOURCE_GROUP"),
'subscription_id': getenv("AZURE_SUBSCRIPTION_ID"),
'pub_key': getenv("AZURE_PUB_KEY", None),
'vnet_name': getenv("AZURE_VNET_NAME", 'myNetwork'),
}
virtualMachine = {
'name': 'sergio',
'description': 'new VM',
'status': 'running',
'image': {
'publisher': 'Canonical',
'offer': 'UbuntuServer',
'sku': '16.04.0-LTS',
'version': 'latest'
},
'hardware_profile': {
'vm_size': 'Standard_DS1_v2'
},
'networks': [
'sergio'
]
}
vnet_config = {
'subnet_address': '10.1.2.0/24',
#'subnet_name': 'subnet-oam'
}
###########################
azure = vimconnector(vim_id, vim_name, tenant_id=test_params["tenant"], tenant_name=None, url=None, url_admin=None,
user=test_params["client_id"], passwd=test_params["secret"], log_level=None, config=config)
# azure.get_flavor_id_from_data("here")
# subnets=azure.get_network_list()
# azure.new_vminstance(virtualMachine['name'], virtualMachine['description'], virtualMachine['status'],
# virtualMachine['image'], virtualMachine['hardware_profile']['vm_size'], subnets)
azure.new_network("mynet", None)
net_id = "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/Microsoft."\
"Network/virtualNetworks/test"
net_id_not_found = "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/"\
"Microsoft.Network/virtualNetworks/testALF"
azure.refresh_nets_status([net_id, net_id_not_found])