1 # -*- coding: utf-8 -*-
3 __author__
='Sergio Gonzalez'
4 __date__
='$18-apr-2019 23:59:59$'
13 from uuid
import uuid4
15 from azure
.common
.credentials
import ServicePrincipalCredentials
16 from azure
.mgmt
.resource
import ResourceManagementClient
17 from azure
.mgmt
.network
import NetworkManagementClient
18 from azure
.mgmt
.compute
import ComputeManagementClient
22 from msrestazure
.azure_exceptions
import CloudError
24 if getenv('OSMRO_PDB_DEBUG'):
31 class vimconnector(vimconn
.vimconnector
):
33 provision_state2osm
= {
34 "Deleting": "INACTIVE",
36 "Succeeded": "ACTIVE",
40 def __init__(self
, uuid
, name
, tenant_id
, tenant_name
, url
, url_admin
=None, user
=None, passwd
=None, log_level
=None,
41 config
={}, persistent_info
={}):
43 vimconn
.vimconnector
.__init
__(self
, uuid
, name
, tenant_id
, tenant_name
, url
, url_admin
, user
, passwd
, log_level
,
44 config
, persistent_info
)
46 self
.vnet_address_space
= None
48 self
.logger
= logging
.getLogger('openmano.vim.azure')
51 self
.logger
.setLevel(getattr(logging
, log_level
))
54 self
.credentials
= ServicePrincipalCredentials(
57 tenant
=(tenant_id
or tenant_name
)
60 self
.tenant
=(tenant_id
or tenant_name
)
63 if 'subscription_id' in config
:
64 self
.subscription_id
= config
.get('subscription_id')
65 self
.logger
.debug('Setting subscription '+str(self
.subscription_id
))
67 raise vimconn
.vimconnException('Subscription not specified')
69 if 'region_name' in config
:
70 self
.region
= config
.get('region_name')
72 raise vimconn
.vimconnException('Azure region_name is not specified at config')
74 if 'resource_group' in config
:
75 self
.resource_group
= config
.get('resource_group')
77 raise vimconn
.vimconnException('Azure resource_group is not specified at config')
79 if 'vnet_name' in config
:
80 self
.vnet_name
= config
["vnet_name"]
83 self
.pub_key
= config
.get('pub_key')
85 def _reload_connection(self
):
87 Sets connections to work with Azure service APIs
90 self
.logger
.debug('Reloading API Connection')
92 self
.conn
= ResourceManagementClient(self
.credentials
, self
.subscription_id
)
93 self
.conn_compute
= ComputeManagementClient(self
.credentials
, self
.subscription_id
)
94 self
.conn_vnet
= NetworkManagementClient(self
.credentials
, self
.subscription_id
)
95 self
._check
_or
_create
_resource
_group
()
96 self
._check
_or
_create
_vnet
()
97 except Exception as e
:
98 self
.format_vimconn_exception(e
)
100 def _get_resource_name_from_resource_id(self
, resource_id
):
103 resource
=str(resource_id
.split('/')[-1])
105 except Exception as e
:
106 raise vimconn
.vimconnNotFoundException("Resource name '{}' not found".format(resource_id
))
108 def _get_location_from_resource_group(self
, resource_group_name
):
111 location
=self
.conn
.resource_groups
.get(resource_group_name
).location
113 except Exception as e
:
114 raise vimconn
.vimconnNotFoundException("Location '{}' not found".format(resource_group_name
))
117 def _get_resource_group_name_from_resource_id(self
, resource_id
):
120 rg
=str(resource_id
.split('/')[4])
122 except Exception as e
:
123 raise vimconn
.vimconnNotFoundException("Resource group '{}' not found".format(resource_id
))
126 def _get_net_name_from_resource_id(self
, resource_id
):
129 net_name
=str(resource_id
.split('/')[8])
131 except Exception as e
:
132 raise vimconn
.vimconnNotFoundException("Net name '{}' not found".format(resource_id
))
135 def _check_subnets_for_vm(self
, net_list
):
136 # All subnets must belong to the same resource group and vnet
138 # File "/root/RO/build/osm_ro/vimconn_azure.py", line 110, in <genexpr>
139 # self._get_resource_name_from_resource_id(net['id']) for net in net_list)) != 1:
140 #if len(set(self._get_resource_group_name_from_resource_id(net['net_id']) +
141 # self._get_resource_name_from_resource_id(net['net_id']) for net in net_list)) != 2:
142 # raise self.format_vimconn_exception('Azure VMs can only attach to subnets in same VNET')
143 self
.logger
.debug('Checking subnets for VM')
144 num_elem_set
= len(set(self
._get
_resource
_group
_name
_from
_resource
_id
(net
['net_id']) +
145 self
._get
_resource
_name
_from
_resource
_id
(net
['net_id']) for net
in net_list
))
147 if ( num_elem_set
!= 1 ):
148 raise self
.format_vimconn_exception('Azure VMs can only attach to subnets in same VNET')
150 def format_vimconn_exception(self
, e
):
152 Params: an Exception object
154 :return: Raises the proper vimconnException
157 self
.conn_vnet
= None
158 raise vimconn
.vimconnException(type(e
).__name
__ + ': ' + str(e
))
160 def _check_or_create_resource_group(self
):
162 Creates a resource group in indicated region
165 self
.logger
.debug('Creating RG {} in location {}'.format(self
.resource_group
, self
.region
))
166 self
.conn
.resource_groups
.create_or_update(self
.resource_group
, {'location': self
.region
})
168 def _check_or_create_vnet(self
):
171 vnet
= self
.conn_vnet
.virtual_networks
.get(self
.resource_group
, self
.vnet_name
)
172 self
.vnet_address_space
= vnet
.address_space
.address_prefixes
[0]
173 self
.vnet_id
= vnet
.id
176 except CloudError
as e
:
177 if e
.error
.error
== "ResourceNotFound":
181 # if not exist, creates it
184 'location': self
.region
,
186 'address_prefixes': ["10.0.0.0/8"]
189 self
.vnet_address_space
= "10.0.0.0/8"
191 self
.conn_vnet
.virtual_networks
.create_or_update(self
.resource_group
, self
.vnet_name
, vnet_params
)
192 vnet
= self
.conn_vnet
.virtual_networks
.get(self
.resource_group
, self
.vnet_name
)
193 self
.vnet_id
= vnet
.id
194 except Exception as e
:
195 self
.format_vimconn_exception(e
)
197 def new_network(self
, net_name
, net_type
, ip_profile
=None, shared
=False, vlan
=None):
199 Adds a tenant network to VIM
200 :param net_name: name of the network
202 :param ip_profile: is a dict containing the IP parameters of the network (Currently only IPv4 is implemented)
203 'ip-version': can be one of ['IPv4','IPv6']
204 'subnet-address': ip_prefix_schema, that is X.X.X.X/Y
205 'gateway-address': (Optional) ip_schema, that is X.X.X.X
206 'dns-address': (Optional) ip_schema,
207 'dhcp': (Optional) dict containing
208 'enabled': {'type': 'boolean'},
209 'start-address': ip_schema, first IP to grant
210 'count': number of IPs to grant.
213 :return: a tuple with the network identifier and created_items, or raises an exception on error
214 created_items can be None or a dictionary where this method can include key-values that will be passed to
215 the method delete_network. Can be used to store created segments, created l2gw connections, etc.
216 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
219 return self
._new
_subnet
(net_name
, ip_profile
)
221 def _new_subnet(self
, net_name
, ip_profile
):
223 Adds a tenant network to VIM. It creates a new VNET with a single subnet
228 self
.logger
.debug('Adding a subnet to VNET '+self
.vnet_name
)
229 self
._reload
_connection
()
231 if ip_profile
is None:
232 # get a non used vnet ip range /24 and allocate automatically inside the range self.vnet_address_space
233 used_subnets
= self
.get_network_list()
234 for ip_range
in netaddr
.IPNetwork(self
.vnet_address_space
).subnet(24):
235 for used_subnet
in used_subnets
:
236 subnet_range
= netaddr
.IPNetwork(used_subnet
["cidr_block"])
237 if subnet_range
in ip_range
or ip_range
in subnet_range
:
238 # this range overlaps with an existing subnet ip range. Breaks and look for another
241 ip_profile
= {"subnet_address": str(ip_range
)}
242 self
.logger
.debug('ip_profile: ' + str(ip_range
))
245 vimconn
.vimconnException("Cannot find a non-used subnet range in {}".format(self
.vnet_address_space
))
247 ip_profile
= {"subnet_address": ip_profile
['subnet_address']}
250 #subnet_name = "{}-{}".format(net_name[:24], uuid4())
251 subnet_name
= net_name
[:24]
253 'address_prefix': ip_profile
['subnet_address']
255 self
.logger
.debug('subnet_name : {}'.format(subnet_name
))
256 async_creation
=self
.conn_vnet
.subnets
.create_or_update(self
.resource_group
, self
.vnet_name
, subnet_name
, subnet_params
)
257 async_creation
.wait()
259 #return "{}/subnet/{}".format(self.vnet_id, subnet_name), None
260 return "{}/subnets/{}".format(self
.vnet_id
, subnet_name
), None
261 except Exception as e
:
262 self
.format_vimconn_exception(e
)
264 def _create_nic(self
, net
, nic_name
, static_ip
=None):
266 self
._reload
_connection
()
268 subnet_id
= net
['net_id']
269 location
= self
._get
_location
_from
_resource
_group
(self
.resource_group
)
273 async_nic_creation
= self
.conn_vnet
.network_interfaces
.create_or_update(
277 'location': location
,
278 'ip_configurations': [{
279 'name': nic_name
+ '-ipconfiguration',
280 'privateIPAddress': static_ip
,
281 'privateIPAllocationMethod': 'Static',
288 async_nic_creation
.wait()
290 ip_configuration_name
= nic_name
+ '-ipconfiguration'
291 self
.logger
.debug('Create NIC')
292 async_nic_creation
= self
.conn_vnet
.network_interfaces
.create_or_update(
296 'location': location
,
297 'ip_configurations': [{
298 'name': ip_configuration_name
,
305 async_nic_creation
.wait()
307 public_ip
= net
.get('floating_ip')
308 if public_ip
and public_ip
== True:
309 self
.logger
.debug('Creating PUBLIC IP')
310 public_ip_addess_params
= {
311 'location': location
,
312 'public_ip_allocation_method': 'Dynamic'
314 public_ip_name
= nic_name
+ '-public-ip'
315 public_ip
= self
.conn_vnet
.public_ip_addresses
.create_or_update(
318 public_ip_addess_params
320 self
.logger
.debug('Create PUBLIC IP: {}'.format(public_ip
.result()))
322 # Asociate NIC to Public IP
323 self
.logger
.debug('Getting NIC DATA')
324 nic_data
= self
.conn_vnet
.network_interfaces
.get(
328 nic_data
.ip_configurations
[0].public_ip_address
= public_ip
.result()
330 self
.logger
.debug('Updating NIC with public IP')
331 self
.conn_vnet
.network_interfaces
.create_or_update(
336 except Exception as e
:
337 self
.format_vimconn_exception(e
)
339 result
= async_nic_creation
.result()
340 return async_nic_creation
.result()
342 def new_flavor(self
, flavor_data
):
345 flavor_id
= self
.get_flavor_id_from_data(flavor_data
)
350 raise vimconn
.vimconnNotFoundException("flavor '{}' not found".format(flavor_data
))
352 vimconn
.vimconnException("There is no data in the flavor_data input parameter")
354 def new_tenant(self
,tenant_name
,tenant_description
):
356 raise vimconn
.vimconnAuthException("It is not possible to create a TENANT in AZURE")
358 def new_image(self
, image_dict
):
360 self
._reload
_connection
()
363 self
.logger
.debug('new_image - image_dict - {}'.format(image_dict
))
365 if image_dict
.get("name"):
366 image_name
= image_dict
.get("name")
368 raise vimconn
.vimconnException("There is no name in the image input data")
370 if image_dict
.get("location"):
371 params
= image_dict
["location"].split(":")
373 publisher
= params
[0]
377 #image_params = {'location': self.region, 'publisher': publisher, 'offer': offer, 'sku': sku, 'version': version }
378 image_params
= {'location': self
.region
}
380 self
.conn_compute
.images
.create_or_update()
381 async_creation
=self
.conn_compute
.images
.create_or_update(self
.resource_group
, image_name
, image_params
)
382 image_id
= async_creation
.result().id
384 raise vimconn
.vimconnException("The image location is not correct: {}".format(image_dict
["location"]))
387 except Exception as e
:
388 self
.format_vimconn_exception(e
)
390 def get_image_id_from_path(self
, path
):
391 """Get the image id from image path in the VIM database.
392 Returns the image_id or raises a vimconnNotFoundException
395 def get_image_list(self
, filter_dict
={}):
396 """Obtain tenant images from VIM
400 checksum: image checksum
402 Returns the image list of dictionaries:
403 [{<the fields at Filter_dict plus some VIM specific>}, ...]
406 self
._reload
_connection
()
409 if filter_dict
.get("name"):
410 params
= filter_dict
["name"].split(":")
412 publisher
= params
[0]
418 images
= self
.conn_compute
.virtual_machine_images
.list(self
.region
, publisher
, offer
, sku
)
421 image_version
= str(image
.id).split("/")[-1]
422 if image_version
!= version
:
426 'name': self
._get
_resource
_name
_from
_resource
_id
(image
.id)
431 def get_network_list(self
, filter_dict
={}):
432 """Obtain tenant networks of VIM
438 admin_state_up: boolean
440 Returns the network list of dictionaries
442 self
.logger
.debug('Getting all subnets from VIM')
444 self
._reload
_connection
()
446 vnet
= self
.conn_vnet
.virtual_networks
.get(self
.resource_group
, self
.vnet_name
)
449 for subnet
in vnet
.subnets
:
452 if filter_dict
.get("id") and str(subnet
.id) != filter_dict
["id"]:
454 if filter_dict
.get("name") and \
455 str(subnet
.id) != filter_dict
["name"]:
458 name
= self
._get
_resource
_name
_from
_resource
_id
(subnet
.id)
461 'id': str(subnet
.id),
462 'name': self
._get
_resource
_name
_from
_resource
_id
(subnet
.id),
463 'status' : self
.provision_state2osm
[subnet
.provisioning_state
],
464 'cidr_block': str(subnet
.address_prefix
),
471 except Exception as e
:
472 self
.format_vimconn_exception(e
)
474 def new_vminstance(self
, vm_name
, description
, start
, image_id
, flavor_id
, net_list
, cloud_config
=None,
475 disk_list
=None, availability_zone_index
=None, availability_zone_list
=None):
477 return self
._new
_vminstance
(vm_name
, image_id
, flavor_id
, net_list
)
479 #def _new_vminstance(self, vm_name, image_id, flavor_id, net_list, cloud_config=None, disk_list=None,
480 # availability_zone_index=None, availability_zone_list=None):
481 def new_vminstance(self
, name
, description
, start
, image_id
, flavor_id
, net_list
, cloud_config
=None,
483 availability_zone_index
=None, availability_zone_list
=None):
485 self
._check
_subnets
_for
_vm
(net_list
)
487 for idx
, net
in enumerate(net_list
):
488 # Fault with subnet_id
489 # subnet_id=net['subnet_id']
490 # subnet_id=net['net_id']
492 nic_name
= name
+ '-nic-'+str(idx
)
493 vm_nic
= self
._create
_nic
(net
, nic_name
)
494 vm_nics
.append({ 'id': str(vm_nic
.id)})
497 # image_id are several fields of the image_id
498 image_reference
= self
.get_image_reference(image_id
)
500 # The virtual machine name must have less or 64 characters and it can not have the following
501 # characters: (~ ! @ # $ % ^ & * ( ) = + _ [ ] { } \ | ; : ' " , < > / ?.)
502 vm_name_aux
= self
.check_vm_name(name
)
504 # cloud-init configuration
507 config_drive
, userdata
= self
._create
_user
_data
(cloud_config
)
508 custom_data
= base64
.b64encode(userdata
.encode('utf-8')).decode('latin-1')
510 'computer_name': vm_name_aux
, # TODO if vm_name cannot be repeated add uuid4() suffix
511 'admin_username': 'osm', # TODO is it mandatory???
512 'admin_password': 'Osm-osm', # TODO is it mandatory???
513 'custom_data': custom_data
517 'computer_name': vm_name_aux
, # TODO if vm_name cannot be repeated add uuid4() suffix
518 'admin_username': 'osm', # TODO is it mandatory???
519 'admin_password': 'Osm-osm', # TODO is it mandatory???
523 'location': self
.region
,
524 'os_profile': os_profile
,
525 'hardware_profile': {
529 'image_reference': image_reference
532 'network_interfaces': [
538 creation_result
= self
.conn_compute
.virtual_machines
.create_or_update(
544 #creation_result.wait()
545 result
= creation_result
.result()
547 for index
, subnet
in enumerate(net_list
):
548 net_list
[index
]['vim_id'] = result
.id
551 #self.logger.debug('Arrancamos VM y esperamos')
552 start_result
= self
.conn_compute
.virtual_machines
.start(
557 return result
.id, None
559 #run_command_parameters = {
560 # 'command_id': 'RunShellScript', # For linux, don't change it
562 # 'date > /tmp/test.txt'
565 except Exception as e
:
566 #self.logger.debug('AZURE <=== EX: _new_vminstance', exc_info=True)
567 self
.format_vimconn_exception(e
)
569 # It is necesary extract from image_id data to create the VM with this format
570 # 'image_reference': {
571 # 'publisher': vm_reference['publisher'],
572 # 'offer': vm_reference['offer'],
573 # 'sku': vm_reference['sku'],
574 # 'version': vm_reference['version']
576 def get_image_reference(self
, imagen
):
578 # The data input format example:
579 # /Subscriptions/ca3d18ab-d373-4afb-a5d6-7c44f098d16a/Providers/Microsoft.Compute/Locations/westeurope/
580 # Publishers/Canonical/ArtifactTypes/VMImage/
581 # Offers/UbuntuServer/
583 # Versions/18.04.201809110
584 publiser
= str(imagen
.split('/')[8])
585 offer
= str(imagen
.split('/')[12])
586 sku
= str(imagen
.split('/')[14])
587 version
= str(imagen
.split('/')[16])
590 'publisher': publiser
,
596 # Azure VM names can not have some special characters
597 def check_vm_name( self
, vm_name
):
599 #chars_not_allowed_list = ['~','!','@','#','$','%','^','&','*','(',')','=','+','_','[',']','{','}','|',';',':','<','>','/','?','.']
600 chars_not_allowed_list
= "~!@#$%^&*()=+_[]{}|;:<>/?."
602 # First: the VM name max length is 64 characters
603 vm_name_aux
= vm_name
[:64]
605 # Second: replace not allowed characters
606 for elem
in chars_not_allowed_list
:
607 # Check if string is in the main string
608 if elem
in vm_name_aux
:
609 #self.logger.debug('Dentro del IF')
611 vm_name_aux
= vm_name_aux
.replace(elem
, '-')
616 def get_flavor_id_from_data(self
, flavor_dict
):
617 self
.logger
.debug("Getting flavor id from data")
620 self
._reload
_connection
()
621 vm_sizes_list
= [vm_size
.serialize() for vm_size
in self
.conn_compute
.virtual_machine_sizes
.list(self
.region
)]
623 cpus
= flavor_dict
['vcpus']
624 memMB
= flavor_dict
['ram']
626 filteredSizes
= [size
for size
in vm_sizes_list
if size
['numberOfCores'] >= cpus
and size
['memoryInMB'] >= memMB
]
627 listedFilteredSizes
= sorted(filteredSizes
, key
=lambda k
: k
['numberOfCores'])
629 return listedFilteredSizes
[0]['name']
631 except Exception as e
:
632 self
.format_vimconn_exception(e
)
634 def _get_flavor_id_from_flavor_name(self
, flavor_name
):
635 self
.logger
.debug("Getting flavor id from falvor name {}".format(flavor_name
))
638 self
._reload
_connection
()
639 vm_sizes_list
= [vm_size
.serialize() for vm_size
in self
.conn_compute
.virtual_machine_sizes
.list(self
.region
)]
642 for size
in vm_sizes_list
:
643 if size
['name'] == flavor_name
:
648 except Exception as e
:
649 self
.format_vimconn_exception(e
)
651 def check_vim_connectivity(self
):
653 self
._reload
_connection
()
655 except Exception as e
:
656 raise vimconn
.vimconnException("Connectivity issue with Azure API: {}".format(e
))
658 def get_network(self
, net_id
):
660 resName
= self
._get
_resource
_name
_from
_resource
_id
(net_id
)
662 self
._reload
_connection
()
664 filter_dict
= {'name' : net_id
}
665 network_list
= self
.get_network_list(filter_dict
)
668 raise vimconn
.vimconnNotFoundException("network '{}' not found".format(net_id
))
670 return network_list
[0]
672 # Added created_items because it is neccesary
673 # self.vim.delete_network(net_vim_id, task["extra"].get("created_items"))
674 # TypeError: delete_network() takes exactly 2 arguments (3 given)
675 def delete_network(self
, net_id
, created_items
=None):
677 self
.logger
.debug('Deletting network {} - {}'.format(self
.resource_group
, net_id
))
679 resName
= self
._get
_resource
_name
_from
_resource
_id
(net_id
)
681 self
._reload
_connection
()
683 filter_dict
= {'name' : net_id
}
684 network_list
= self
.get_network_list(filter_dict
)
686 raise vimconn
.vimconnNotFoundException("network '{}' not found".format(net_id
))
689 # Subnet API fails (CloudError: Azure Error: ResourceNotFound)
690 # Put the initial virtual_network API
691 async_delete
=self
.conn_vnet
.subnets
.delete(self
.resource_group
, self
.vnet_name
, resName
)
694 except CloudError
as e
:
695 if e
.error
.error
== "ResourceNotFound":
696 raise vimconn
.vimconnNotFoundException("network '{}' not found".format(net_id
))
699 except Exception as e
:
700 self
.format_vimconn_exception(e
)
704 # Added third parameter because it is necesary
705 def delete_vminstance(self
, vm_id
, created_items
=None):
707 self
.logger
.debug('Deletting VM instance {} - {}'.format(self
.resource_group
, vm_id
))
708 self
._reload
_connection
()
712 resName
= self
._get
_resource
_name
_from
_resource
_id
(vm_id
)
713 vm
= self
.conn_compute
.virtual_machines
.get(self
.resource_group
, resName
)
715 # Shuts down the virtual machine and releases the compute resources
716 #vm_stop = self.conn_compute.virtual_machines.power_off(self.resource_group, resName)
719 vm_delete
= self
.conn_compute
.virtual_machines
.delete(self
.resource_group
, resName
)
723 os_disk_name
= vm
.storage_profile
.os_disk
.name
724 self
.logger
.debug('Delete OS DISK - ' + os_disk_name
)
725 self
.conn_compute
.disks
.delete(self
.resource_group
, os_disk_name
)
727 # After deletting VM, it is necessary delete NIC, because if is not deleted delete_network
728 # does not work because Azure says that is in use the subnet
729 network_interfaces
= vm
.network_profile
.network_interfaces
731 for network_interface
in network_interfaces
:
733 #self.logger.debug('nic - {}'.format(network_interface))
735 nic_name
= self
._get
_resource
_name
_from
_resource
_id
(network_interface
.id)
737 #self.logger.debug('nic_name - {}'.format(nic_name))
739 nic_data
= self
.conn_vnet
.network_interfaces
.get(
743 exist_public_ip
= nic_data
.ip_configurations
[0].public_ip_address
745 public_ip_id
= nic_data
.ip_configurations
[0].public_ip_address
.id
746 self
.logger
.debug('Public ip id - ' + public_ip_id
)
748 self
.logger
.debug('Delete NIC - ' + nic_name
)
749 nic_delete
= self
.conn_vnet
.network_interfaces
.delete(self
.resource_group
, nic_name
)
753 public_ip_name
= self
._get
_resource
_name
_from
_resource
_id
(public_ip_id
)
755 self
.logger
.debug('Delete PUBLIC IP - ' + public_ip_name
)
756 public_ip
= self
.conn_vnet
.public_ip_addresses
.delete(self
.resource_group
, public_ip_name
)
757 except CloudError
as e
:
758 if e
.error
.error
== "ResourceNotFound":
759 raise vimconn
.vimconnNotFoundException("No vminstance found '{}'".format(vm_id
))
762 except Exception as e
:
763 self
.format_vimconn_exception(e
)
765 def action_vminstance(self
, vm_id
, action_dict
, created_items
={}):
766 """Send and action over a VM instance from VIM
767 Returns the vm_id if the action was successfully sent to the VIM"""
769 self
.logger
.debug("Action over VM '%s': %s", vm_id
, str(action_dict
))
771 self
._reload
_connection
()
772 resName
= self
._get
_resource
_name
_from
_resource
_id
(vm_id
)
773 if "start" in action_dict
:
774 self
.conn_compute
.virtual_machines
.start(self
.resource_group
,resName
)
775 elif "stop" in action_dict
or "shutdown" in action_dict
or "shutoff" in action_dict
:
776 self
.conn_compute
.virtual_machines
.power_off(self
.resource_group
,resName
)
777 elif "terminate" in action_dict
:
778 self
.conn_compute
.virtual_machines
.delete(self
.resource_group
,resName
)
779 elif "reboot" in action_dict
:
780 self
.conn_compute
.virtual_machines
.restart(self
.resource_group
,resName
)
782 except CloudError
as e
:
783 if e
.error
.error
== "ResourceNotFound":
784 raise vimconn
.vimconnNotFoundException("No vm found '{}'".format(vm_id
))
787 except Exception as e
:
788 self
.format_vimconn_exception(e
)
790 def delete_flavor(self
, flavor_id
):
792 raise vimconn
.vimconnAuthException("It is not possible to delete a FLAVOR in AZURE")
794 def delete_tenant(self
,tenant_id
,):
796 raise vimconn
.vimconnAuthException("It is not possible to delete a TENANT in AZURE")
798 def delete_image(self
, image_id
):
800 raise vimconn
.vimconnAuthException("It is not possible to delete a IMAGE in AZURE")
802 def get_vminstance(self
, vm_id
):
804 self
._reload
_connection
()
806 resName
= self
._get
_resource
_name
_from
_resource
_id
(vm_id
)
807 vm
=self
.conn_compute
.virtual_machines
.get(self
.resource_group
, resName
)
808 except CloudError
as e
:
809 if e
.error
.error
== "ResourceNotFound":
810 raise vimconn
.vimconnNotFoundException("No vminstance found '{}'".format(vm_id
))
813 except Exception as e
:
814 self
.format_vimconn_exception(e
)
818 def get_flavor(self
, flavor_id
):
819 self
._reload
_connection
()
821 flavor_data
= self
._get
_flavor
_id
_from
_flavor
_name
(flavor_id
)
826 'ram': flavor_data
['memoryInMB'],
827 'vcpus': flavor_data
['numberOfCores'],
828 'disk': flavor_data
['resourceDiskSizeInMB']
832 raise vimconn
.vimconnNotFoundException("flavor '{}' not found".format(flavor_id
))
835 def get_tenant_list(self
, filter_dict
={}):
837 tenants_azure
=[{'name': self
.tenant
, 'id': self
.tenant
}]
840 for tenant_azure
in tenants_azure
:
842 if filter_dict
.get("id") and str(tenant_azure
.get("id")) != filter_dict
["id"]:
844 if filter_dict
.get("name") and str(tenant_azure
.get("name")) != filter_dict
["name"]:
847 tenant_list
.append(tenant_azure
)
851 def refresh_nets_status(self
, net_list
):
854 self
._reload
_connection
()
855 for net_id
in net_list
:
857 netName
= self
._get
_net
_name
_from
_resource
_id
(net_id
)
858 resName
= self
._get
_resource
_name
_from
_resource
_id
(net_id
)
860 net
= self
.conn_vnet
.subnets
.get(self
.resource_group
, netName
, resName
)
863 "status": self
.provision_state2osm
[net
.provisioning_state
],
866 except CloudError
as e
:
867 if e
.error
.error
== "ResourceNotFound":
874 except vimconn
.vimconnNotFoundException
as e
:
879 except Exception as e
:
880 # TODO distinguish when it is deleted
882 "status": "VIM_ERROR",
887 def refresh_vms_status(self
, vm_list
):
891 self
._reload
_connection
()
893 for vm_id
in vm_list
:
896 resName
= self
._get
_resource
_name
_from
_resource
_id
(vm_id
)
898 vm
= self
.conn_compute
.virtual_machines
.get(self
.resource_group
, resName
)
899 out_vms_dict
['status'] = self
.provision_state2osm
[vm
.provisioning_state
]
900 out_vms_dict
['interfaces'] = []
903 network_interfaces
= vm
.network_profile
.network_interfaces
905 for network_interface
in network_interfaces
:
907 nic_name
= self
._get
_resource
_name
_from
_resource
_id
(network_interface
.id)
908 interface_dict
['vim_interface_id'] = vm_id
910 nic_data
= self
.conn_vnet
.network_interfaces
.get(
914 private_ip
= nic_data
.ip_configurations
[0].private_ip_address
916 interface_dict
['mac_address'] = nic_data
.mac_address
917 interface_dict
['ip_address'] = private_ip
918 out_vms_dict
['interfaces'].append(interface_dict
)
920 except Exception as e
:
921 out_vms_dict
['status'] = "DELETED"
922 out_vms_dict
['error_msg'] = str(e
)
926 out_vms_dict
['vim_info'] = str(vm
)
928 out_vms
[vm_id
] = out_vms_dict
933 if __name__
== "__main__":
935 # Making some basic test
938 needed_test_params
= {
939 "client_id": "AZURE_CLIENT_ID",
940 "secret": "AZURE_SECRET",
941 "tenant": "AZURE_TENANT",
942 "resource_group": "AZURE_RESOURCE_GROUP",
943 "subscription_id": "AZURE_SUBSCRIPTION_ID",
944 "vnet_name": "AZURE_VNET_NAME",
948 for param
, env_var
in needed_test_params
.items():
949 value
= getenv(env_var
)
951 raise Exception("Provide a valid value for env '{}'".format(env_var
))
952 test_params
[param
] = value
955 'region_name': getenv("AZURE_REGION_NAME", 'westeurope'),
956 'resource_group': getenv("AZURE_RESOURCE_GROUP"),
957 'subscription_id': getenv("AZURE_SUBSCRIPTION_ID"),
958 'pub_key': getenv("AZURE_PUB_KEY", None),
959 'vnet_name': getenv("AZURE_VNET_NAME", 'myNetwork'),
964 'description': 'new VM',
967 'publisher': 'Canonical',
968 'offer': 'UbuntuServer',
969 'sku': '16.04.0-LTS',
972 'hardware_profile': {
973 'vm_size': 'Standard_DS1_v2'
981 'subnet_address': '10.1.2.0/24',
982 #'subnet_name': 'subnet-oam'
984 ###########################
986 azure
= vimconnector(vim_id
, vim_name
, tenant_id
=test_params
["tenant"], tenant_name
=None, url
=None, url_admin
=None,
987 user
=test_params
["client_id"], passwd
=test_params
["secret"], log_level
=None, config
=config
)
989 # azure.get_flavor_id_from_data("here")
990 # subnets=azure.get_network_list()
991 # azure.new_vminstance(virtualMachine['name'], virtualMachine['description'], virtualMachine['status'],
992 # virtualMachine['image'], virtualMachine['hardware_profile']['vm_size'], subnets)
994 azure
.new_network("mynet", None)
995 net_id
= "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/Microsoft."\
996 "Network/virtualNetworks/test"
997 net_id_not_found
= "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/"\
998 "Microsoft.Network/virtualNetworks/testALF"
999 azure
.refresh_nets_status([net_id
, net_id_not_found
])