Collect null project_ids as empty strings
[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):
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(vrops_site=vim_account['vrops_site'],
51 vrops_user=vim_account['vrops_user'],
52 vrops_password=vim_account['vrops_password'])
53
54 def connect_as_admin(self):
55 """ Method connect as pvdc admin user to vCloud director.
56 There are certain action that can be done only by provider vdc admin user.
57 Organization creation / provider network creation etc.
58
59 Returns:
60 The return client object that letter can be used to connect to vcloud direct as admin for provider vdc
61 """
62
63 log.debug("Logging into vCD org as admin.")
64
65 admin_user = None
66 try:
67 host = self.vcloud_site
68 admin_user = self.admin_username
69 admin_passwd = self.admin_password
70 org = 'System'
71 client = Client(host, verify_ssl_certs=False)
72 client.set_highest_supported_version()
73 client.set_credentials(BasicLoginCredentials(admin_user, org,
74 admin_passwd))
75 return client
76
77 except Exception as e:
78 log.error("Can't connect to a vCloud director as: {} with exception {}".format(admin_user, e))
79
80 def get_vim_account(self, vim_account_id: str):
81 """
82 Method to get VIM account details by its ID
83 arg - VIM ID
84 return - dict with vim account details
85 """
86 vim_account = {}
87 vim_account_info = self.common_db.get_vim_account(vim_account_id)
88
89 vim_account['vim_url'] = vim_account_info['vim_url']
90
91 vim_config = vim_account_info['config']
92 vim_account['admin_username'] = vim_config['admin_username']
93 vim_account['admin_password'] = vim_config['admin_password']
94 vim_account['vrops_site'] = vim_config['vrops_site']
95 vim_account['vrops_user'] = vim_config['vrops_user']
96 vim_account['vrops_password'] = vim_config['vrops_password']
97
98 return vim_account
99
100 def get_vm_moref_id(self, vapp_uuid):
101 """
102 Method to get the moref_id of given VM
103 arg - vapp_uuid
104 return - VM mored_id
105 """
106 vm_moref_id = None
107 try:
108 if vapp_uuid:
109 vm_details = self.get_vapp_details_rest(vapp_uuid)
110
111 if vm_details and "vm_vcenter_info" in vm_details:
112 vm_moref_id = vm_details["vm_vcenter_info"].get("vm_moref_id", None)
113 log.debug("Found vm_moref_id: {} for vApp UUID: {}".format(vm_moref_id, vapp_uuid))
114 else:
115 log.error("Failed to find vm_moref_id from vApp UUID: {}".format(vapp_uuid))
116
117 except Exception as exp:
118 log.warning("Error occurred while getting VM moref ID for VM: {}\n{}".format(exp, traceback.format_exc()))
119
120 return vm_moref_id
121
122 def get_vapp_details_rest(self, vapp_uuid=None):
123 """
124 Method retrieve vapp detail from vCloud director
125 vapp_uuid - is vapp identifier.
126 Returns - VM MOref ID or return None
127 """
128 parsed_respond = {}
129
130 if vapp_uuid is None:
131 return parsed_respond
132
133 vca = self.connect_as_admin()
134
135 if not vca:
136 log.error("Failed to connect to vCD")
137 return parsed_respond
138
139 url_list = [self.vcloud_site, '/api/vApp/vapp-', vapp_uuid]
140 get_vapp_restcall = ''.join(url_list)
141
142 if vca._session:
143 headers = {'Accept': 'application/*+xml;version=' + API_VERSION,
144 'x-vcloud-authorization': vca._session.headers['x-vcloud-authorization']}
145 response = requests.get(get_vapp_restcall,
146 headers=headers,
147 verify=False)
148
149 if response.status_code != 200:
150 log.error("REST API call {} failed. Return status code {}".format(get_vapp_restcall,
151 response.content))
152 return parsed_respond
153
154 try:
155 xmlroot_respond = XmlElementTree.fromstring(response.content)
156
157 namespaces = {'vm': 'http://www.vmware.com/vcloud/v1.5',
158 "vmext": "http://www.vmware.com/vcloud/extension/v1.5",
159 "xmlns": "http://www.vmware.com/vcloud/v1.5"}
160
161 # parse children section for other attrib
162 children_section = xmlroot_respond.find('vm:Children/', namespaces)
163 if children_section is not None:
164 vCloud_extension_section = children_section.find('xmlns:VCloudExtension', namespaces)
165 if vCloud_extension_section is not None:
166 vm_vcenter_info = {}
167 vim_info = vCloud_extension_section.find('vmext:VmVimInfo', namespaces)
168 vmext = vim_info.find('vmext:VmVimObjectRef', namespaces)
169 if vmext is not None:
170 vm_vcenter_info["vm_moref_id"] = vmext.find('vmext:MoRef', namespaces).text
171 parsed_respond["vm_vcenter_info"] = vm_vcenter_info
172
173 except Exception as exp:
174 log.warning("Error occurred for getting vApp details: {}\n{}".format(exp,
175 traceback.format_exc()))
176
177 return parsed_respond
178
179 def collect(self, vnfr: dict):
180 vnfd = self.common_db.get_vnfd(vnfr['vnfd-id'])
181 vdu_mappings = {}
182
183 # Populate extra tags for metrics
184 nsr_id = vnfr['nsr-id-ref']
185 tags = {}
186 tags['ns_name'] = self.common_db.get_nsr(nsr_id)['name']
187 if vnfr['_admin']['projects_read']:
188 tags['project_id'] = vnfr['_admin']['projects_read'][0]
189 else:
190 tags['project_id'] = ''
191
192 # Fetch the list of all known resources from vROPS.
193 resource_list = self.vrops.get_vm_resource_list_from_vrops()
194
195 for vdur in vnfr['vdur']:
196 # This avoids errors when vdur records have not been completely filled
197 if 'name' not in vdur:
198 continue
199 vdu = next(
200 filter(lambda vdu: vdu['id'] == vdur['vdu-id-ref'], vnfd['vdu'])
201 )
202
203 if 'monitoring-param' not in vdu:
204 continue
205
206 resource_uuid = vdur['vim-id']
207 # Find vm_moref_id from vApp uuid in vCD
208 vim_id = self.get_vm_moref_id(resource_uuid)
209 if vim_id is None:
210 log.debug("Failed to find vROPS ID for vApp in vCD: {}".format(resource_uuid))
211 continue
212
213 vdu_mappings[vim_id] = {'name': vdur['name']}
214
215 # Map the vROPS instance id to the vim-id so we can look it up.
216 for resource in resource_list:
217 for resourceIdentifier in resource['resourceKey']['resourceIdentifiers']:
218 if resourceIdentifier['identifierType']['name'] == 'VMEntityObjectID':
219 if resourceIdentifier['value'] != vim_id:
220 continue
221 vdu_mappings[vim_id]['vrops_id'] = resource['identifier']
222
223 if len(vdu_mappings) != 0:
224 return self.vrops.get_metrics(vdu_mappings=vdu_mappings,
225 monitoring_params=vdu['monitoring-param'],
226 vnfr=vnfr,
227 tags=tags
228 )
229 else:
230 return []