class AzureServicesManager: # Storage container = 'vhds' windows_blob_url = 'blob.core.windows.net' # Linux linux_user = '******' linux_pass = '******' location = 'West US' # SSH Keys def __init__(self, subscription_id, cert_file): self.subscription_id = subscription_id self.cert_file = cert_file self.sms = ServiceManagementService(self.subscription_id, self.cert_file) @property def sms(self): return self.sms def list_locations(self): locations = self.sms.list_locations() for location in locations: print location def list_images(self): return self.sms.list_os_images() @utils.resource_not_found_handler def get_hosted_service(self, service_name): resp = self.sms.get_hosted_service_properties(service_name) properties = resp.hosted_service_properties return properties.__dict__ def delete_hosted_service(self, service_name): res = self.sms.check_hosted_service_name_availability(service_name) if not res.result: return self.sms.delete_hosted_service(service_name) def create_hosted_service(self, os_user, service_name=None, random=False): if not service_name: service_name = self.generate_cloud_service_name(os_user, random) available = False while not available: res = self.sms.check_hosted_service_name_availability(service_name) if not res.result: service_name = self.generate_cloud_service_name(os_user, random) else: available = True self.sms.create_hosted_service(service_name=service_name, label=service_name, location='West US') return service_name def create_virtual_machine(self, service_name, vm_name, image_name, role_size): media_link = self._get_media_link(vm_name) # Linux VM configuration hostname = '-'.join((vm_name, 'host')) linux_config = LinuxConfigurationSet(hostname, self.linux_user, self.linux_pass, True) # Hard disk for the OS os_hd = OSVirtualHardDisk(image_name, media_link) # Create vm result = self.sms.create_virtual_machine_deployment( service_name=service_name, deployment_name=vm_name, deployment_slot='production', label=vm_name, role_name=vm_name, system_config=linux_config, os_virtual_hard_disk=os_hd, role_size=role_size ) request_id = result.request_id return { 'request_id': request_id, 'media_link': media_link } def delete_virtual_machine(self, service_name, vm_name): resp = self.sms.delete_deployment(service_name, vm_name, True) self.sms.wait_for_operation_status(resp.request_id) result = self.sms.delete_hosted_service(service_name) return result def generate_cloud_service_name(self, os_user=None, random=False): if random: return utils.generate_random_name(10) return '-'.join((os_user, utils.generate_random_name(6))) @utils.resource_not_found_handler def get_virtual_machine_info(self, service_name, vm_name): vm_info = {} deploy_info = self.sms.get_deployment_by_name(service_name, vm_name) if deploy_info and deploy_info.role_instance_list: vm_info = deploy_info.role_instance_list[0].__dict__ return vm_info def list_virtual_machines(self): vm_list = [] services = self.sms.list_hosted_services() for service in services: deploys = service.deployments if deploys and deploys.role_instance_list: vm_name = deploys.role_instance_list[0].instance_name vm_list.append(vm_name) return vm_list def power_on(self, service_name, vm_name): resp = self.sms.start_role(service_name, vm_name, vm_name) return resp.request_id def power_off(self, service_name, vm_name): resp = self.sms.shutdown_role(service_name, vm_name, vm_name) return resp.request_id def soft_reboot(self, service_name, vm_name): resp = self.sms.restart_role(service_name, vm_name, vm_name) return resp.request_id def hard_reboot(self, service_name, vm_name): resp = self.sms.reboot_role_instance(service_name, vm_name, vm_name) return resp.request_id def attach_volume(self, service_name, vm_name, size, lun): disk_name = utils.generate_random_name(5, vm_name) media_link = self._get_media_link(vm_name, disk_name) self.sms.add_data_disk(service_name, vm_name, vm_name, lun, host_caching='ReadWrite', media_link=media_link, disk_name=disk_name, logical_disk_size_in_gb=size) def detach_volume(self, service_name, vm_name, lun): self.sms.delete_data_disk(service_name, vm_name, vm_name, lun, True) def get_available_lun(self, service_name, vm_name): try: role = self.sms.get_role(service_name, vm_name, vm_name) except Exception: return 0 disks = role.data_virtual_hard_disks luns = [disk.lun for disk in disks].sort() for i in range(1, 16): if i not in luns: return i return None def snapshot(self, service_name, vm_name, image_id, snanshot_name): image_desc = 'Snapshot for image %s' % vm_name image = CaptureRoleAsVMImage('Specialized', snanshot_name, image_id, image_desc, 'english') resp = self.sms.capture_vm_image(service_name, vm_name, vm_name, image) self.sms.wait_for_operation_status(resp.request_id) def _get_media_link(self, vm_name, filename=None, storage_account=None): """ The MediaLink should be constructed as: https://<storageAccount>.<blobLink>/<blobContainer>/<filename>.vhd """ if not storage_account: storage_account = self._get_or_create_storage_account() container = self.container filename = vm_name if filename is None else filename blob = vm_name + '-' + filename + '.vhd' media_link = "http://%s.%s/%s/%s" % (storage_account, self.windows_blob_url, container, blob) return media_link def _get_or_create_storage_account(self): account_list = self.sms.list_storage_accounts() if account_list: return account_list[-1].service_name storage_account = utils.generate_random_name(10) description = "Storage account %s description" % storage_account label = storage_account + 'label' self.sms.create_storage_account(storage_account, description, label, location=self.location) return storage_account def _wait_for_operation(self, request_id, timeout=3000, failure_callback=None, failure_callback_kwargs=None): try: self.sms.wait_for_operation_status(request_id, timeout=timeout) except Exception as ex: if failure_callback and failure_callback_kwargs: failure_callback(**failure_callback_kwargs) raise ex
class AffinityGroupManagementServiceTest(AzureTestCase): def setUp(self): self.sms = ServiceManagementService(credentials.getSubscriptionId(), credentials.getManagementCertFile()) self.sms.set_proxy(credentials.getProxyHost(), credentials.getProxyPort(), credentials.getProxyUser(), credentials.getProxyPassword()) self.affinity_group_name = getUniqueNameBasedOnCurrentTime('utaffgrp') self.hosted_service_name = None self.storage_account_name = None def tearDown(self): try: if self.hosted_service_name is not None: self.sms.delete_hosted_service(self.hosted_service_name) except: pass try: if self.storage_account_name is not None: self.sms.delete_storage_account(self.storage_account_name) except: pass try: self.sms.delete_affinity_group(self.affinity_group_name) except: pass #--Helpers----------------------------------------------------------------- def _create_affinity_group(self, name): result = self.sms.create_affinity_group(name, 'tstmgmtaffgrp', 'West US', 'tstmgmt affinity group') self.assertIsNone(result) def _affinity_group_exists(self, name): try: props = self.sms.get_affinity_group_properties(name) return props is not None except: return False #--Test cases for affinity groups ------------------------------------ def test_list_affinity_groups(self): # Arrange self._create_affinity_group(self.affinity_group_name) # Act result = self.sms.list_affinity_groups() # Assert self.assertIsNotNone(result) self.assertTrue(len(result) > 0) group = None for temp in result: if temp.name == self.affinity_group_name: group = temp break self.assertIsNotNone(group) self.assertIsNotNone(group.name) self.assertIsNotNone(group.label) self.assertIsNotNone(group.description) self.assertIsNotNone(group.location) self.assertIsNotNone(group.capabilities) self.assertTrue(len(group.capabilities) > 0) def test_get_affinity_group_properties(self): # Arrange self.hosted_service_name = getUniqueNameBasedOnCurrentTime('utsvc') self.storage_account_name = getUniqueNameBasedOnCurrentTime('utstorage') self._create_affinity_group(self.affinity_group_name) self.sms.create_hosted_service(self.hosted_service_name, 'affgrptestlabel', 'affgrptestdesc', None, self.affinity_group_name) self.sms.create_storage_account(self.storage_account_name, self.storage_account_name + 'desc', self.storage_account_name + 'label', self.affinity_group_name) # Act result = self.sms.get_affinity_group_properties(self.affinity_group_name) # Assert self.assertIsNotNone(result) self.assertEqual(result.name, self.affinity_group_name) self.assertIsNotNone(result.label) self.assertIsNotNone(result.description) self.assertIsNotNone(result.location) self.assertIsNotNone(result.hosted_services[0]) self.assertEqual(result.hosted_services[0].service_name, self.hosted_service_name) self.assertEqual(result.hosted_services[0].hosted_service_properties.affinity_group, self.affinity_group_name) # not sure why azure does not return any storage service self.assertTrue(len(result.capabilities) > 0) def test_create_affinity_group(self): # Arrange label = 'tstmgmtaffgrp' description = 'tstmgmt affinity group' # Act result = self.sms.create_affinity_group(self.affinity_group_name, label, 'West US', description) # Assert self.assertIsNone(result) self.assertTrue(self._affinity_group_exists(self.affinity_group_name)) def test_update_affinity_group(self): # Arrange self._create_affinity_group(self.affinity_group_name) label = 'tstlabelupdate' description = 'testmgmt affinity group update' # Act result = self.sms.update_affinity_group(self.affinity_group_name, label, description) # Assert self.assertIsNone(result) props = self.sms.get_affinity_group_properties(self.affinity_group_name) self.assertEqual(props.label, label) self.assertEqual(props.description, description) def test_delete_affinity_group(self): # Arrange self._create_affinity_group(self.affinity_group_name) # Act result = self.sms.delete_affinity_group(self.affinity_group_name) # Assert self.assertIsNone(result) self.assertFalse(self._affinity_group_exists(self.affinity_group_name)) #--Test cases for locations ------------------------------------------ def test_list_locations(self): # Arrange # Act result = self.sms.list_locations() # Assert self.assertIsNotNone(result) self.assertTrue(len(result) > 0) self.assertIsNotNone(result[0].name) self.assertIsNotNone(result[0].display_name) self.assertIsNotNone(result[0].available_services) self.assertTrue(len(result[0].available_services) > 0)
# The MIT License (MIT) # # Copyright (c) 2015 Taio Jia (jiasir) <*****@*****.**> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR from azure.servicemanagement import ServiceManagementService subscription_id = '7f32b7c7-8622-4070-84d0-1ec5bc64dd8f' cert_file = '/Users/Taio/Downloads/Microsoft_Azure_credentials.pem' sms = ServiceManagementService(subscription_id, cert_file) locations = sms.list_locations() for location in locations: print(location.name)
class AzureNodeDriver(NodeDriver): name = "Azure Node Provider" type = Provider.AZURE website = 'http://windowsazure.com' sms = None rolesizes = None NODE_STATE_MAP = { 'RoleStateUnknown': NodeState.UNKNOWN, 'CreatingVM': NodeState.PENDING, 'StartingVM': NodeState.PENDING, 'CreatingRole': NodeState.PENDING, 'StartingRole': NodeState.PENDING, 'ReadyRole': NodeState.RUNNING, 'BusyRole': NodeState.PENDING, 'StoppingRole': NodeState.PENDING, 'StoppingVM': NodeState.PENDING, 'DeletingVM': NodeState.PENDING, 'StoppedVM': NodeState.STOPPED, 'RestartingRole': NodeState.REBOOTING, 'CyclingRole': NodeState.TERMINATED, 'FailedStartingRole': NodeState.TERMINATED, 'FailedStartingVM': NodeState.TERMINATED, 'UnresponsiveRole': NodeState.TERMINATED, 'StoppedDeallocated': NodeState.TERMINATED, } def __init__(self, subscription_id=None, key_file=None, **kwargs): """ subscription_id contains the Azure subscription id in the form of GUID key_file contains the Azure X509 certificate in .pem form """ self.subscription_id = subscription_id self.key_file = key_file self.sms = ServiceManagementService(subscription_id, key_file) super(AzureNodeDriver, self).__init__( self.subscription_id, self.key_file, secure=True, **kwargs) def list_sizes(self): """ Lists all sizes from azure :rtype: ``list`` of :class:`NodeSize` """ if self.rolesizes is None: # refresh rolesizes data = self.sms.list_role_sizes() self.rolesizes = [self._to_node_size(i) for i in data] return self.rolesizes def list_images(self, location=None): """ Lists all sizes from azure :rtype: ``list`` of :class:`NodeSize` """ data = self.sms.list_os_images() images = [self._to_image(i) for i in data] if location is not None: images = [image for image in images if location in image.extra["location"]] return images def list_locations(self): """ Lists all Location from azure :rtype: ``list`` of :class:`NodeLocation` """ data = self.sms.list_locations() locations = [self._to_location(i) for i in data] return locations def list_virtual_net(self): """ List all VirtualNetworkSites :rtype: ``list`` of :class:`VirtualNetwork` """ data = self.sms.list_virtual_network_sites() virtualnets = [self._to_virtual_network(i) for i in data] return virtualnets def create_node(self, name, image, size, storage, service_name, vm_user, vm_password, location=None, affinity_group=None, virtual_network=None): """ Create a vm deploiement request :rtype: :class:`.Node` :return: ``Node`` Node instance on success. """ try: self.sms.get_hosted_service_properties(service_name) pass except WindowsAzureMissingResourceError: # create cloud service if bool(location is not None) != bool(affinity_group is not None): raise ValueError( "For ressource creation, set location or affinity_group" + " not both") if location is not None: try: self.sms.create_hosted_service( service_name=service_name, label=service_name, location=location) pass except Exception, e: raise e else: try: self.sms.create_hosted_service( service_name=service_name, label=service_name, affinity_group=affinity_group) except Exception, e: raise e
class AzureServicesManager: # Storage container = 'vhds' windows_blob_url = 'blob.core.windows.net' # Linux linux_user = '******' linux_pass = '******' location = 'West US' # SSH Keys def __init__(self, subscription_id, cert_file): self.subscription_id = subscription_id self.cert_file = cert_file self.sms = ServiceManagementService(self.subscription_id, self.cert_file) @property def sms(self): return self.sms def list_locations(self): locations = self.sms.list_locations() for location in locations: print location def list_images(self): return self.sms.list_os_images() @utils.resource_not_found_handler def get_hosted_service(self, service_name): resp = self.sms.get_hosted_service_properties(service_name) properties = resp.hosted_service_properties return properties.__dict__ def delete_hosted_service(self, service_name): res = self.sms.check_hosted_service_name_availability(service_name) if not res.result: return self.sms.delete_hosted_service(service_name) def create_hosted_service(self, os_user, service_name=None, random=False): if not service_name: service_name = self.generate_cloud_service_name(os_user, random) available = False while not available: res = self.sms.check_hosted_service_name_availability(service_name) if not res.result: service_name = self.generate_cloud_service_name( os_user, random) else: available = True self.sms.create_hosted_service(service_name=service_name, label=service_name, location='West US') return service_name def create_virtual_machine(self, service_name, vm_name, image_name, role_size): media_link = self._get_media_link(vm_name) # Linux VM configuration hostname = '-'.join((vm_name, 'host')) linux_config = LinuxConfigurationSet(hostname, self.linux_user, self.linux_pass, True) # Hard disk for the OS os_hd = OSVirtualHardDisk(image_name, media_link) # Create vm result = self.sms.create_virtual_machine_deployment( service_name=service_name, deployment_name=vm_name, deployment_slot='production', label=vm_name, role_name=vm_name, system_config=linux_config, os_virtual_hard_disk=os_hd, role_size=role_size) request_id = result.request_id return {'request_id': request_id, 'media_link': media_link} def delete_virtual_machine(self, service_name, vm_name): resp = self.sms.delete_deployment(service_name, vm_name, True) self.sms.wait_for_operation_status(resp.request_id) result = self.sms.delete_hosted_service(service_name) return result def generate_cloud_service_name(self, os_user=None, random=False): if random: return utils.generate_random_name(10) return '-'.join((os_user, utils.generate_random_name(6))) @utils.resource_not_found_handler def get_virtual_machine_info(self, service_name, vm_name): vm_info = {} deploy_info = self.sms.get_deployment_by_name(service_name, vm_name) if deploy_info and deploy_info.role_instance_list: vm_info = deploy_info.role_instance_list[0].__dict__ return vm_info def list_virtual_machines(self): vm_list = [] services = self.sms.list_hosted_services() for service in services: deploys = service.deployments if deploys and deploys.role_instance_list: vm_name = deploys.role_instance_list[0].instance_name vm_list.append(vm_name) return vm_list def power_on(self, service_name, vm_name): resp = self.sms.start_role(service_name, vm_name, vm_name) return resp.request_id def power_off(self, service_name, vm_name): resp = self.sms.shutdown_role(service_name, vm_name, vm_name) return resp.request_id def soft_reboot(self, service_name, vm_name): resp = self.sms.restart_role(service_name, vm_name, vm_name) return resp.request_id def hard_reboot(self, service_name, vm_name): resp = self.sms.reboot_role_instance(service_name, vm_name, vm_name) return resp.request_id def attach_volume(self, service_name, vm_name, size, lun): disk_name = utils.generate_random_name(5, vm_name) media_link = self._get_media_link(vm_name, disk_name) self.sms.add_data_disk(service_name, vm_name, vm_name, lun, host_caching='ReadWrite', media_link=media_link, disk_name=disk_name, logical_disk_size_in_gb=size) def detach_volume(self, service_name, vm_name, lun): self.sms.delete_data_disk(service_name, vm_name, vm_name, lun, True) def get_available_lun(self, service_name, vm_name): try: role = self.sms.get_role(service_name, vm_name, vm_name) except Exception: return 0 disks = role.data_virtual_hard_disks luns = [disk.lun for disk in disks].sort() for i in range(1, 16): if i not in luns: return i return None def snapshot(self, service_name, vm_name, image_id, snanshot_name): image_desc = 'Snapshot for image %s' % vm_name image = CaptureRoleAsVMImage('Specialized', snanshot_name, image_id, image_desc, 'english') resp = self.sms.capture_vm_image(service_name, vm_name, vm_name, image) self.sms.wait_for_operation_status(resp.request_id) def _get_media_link(self, vm_name, filename=None, storage_account=None): """ The MediaLink should be constructed as: https://<storageAccount>.<blobLink>/<blobContainer>/<filename>.vhd """ if not storage_account: storage_account = self._get_or_create_storage_account() container = self.container filename = vm_name if filename is None else filename blob = vm_name + '-' + filename + '.vhd' media_link = "http://%s.%s/%s/%s" % ( storage_account, self.windows_blob_url, container, blob) return media_link def _get_or_create_storage_account(self): account_list = self.sms.list_storage_accounts() if account_list: return account_list[-1].service_name storage_account = utils.generate_random_name(10) description = "Storage account %s description" % storage_account label = storage_account + 'label' self.sms.create_storage_account(storage_account, description, label, location=self.location) return storage_account def _wait_for_operation(self, request_id, timeout=3000, failure_callback=None, failure_callback_kwargs=None): try: self.sms.wait_for_operation_status(request_id, timeout=timeout) except Exception as ex: if failure_callback and failure_callback_kwargs: failure_callback(**failure_callback_kwargs) raise ex
class AffinityGroupManagementServiceTest(AzureTestCase): def setUp(self): proxy_host = credentials.getProxyHost() proxy_port = credentials.getProxyPort() self.sms = ServiceManagementService( credentials.getSubscriptionId(), credentials.getManagementCertFile()) if proxy_host: self.sms.set_proxy(proxy_host, proxy_port) self.affinity_group_name = getUniqueNameBasedOnCurrentTime('utaffgrp') self.hosted_service_name = None self.storage_account_name = None def tearDown(self): try: if self.hosted_service_name is not None: self.sms.delete_hosted_service(self.hosted_service_name) except: pass try: if self.storage_account_name is not None: self.sms.delete_storage_account(self.storage_account_name) except: pass try: self.sms.delete_affinity_group(self.affinity_group_name) except: pass #--Helpers----------------------------------------------------------------- def _create_affinity_group(self, name): result = self.sms.create_affinity_group(name, 'tstmgmtaffgrp', 'West US', 'tstmgmt affinity group') self.assertIsNone(result) def _affinity_group_exists(self, name): try: props = self.sms.get_affinity_group_properties(name) return props is not None except: return False #--Test cases for affinity groups ------------------------------------ def test_list_affinity_groups(self): # Arrange self._create_affinity_group(self.affinity_group_name) # Act result = self.sms.list_affinity_groups() # Assert self.assertIsNotNone(result) self.assertTrue(len(result) > 0) group = None for temp in result: if temp.name == self.affinity_group_name: group = temp break self.assertIsNotNone(group) self.assertIsNotNone(group.name) self.assertIsNotNone(group.label) self.assertIsNotNone(group.description) self.assertIsNotNone(group.location) self.assertIsNotNone(group.capabilities) self.assertTrue(len(group.capabilities) > 0) def test_get_affinity_group_properties(self): # Arrange self.hosted_service_name = getUniqueNameBasedOnCurrentTime('utsvc') self.storage_account_name = getUniqueNameBasedOnCurrentTime( 'utstorage') self._create_affinity_group(self.affinity_group_name) self.sms.create_hosted_service(self.hosted_service_name, 'affgrptestlabel', 'affgrptestdesc', None, self.affinity_group_name) self.sms.create_storage_account(self.storage_account_name, self.storage_account_name + 'desc', self.storage_account_name + 'label', self.affinity_group_name) # Act result = self.sms.get_affinity_group_properties( self.affinity_group_name) # Assert self.assertIsNotNone(result) self.assertEqual(result.name, self.affinity_group_name) self.assertIsNotNone(result.label) self.assertIsNotNone(result.description) self.assertIsNotNone(result.location) self.assertIsNotNone(result.hosted_services[0]) self.assertEqual(result.hosted_services[0].service_name, self.hosted_service_name) self.assertEqual( result.hosted_services[0].hosted_service_properties.affinity_group, self.affinity_group_name) # not sure why azure does not return any storage service self.assertTrue(len(result.capabilities) > 0) def test_create_affinity_group(self): # Arrange label = 'tstmgmtaffgrp' description = 'tstmgmt affinity group' # Act result = self.sms.create_affinity_group(self.affinity_group_name, label, 'West US', description) # Assert self.assertIsNone(result) self.assertTrue(self._affinity_group_exists(self.affinity_group_name)) def test_update_affinity_group(self): # Arrange self._create_affinity_group(self.affinity_group_name) label = 'tstlabelupdate' description = 'testmgmt affinity group update' # Act result = self.sms.update_affinity_group(self.affinity_group_name, label, description) # Assert self.assertIsNone(result) props = self.sms.get_affinity_group_properties( self.affinity_group_name) self.assertEqual(props.label, label) self.assertEqual(props.description, description) def test_delete_affinity_group(self): # Arrange self._create_affinity_group(self.affinity_group_name) # Act result = self.sms.delete_affinity_group(self.affinity_group_name) # Assert self.assertIsNone(result) self.assertFalse(self._affinity_group_exists(self.affinity_group_name)) #--Test cases for locations ------------------------------------------ def test_list_locations(self): # Arrange # Act result = self.sms.list_locations() # Assert self.assertIsNotNone(result) self.assertTrue(len(result) > 0) self.assertIsNotNone(result[0].name) self.assertIsNotNone(result[0].display_name) self.assertIsNotNone(result[0].available_services) self.assertTrue(len(result[0].available_services) > 0)
if not os.path.exists('./azure/data'): os.mkdir('./azure/data') result = sms.list_os_images() process_sms_list(result.images, './azure/data/azure_os_images.csv') print ('Azure OS images saved in azure_os_images.csv') result = sms.list_vm_images() process_sms_list(result.vm_images, './azure/data/azure_vm_images.csv') print ('Azure VM images saved in azure_vm_images.csv') result = sms.list_role_sizes() process_sms_list(result.role_sizes, './azure/data/azure_role_sizes.csv') print ('Azure Role sizes saved in azure_role_sizes.csv') result = sms.list_locations() process_sms_list(result.locations, './azure/data/azure_locations.csv') print ('Azure Locations saved in azure_locations.csv') result = sms.list_storage_accounts() process_sms_list(result.storage_services, './azure/data/azure_storage_accounts.csv') print ('Azure Storage accounts saved in azure_storage_accounts.csv') # Put this result always next to for loop! result = sms.list_hosted_services() process_sms_list(result.hosted_services, './azure/data/azure_hosted_services.csv') print ('Azure Hosted services saved in azure_hosted_services.csv') for hs in result.hosted_services: subr = sms.list_service_certificates(hs.service_name) process_sms_list(subr.certificates, './azure/data/azure_service_certificates-{0}.csv'.format(hs.service_name))