Reformat files according to new black validation
[osm/NG-SA.git] / src / osm_ngsa / osm_mon / vim_connectors / azure.py
1 #######################################################################################
2 # Copyright ETSI Contributors and Others.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #######################################################################################
17 import logging
18 from typing import Dict, List
19
20 from azure.identity import ClientSecretCredential
21 from azure.mgmt.compute import ComputeManagementClient
22 from azure.profiles import ProfileDefinition
23 from osm_mon.vim_connectors.base_vim import VIMConnector
24
25
26 log = logging.getLogger(__name__)
27
28
29 class AzureCollector(VIMConnector):
30 # Translate azure provisioning state to OSM provision state.
31 # The first three ones are the transitional status once a user initiated
32 # action has been requested. Once the operation is complete, it will
33 # transition into the states Succeeded or Failed
34 # https://docs.microsoft.com/en-us/azure/virtual-machines/windows/states-lifecycle
35 provision_state2osm = {
36 "Creating": "BUILD",
37 "Updating": "BUILD",
38 "Deleting": "INACTIVE",
39 "Succeeded": "ACTIVE",
40 "Failed": "ERROR",
41 }
42
43 # Translate azure power state to OSM provision state
44 power_state2osm = {
45 "starting": "INACTIVE",
46 "running": "ACTIVE",
47 "stopping": "INACTIVE",
48 "stopped": "INACTIVE",
49 "unknown": "OTHER",
50 "deallocated": "BUILD",
51 "deallocating": "BUILD",
52 }
53
54 AZURE_COMPUTE_MGMT_CLIENT_API_VERSION = "2021-03-01"
55 AZURE_COMPUTE_MGMT_PROFILE_TAG = "azure.mgmt.compute.ComputeManagementClient"
56 AZURE_COMPUTE_MGMT_PROFILE = ProfileDefinition(
57 {
58 AZURE_COMPUTE_MGMT_PROFILE_TAG: {
59 None: AZURE_COMPUTE_MGMT_CLIENT_API_VERSION,
60 "availability_sets": "2020-12-01",
61 "dedicated_host_groups": "2020-12-01",
62 "dedicated_hosts": "2020-12-01",
63 "disk_accesses": "2020-12-01",
64 "disk_encryption_sets": "2020-12-01",
65 "disk_restore_point": "2020-12-01",
66 "disks": "2020-12-01",
67 "galleries": "2020-09-30",
68 "gallery_application_versions": "2020-09-30",
69 "gallery_applications": "2020-09-30",
70 "gallery_image_versions": "2020-09-30",
71 "gallery_images": "2020-09-30",
72 "gallery_sharing_profile": "2020-09-30",
73 "images": "2020-12-01",
74 "log_analytics": "2020-12-01",
75 "operations": "2020-12-01",
76 "proximity_placement_groups": "2020-12-01",
77 "resource_skus": "2019-04-01",
78 "shared_galleries": "2020-09-30",
79 "shared_gallery_image_versions": "2020-09-30",
80 "shared_gallery_images": "2020-09-30",
81 "snapshots": "2020-12-01",
82 "ssh_public_keys": "2020-12-01",
83 "usage": "2020-12-01",
84 "virtual_machine_extension_images": "2020-12-01",
85 "virtual_machine_extensions": "2020-12-01",
86 "virtual_machine_images": "2020-12-01",
87 "virtual_machine_images_edge_zone": "2020-12-01",
88 "virtual_machine_run_commands": "2020-12-01",
89 "virtual_machine_scale_set_extensions": "2020-12-01",
90 "virtual_machine_scale_set_rolling_upgrades": "2020-12-01",
91 "virtual_machine_scale_set_vm_extensions": "2020-12-01",
92 "virtual_machine_scale_set_vm_run_commands": "2020-12-01",
93 "virtual_machine_scale_set_vms": "2020-12-01",
94 "virtual_machine_scale_sets": "2020-12-01",
95 "virtual_machine_sizes": "2020-12-01",
96 "virtual_machines": "2020-12-01",
97 }
98 },
99 AZURE_COMPUTE_MGMT_PROFILE_TAG + " osm",
100 )
101
102 def __init__(self, vim_account: Dict):
103 self.vim_account = vim_account
104 self.reload_client = True
105 logger = logging.getLogger("azure")
106 logger.setLevel(logging.ERROR)
107 # Store config to create azure subscription later
108 self._config = {
109 "user": vim_account["vim_user"],
110 "passwd": vim_account["vim_password"],
111 "tenant": vim_account["vim_tenant_name"],
112 }
113
114 # SUBSCRIPTION
115 config = vim_account["config"]
116 if "subscription_id" in config:
117 self._config["subscription_id"] = config.get("subscription_id")
118 log.info("Subscription: %s", self._config["subscription_id"])
119 else:
120 log.error("Subscription not specified")
121 return
122
123 # RESOURCE_GROUP
124 if "resource_group" in config:
125 self.resource_group = config.get("resource_group")
126 else:
127 log.error("Azure resource_group is not specified at config")
128 return
129
130 def _reload_connection(self):
131 if self.reload_client:
132 log.debug("reloading azure client")
133 try:
134 self.credentials = ClientSecretCredential(
135 client_id=self._config["user"],
136 client_secret=self._config["passwd"],
137 tenant_id=self._config["tenant"],
138 )
139 self.conn_compute = ComputeManagementClient(
140 self.credentials,
141 self._config["subscription_id"],
142 profile=self.AZURE_COMPUTE_MGMT_PROFILE,
143 )
144 # Set to client created
145 self.reload_client = False
146 except Exception as e:
147 log.error(e)
148
149 def collect_servers_status(self) -> List[Dict]:
150 servers = []
151 log.debug("collect_servers_status")
152 self._reload_connection()
153 try:
154 for vm in self.conn_compute.virtual_machines.list(self.resource_group):
155 id = vm.id
156 array = id.split("/")
157 name = array[-1]
158 status = self.provision_state2osm.get(vm.provisioning_state, "OTHER")
159 if vm.provisioning_state == "Succeeded":
160 # check if machine is running or stopped
161 instance_view = self.conn_compute.virtual_machines.instance_view(
162 self.resource_group, name
163 )
164 for status in instance_view.statuses:
165 splitted_status = status.code.split("/")
166 if (
167 len(splitted_status) == 2
168 and splitted_status[0] == "PowerState"
169 ):
170 status = self.power_state2osm.get(
171 splitted_status[1], "OTHER"
172 )
173 # log.info(f'id: {id}, name: {name}, status: {status}')
174 vm = {
175 "id": id,
176 "name": name,
177 "status": (1 if (status == "ACTIVE") else 0),
178 }
179 servers.append(vm)
180 except Exception as e:
181 log.error(e)
182 return servers
183
184 def is_vim_ok(self) -> bool:
185 status = False
186 self.reload_client = True
187 try:
188 self._reload_connection()
189 status = True
190 except Exception as e:
191 log.error(e)
192 return status