Fix bug 1884 MON openstack token optimization
[osm/MON.git] / osm_mon / collector / vnf_collectors / vmware.py
1 # -*- coding: utf-8 -*-
2
3 ##
4 # Copyright 2016-2019 VMware Inc.
5 # This file is part of ETSI OSM
6 # All Rights Reserved.
7 #
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
18 # under the License.
19 #
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact: osslegalrouting@vmware.com
22 ##
23
24 import logging
25 import traceback
26 from xml.etree import ElementTree as XmlElementTree
27
28 import requests
29 from pyvcloud.vcd.client import BasicLoginCredentials
30 from pyvcloud.vcd.client import Client
31
32 from osm_mon.collector.vnf_collectors.base_vim import BaseVimCollector
33 from osm_mon.collector.vnf_collectors.vrops.vrops_helper import vROPS_Helper
34 from osm_mon.core.common_db import CommonDbClient
35 from osm_mon.core.config import Config
36
37 log = logging.getLogger(__name__)
38
39 API_VERSION = "27.0"
40
41
42 class VMwareCollector(BaseVimCollector):
43 def __init__(self, config: Config, vim_account_id: str, vim_session: object):
44 super().__init__(config, vim_account_id)
45 self.common_db = CommonDbClient(config)
46 vim_account = self.get_vim_account(vim_account_id)
47 self.vcloud_site = vim_account["vim_url"]
48 self.admin_username = vim_account["admin_username"]
49 self.admin_password = vim_account["admin_password"]
50 self.vrops = vROPS_Helper(
51 vrops_site=vim_account["vrops_site"],
52 vrops_user=vim_account["vrops_user"],
53 vrops_password=vim_account["vrops_password"],
54 )
55
56 def connect_as_admin(self):
57 """Method connect as pvdc admin user to vCloud director.
58 There are certain action that can be done only by provider vdc admin user.
59 Organization creation / provider network creation etc.
60
61 Returns:
62 The return client object that letter can be used to connect to vcloud direct as admin for provider vdc
63 """
64
65 log.debug("Logging into vCD org as admin.")
66
67 admin_user = None
68 try:
69 host = self.vcloud_site
70 admin_user = self.admin_username
71 admin_passwd = self.admin_password
72 org = "System"
73 client = Client(host, verify_ssl_certs=False)
74 client.set_highest_supported_version()
75 client.set_credentials(BasicLoginCredentials(admin_user, org, admin_passwd))
76 return client
77
78 except Exception as e:
79 log.error(
80 "Can't connect to a vCloud director as: {} with exception {}".format(
81 admin_user, e
82 )
83 )
84
85 def get_vim_account(self, vim_account_id: str):
86 """
87 Method to get VIM account details by its ID
88 arg - VIM ID
89 return - dict with vim account details
90 """
91 vim_account = {}
92 vim_account_info = self.common_db.get_vim_account(vim_account_id)
93
94 vim_account["vim_url"] = vim_account_info["vim_url"]
95
96 vim_config = vim_account_info["config"]
97 vim_account["admin_username"] = vim_config["admin_username"]
98 vim_account["admin_password"] = vim_config["admin_password"]
99 vim_account["vrops_site"] = vim_config["vrops_site"]
100 vim_account["vrops_user"] = vim_config["vrops_user"]
101 vim_account["vrops_password"] = vim_config["vrops_password"]
102
103 return vim_account
104
105 def get_vm_moref_id(self, vapp_uuid):
106 """
107 Method to get the moref_id of given VM
108 arg - vapp_uuid
109 return - VM mored_id
110 """
111 vm_moref_id = None
112 try:
113 if vapp_uuid:
114 vm_details = self.get_vapp_details_rest(vapp_uuid)
115
116 if vm_details and "vm_vcenter_info" in vm_details:
117 vm_moref_id = vm_details["vm_vcenter_info"].get("vm_moref_id", None)
118 log.debug(
119 "Found vm_moref_id: {} for vApp UUID: {}".format(
120 vm_moref_id, vapp_uuid
121 )
122 )
123 else:
124 log.error(
125 "Failed to find vm_moref_id from vApp UUID: {}".format(
126 vapp_uuid
127 )
128 )
129
130 except Exception as exp:
131 log.warning(
132 "Error occurred while getting VM moref ID for VM: {}\n{}".format(
133 exp, traceback.format_exc()
134 )
135 )
136
137 return vm_moref_id
138
139 def get_vapp_details_rest(self, vapp_uuid=None):
140 """
141 Method retrieve vapp detail from vCloud director
142 vapp_uuid - is vapp identifier.
143 Returns - VM MOref ID or return None
144 """
145 parsed_respond = {}
146
147 if vapp_uuid is None:
148 return parsed_respond
149
150 vca = self.connect_as_admin()
151
152 if not vca:
153 log.error("Failed to connect to vCD")
154 return parsed_respond
155
156 url_list = [self.vcloud_site, "/api/vApp/vapp-", vapp_uuid]
157 get_vapp_restcall = "".join(url_list)
158
159 if vca._session:
160 headers = {
161 "Accept": "application/*+xml;version=" + API_VERSION,
162 "x-vcloud-authorization": vca._session.headers[
163 "x-vcloud-authorization"
164 ],
165 }
166 response = requests.get(get_vapp_restcall, headers=headers, verify=False)
167
168 if response.status_code != 200:
169 log.error(
170 "REST API call {} failed. Return status code {}".format(
171 get_vapp_restcall, response.content
172 )
173 )
174 return parsed_respond
175
176 try:
177 xmlroot_respond = XmlElementTree.fromstring(response.content)
178
179 namespaces = {
180 "vm": "http://www.vmware.com/vcloud/v1.5",
181 "vmext": "http://www.vmware.com/vcloud/extension/v1.5",
182 "xmlns": "http://www.vmware.com/vcloud/v1.5",
183 }
184
185 # parse children section for other attrib
186 children_section = xmlroot_respond.find("vm:Children/", namespaces)
187 if children_section is not None:
188 vCloud_extension_section = children_section.find(
189 "xmlns:VCloudExtension", namespaces
190 )
191 if vCloud_extension_section is not None:
192 vm_vcenter_info = {}
193 vim_info = vCloud_extension_section.find(
194 "vmext:VmVimInfo", namespaces
195 )
196 vmext = vim_info.find("vmext:VmVimObjectRef", namespaces)
197 if vmext is not None:
198 vm_vcenter_info["vm_moref_id"] = vmext.find(
199 "vmext:MoRef", namespaces
200 ).text
201 parsed_respond["vm_vcenter_info"] = vm_vcenter_info
202
203 except Exception as exp:
204 log.warning(
205 "Error occurred for getting vApp details: {}\n{}".format(
206 exp, traceback.format_exc()
207 )
208 )
209
210 return parsed_respond
211
212 def collect(self, vnfr: dict):
213 vnfd = self.common_db.get_vnfd(vnfr["vnfd-id"])
214 vdu_mappings = {}
215
216 # Populate extra tags for metrics
217 nsr_id = vnfr["nsr-id-ref"]
218 tags = {}
219 tags["ns_name"] = self.common_db.get_nsr(nsr_id)["name"]
220 if vnfr["_admin"]["projects_read"]:
221 tags["project_id"] = vnfr["_admin"]["projects_read"][0]
222 else:
223 tags["project_id"] = ""
224
225 # Fetch the list of all known resources from vROPS.
226 resource_list = self.vrops.get_vm_resource_list_from_vrops()
227
228 for vdur in vnfr["vdur"]:
229 # This avoids errors when vdur records have not been completely filled
230 if "name" not in vdur:
231 continue
232 vdu = next(filter(lambda vdu: vdu["id"] == vdur["vdu-id-ref"], vnfd["vdu"]))
233
234 if "monitoring-parameter" not in vdu:
235 continue
236
237 resource_uuid = vdur["vim-id"]
238 # Find vm_moref_id from vApp uuid in vCD
239 vim_id = self.get_vm_moref_id(resource_uuid)
240 if vim_id is None:
241 log.debug(
242 "Failed to find vROPS ID for vApp in vCD: {}".format(resource_uuid)
243 )
244 continue
245
246 vdu_mappings[vim_id] = {"name": vdur["name"]}
247
248 # Map the vROPS instance id to the vim-id so we can look it up.
249 for resource in resource_list:
250 for resourceIdentifier in resource["resourceKey"][
251 "resourceIdentifiers"
252 ]:
253 if (
254 resourceIdentifier["identifierType"]["name"]
255 == "VMEntityObjectID"
256 ):
257 if resourceIdentifier["value"] != vim_id:
258 continue
259 vdu_mappings[vim_id]["vrops_id"] = resource["identifier"]
260
261 if len(vdu_mappings) != 0:
262 return self.vrops.get_metrics(
263 vdu_mappings=vdu_mappings,
264 monitoring_params=vdu["monitoring-parameter"],
265 vnfr=vnfr,
266 tags=tags,
267 )
268 else:
269 return []