Modifies MON to use mongodb directly for vim info and do vim pass decryption on demand
[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'] = self.common_db.decrypt_vim_password(vim_config['admin_password'],
94 vim_account_info['schema_version'],
95 vim_account_id)
96 vim_account['vrops_site'] = vim_config['vrops_site']
97 vim_account['vrops_user'] = vim_config['vrops_user']
98 vim_account['vrops_password'] = self.common_db.decrypt_vim_password(vim_config['vrops_password'],
99 vim_account_info['schema_version'],
100 vim_account_id)
101
102 return vim_account
103
104 def get_vm_moref_id(self, vapp_uuid):
105 """
106 Method to get the moref_id of given VM
107 arg - vapp_uuid
108 return - VM mored_id
109 """
110 vm_moref_id = None
111 try:
112 if vapp_uuid:
113 vm_details = self.get_vapp_details_rest(vapp_uuid)
114
115 if vm_details and "vm_vcenter_info" in vm_details:
116 vm_moref_id = vm_details["vm_vcenter_info"].get("vm_moref_id", None)
117 log.debug("Found vm_moref_id: {} for vApp UUID: {}".format(vm_moref_id, vapp_uuid))
118 else:
119 log.error("Failed to find vm_moref_id from vApp UUID: {}".format(vapp_uuid))
120
121 except Exception as exp:
122 log.warning("Error occurred while getting VM moref ID for VM: {}\n{}".format(exp, traceback.format_exc()))
123
124 return vm_moref_id
125
126 def get_vapp_details_rest(self, vapp_uuid=None):
127 """
128 Method retrieve vapp detail from vCloud director
129 vapp_uuid - is vapp identifier.
130 Returns - VM MOref ID or return None
131 """
132 parsed_respond = {}
133
134 if vapp_uuid is None:
135 return parsed_respond
136
137 vca = self.connect_as_admin()
138
139 if not vca:
140 log.error("Failed to connect to vCD")
141 return parsed_respond
142
143 url_list = [self.vcloud_site, '/api/vApp/vapp-', vapp_uuid]
144 get_vapp_restcall = ''.join(url_list)
145
146 if vca._session:
147 headers = {'Accept': 'application/*+xml;version=' + API_VERSION,
148 'x-vcloud-authorization': vca._session.headers['x-vcloud-authorization']}
149 response = requests.get(get_vapp_restcall,
150 headers=headers,
151 verify=False)
152
153 if response.status_code != 200:
154 log.error("REST API call {} failed. Return status code {}".format(get_vapp_restcall,
155 response.content))
156 return parsed_respond
157
158 try:
159 xmlroot_respond = XmlElementTree.fromstring(response.content)
160
161 namespaces = {'vm': 'http://www.vmware.com/vcloud/v1.5',
162 "vmext": "http://www.vmware.com/vcloud/extension/v1.5",
163 "xmlns": "http://www.vmware.com/vcloud/v1.5"}
164
165 # parse children section for other attrib
166 children_section = xmlroot_respond.find('vm:Children/', namespaces)
167 if children_section is not None:
168 vCloud_extension_section = children_section.find('xmlns:VCloudExtension', namespaces)
169 if vCloud_extension_section is not None:
170 vm_vcenter_info = {}
171 vim_info = vCloud_extension_section.find('vmext:VmVimInfo', namespaces)
172 vmext = vim_info.find('vmext:VmVimObjectRef', namespaces)
173 if vmext is not None:
174 vm_vcenter_info["vm_moref_id"] = vmext.find('vmext:MoRef', namespaces).text
175 parsed_respond["vm_vcenter_info"] = vm_vcenter_info
176
177 except Exception as exp:
178 log.warning("Error occurred for getting vApp details: {}\n{}".format(exp,
179 traceback.format_exc()))
180
181 return parsed_respond
182
183 def collect(self, vnfr: dict):
184 vnfd = self.common_db.get_vnfd(vnfr['vnfd-id'])
185 vdu_mappings = {}
186
187 # Fetch the list of all known resources from vROPS.
188 resource_list = self.vrops.get_vm_resource_list_from_vrops()
189
190 for vdur in vnfr['vdur']:
191 # This avoids errors when vdur records have not been completely filled
192 if 'name' not in vdur:
193 continue
194 vdu = next(
195 filter(lambda vdu: vdu['id'] == vdur['vdu-id-ref'], vnfd['vdu'])
196 )
197
198 if 'monitoring-param' not in vdu:
199 continue
200
201 resource_uuid = vdur['vim-id']
202 # Find vm_moref_id from vApp uuid in vCD
203 vim_id = self.get_vm_moref_id(resource_uuid)
204 if vim_id is None:
205 log.debug("Failed to find vROPS ID for vApp in vCD: {}".format(resource_uuid))
206 continue
207
208 vdu_mappings[vim_id] = {'name': vdur['name']}
209
210 # Map the vROPS instance id to the vim-id so we can look it up.
211 for resource in resource_list:
212 for resourceIdentifier in resource['resourceKey']['resourceIdentifiers']:
213 if resourceIdentifier['identifierType']['name'] == 'VMEntityObjectID':
214 if resourceIdentifier['value'] != vim_id:
215 continue
216 vdu_mappings[vim_id]['vrops_id'] = resource['identifier']
217
218 if len(vdu_mappings) != 0:
219 return self.vrops.get_metrics(vdu_mappings=vdu_mappings,
220 monitoring_params=vdu['monitoring-param'],
221 vnfr=vnfr)
222 else:
223 return []