From 806fe459500347c2ed0b8c787aae2d94b709d836 Mon Sep 17 00:00:00 2001 From: Atul Agarwal Date: Mon, 15 Mar 2021 09:16:09 +0000 Subject: [PATCH] Fix for bug 1447 Grafana user not associated with team Change-Id: I69aced0620b1bbf8d79f862ee9bf352d1ea9b4d5 Signed-off-by: palsus Signed-off-by: Atul Agarwal --- osm_mon/core/common_db.py | 3 + osm_mon/core/keystone.py | 30 ++++++++ osm_mon/dashboarder/backends/grafana.py | 18 +++++ osm_mon/dashboarder/dashboarder.py | 36 ++++++++- osm_mon/dashboarder/service.py | 99 ++++++++++++++++++++----- 5 files changed, 164 insertions(+), 22 deletions(-) diff --git a/osm_mon/core/common_db.py b/osm_mon/core/common_db.py index ce44d4d..aa65388 100644 --- a/osm_mon/core/common_db.py +++ b/osm_mon/core/common_db.py @@ -162,3 +162,6 @@ class CommonDbClient: def get_role_by_name(self, name: str): return self.common_db.get_one('roles', {'name': name}) + + def get_role_by_id(self, role_id: str): + return self.common_db.get_one('roles', {'_id': role_id}) diff --git a/osm_mon/core/keystone.py b/osm_mon/core/keystone.py index 98a8d78..f389085 100644 --- a/osm_mon/core/keystone.py +++ b/osm_mon/core/keystone.py @@ -57,8 +57,38 @@ class KeystoneConnection: """ return self.keystone_client.projects.list() + def getProjectsById(self, user_id): + """ + Grabs projects filtered by user ID from keystone using the client and session build in the constructor + """ + return self.keystone_client.projects.list(user=user_id) + def getUserById(self, user_id): """ Grabs user object from keystone using user id """ return self.keystone_client.users.get(user_id) + + def getRoleById(self, role_id): + """ + Grabs role object from keystone using id + """ + return self.keystone_client.roles.get(role_id) + + def getRoleByName(self, role): + """ + Grabs role object from keystone using name + """ + return self.keystone_client.roles.list(name=role) + + def getProjectsByProjectId(self, project_id): + """ + Grabs projects object from keystone using id + """ + return self.keystone_client.projects.get(project_id) + + def getProjectsByProjectName(self, project): + """ + Grabs projects object from keystone name + """ + return self.keystone_client.projects.list(name=project) diff --git a/osm_mon/dashboarder/backends/grafana.py b/osm_mon/dashboarder/backends/grafana.py index eeb5e75..a1cbcba 100644 --- a/osm_mon/dashboarder/backends/grafana.py +++ b/osm_mon/dashboarder/backends/grafana.py @@ -207,6 +207,7 @@ class GrafanaBackend: requests.request("POST", self.url + "/api/folders/{}/permissions".format(folder_name), json=permission_data, headers=self.headers) + # delete user from grafana def delete_grafana_users(self, user_name): # Get user id response_id = requests.request("GET", self.url + "/api/users/lookup?loginOrEmail={}".format(user_name), @@ -220,6 +221,7 @@ class GrafanaBackend: log.info("User %s deleted in Grafana", user_name) return response + # delete team from grafana def delete_grafana_team(self, project_name): # Delete Grafana folder requests.request("DELETE", self.url + "/api/folders/{}".format(project_name), @@ -232,6 +234,7 @@ class GrafanaBackend: log.info("Team %s deleted in Grafana", project_name) return response + # update grafana team def update_grafana_teams(self, project_new_name, project_old_name): team_obj = requests.request("GET", self.url + "/api/teams/search?name={}".format(project_old_name), headers=self.headers) @@ -240,3 +243,18 @@ class GrafanaBackend: response = requests.request("PUT", self.url + "/api/teams/{}".format(team_id), json=data, headers=self.headers) log.info("Grafana team updated %s", response.text) return response + + # remove member from grafana team + def remove_grafana_team_member(self, user_name, project_data): + # Get user id + response_id = requests.request("GET", self.url + "/api/users/lookup?loginOrEmail={}".format(user_name), + headers=self.headers) + user_id = json.loads(response_id.text)["id"] + for project in project_data: + # Get team id + team_obj = requests.request("GET", self.url + "/api/teams/search?name={}".format(project['project']), + headers=self.headers) + team_id = json.loads(team_obj.text)["teams"][0]["id"] + response = requests.request("DELETE", self.url + "/api/teams/{}/members/{}".format(team_id, user_id), + headers=self.headers) + return response diff --git a/osm_mon/dashboarder/dashboarder.py b/osm_mon/dashboarder/dashboarder.py index a6ff5bc..35364d6 100644 --- a/osm_mon/dashboarder/dashboarder.py +++ b/osm_mon/dashboarder/dashboarder.py @@ -55,8 +55,28 @@ class Dashboarder: try: if topic == "users" and key == "created": log.debug("Received message from kafka for creating user") - user = values['username'] + if values.get('username'): + user = values['username'] + else: + user = values['changes']['username'] self.service.create_grafana_user(user) + # user-created and mapping is done with osm cli + if values.get('changes'): + # user-project-role mapping is included in change + if values['changes'].get('project_role_mappings'): + user_id = values["_id"] + project_data = values["changes"]["project_role_mappings"] + project_list = values["changes"].get("projects") + self.service.create_grafana_team_member(project_data, user_id, project_list) + elif values.get('project_role_mappings'): + # for fresh project-role-mapping + user_id = values.get("_id") + project_data = values["project_role_mappings"] + if user_id: + self.service.create_grafana_team_member(project_data, user_id) + else: + # for keystone we will get username + self.service.create_grafana_team_member(project_data, user=values['username']) elif topic == "users" and key == "deleted": log.debug("Received message from kafka for deleting user") user = values['username'] @@ -64,8 +84,18 @@ class Dashboarder: elif topic == "users" and key == "edited": log.debug("Received message from kafka for associating user to team") user_id = values["_id"] - project_data = values["changes"]["project_role_mappings"] - self.service.create_grafana_team_member(project_data, user_id) + if values["changes"].get("remove_project_role_mappings") and not \ + values["changes"].get("add_project_role_mappings"): + # Removing user-project role mapping + self.service.remove_grafana_team_members(user_id, + values["changes"].get("remove_project_role_mappings")) + else: + # Changing user project role mapping + if values["changes"].get("project_role_mappings"): + project_data = values["changes"]["project_role_mappings"] + else: + project_data = values["changes"]["add_project_role_mappings"] + self.service.create_grafana_team_member(project_data, user_id) elif topic == "project" and key == "created": log.debug("Received message from kafka for creating team") team_name = values["name"] diff --git a/osm_mon/dashboarder/service.py b/osm_mon/dashboarder/service.py index 79cccb4..d791fa9 100644 --- a/osm_mon/dashboarder/service.py +++ b/osm_mon/dashboarder/service.py @@ -135,27 +135,72 @@ class DashboarderService: def create_grafana_user(self, user): self.grafana.create_grafana_users(user) - def create_grafana_team_member(self, project_data, userid): - try: - # Get user details from commondb - user = self.common_db.get_user_by_id(userid) - user_name = user["username"] - except Exception as e: - # User not found in commondb + def create_grafana_team_member(self, project_data, userid=None, project_list=None, user=None): + if user: + user_name = user + else: + try: + # Get user details from commondb + user = self.common_db.get_user_by_id(userid) + user_name = user["username"] + except Exception as e: + # User not found in commondb + if self.keystone: + # Search user in keystone + user = self.keystone.getUserById(userid) + user_name = user.name + else: + log.info('User %s not found', userid) + log.debug('Exception %s' % e) + if project_list: + # user-project mapping is done by osm cli + for proj in project_data: + project = self.common_db.get_project(proj["project"]) + proj_name = project['name'] + role_obj = self.common_db.get_role_by_id(proj["role"]) + is_admin = role_obj["permissions"].get("admin") + self.grafana.create_grafana_teams_members(proj_name, user_name, is_admin, project_list) + else: + # user-project mapping is done by osm ui + proj_list = [] if self.keystone: - # Serach user in keystone - user = self.keystone.getUserById(userid) - user_name = user.name + users_proj_list = self.keystone.getProjectsById(userid) + for project in users_proj_list: + proj_list.append(project.name) else: - log.info('User %s not found', userid) - log.debug('Exception %s' % e) - proj_list = [] - for project in project_data: - proj_list.append(project["project"]) - for proj in project_data: - role_obj = self.common_db.get_role_by_name(proj["role"]) - is_admin = role_obj["permissions"].get("admin") - self.grafana.create_grafana_teams_members(proj["project"], user_name, is_admin, proj_list) + users_proj_list = user.get("project_role_mappings") + for project in users_proj_list: + proj_data = self.common_db.get_project(project["project"]) + proj_list.append(proj_data['name']) + for proj in project_data: + if self.keystone: + # Backend authentication type is keystone + try: + # Getting project and role objects from keystone using ids + role_obj = self.keystone.getRoleById(proj["role"]) + proj_data = self.keystone.getProjectsByProjectId(proj["project"]) + log.info('role object {} {}'.format(role_obj.permissions, proj_data.name)) + is_admin = role_obj.permissions['admin'] + except Exception: + # Getting project and role objects from keystone using names + role_obj = self.keystone.getRoleByName(proj["role"])[0] + proj_data = self.keystone.getProjectsByProjectName(proj["project"])[0] + is_admin = role_obj.to_dict().get("permissions").get('admin') + log.info('role object {} {}'.format(role_obj.to_dict(), proj_data.name)) + proj_name = proj_data.name + else: + # Backend authentication type is internal + try: + # Getting project and role object from commondb using names + role_obj = self.common_db.get_role_by_name(proj["role"]) + proj_name = proj["project"] + except Exception: + # Getting project and role object from commondb using ids + role_obj = self.common_db.get_role_by_id(proj["role"]) + proj_data = self.common_db.get_project(proj["project"]) + proj_name = proj_data['name'] + is_admin = role_obj["permissions"].get("admin") + self.grafana.create_grafana_teams_members(proj_name, user_name, is_admin, proj_list) def create_grafana_team(self, team_name): self.grafana.create_grafana_teams(team_name) @@ -168,3 +213,19 @@ class DashboarderService: def update_grafana_team(self, project_new_name, project_old_name): self.grafana.update_grafana_teams(project_new_name, project_old_name) + + def remove_grafana_team_members(self, user_id, proj_data): + try: + # Get user details from commondb + user = self.common_db.get_user_by_id(user_id) + user_name = user["username"] + except Exception as e: + # User not found in commondb + if self.keystone: + # Find user in keystone + user = self.keystone.getUserById(user_id) + user_name = user.name + else: + log.info('User %s not found', user_id) + log.debug('Exception %s' % e) + self.grafana.remove_grafana_team_member(user_name, proj_data) -- 2.25.1