329d61d880fa3ffa8b491bd6d8e12a5ded625180
[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 json
25 import logging
26 import traceback
27 from xml.etree import ElementTree as XmlElementTree
28
29 import requests
30 from pyvcloud.vcd.client import BasicLoginCredentials
31 from pyvcloud.vcd.client import Client
32
33 from osm_mon.collector.utils.collector import CollectorUtils
34 from osm_mon.collector.vnf_collectors.base_vim import BaseVimCollector
35 from osm_mon.core.common_db import CommonDbClient
36 from osm_mon.core.config import Config
37 from osm_mon.collector.vnf_collectors.vrops.vrops_helper import vROPS_Helper
38
39 log = logging.getLogger(__name__)
40
41 API_VERSION = '27.0'
42
43
44 class VMwareCollector(BaseVimCollector):
45 def __init__(self, config: Config, vim_account_id: str):
46 super().__init__(config, vim_account_id)
47 self.common_db = CommonDbClient(config)
48 vim_account = self.get_vim_account(vim_account_id)
49 self.vcloud_site = vim_account['vim_url']
50 self.admin_username = vim_account['admin_username']
51 self.admin_password = vim_account['admin_password']
52 self.vrops = vROPS_Helper(vrops_site=vim_account['vrops_site'],
53 vrops_user=vim_account['vrops_user'],
54 vrops_password=vim_account['vrops_password'])
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,
76 admin_passwd))
77 return client
78
79 except Exception as e:
80 log.error("Can't connect to a vCloud director as: {} with exception {}".format(admin_user, e))
81
82 def get_vim_account(self, vim_account_id: str):
83 """
84 Method to get VIM account details by its ID
85 arg - VIM ID
86 return - dict with vim account details
87 """
88 vim_account = {}
89 vim_account_info = CollectorUtils.get_credentials(vim_account_id)
90
91 vim_account['vim_url'] = vim_account_info.url
92
93 vim_config = json.loads(vim_account_info.config)
94 vim_account['admin_username'] = vim_config['admin_username']
95 vim_account['admin_password'] = vim_config['admin_password']
96 vim_account['vrops_site'] = vim_config['vrops_site']
97 vim_account['vrops_user'] = vim_config['vrops_user']
98 vim_account['vrops_password'] = vim_config['vrops_password']
99
100 return vim_account
101
102 def get_vm_moref_id(self, vapp_uuid):
103 """
104 Method to get the moref_id of given VM
105 arg - vapp_uuid
106 return - VM mored_id
107 """
108 vm_moref_id = None
109 try:
110 if vapp_uuid:
111 vm_details = self.get_vapp_details_rest(vapp_uuid)
112
113 if vm_details and "vm_vcenter_info" in vm_details:
114 vm_moref_id = vm_details["vm_vcenter_info"].get("vm_moref_id", None)
115 log.debug("Found vm_moref_id: {} for vApp UUID: {}".format(vm_moref_id, vapp_uuid))
116 else:
117 log.error("Failed to find vm_moref_id from vApp UUID: {}".format(vapp_uuid))
118
119 except Exception as exp:
120 log.warning("Error occurred while getting VM moref ID for VM: {}\n{}".format(exp, traceback.format_exc()))
121
122 return vm_moref_id
123
124 def get_vapp_details_rest(self, vapp_uuid=None):
125 """
126 Method retrieve vapp detail from vCloud director
127 vapp_uuid - is vapp identifier.
128 Returns - VM MOref ID or return None
129 """
130 parsed_respond = {}
131
132 if vapp_uuid is None:
133 return parsed_respond
134
135 vca = self.connect_as_admin()
136
137 if not vca:
138 log.error("Failed to connect to vCD")
139 return parsed_respond
140
141 url_list = [self.vcloud_site, '/api/vApp/vapp-', vapp_uuid]
142 get_vapp_restcall = ''.join(url_list)
143
144 if vca._session:
145 headers = {'Accept': 'application/*+xml;version=' + API_VERSION,
146 'x-vcloud-authorization': vca._session.headers['x-vcloud-authorization']}
147 response = requests.get(get_vapp_restcall,
148 headers=headers,
149 verify=False)
150
151 if response.status_code != 200:
152 log.error("REST API call {} failed. Return status code {}".format(get_vapp_restcall,
153 response.content))
154 return parsed_respond
155
156 try:
157 xmlroot_respond = XmlElementTree.fromstring(response.content)
158
159 namespaces = {'vm': 'http://www.vmware.com/vcloud/v1.5',
160 "vmext": "http://www.vmware.com/vcloud/extension/v1.5",
161 "xmlns": "http://www.vmware.com/vcloud/v1.5"}
162
163 # parse children section for other attrib
164 children_section = xmlroot_respond.find('vm:Children/', namespaces)
165 if children_section is not None:
166 vCloud_extension_section = children_section.find('xmlns:VCloudExtension', namespaces)
167 if vCloud_extension_section is not None:
168 vm_vcenter_info = {}
169 vim_info = vCloud_extension_section.find('vmext:VmVimInfo', namespaces)
170 vmext = vim_info.find('vmext:VmVimObjectRef', namespaces)
171 if vmext is not None:
172 vm_vcenter_info["vm_moref_id"] = vmext.find('vmext:MoRef', namespaces).text
173 parsed_respond["vm_vcenter_info"] = vm_vcenter_info
174
175 except Exception as exp:
176 log.warning("Error occurred for getting vApp details: {}\n{}".format(exp,
177 traceback.format_exc()))
178
179 return parsed_respond
180
181 def collect(self, vnfr: dict):
182 vnfd = self.common_db.get_vnfd(vnfr['vnfd-id'])
183 vdu_mappings = {}
184
185 # Fetch the list of all known resources from vROPS.
186 resource_list = self.vrops.get_vm_resource_list_from_vrops()
187
188 for vdur in vnfr['vdur']:
189 # This avoids errors when vdur records have not been completely filled
190 if 'name' not in vdur:
191 continue
192 vdu = next(
193 filter(lambda vdu: vdu['id'] == vdur['vdu-id-ref'], vnfd['vdu'])
194 )
195
196 if 'monitoring-param' not in vdu:
197 continue
198
199 resource_uuid = vdur['vim-id']
200 # Find vm_moref_id from vApp uuid in vCD
201 vim_id = self.get_vm_moref_id(resource_uuid)
202 if vim_id is None:
203 log.debug("Failed to find vROPS ID for vApp in vCD: {}".format(resource_uuid))
204 continue
205
206 vdu_mappings[vim_id] = {'name': vdur['name']}
207
208 # Map the vROPS instance id to the vim-id so we can look it up.
209 for resource in resource_list:
210 for resourceIdentifier in resource['resourceKey']['resourceIdentifiers']:
211 if resourceIdentifier['identifierType']['name'] == 'VMEntityObjectID':
212 if resourceIdentifier['value'] != vim_id:
213 continue
214 vdu_mappings[vim_id]['vrops_id'] = resource['identifier']
215
216 if len(vdu_mappings) != 0:
217 return self.vrops.get_metrics(vdu_mappings=vdu_mappings,
218 monitoring_params=vdu['monitoring-param'],
219 vnfr=vnfr)
220 else:
221 return []