1 # -*- coding: utf-8 -*-
3 # Copyright 2018 Whitestack, LLC
4 # *************************************************************
6 # This file is part of OSM Monitoring module
7 # All Rights Reserved to Whitestack, LLC
9 # Licensed under the Apache License, Version 2.0 (the "License"); you may
10 # not use this file except in compliance with the License. You may obtain
11 # a copy of the License at
13 # http://www.apache.org/licenses/LICENSE-2.0
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18 # License for the specific language governing permissions and limitations
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact: glavado@whitestack.com or fbravo@whitestack.com
27 from osm_mon
.core
.config
import Config
29 log
= logging
.getLogger(__name__
)
33 def __init__(self
, config
: Config
):
35 self
.url
= config
.get("grafana", "url")
36 grafana_user
= config
.get("grafana", "user")
37 grafana_password
= config
.get("grafana", "password")
39 "content-type": "application/json",
40 "authorization": "Basic %s"
42 (grafana_user
+ ":" + grafana_password
).encode("utf-8")
46 def get_all_dashboard_uids(self
):
47 # Gets only dashboards that were automated by OSM (with tag 'osm_automated')
48 response
= requests
.request(
49 "GET", self
.url
+ "/api/search?tag=osm_automated", headers
=self
.headers
51 dashboards
= response
.json()
53 for dashboard
in dashboards
:
54 dashboard_uids
.append(dashboard
["uid"])
55 log
.debug("Searching for all dashboard uids: %s", dashboard_uids
)
58 def get_all_datasource_names(self
, datasource_name_substr
):
59 # Gets only dashboards that were created for prom-operator
60 response
= requests
.request(
61 "GET", self
.url
+ "/api/datasources", headers
=self
.headers
63 datasources
= response
.json()
65 for datasource
in datasources
:
66 if datasource
["name"].startswith(datasource_name_substr
):
67 datasource_names
.append(datasource
["name"])
68 log
.debug("Searching for all datasource names: %s", datasource_names
)
69 return datasource_names
71 def get_dashboard_status(self
, uid
):
72 response
= requests
.request(
73 "GET", self
.url
+ "/api/dashboards/uid/" + uid
, headers
=self
.headers
75 log
.debug("Searching for dashboard result: %s", response
.text
)
79 self
, uid
, name
, json_file
, project_name
=None, datasource_name
=None
82 with
open(json_file
) as f
:
83 dashboard_data
= f
.read()
85 dashboard_data
= dashboard_data
.replace("OSM_ID", uid
).replace(
89 dashboard_data
= dashboard_data
.replace(
90 "OSM_DATASOURCE_NAME", datasource_name
92 dashboard_json_data
= json
.loads(dashboard_data
)
95 folder_name
= project_name
98 response_folder_id
= requests
.request(
100 self
.url
+ "/api/folders/{}".format(folder_name
),
101 headers
=self
.headers
,
103 if response_folder_id
.status_code
== 200:
104 folder_id
= json
.loads(response_folder_id
.text
)["id"]
105 dashboard_json_data
["folderId"] = folder_id
106 dashboard_json_data
["overwrite"] = False
108 response
= self
.send_request_for_creating_dashboard(dashboard_json_data
)
110 # Admin dashboard will be created if already exists. Rest will remain same.
111 if json
.loads(response
.text
).get("status") == "name-exists":
112 # Delete any previous project-admin dashboard if it already exist.
114 self
.delete_admin_dashboard()
115 response
= self
.send_request_for_creating_dashboard(
122 if project_name
is not None:
124 response_team
= requests
.request(
126 self
.url
+ "/api/teams/search?name={}".format(name
),
127 headers
=self
.headers
,
130 # Remove default permissions of admin user's dashboard so that it is not visible to non-admin users
131 if len(json
.loads(response_team
.text
)["teams"]) == 0:
132 # As team information is not available so it is admin user
133 dahboard_id
= json
.loads(response
.text
)["id"]
136 self
.url
+ "/api/dashboards/id/{}/permissions".format(dahboard_id
),
137 headers
=self
.headers
,
140 log
.info("Dashboard %s is created in Grafana", name
)
143 log
.exception("Exception processing message: ")
145 def create_datasource(self
, datasource_name
, datasource_type
, datasource_url
):
148 "name": datasource_name
,
149 "type": datasource_type
,
150 "url": datasource_url
,
155 response
= requests
.request(
157 self
.url
+ "/api/datasources",
158 data
=json
.dumps(datasource_data
),
159 headers
=self
.headers
,
161 log
.info("Datasource %s is created in Grafana", datasource_name
)
162 log
.info("************* response: {}".format(response
.__dict
__))
165 log
.exception("Exception processing request for creating datasource: ")
167 def send_request_for_creating_dashboard(self
, dashboard_data
):
168 response
= requests
.request(
170 self
.url
+ "/api/dashboards/db/",
171 data
=json
.dumps(dashboard_data
),
172 headers
=self
.headers
,
176 def delete_dashboard(self
, uid
):
177 response
= requests
.request(
178 "DELETE", self
.url
+ "/api/dashboards/uid/" + uid
, headers
=self
.headers
180 log
.debug("Dashboard %s deleted from Grafana", uid
)
183 def delete_datasource(self
, datasource_name
):
184 response
= requests
.request(
186 self
.url
+ "/api/datasources/name/" + datasource_name
,
187 headers
=self
.headers
,
189 log
.debug("Datasource %s deleted from Grafana", datasource_name
)
192 def delete_admin_dashboard(self
):
195 self
.url
+ "/api/dashboards/db/osm-project-status-admin",
196 headers
=self
.headers
,
198 log
.debug("Dashboard osm-project-status-admin deleted from Grafana")
200 def create_grafana_users(self
, user
):
201 email
= "{}@osm.etsi.org".format(user
)
208 response_users
= requests
.request(
210 self
.url
+ "/api/admin/users/",
212 headers
=self
.headers
,
214 json_data
= json
.loads(response_users
.text
)
215 url
= "/api/org/users/{}/".format(json_data
["id"])
216 permission_payload
= {
220 "PATCH", self
.url
+ url
, json
=permission_payload
, headers
=self
.headers
222 log
.info("New user %s created in Grafana", user
)
223 return response_users
226 def get_grafana_users(self
):
227 response_users
= requests
.request(
229 self
.url
+ "/api/users",
230 headers
=self
.headers
,
233 users
= json
.loads(response_users
.text
)
235 if user
["name"] and user
["name"] != "admin":
236 user_list
.append(user
["name"])
239 # Create Grafana team with member
240 def create_grafana_teams_members(
241 self
, project_name
, user_name
, is_admin
, proj_list
243 # Check if user exist in Grafana
244 user_response
= requests
.request(
246 self
.url
+ "/api/users/lookup?loginOrEmail={}".format(user_name
),
247 headers
=self
.headers
,
249 user_obj
= json
.loads(user_response
.text
)
250 if user_response
.status_code
!= 200:
251 user_response
= self
.create_grafana_users(user_name
)
252 user_obj
= json
.loads(user_response
.text
)
254 user_id
= user_obj
["id"]
257 team_objs
= requests
.request(
259 self
.url
+ "/api/users/{}/teams".format(user_id
),
260 headers
=self
.headers
,
262 team_obj
= json
.loads(team_objs
.text
)
265 for team
in team_obj
:
266 team_list
.append(team
["name"])
268 proj_unlink
= set(team_list
) - set(proj_list
)
269 for prj
in proj_unlink
:
270 response_team
= requests
.request(
272 self
.url
+ "/api/teams/search?name={}".format(prj
),
273 headers
=self
.headers
,
275 team_id
= json
.loads(response_team
.text
)["teams"][0]["id"]
278 self
.url
+ "/api/teams/{}/members/{}".format(team_id
, user_id
),
279 headers
=self
.headers
,
281 if project_name
!= "admin":
283 response_team
= requests
.request(
285 self
.url
+ "/api/teams/search?name={}".format(project_name
),
286 headers
=self
.headers
,
289 # Search if team in Grafana corresponding to the project already exists
290 if not json
.loads(response_team
.text
)["teams"]:
291 self
.create_grafana_teams(project_name
)
292 response_team
= requests
.request(
294 self
.url
+ "/api/teams/search?name={}".format(project_name
),
295 headers
=self
.headers
,
297 team_id
= json
.loads(response_team
.text
)["teams"][0]["id"]
298 if project_name
not in team_list
:
299 # Create a team in Grafana corresponding to the project as it doesn't exist
300 member_payload
= {"userId": user_id
}
303 self
.url
+ "/api/teams/{}/members".format(team_id
),
305 headers
=self
.headers
,
307 # Check if user role or project name is admin
308 if is_admin
or project_name
== "admin":
309 # Give admin righsts to user
310 url
= "/api/org/users/{}/".format(user_id
)
311 permission_payload
= {
315 "PATCH", self
.url
+ url
, json
=permission_payload
, headers
=self
.headers
317 log
.info("User %s is assigned Admin permission", user_name
)
319 # Give editor rights to user
320 url
= "/api/org/users/{}/".format(user_id
)
321 permission_payload
= {
325 "PATCH", self
.url
+ url
, json
=permission_payload
, headers
=self
.headers
327 log
.info("User %s is assigned Editor permission", user_name
)
329 # Create team in Grafana
330 def create_grafana_teams(self
, team_name
):
335 "POST", self
.url
+ "/api/teams", json
=team_payload
, headers
=self
.headers
337 log
.info("New team %s created in Grafana", team_name
)
339 # Create folder in Grafana
340 def create_grafana_folders(self
, folder_name
):
341 folder_payload
= {"uid": folder_name
, "title": folder_name
}
343 "POST", self
.url
+ "/api/folders", json
=folder_payload
, headers
=self
.headers
345 log
.info("Dashboard folder %s created", folder_name
)
347 response_team
= requests
.request(
349 self
.url
+ "/api/teams/search?name={}".format(folder_name
),
350 headers
=self
.headers
,
352 # Create team if it doesn't already exists
353 if len(json
.loads(response_team
.text
)["teams"]) == 0:
354 self
.create_grafana_teams(folder_name
)
355 response_team
= requests
.request(
357 self
.url
+ "/api/teams/search?name={}".format(folder_name
),
358 headers
=self
.headers
,
360 # Assign required permission to the team's folder
361 team_id
= json
.loads(response_team
.text
)["teams"][0]["id"]
364 {"teamId": team_id
, "permission": 2},
369 self
.url
+ "/api/folders/{}/permissions".format(folder_name
),
370 json
=permission_data
,
371 headers
=self
.headers
,
374 # delete user from grafana
375 def delete_grafana_users(self
, user_name
):
377 response_id
= requests
.request(
379 self
.url
+ "/api/users/lookup?loginOrEmail={}".format(user_name
),
380 headers
=self
.headers
,
383 user_id
= json
.loads(response_id
.text
)["id"]
385 log
.exception("Exception processing message: ")
387 response
= requests
.request(
389 self
.url
+ "/api/admin/users/{}".format(user_id
),
390 headers
=self
.headers
,
392 log
.info("User %s deleted in Grafana", user_name
)
395 # delete team from grafana
396 def delete_grafana_team(self
, project_name
):
397 # Delete Grafana folder
400 self
.url
+ "/api/folders/{}".format(project_name
),
401 headers
=self
.headers
,
403 # Delete Grafana team
404 team_obj
= requests
.request(
406 self
.url
+ "/api/teams/search?name={}".format(project_name
),
407 headers
=self
.headers
,
409 team_id
= json
.loads(team_obj
.text
)["teams"][0]["id"]
410 response
= requests
.request(
411 "DELETE", self
.url
+ "/api/teams/{}".format(team_id
), headers
=self
.headers
413 log
.info("Team %s deleted in Grafana", project_name
)
416 # update grafana team
417 def update_grafana_teams(self
, project_new_name
, project_old_name
):
418 team_obj
= requests
.request(
420 self
.url
+ "/api/teams/search?name={}".format(project_old_name
),
421 headers
=self
.headers
,
423 team_id
= json
.loads(team_obj
.text
)["teams"][0]["id"]
425 "name": project_new_name
,
427 response
= requests
.request(
429 self
.url
+ "/api/teams/{}".format(team_id
),
431 headers
=self
.headers
,
433 log
.info("Grafana team updated %s", response
.text
)
436 # remove member from grafana team
437 def remove_grafana_team_member(self
, user_name
, project_data
):
439 response_id
= requests
.request(
441 self
.url
+ "/api/users/lookup?loginOrEmail={}".format(user_name
),
442 headers
=self
.headers
,
444 user_id
= json
.loads(response_id
.text
)["id"]
445 for project
in project_data
:
447 team_obj
= requests
.request(
449 self
.url
+ "/api/teams/search?name={}".format(project
["project"]),
450 headers
=self
.headers
,
452 team_id
= json
.loads(team_obj
.text
)["teams"][0]["id"]
453 response
= requests
.request(
455 self
.url
+ "/api/teams/{}/members/{}".format(team_id
, user_id
),
456 headers
=self
.headers
,