| #!/usr/bin/env python |
| |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| |
| import json |
| import logging |
| import os |
| |
| from requests import Session, Response |
| |
| from apache_ranger.exceptions import RangerServiceException |
| from apache_ranger.model.ranger_base import RangerBase |
| from apache_ranger.model.ranger_role import RangerRole |
| from apache_ranger.model.ranger_policy import RangerPolicy |
| from apache_ranger.model.ranger_service import RangerService |
| from apache_ranger.model.ranger_service_def import RangerServiceDef |
| from apache_ranger.model.ranger_security_zone import RangerSecurityZone |
| from apache_ranger.utils import * |
| |
| |
| |
| LOG = logging.getLogger(__name__) |
| |
| |
| class RangerClient: |
| def __init__(self, url, auth): |
| self.url = url |
| self.session = Session() |
| self.session.auth = auth |
| |
| logging.getLogger("requests").setLevel(logging.WARNING) |
| |
| |
| # Service Definition APIs |
| def create_service_def(self, serviceDef): |
| resp = self.__call_api(RangerClient.CREATE_SERVICEDEF, request_data=serviceDef) |
| |
| return type_coerce(resp, RangerServiceDef) |
| |
| def update_service_def_by_id(self, serviceDefId, serviceDef): |
| resp = self.__call_api(RangerClient.UPDATE_SERVICEDEF_BY_ID.format_path({ 'id': serviceDefId }), request_data=serviceDef) |
| |
| return type_coerce(resp, RangerServiceDef) |
| |
| def update_service_def(self, serviceDefName, serviceDef): |
| resp = self.__call_api(RangerClient.UPDATE_SERVICEDEF_BY_NAME.format_path({ 'name': serviceDefName }), request_data=serviceDef) |
| |
| return type_coerce(resp, RangerServiceDef) |
| |
| def delete_service_def_by_id(self, serviceDefId): |
| self.__call_api(RangerClient.DELETE_SERVICEDEF_BY_ID.format_path({ 'id': serviceDefId })) |
| |
| def delete_service_def(self, serviceDefName): |
| self.__call_api(RangerClient.DELETE_SERVICEDEF_BY_NAME.format_path({ 'name': serviceDefName })) |
| |
| def get_service_def_by_id(self, serviceDefId): |
| resp = self.__call_api(RangerClient.GET_SERVICEDEF_BY_ID.format_path({ 'id': serviceDefId })) |
| |
| return type_coerce(resp, RangerServiceDef) |
| |
| def get_service_def(self, serviceDefName): |
| resp = self.__call_api(RangerClient.GET_SERVICEDEF_BY_NAME.format_path({ 'name': serviceDefName })) |
| |
| return type_coerce(resp, RangerServiceDef) |
| |
| def find_service_defs(self, filter=None): |
| if filter is None: |
| filter = {} |
| |
| resp = self.__call_api(RangerClient.FIND_SERVICEDEFS, filter) |
| |
| return type_coerce_list(resp, RangerServiceDef) |
| |
| |
| # Service APIs |
| def create_service(self, service): |
| resp = self.__call_api(RangerClient.CREATE_SERVICE, request_data=service) |
| |
| return type_coerce(resp, RangerService) |
| |
| def get_service_by_id(self, serviceId): |
| resp = self.__call_api(RangerClient.GET_SERVICE_BY_ID.format_path({ 'id': serviceId })) |
| |
| return type_coerce(resp, RangerService) |
| |
| def get_service(self, serviceName): |
| resp = self.__call_api(RangerClient.GET_SERVICE_BY_NAME.format_path({ 'name': serviceName })) |
| |
| return type_coerce(resp, RangerService) |
| |
| def update_service_by_id(self, serviceId, service): |
| resp = self.__call_api(RangerClient.UPDATE_SERVICE_BY_ID.format_path({ 'id': serviceId }), request_data=service) |
| |
| return type_coerce(resp, RangerService) |
| |
| def update_service(self, serviceName, service): |
| resp = self.__call_api(RangerClient.UPDATE_SERVICE_BY_NAME.format_path({ 'name': serviceName }), request_data=service) |
| |
| return type_coerce(resp, RangerService) |
| |
| def delete_service_by_id(self, serviceId): |
| self.__call_api(RangerClient.DELETE_SERVICE_BY_ID.format_path({ 'id': serviceId })) |
| |
| def delete_service(self, serviceName): |
| self.__call_api(RangerClient.DELETE_SERVICE_BY_NAME.format_path({ 'name': serviceName })) |
| |
| def find_services(self, filter=None): |
| if filter is None: |
| filter = {} |
| |
| resp = self.__call_api(RangerClient.FIND_SERVICES, filter) |
| |
| return type_coerce_list(resp, RangerService) |
| |
| |
| # Policy APIs |
| def create_policy(self, policy): |
| resp = self.__call_api(RangerClient.CREATE_POLICY, request_data=policy) |
| |
| return type_coerce(resp, RangerPolicy) |
| |
| def get_policy_by_id(self, policyId): |
| resp = self.__call_api(RangerClient.GET_POLICY_BY_ID.format_path({ 'id': policyId })) |
| |
| return type_coerce(resp, RangerPolicy) |
| |
| def get_policy(self, serviceName, policyName): |
| resp = self.__call_api(RangerClient.GET_POLICY_BY_NAME.format_path({ 'serviceName': serviceName, 'policyName': policyName})) |
| |
| return type_coerce(resp, RangerPolicy) |
| |
| def get_policies_in_service(self, serviceName): |
| resp = self.__call_api(RangerClient.GET_POLICIES_IN_SERVICE.format_path({ 'serviceName': serviceName })) |
| |
| return type_coerce_list(resp, RangerPolicy) |
| |
| def update_policy_by_id(self, policyId, policy): |
| resp = self.__call_api(RangerClient.UPDATE_POLICY_BY_ID.format_path({ 'id': policyId }), request_data=policy) |
| |
| return type_coerce(resp, RangerPolicy) |
| |
| def update_policy(self, serviceName, policyName, policy): |
| resp = self.__call_api(RangerClient.UPDATE_POLICY_BY_NAME.format_path({ 'serviceName': serviceName, 'policyName': policyName}), request_data=policy) |
| |
| return type_coerce(resp, RangerPolicy) |
| |
| def apply_policy(self, policy): |
| resp = self.__call_api(RangerClient.APPLY_POLICY, request_data=policy) |
| |
| return type_coerce(resp, RangerPolicy) |
| |
| def delete_policy_by_id(self, policyId): |
| self.__call_api(RangerClient.DELETE_POLICY_BY_ID.format_path({ 'id': policyId })) |
| |
| def delete_policy(self, serviceName, policyName): |
| self.__call_api(RangerClient.DELETE_POLICY_BY_NAME, { 'servicename': serviceName, 'policyname': policyName }) |
| |
| def find_policies(self, filter={}): |
| resp = self.__call_api(RangerClient.FIND_POLICIES, filter) |
| |
| return type_coerce_list(resp, RangerPolicy) |
| |
| |
| # SecurityZone APIs |
| def create_security_zone(self, securityZone): |
| resp = self.__call_api(RangerClient.CREATE_ZONE, request_data=securityZone) |
| |
| return type_coerce(resp, RangerSecurityZone) |
| |
| def update_security_zone_by_id(self, zoneId, securityZone): |
| resp = self.__call_api(RangerClient.UPDATE_ZONE_BY_ID.format_path({ 'id': zoneId }), request_data=securityZone) |
| |
| return type_coerce(resp, RangerSecurityZone) |
| |
| def update_security_zone(self, zoneName, securityZone): |
| resp = self.__call_api(RangerClient.UPDATE_ZONE_BY_NAME.format_path({ 'name': zoneName }), request_data=securityZone) |
| |
| return type_coerce(resp, RangerSecurityZone) |
| |
| def delete_security_zone_by_id(self, zoneId): |
| self.__call_api(RangerClient.DELETE_ZONE_BY_ID.format_path({ 'id': zoneId })) |
| |
| def delete_security_zone(self, zoneName): |
| self.__call_api(RangerClient.DELETE_ZONE_BY_NAME.format_path({ 'name': zoneName })) |
| |
| def get_security_zone_by_id(self, zoneId): |
| resp = self.__call_api(RangerClient.GET_ZONE_BY_ID.format_path({ 'id': zoneId })) |
| |
| return type_coerce(resp, RangerSecurityZone) |
| |
| def get_security_zone(self, zoneName): |
| resp = self.__call_api(RangerClient.GET_ZONE_BY_NAME.format_path({ 'name': zoneName })) |
| |
| return type_coerce(resp, RangerSecurityZone) |
| |
| def find_security_zones(self, filter={}): |
| resp = self.__call_api(RangerClient.FIND_ZONES, filter) |
| |
| return type_coerce_list(resp, RangerSecurityZone) |
| |
| |
| # Role APIs |
| def create_role(self, serviceName, role): |
| resp = self.__call_api(RangerClient.CREATE_ROLE, { 'serviceName': serviceName }, role) |
| |
| return type_coerce(resp, RangerRole) |
| |
| def update_role(self, roleId, role): |
| resp = self.__call_api(RangerClient.UPDATE_ROLE_BY_ID.format_path({ 'id': roleId }), request_data=role) |
| |
| return type_coerce(resp, RangerRole) |
| |
| def delete_role_by_id(self, roleId): |
| self.__call_api(RangerClient.DELETE_ROLE_BY_ID.format_path({ 'id': roleId })) |
| |
| def delete_role(self, roleName, execUser, serviceName): |
| self.__call_api(RangerClient.DELETE_ROLE_BY_NAME.format_path({ 'name': roleName }), { 'execUser': execUser, 'serviceName': serviceName }) |
| |
| def get_role_by_id(self, roleId): |
| resp = self.__call_api(RangerClient.GET_ROLE_BY_ID.format_path({ 'id': roleId })) |
| |
| return type_coerce(resp, RangerRole) |
| |
| def get_role(self, roleName, execUser, serviceName): |
| resp = self.__call_api(RangerClient.GET_ROLE_BY_NAME.format_path({ 'name': roleName }), { 'execUser': execUser, 'serviceName': serviceName }) |
| |
| return type_coerce(resp, RangerRole) |
| |
| def get_all_role_names(self, execUser, serviceName): |
| resp = self.__call_api(RangerClient.GET_ALL_ROLE_NAMES.format_path({ 'name': serviceName }), { 'execUser': execUser, 'serviceName': serviceName }) |
| |
| return resp |
| |
| def get_user_roles(self, user): |
| ret = self.__call_api(RangerClient.GET_USER_ROLES.format_path({ 'name': user })) |
| |
| return list(ret) if ret is not None else None |
| |
| def find_roles(self, filter={}): |
| resp = self.__call_api(RangerClient.FIND_ROLES, filter) |
| |
| return type_coerce_list(resp, RangerRole) |
| |
| def grant_role(self, serviceName, request): |
| resp = self.__call_api(RangerClient.GRANT_ROLE.format_path({ 'name': serviceName }), request_data=request) |
| |
| return type_coerce(resp, RESTResponse) |
| |
| def revoke_role(self, serviceName, request): |
| resp = self.__call_api(RangerClient.REVOKE_ROLE.format_path({ 'name': serviceName }), request_data=request) |
| |
| return type_coerce(resp, RESTResponse) |
| |
| |
| # Admin APIs |
| def delete_policy_deltas(self, days, reloadServicePoliciesCache): |
| self.__call_api(RangerClient.DELETE_POLICY_DELTAS, { 'days': days, 'reloadServicePoliciesCache': reloadServicePoliciesCache}) |
| |
| |
| |
| def __call_api(self, api, query_params=None, request_data=None): |
| ret = None |
| params = { 'headers': { 'Accept': api.consumes, 'Content-type': api.produces } } |
| |
| if query_params: |
| params['params'] = query_params |
| |
| if request_data: |
| params['data'] = json.dumps(request_data) |
| |
| path = os.path.join(self.url, api.path) |
| |
| if LOG.isEnabledFor(logging.DEBUG): |
| LOG.debug("------------------------------------------------------") |
| LOG.debug("Call : %s %s", api.method, path) |
| LOG.debug("Content-type : %s", api.consumes) |
| LOG.debug("Accept : %s", api.produces) |
| |
| response = None |
| |
| if api.method == HttpMethod.GET: |
| response = self.session.get(path, **params) |
| elif api.method == HttpMethod.POST: |
| response = self.session.post(path, **params) |
| elif api.method == HttpMethod.PUT: |
| response = self.session.put(path, **params) |
| elif api.method == HttpMethod.DELETE: |
| response = self.session.delete(path, **params) |
| |
| if LOG.isEnabledFor(logging.DEBUG): |
| LOG.debug("HTTP Status: %s", response.status_code if response else "None") |
| |
| if response is None: |
| ret = None |
| elif response.status_code == api.expected_status: |
| try: |
| if response.content is not None: |
| if LOG.isEnabledFor(logging.DEBUG): |
| LOG.debug("<== __call_api(%s, %s, %s), result=%s", vars(api), params, request_data, response) |
| |
| LOG.debug(response.json()) |
| |
| ret = response.json() |
| else: |
| ret = None |
| except Exception as e: |
| print(e) |
| |
| LOG.exception("Exception occurred while parsing response with msg: %s", e) |
| |
| raise RangerServiceException(api, response) |
| elif response.status_code == HTTPStatus.SERVICE_UNAVAILABLE: |
| LOG.error("Ranger admin unavailable. HTTP Status: %s", HTTPStatus.SERVICE_UNAVAILABLE) |
| |
| ret = None |
| else: |
| raise RangerServiceException(api, response) |
| |
| return ret |
| |
| |
| # URIs |
| URI_BASE = "service/public/v2/api" |
| |
| URI_SERVICEDEF = URI_BASE + "/servicedef" |
| URI_SERVICEDEF_BY_ID = URI_SERVICEDEF + "/{id}" |
| URI_SERVICEDEF_BY_NAME = URI_SERVICEDEF + "/name/{name}" |
| |
| URI_SERVICE = URI_BASE + "/service" |
| URI_SERVICE_BY_ID = URI_SERVICE + "/{id}" |
| URI_SERVICE_BY_NAME = URI_SERVICE + "/name/{name}" |
| URI_POLICIES_IN_SERVICE = URI_SERVICE + "/{serviceName}/policy" |
| |
| URI_POLICY = URI_BASE + "/policy" |
| URI_APPLY_POLICY = URI_POLICY + "/apply" |
| URI_POLICY_BY_ID = URI_POLICY + "/{id}" |
| URI_POLICY_BY_NAME = URI_SERVICE + "/{serviceName}/policy/{policyName}" |
| |
| URI_ROLE = URI_BASE + "/roles" |
| URI_ROLE_NAMES = URI_ROLE + "/names" |
| URI_ROLE_BY_ID = URI_ROLE + "/{id}" |
| URI_ROLE_BY_NAME = URI_ROLE + "/name/{name}" |
| URI_USER_ROLES = URI_ROLE + "/user/{name}" |
| URI_GRANT_ROLE = URI_ROLE + "/grant/{name}" |
| URI_REVOKE_ROLE = URI_ROLE + "/revoke/{name}" |
| |
| URI_ZONE = URI_BASE + "/zones" |
| URI_ZONE_BY_ID = URI_ZONE + "/{id}" |
| URI_ZONE_BY_NAME = URI_ZONE + "/name/{name}" |
| |
| URI_PLUGIN_INFO = URI_BASE + "/plugins/info" |
| URI_POLICY_DELTAS = URI_BASE + "/server/policydeltas" |
| |
| # APIs |
| CREATE_SERVICEDEF = API(URI_SERVICEDEF, HttpMethod.POST, HTTPStatus.OK) |
| UPDATE_SERVICEDEF_BY_ID = API(URI_SERVICEDEF_BY_ID, HttpMethod.PUT, HTTPStatus.OK) |
| UPDATE_SERVICEDEF_BY_NAME = API(URI_SERVICEDEF_BY_NAME, HttpMethod.PUT, HTTPStatus.OK) |
| DELETE_SERVICEDEF_BY_ID = API(URI_SERVICEDEF_BY_ID, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) |
| DELETE_SERVICEDEF_BY_NAME = API(URI_SERVICEDEF_BY_NAME, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) |
| GET_SERVICEDEF_BY_ID = API(URI_SERVICEDEF_BY_ID, HttpMethod.GET, HTTPStatus.OK) |
| GET_SERVICEDEF_BY_NAME = API(URI_SERVICEDEF_BY_NAME, HttpMethod.GET, HTTPStatus.OK) |
| FIND_SERVICEDEFS = API(URI_SERVICEDEF, HttpMethod.GET, HTTPStatus.OK) |
| |
| CREATE_SERVICE = API(URI_SERVICE, HttpMethod.POST, HTTPStatus.OK) |
| UPDATE_SERVICE_BY_ID = API(URI_SERVICE_BY_ID, HttpMethod.PUT, HTTPStatus.OK) |
| UPDATE_SERVICE_BY_NAME = API(URI_SERVICE_BY_NAME, HttpMethod.PUT, HTTPStatus.OK) |
| DELETE_SERVICE_BY_ID = API(URI_SERVICE_BY_ID, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) |
| DELETE_SERVICE_BY_NAME = API(URI_SERVICE_BY_NAME, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) |
| GET_SERVICE_BY_ID = API(URI_SERVICE_BY_ID, HttpMethod.GET, HTTPStatus.OK) |
| GET_SERVICE_BY_NAME = API(URI_SERVICE_BY_NAME, HttpMethod.GET, HTTPStatus.OK) |
| FIND_SERVICES = API(URI_SERVICE, HttpMethod.GET, HTTPStatus.OK) |
| |
| CREATE_POLICY = API(URI_POLICY, HttpMethod.POST, HTTPStatus.OK) |
| UPDATE_POLICY_BY_ID = API(URI_POLICY_BY_ID, HttpMethod.PUT, HTTPStatus.OK) |
| UPDATE_POLICY_BY_NAME = API(URI_POLICY_BY_NAME, HttpMethod.PUT, HTTPStatus.OK) |
| APPLY_POLICY = API(URI_APPLY_POLICY, HttpMethod.POST, HTTPStatus.OK) |
| DELETE_POLICY_BY_ID = API(URI_POLICY_BY_ID, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) |
| DELETE_POLICY_BY_NAME = API(URI_POLICY, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) |
| GET_POLICY_BY_ID = API(URI_POLICY_BY_ID, HttpMethod.GET, HTTPStatus.OK) |
| GET_POLICY_BY_NAME = API(URI_POLICY_BY_NAME, HttpMethod.GET, HTTPStatus.OK) |
| GET_POLICIES_IN_SERVICE = API(URI_POLICIES_IN_SERVICE, HttpMethod.GET, HTTPStatus.OK) |
| FIND_POLICIES = API(URI_POLICY, HttpMethod.GET, HTTPStatus.OK) |
| |
| CREATE_ZONE = API(URI_ZONE, HttpMethod.POST, HTTPStatus.OK) |
| UPDATE_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.PUT, HTTPStatus.OK) |
| UPDATE_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.PUT, HTTPStatus.OK) |
| DELETE_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) |
| DELETE_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) |
| GET_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.GET, HTTPStatus.OK) |
| GET_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.GET, HTTPStatus.OK) |
| FIND_ZONES = API(URI_ZONE, HttpMethod.GET, HTTPStatus.OK) |
| |
| CREATE_ROLE = API(URI_ROLE, HttpMethod.POST, HTTPStatus.OK) |
| UPDATE_ROLE_BY_ID = API(URI_ROLE_BY_ID, HttpMethod.PUT, HTTPStatus.OK) |
| DELETE_ROLE_BY_ID = API(URI_ROLE_BY_ID, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) |
| DELETE_ROLE_BY_NAME = API(URI_ROLE_BY_NAME, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) |
| GET_ROLE_BY_ID = API(URI_ROLE_BY_ID, HttpMethod.GET, HTTPStatus.OK) |
| GET_ROLE_BY_NAME = API(URI_ROLE_BY_NAME, HttpMethod.GET, HTTPStatus.OK) |
| GET_ALL_ROLE_NAMES = API(URI_ROLE_NAMES, HttpMethod.GET, HTTPStatus.OK) |
| GET_USER_ROLES = API(URI_USER_ROLES, HttpMethod.GET, HTTPStatus.OK) |
| GRANT_ROLE = API(URI_GRANT_ROLE, HttpMethod.PUT, HTTPStatus.OK) |
| REVOKE_ROLE = API(URI_REVOKE_ROLE, HttpMethod.PUT, HTTPStatus.OK) |
| FIND_ROLES = API(URI_ROLE, HttpMethod.GET, HTTPStatus.OK) |
| |
| GET_PLUGIN_INFO = API(URI_PLUGIN_INFO, HttpMethod.GET, HTTPStatus.OK) |
| DELETE_POLICY_DELTAS = API(URI_POLICY_DELTAS, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) |
| |
| |
| class Message(RangerBase): |
| def __init__(self, attrs=None): |
| if attrs is None: |
| attrs = {} |
| |
| RangerBase.__init__(self, attrs) |
| |
| self.name = attrs.get('name') |
| self.rbKey = attrs.get('rbKey') |
| self.message = attrs.get('message') |
| self.objectId = attrs.get('objectId') |
| self.fieldName = attrs.get('fieldName') |
| |
| |
| class RESTResponse(RangerBase): |
| def __init__(self, attrs=None): |
| if attrs is None: |
| attrs = {} |
| |
| RangerBase.__init__(self, attrs) |
| |
| self.httpStatusCode = attrs.get('httpStatusCode') |
| self.statusCode = attrs.get('statusCode') |
| self.msgDesc = attrs.get('msgDesc') |
| self.messageList = non_null(attrs.get('messageList'), []) |
| |
| def type_coerce_attrs(self): |
| super(RangerPolicy, self).type_coerce_attrs() |
| |
| self.messageList = type_coerce_dict(self.messageList, Message) |