This is an automated email from the ASF dual-hosted git repository. madhan pushed a commit to branch ranger-2.1 in repository https://gitbox.apache.org/repos/asf/ranger.git
commit 67457efd63a833a2dc8ac4e59172652a9a8e5841 Author: Abhishek Kumar <[email protected]> AuthorDate: Fri Aug 14 19:26:42 2020 -0400 RANGER-2927: Python client libraries for Publicv2APIs Signed-off-by: Sailaja Polavarapu <[email protected]> (cherry picked from commit a07bde1024518126b4881b0e71f4fd30b8405edd) --- .gitignore | 1 + intg/.gitignore | 3 +- intg/pom.xml | 107 ++++- intg/scripts/build.sh | 23 + intg/scripts/setup.py | 30 ++ .../main/java/org/apache/ranger/RangerClient.java | 8 +- intg/src/main/python/__init__.py | 17 + intg/src/main/python/ranger/client/__init__.py | 17 + .../src/main/python/ranger/client/ranger_client.py | 496 +++++++++++++++++++++ intg/src/main/python/ranger/model/__init__.py | 17 + .../ranger/model/grant_revoke_role_request.py | 39 ++ intg/src/main/python/ranger/model/ranger_base.py | 34 ++ intg/src/main/python/ranger/model/ranger_policy.py | 127 ++++++ intg/src/main/python/ranger/model/ranger_role.py | 48 ++ .../python/ranger/model/ranger_security_zone.py | 48 ++ .../src/main/python/ranger/model/ranger_service.py | 43 ++ .../main/python/ranger/model/ranger_service_def.py | 136 ++++++ intg/src/main/resources/logging.conf | 40 ++ intg/src/test/python/test_ranger_client.py | 109 +++++ pom.xml | 5 +- .../distro/src/main/assembly/sample-client.xml | 21 +- ranger-examples/sample-client/.gitignore | 3 +- .../sample-client/conf/config.properties | 21 + ranger-examples/sample-client/pom.xml | 38 ++ .../sample-client/scripts/run-pyclient.sh | 50 +++ ranger-examples/sample-client/scripts/setup.py | 30 ++ .../sample-client/src/main/python/sample_client.py | 110 +++++ 27 files changed, 1611 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index c2def9d..e351815 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ .classpath .project /target/ +/venv/ winpkg/target .DS_Store .idea diff --git a/intg/.gitignore b/intg/.gitignore index a6f89c2..897593c 100644 --- a/intg/.gitignore +++ b/intg/.gitignore @@ -1 +1,2 @@ -/target/ \ No newline at end of file +/target/ +/venv/ \ No newline at end of file diff --git a/intg/pom.xml b/intg/pom.xml index c8eb330..83b87d8 100644 --- a/intg/pom.xml +++ b/intg/pom.xml @@ -19,7 +19,6 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <packaging>jar</packaging> <parent> <artifactId>ranger</artifactId> <groupId>org.apache.ranger</groupId> @@ -28,6 +27,112 @@ <modelVersion>4.0.0</modelVersion> <artifactId>ranger-intg</artifactId> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + <version>${maven.pmd.plugin.version}</version> + <executions> + <execution> + <phase>verify</phase> + <goals> + <goal>check</goal> + </goals> + </execution> + </executions> + <configuration> + <rulesets> + <ruleset>${project.parent.basedir}/dev-support/ranger-pmd-ruleset.xml</ruleset> + </rulesets> + <sourceEncoding>UTF-8</sourceEncoding> + <failOnViolation>true</failOnViolation> + <linkXRef>false</linkXRef> + <includeTests>true</includeTests> + <verbose>true</verbose> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-clean-plugin</artifactId> + <version>2.6.1</version> + <configuration> + <filesets> + <fileset> + <directory>venv</directory> + </fileset> + </filesets> + </configuration> + </plugin> + + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>${maven.exec.plugin.version}</version> + <executions> + <execution> + <configuration> + <skip>${skipTests}</skip> + <executable>python3</executable> + <arguments> + <argument>-m</argument> + <argument>venv</argument> + <argument>venv</argument> + </arguments> + </configuration> + <id>create-venv</id> + <phase>validate</phase> + <goals> + <goal>exec</goal> + </goals> + </execution> + <execution> + <phase>test</phase> + <goals> + <goal>exec</goal> + </goals> + <configuration> + <skip>${skipTests}</skip> + <executable>bash</executable> + <commandlineArgs>scripts/build.sh</commandlineArgs> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <version>2.7</version> + <executions> + <execution> + <id>copy-resources</id> + <phase>initialize</phase> + <goals> + <goal>copy-resources</goal> + </goals> + <configuration> + <outputDirectory>venv/pylib</outputDirectory> + <resources> + <resource> + <directory>src/main/python</directory> + <includes> + <include>**/*.py</include> + </includes> + </resource> + <resource> + <directory>src/test/python</directory> + </resource> + <resource> + <directory>src/main/resources</directory> + </resource> + </resources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> <dependencies> <dependency> <groupId>org.apache.ranger</groupId> diff --git a/intg/scripts/build.sh b/intg/scripts/build.sh new file mode 100644 index 0000000..a875da1 --- /dev/null +++ b/intg/scripts/build.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# 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. + +cd venv || exit +source bin/activate +INSTALL="python3 ./../scripts/setup.py install" +$INSTALL >> build.log +TEST="python3 build/lib/pylib/test_ranger_client.py" +$TEST diff --git a/intg/scripts/setup.py b/intg/scripts/setup.py new file mode 100644 index 0000000..9ce9773 --- /dev/null +++ b/intg/scripts/setup.py @@ -0,0 +1,30 @@ +#!/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. + +from setuptools import setup, find_packages + +# External dependencies +requirements = ['requests>=2.24'] + +setup( + name='pyclient', + packages=['pylib', 'pylib/ranger/client', 'pylib/ranger/model'], + data_files=[('../../lib/resources', ['./../src/main/resources/logging.conf'])], + install_requires=requirements, + zip_safe=False +) diff --git a/intg/src/main/java/org/apache/ranger/RangerClient.java b/intg/src/main/java/org/apache/ranger/RangerClient.java index 0e2fe56..bef3857 100644 --- a/intg/src/main/java/org/apache/ranger/RangerClient.java +++ b/intg/src/main/java/org/apache/ranger/RangerClient.java @@ -468,7 +468,7 @@ public class RangerClient { } if (clientResponse == null) { - throw new RangerServiceException(api, clientResponse); + throw new RangerServiceException(api, null); } else if (clientResponse.getStatus() == api.getExpectedStatus().getStatusCode()) { if (responseType != null) { ret = clientResponse.getEntity(responseType); @@ -542,11 +542,9 @@ public class RangerClient { try { URI uri = new URI(path); - if (uri != null) { - URI normalizedUri = uri.normalize(); + URI normalizedUri = uri.normalize(); - ret = normalizedUri.toString(); - } + ret = normalizedUri.toString(); } catch (Exception e) { LOG.error("getNormalizedPath() caught exception for path={}", path, e); diff --git a/intg/src/main/python/__init__.py b/intg/src/main/python/__init__.py new file mode 100644 index 0000000..ed9d0b3 --- /dev/null +++ b/intg/src/main/python/__init__.py @@ -0,0 +1,17 @@ +#!/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. diff --git a/intg/src/main/python/ranger/client/__init__.py b/intg/src/main/python/ranger/client/__init__.py new file mode 100644 index 0000000..ed9d0b3 --- /dev/null +++ b/intg/src/main/python/ranger/client/__init__.py @@ -0,0 +1,17 @@ +#!/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. diff --git a/intg/src/main/python/ranger/client/ranger_client.py b/intg/src/main/python/ranger/client/ranger_client.py new file mode 100644 index 0000000..319261d --- /dev/null +++ b/intg/src/main/python/ranger/client/ranger_client.py @@ -0,0 +1,496 @@ +#!/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 enum +import json +import logging +import requests +import logging.config + +from os import path +from http import HTTPStatus +from requests import Session, Response + +from ranger.model.ranger_role import RangerRole +from ranger.model.ranger_policy import RangerPolicy +from ranger.model.ranger_service import RangerService +from ranger.model.ranger_service_def import RangerServiceDef +from ranger.model.ranger_security_zone import RangerSecurityZone + + +APPLICATION_JSON = 'application/json' +LOG_CONFIG = path.dirname(__file__) + '/../../../resources/logging.conf' + +logging.config.fileConfig(LOG_CONFIG, disable_existing_loggers=False) +requests.packages.urllib3.disable_warnings() + + +class Message: + def __init__(self, name=None, rbKey=None, message=None, objectId=None, fieldName=None): + self.name = name + self.rbKey = rbKey + self.message = message + self.objectId = objectId + self.fieldName = fieldName + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RESTResponse: + def __init__(self, httpStatusCode=None, statusCode=None, msgDesc=None, messageList=None): + self.httpStatusCode = httpStatusCode + self.statusCode = statusCode + self.msgDesc = msgDesc + self.messageList = messageList if messageList is not None else [] + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class HttpMethod(enum.Enum): + GET = "GET" + PUT = "PUT" + POST = "POST" + DELETE = "DELETE" + + +class API: + def __init__(self, path, method, expected_status, consumes=APPLICATION_JSON, produces=APPLICATION_JSON): + self.log = logging.getLogger(__name__) + self.path = path + self.method = method + self.expected_status = expected_status + self.consumes = consumes + self.produces = produces + + def call(self, session, baseUrl, params, request): + session.headers['Accept'] = self.consumes + session.headers['Content-type'] = self.produces + + if self.log.isEnabledFor(logging.DEBUG): + self.log.debug('==> call({},{},{})'.format(self, params, request)) + self.log.debug('------------------------------------------------------') + self.log.debug('Call : {} {}'.format(self.method, self.path)) + self.log.debug('Content-type : {}'.format(self.consumes)) + self.log.debug('Accept : {}'.format(self.produces)) + + if request is not None: + self.log.debug("Request : {}".format(request)) + + path = baseUrl + self.path + + if self.method == HttpMethod.GET: + client_response = session.get(path) + elif self.method == HttpMethod.POST: + client_response = session.post(path, data=request.__repr__()) + elif self.method == HttpMethod.PUT: + client_response = session.put(path, data=request.__repr__()) + elif self.method == HttpMethod.DELETE: + client_response = session.delete(path, params=params) + else: + raise Exception('Unsupported HTTP Method {}'.format(self.method)) + + if client_response.status_code == self.expected_status: + if client_response.content: + if self.log.isEnabledFor(logging.DEBUG): + self.log.debug('Response: {}'.format(client_response.text)) + else: + return None + elif client_response.status_code == HTTPStatus.SERVICE_UNAVAILABLE: + self.log.error('Ranger Admin unavailable. HTTP Status: {}'.format(HTTPStatus.SERVICE_UNAVAILABLE)) + self.log.error("client_response=: {}" + str(client_response)) + return None + else: + raise Exception(client_response.text) + + __json = json.loads(str(json.dumps(client_response.json()))) + + if self.log.isEnabledFor(logging.DEBUG): + self.log.debug('<== call({},{},{}), result = {}'.format(self, params, request, client_response)) + + return __json + + def apply_url_params(self, params): + try: + return API(self.path.format(**params), self.method, self.expected_status, self.consumes, self.produces) + except (KeyError, TypeError) as e: + self.log.error('Arguments not formatted properly' + str(e)) + raise e + + +class RangerClient: + # Query Params + PARAM_ID = "id" + PARAM_NAME = "name" + PARAM_DAYS = "days" + PARAM_EXEC_USER = "execUser" + PARAM_POLICY_NAME = "policyname" + PARAM_SERVICE_NAME = "serviceName" + PARAM_RELOAD_SERVICE_POLICIES_CACHE = "reloadServicePoliciesCache" + + # 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) + + def __init__(self, url, username, password): + self.log = logging.getLogger(__name__) + self.__password = password + self.url = url + self.username = username + self.session = Session() + self.session.auth = (username, password) + self.session.verify = False + + def __call_api(self, api, params, request): + return api.call(self.session, self.url, params, request) + + def __call_api_with_url_params(self, api, urlParams, params, request): + return api.apply_url_params(urlParams).call(self.session, self.url, params, request) + + # Service Definition APIs + def create_service_def(self, serviceDef): + ret = self.__call_api(RangerClient.CREATE_SERVICEDEF, {}, serviceDef) + + return RangerServiceDef(**ret) if ret is not None else None + + def update_service_def_by_id(self, serviceDefId, serviceDef): + ret = self.__call_api_with_url_params(RangerClient.UPDATE_SERVICEDEF_BY_ID, { RangerClient.PARAM_ID: serviceDefId }, {}, serviceDef) + + return RangerServiceDef(**ret) if ret is not None else None + + def update_service_def(self, serviceDefName, serviceDef): + ret = self.__call_api_with_url_params(RangerClient.UPDATE_SERVICEDEF_BY_NAME, { RangerClient.PARAM_NAME: serviceDefName }, {}, serviceDef) + + return RangerServiceDef(**ret) if ret is not None else None + + def delete_service_def_by_id(self, serviceDefId): + self.__call_api_with_url_params(RangerClient.DELETE_SERVICEDEF_BY_ID, { RangerClient.PARAM_ID: serviceDefId }, {}, {}) + + return None + + def delete_service_def(self, serviceDefName): + self.__call_api_with_url_params(RangerClient.DELETE_SERVICEDEF_BY_NAME, { RangerClient.PARAM_NAME: serviceDefName }, {}, {}) + + return None + + def get_service_def_by_id(self, serviceDefId): + ret = self.__call_api_with_url_params(RangerClient.GET_SERVICEDEF_BY_ID, { RangerClient.PARAM_ID: serviceDefId }, {}, {}) + + return RangerServiceDef(**ret) if ret is not None else None + + def get_service_def(self, serviceDefName): + ret = self.__call_api_with_url_params(RangerClient.GET_SERVICEDEF_BY_NAME, { RangerClient.PARAM_NAME: serviceDefName }, {}, {}) + + return RangerServiceDef(**ret) if ret is not None else None + + def find_service_defs(self, filter): + ret = self.__call_api(RangerClient.FIND_SERVICEDEFS, filter, {}) + + return list(ret) if ret is not None else None + + # Service APIs + def create_service(self, service): + ret = self.__call_api(RangerClient.CREATE_SERVICE, {}, service) + + return RangerService(**ret) if ret is not None else None + + def update_service_by_id(self, serviceId, service): + ret = self.__call_api_with_url_params(RangerClient.UPDATE_SERVICE_BY_ID, { RangerClient.PARAM_ID: serviceId }, {}, service) + + return RangerService(**ret) if ret is not None else None + + def update_service(self, serviceName, service): + ret = self.__call_api_with_url_params(RangerClient.UPDATE_SERVICE_BY_NAME, { RangerClient.PARAM_NAME: serviceName }, {}, service) + + return RangerService(**ret) if ret is not None else None + + def delete_service_by_id(self, serviceId): + self.__call_api_with_url_params(RangerClient.DELETE_SERVICE_BY_ID, { RangerClient.PARAM_ID: serviceId }, {}, {}) + + return None + + def delete_service(self, serviceName): + self.__call_api_with_url_params(RangerClient.DELETE_SERVICE_BY_NAME, { RangerClient.PARAM_NAME: serviceName }, {}, {}) + + return None + + def get_service_by_id(self, serviceId): + ret = self.__call_api_with_url_params(RangerClient.GET_SERVICE_BY_ID, { RangerClient.PARAM_ID: serviceId }, {}, {}) + + return RangerService(**ret) if ret is not None else None + + def get_service(self, serviceName): + ret = self.__call_api_with_url_params(RangerClient.GET_SERVICE_BY_NAME, { RangerClient.PARAM_NAME: serviceName }, {}, {}) + + return RangerService(**ret) if ret is not None else None + + def find_services(self, filter): + ret = self.__call_api(RangerClient.FIND_SERVICES, filter, {}) + + return list(ret) if ret is not None else None + + # Policy APIs + def create_policy(self, policy): + ret = self.__call_api(RangerClient.CREATE_POLICY, {}, policy) + + return RangerPolicy(**ret) if ret is not None else None + + def update_policy_by_id(self, policyId, policy): + ret = self.__call_api_with_url_params(RangerClient.UPDATE_POLICY_BY_ID, { RangerClient.PARAM_ID: policyId }, {}, policy) + + return RangerPolicy(**ret) if ret is not None else None + + def update_policy(self, serviceName, policyName, policy): + path_params = { RangerClient.PARAM_SERVICE_NAME: serviceName, RangerClient.PARAM_POLICY_NAME: policyName } + ret = self.__call_api_with_url_params(RangerClient.UPDATE_POLICY_BY_NAME, path_params, {}, policy) + + return RangerPolicy(**ret) if ret is not None else None + + def apply_policy(self, policy): + ret = self.__call_api(RangerClient.APPLY_POLICY, {}, policy) + + return RangerPolicy(**ret) if ret is not None else None + + def delete_policy_by_id(self, policyId): + self.__call_api_with_url_params(RangerClient.DELETE_POLICY_BY_ID, { RangerClient.PARAM_ID: policyId }, {}, {}) + + return None + + def delete_policy(self, serviceName, policyName): + query_params = { RangerClient.PARAM_POLICY_NAME: policyName, 'servicename': serviceName } + + self.__call_api(RangerClient.DELETE_POLICY_BY_NAME, query_params, {}) + + return None + + def get_policy_by_id(self, policyId): + ret = self.__call_api_with_url_params(RangerClient.GET_POLICY_BY_ID, { RangerClient.PARAM_ID: policyId }, {}, {}) + + return RangerPolicy(**ret) if ret is not None else None + + def get_policy(self, serviceName, policyName): + path_params = {RangerClient.PARAM_SERVICE_NAME: serviceName, RangerClient.PARAM_POLICY_NAME: policyName} + ret = self.__call_api_with_url_params(RangerClient.GET_POLICY_BY_NAME, path_params, {}, {}) + + return RangerPolicy(**ret) if ret is not None else None + + def get_policies_in_service(self, serviceName): + ret = self.__call_api_with_url_params(RangerClient.GET_POLICIES_IN_SERVICE, { RangerClient.PARAM_SERVICE_NAME: serviceName }, {}, {}) + + return list(ret) if ret is not None else None + + def find_policies(self, filter): + ret = self.__call_api(RangerClient.FIND_POLICIES, filter, {}) + + return list(ret) if ret is not None else None + + # SecurityZone APIs + def create_security_zone(self, securityZone): + ret = self.__call_api(RangerClient.CREATE_ZONE, {}, securityZone) + + return RangerSecurityZone(**ret) if ret is not None else None + + def update_security_zone_by_id(self, zoneId, securityZone): + ret = self.__call_api_with_url_params(RangerClient.UPDATE_ZONE_BY_ID, { RangerClient.PARAM_ID: zoneId }, {}, securityZone) + + return RangerSecurityZone(**ret) if ret is not None else None + + def update_security_zone(self, zoneName, securityZone): + ret = self.__call_api_with_url_params(RangerClient.UPDATE_ZONE_BY_NAME, { RangerClient.PARAM_NAME: zoneName }, {}, securityZone) + + return RangerSecurityZone(**ret) if ret is not None else None + + def delete_security_zone_by_id(self, zoneId): + self.__call_api_with_url_params(RangerClient.DELETE_ZONE_BY_ID, { RangerClient.PARAM_ID: zoneId }, {}, {}) + return None + + def delete_security_zone(self, zoneName): + self.__call_api_with_url_params(RangerClient.DELETE_ZONE_BY_NAME, { RangerClient.PARAM_NAME: zoneName }, {}, {}) + + return None + + def get_security_zone_by_id(self, zoneId): + ret = self.__call_api_with_url_params(RangerClient.GET_ZONE_BY_ID, { RangerClient.PARAM_ID: zoneId }, {}, {}) + + return RangerSecurityZone(**ret) if ret is not None else None + + def get_security_zone(self, zoneName): + ret = self.__call_api_with_url_params(RangerClient.GET_ZONE_BY_NAME, { RangerClient.PARAM_NAME: zoneName }, {}, {}) + + return RangerSecurityZone(**ret) if ret is not None else None + + def find_security_zones(self, filter): + ret = self.__call_api(RangerClient.FIND_ZONES, filter, {}) + + return list(ret) if ret is not None else None + + # Role APIs + def create_role(self, serviceName, role): + query_params = {RangerClient.PARAM_SERVICE_NAME, serviceName} + ret = self.__call_api(RangerClient.CREATE_ROLE, query_params, role) + + return RangerRole(**ret) if ret is not None else None + + def update_role(self, roleId, role): + ret = self.__call_api_with_url_params(RangerClient.UPDATE_ROLE_BY_ID, { RangerClient.PARAM_ID: roleId }, {}, role) + + return RangerRole(**ret) if ret is not None else None + + def delete_role_by_id(self, roleId): + self.__call_api_with_url_params(RangerClient.DELETE_ROLE_BY_ID, { RangerClient.PARAM_ID: roleId }, {}, {}) + + return None + + def delete_role(self, roleName, execUser, serviceName): + query_params = { RangerClient.PARAM_EXEC_USER: execUser, RangerClient.PARAM_SERVICE_NAME: serviceName } + + self.__call_api_with_url_params(RangerClient.DELETE_ROLE_BY_NAME, { RangerClient.PARAM_NAME: roleName }, query_params, {}) + + return None + + def get_role_by_id(self, roleId): + ret = self.__call_api_with_url_params(RangerClient.GET_ROLE_BY_ID, { RangerClient.PARAM_ID: roleId }, {}, {}) + + return RangerRole(**ret) if ret is not None else None + + def get_role(self, roleName, execUser, serviceName): + query_params = { RangerClient.PARAM_EXEC_USER: execUser, RangerClient.PARAM_SERVICE_NAME: serviceName } + ret = self.__call_api_with_url_params(RangerClient.GET_ROLE_BY_NAME, { RangerClient.PARAM_NAME: roleName }, query_params, {}) + + return RangerRole(**ret) if ret is not None else None + + def get_all_role_names(self, execUser, serviceName): + query_params = { RangerClient.PARAM_EXEC_USER: execUser, RangerClient.PARAM_SERVICE_NAME: serviceName } + ret = self.__call_api_with_url_params(RangerClient.GET_ALL_ROLE_NAMES, { RangerClient.PARAM_NAME: serviceName }, query_params, {}) + + return list(ret) if ret is not None else None + + def get_user_roles(self, user): + ret = self.__call_api_with_url_params(RangerClient.GET_USER_ROLES, { RangerClient.PARAM_NAME: user }, {}, {}) + + return list(ret) if ret is not None else None + + def find_roles(self, filter): + ret = self.__call_api(RangerClient.FIND_ROLES, filter, {}) + + return list(ret) if ret is not None else None + + def grant_role(self, serviceName, request): + ret = self.__call_api_with_url_params(RangerClient.GRANT_ROLE, { RangerClient.PARAM_NAME: serviceName }, {}, request) + + return RESTResponse(**ret) if ret is not None else None + + def revoke_role(self, serviceName, request): + ret = self.__call_api_with_url_params(RangerClient.REVOKE_ROLE, { RangerClient.PARAM_NAME: serviceName }, {}, request) + + return RESTResponse(**ret) if ret is not None else None + + # Admin APIs + def delete_policy_deltas(self, days, reloadServicePoliciesCache): + query_params = { + RangerClient.PARAM_DAYS: days, + RangerClient.PARAM_RELOAD_SERVICE_POLICIES_CACHE: reloadServicePoliciesCache + } + + self.__call_api(RangerClient.DELETE_POLICY_DELTAS, query_params, {}) + + return None diff --git a/intg/src/main/python/ranger/model/__init__.py b/intg/src/main/python/ranger/model/__init__.py new file mode 100644 index 0000000..ed9d0b3 --- /dev/null +++ b/intg/src/main/python/ranger/model/__init__.py @@ -0,0 +1,17 @@ +#!/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. diff --git a/intg/src/main/python/ranger/model/grant_revoke_role_request.py b/intg/src/main/python/ranger/model/grant_revoke_role_request.py new file mode 100644 index 0000000..fb0eab2 --- /dev/null +++ b/intg/src/main/python/ranger/model/grant_revoke_role_request.py @@ -0,0 +1,39 @@ +#!/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 + + +class GrantRevokeRoleRequest: + def __init__(self, grantor=None, grantorGroups=None, targetRoles=None, users=None, groups=None, roles=None, grantOption=None, clientIPAddress=None, clientType=None, requestData=None, sessionId=None, clusterName=None): + self.grantor = grantor + self.grantorGroups = grantorGroups if grantorGroups is not None else [] + self.targetRoles = targetRoles if targetRoles is not None else [] + self.users = users if users is not None else [] + self.groups = groups if groups is not None else [] + self.roles = roles if roles is not None else [] + self.grantOption = grantOption if grantOption is not None else False + self.clientIPAddress = clientIPAddress + self.clientType = clientType + self.requestData = requestData + self.sessionId = sessionId + self.clusterName = clusterName + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + diff --git a/intg/src/main/python/ranger/model/ranger_base.py b/intg/src/main/python/ranger/model/ranger_base.py new file mode 100644 index 0000000..ae8de74 --- /dev/null +++ b/intg/src/main/python/ranger/model/ranger_base.py @@ -0,0 +1,34 @@ +#!/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 + + +class RangerBase: + def __init__(self, id=None, guid=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None, version=None, isEnabled=None): + self.id = id + self.guid = guid + self.isEnabled = isEnabled if isEnabled is not None else True + self.createdBy = createdBy + self.updatedBy = updatedBy + self.createTime = createTime + self.updateTime = updateTime + self.version = version + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) diff --git a/intg/src/main/python/ranger/model/ranger_policy.py b/intg/src/main/python/ranger/model/ranger_policy.py new file mode 100644 index 0000000..9195f4b --- /dev/null +++ b/intg/src/main/python/ranger/model/ranger_policy.py @@ -0,0 +1,127 @@ +#!/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 + +from ranger.model.ranger_base import RangerBase + + +class RangerPolicyResource: + def __init__(self, values=None, isExcludes=None, isRecursive=None): + self.values = values if values is not None else [] + self.isExcludes = isExcludes if isExcludes is not None else False + self.isRecursive = isRecursive if isRecursive is not None else False + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerPolicyItemCondition: + def __init__(self, type=None, values=None): + self.type = type + self.values = values if values is not None else [] + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerPolicyItem: + def __init__(self, accesses=None, users=None, groups=None, roles=None, conditions=None, delegateAdmin=None): + self.accesses = accesses if accesses is not None else [] + self.users = users if users is not None else [] + self.groups = groups if groups is not None else [] + self.roles = roles if roles is not None else [] + self.conditions = conditions if conditions is not None else [] + self.delegateAdmin = delegateAdmin if delegateAdmin is not None else False + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerPolicyItemAccess: + def __init__(self, type=None, isAllowed=None): + self.type = type + self.isAllowed = isAllowed if isAllowed is not None else True + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerPolicyItemDataMaskInfo: + def __init__(self, dataMaskType=None, conditionExpr=None, valueExpr=None): + self.dataMaskType = dataMaskType + self.conditionExpr = conditionExpr + self.valueExpr = valueExpr + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerDataMaskPolicyItem(RangerPolicyItem): + def __init__(self, dataMaskInfo=None, accesses=None, users=None, groups=None, roles=None, conditions=None, delegateAdmin=None): + super().__init__(accesses, users, groups, roles, conditions, delegateAdmin) + + self.dataMaskInfo = dataMaskInfo if dataMaskInfo is not None else RangerPolicyItemDataMaskInfo() + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerRowFilterPolicyItem(RangerPolicyItem): + def __init__(self, rowFilterInfo=None, accesses=None, users=None, groups=None, roles=None, conditions=None, delegateAdmin=None): + super().__init__(accesses, users, groups, roles, conditions, delegateAdmin) + + self.rowFilterInfo = rowFilterInfo + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerPolicy(RangerBase): + def __init__(self, id=None, guid=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None, + service=None, name=None, description=None, isEnabled=True, isAuditEnabled=None, resources=None, + policyItems=None, dataMaskPolicyItems=None, rowFilterPolicyItems=None, serviceType=None, options=None, + policyLabels=None, zoneName=None, isDenyAllElse=None, validitySchedules=None, version=None, + denyPolicyItems=None, denyExceptions=None, allowExceptions=None, resourceSignature=None, + policyType=None, policyPriority=None, conditions=None): + super().__init__(id, guid, createdBy, updatedBy, createTime, updateTime, version, isEnabled) + + self.service = service + self.name = name + self.policyType = policyType + self.policyPriority = policyPriority if policyPriority is not None else 0 + self.description = description + self.resourceSignature = resourceSignature + self.isAuditEnabled = isAuditEnabled if isAuditEnabled is not None else True + self.resources = resources if resources is not None else {} + self.policyItems = policyItems if policyItems is not None else [] + self.denyPolicyItems = denyPolicyItems if denyPolicyItems is not None else [] + self.allowExceptions = allowExceptions if allowExceptions is not None else [] + self.denyExceptions = denyExceptions if denyExceptions is not None else [] + self.dataMaskPolicyItems = dataMaskPolicyItems if dataMaskPolicyItems is not None else [] + self.rowFilterPolicyItems = rowFilterPolicyItems if rowFilterPolicyItems is not None else [] + self.serviceType = serviceType + self.options = options if options is not None else {} + self.validitySchedules = validitySchedules if validitySchedules is not None else [] + self.policyLabels = policyLabels if policyLabels is not None else [] + self.zoneName = zoneName + self.conditions = conditions + self.isDenyAllElse = isDenyAllElse if isDenyAllElse is not None else False + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) diff --git a/intg/src/main/python/ranger/model/ranger_role.py b/intg/src/main/python/ranger/model/ranger_role.py new file mode 100644 index 0000000..aa05216 --- /dev/null +++ b/intg/src/main/python/ranger/model/ranger_role.py @@ -0,0 +1,48 @@ +#!/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 + +from ranger.model.ranger_base import RangerBase + + +class RoleMember: + def __init__(self, name=None, isAdmin=None): + self.name = name + self.isAdmin = isAdmin if isAdmin is not None else False + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerRole(RangerBase): + def __init__(self, id=None, guid=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None, + version=None, isEnabled=None, name=None, description=None, options=None, users=None, groups=None, + roles=None, createdByUser=None): + super().__init__(id, guid, createdBy, updatedBy, createTime, updateTime, version, isEnabled) + + self.name = name + self.description = description + self.options = options if options is not None else {} + self.users = users if users is not None else [] + self.groups = groups if groups is not None else [] + self.roles = roles if roles is not None else [] + self.createdByUser = createdByUser + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) diff --git a/intg/src/main/python/ranger/model/ranger_security_zone.py b/intg/src/main/python/ranger/model/ranger_security_zone.py new file mode 100644 index 0000000..40a5209 --- /dev/null +++ b/intg/src/main/python/ranger/model/ranger_security_zone.py @@ -0,0 +1,48 @@ +#!/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 + +from ranger.model.ranger_base import RangerBase + + +class RangerSecurityZoneService: + def __init__(self, resources=None): + self.resources = resources if resources is not None else [] + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerSecurityZone(RangerBase): + def __init__(self, id=None, guid=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None, + version=None, isEnabled=None, name=None, services=None, tagServices=None, adminUsers=None, + adminUserGroups=None, auditUsers=None, auditUserGroups=None, description=None): + super().__init__(id, guid, createdBy, updatedBy, createTime, updateTime, version, isEnabled) + self.name = name + self.services = services if services is not None else {} + self.tagServices = tagServices if tagServices is not None else [] + self.adminUsers = adminUsers if adminUsers is not None else [] + self.adminUserGroups = adminUserGroups if adminUserGroups is not None else [] + self.auditUsers = auditUsers if auditUsers is not None else [] + self.auditUserGroups = auditUserGroups if auditUserGroups is not None else [] + self.description = description + return + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) diff --git a/intg/src/main/python/ranger/model/ranger_service.py b/intg/src/main/python/ranger/model/ranger_service.py new file mode 100644 index 0000000..637c38f --- /dev/null +++ b/intg/src/main/python/ranger/model/ranger_service.py @@ -0,0 +1,43 @@ +#!/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 + +from ranger.model.ranger_base import RangerBase + + +class RangerService(RangerBase): + def __init__(self, id=None, guid=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None, + version=None, isEnabled=None, type=None, name=None, displayName=None, description=None, + tagService=None, configs=None, policyVersion=None, policyUpdateTime=None, tagVersion=None, + tagUpdateTime=None): + super().__init__(id, guid, createdBy, updatedBy, createTime, updateTime, version, isEnabled) + + self.type = type + self.name = name + self.displayName = displayName + self.description = description + self.tagService = tagService + self.configs = configs if configs is not None else {} + self.policyVersion = policyVersion + self.policyUpdateTime = policyUpdateTime + self.tagVersion = tagVersion + self.tagUpdateTime = tagUpdateTime + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) diff --git a/intg/src/main/python/ranger/model/ranger_service_def.py b/intg/src/main/python/ranger/model/ranger_service_def.py new file mode 100644 index 0000000..8cd4757 --- /dev/null +++ b/intg/src/main/python/ranger/model/ranger_service_def.py @@ -0,0 +1,136 @@ +#!/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 + +from ranger.model.ranger_base import RangerBase + + +class RangerDataMaskDef: + def __init__(self, maskTypes=None, accessTypes=None, resources=None): + self.maskTypes = maskTypes if maskTypes is not None else [] + self.accessTypes = accessTypes if accessTypes is not None else [] + self.resources = resources if resources is not None else [] + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerRowFilterDef: + def __init__(self, accessTypes=None, resources=None): + self.accessTypes = accessTypes if accessTypes is not None else [] + self.resources = resources if resources is not None else [] + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerServiceConfigDef: + def __init__(self, itemId=None, name=None, type=None, subType=None, mandatory=None, defaultValue=None, + validationRegEx=None, validationMessage=None, uiHint=None, label=None, description=None, + rbKeyLabel=None, rbKeyDescription=None, rbKeyValidationMessage=None): + self.itemId = itemId + self.name = name + self.type = type + self.subType = subType + self.mandatory = mandatory if mandatory is not None else False + self.defaultValue = defaultValue + self.validationRegEx = validationRegEx + self.validationMessage = validationMessage + self.uiHint = uiHint + self.label = label + self.description = description + self.rbKeyLabel = rbKeyLabel + self.rbKeyDescription = rbKeyDescription + self.rbKeyValidationMessage = rbKeyValidationMessage + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerAccessTypeDef: + def __init__(self, itemId=None, name=None, label=None, rbKeyLabel=None, impliedGrants=None): + self.itemId = itemId + self.name = name + self.label = label + self.rbKeyLabel = rbKeyLabel + self.impliedGrants = impliedGrants if impliedGrants is not None else [] + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerResourceDef: + def __init__(self, itemId=None, name=None, type=None, level=None, parent=None, mandatory=None, lookupSupported=None, + recursiveSupported=None, excludesSupported=None, matcher=None, matcherOptions=None, + validationRegEx=None, validationMessage=None, uiHint=None, label=None, description=None, + rbKeyLabel=None, rbKeyDescription=None, rbKeyValidationMessage=None, accessTypeRestrictions=None, + isValidLeaf=None): + self.itemId = itemId + self.name = name + self.type = type + self.level = level if level is not None else 1 + self.parent = parent + self.mandatory = mandatory if mandatory is not None else False + self.lookupSupported = lookupSupported if lookupSupported is not None else False + self.recursiveSupported = recursiveSupported if recursiveSupported is not None else False + self.excludesSupported = excludesSupported if excludesSupported is not None else False + self.matcher = matcher + self.matcherOptions = matcherOptions if matcherOptions is not None else {} + self.validationRegEx = validationRegEx + self.validationMessage = validationMessage + self.uiHint = uiHint + self.label = label + self.description = description + self.rbKeyLabel = rbKeyLabel + self.rbKeyDescription = rbKeyDescription + self.rbKeyValidationMessage = rbKeyValidationMessage + self.accessTypeRestrictions = accessTypeRestrictions if accessTypeRestrictions is not None else [] + self.isValidLeaf = isValidLeaf + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) + + +class RangerServiceDef(RangerBase): + def __init__(self, id=None, guid=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None, + version=None, isEnabled=None, name=None, displayName=None, implClass=None, label=None, + description=None, rbKeyLabel=None, rbKeyDescription=None, options=None, configs=None, resources=None, + accessTypes=None, policyConditions=None, contextEnrichers=None, enums=None, dataMaskDef=None, + rowFilterDef=None): + super().__init__(id, guid, createdBy, updatedBy, createTime, updateTime, version, isEnabled) + + self.name = name + self.displayName = displayName + self.implClass = implClass + self.label = label + self.description = description + self.rbKeyLabel = rbKeyLabel + self.rbKeyDescription = rbKeyDescription + self.options = options if options is not None else {} + self.configs = configs if configs is not None else [] + self.resources = resources if resources is not None else [] + self.accessTypes = accessTypes if accessTypes is not None else [] + self.policyConditions = policyConditions if policyConditions is not None else [] + self.contextEnrichers = contextEnrichers if contextEnrichers is not None else [] + self.enums = enums if enums is not None else [] + self.dataMaskDef = dataMaskDef if dataMaskDef is not None else RangerDataMaskDef() + self.rowFilterDef = rowFilterDef if rowFilterDef is not None else RangerRowFilterDef() + + def __repr__(self): + return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) diff --git a/intg/src/main/resources/logging.conf b/intg/src/main/resources/logging.conf new file mode 100644 index 0000000..c168775 --- /dev/null +++ b/intg/src/main/resources/logging.conf @@ -0,0 +1,40 @@ +# +# 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. +# + +[loggers] +keys=root + +[handlers] +keys=consoleHandler + +[formatters] +keys=simpleFormatter + +[logger_root] +level=INFO +handlers=consoleHandler + +[handler_consoleHandler] +class=StreamHandler +level=INFO +formatter=simpleFormatter +args=(sys.stdout,) + +[formatter_simpleFormatter] +format=%(asctime)s.%(msecs)03d %(levelname)s:%(name)s:%(message)s +datefmt=%Y-%m-%d %H:%M:%S diff --git a/intg/src/test/python/test_ranger_client.py b/intg/src/test/python/test_ranger_client.py new file mode 100644 index 0000000..5efda23 --- /dev/null +++ b/intg/src/test/python/test_ranger_client.py @@ -0,0 +1,109 @@ +#!/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 unittest +from unittest.mock import patch +from ranger.model.ranger_service import RangerService +from ranger.client.ranger_client import API, HttpMethod, HTTPStatus, RangerClient + + +class MockResponse: + def __init__(self, status_code, response=None, content=None): + self.status_code = status_code + self.response = response + self.content = content + return + + def json(self): + return [self.response.__repr__()] + + def text(self): + return str(self.content) + + +class TestRangerClient(unittest.TestCase): + URL = "url" + USERNAME = "user" + PASSWORD = "password" + + @patch('ranger.client.ranger_client.Session') + def test_get_service_unavailable(self, mock_session): + mock_session.return_value.get.return_value = MockResponse(HTTPStatus.SERVICE_UNAVAILABLE) + result = RangerClient(TestRangerClient.URL, TestRangerClient.USERNAME, TestRangerClient.PASSWORD).find_services({}) + + self.assertTrue(result is None) + + + @patch('ranger.client.ranger_client.Session') + def test_get_success(self, mock_session): + response = RangerService() + mock_session.return_value.get.return_value = MockResponse(HTTPStatus.OK, response=response, content='Success') + result = RangerClient(TestRangerClient.URL, TestRangerClient.USERNAME, TestRangerClient.PASSWORD).find_services({}) + + self.assertTrue(response.__repr__() in result) + + + @patch('ranger.client.ranger_client.Session') + @patch('ranger.client.ranger_client.Response') + def test_get_unexpected_status_code(self, mock_response, mock_session): + content = 'Internal Server Error' + mock_response.text = content + mock_response.content = content + mock_response.status_code = HTTPStatus.INTERNAL_SERVER_ERROR + mock_session.return_value.get.return_value = mock_response + + try: + RangerClient(TestRangerClient.URL, TestRangerClient.USERNAME, TestRangerClient.PASSWORD).find_services({}) + except Exception as e: + self.assertTrue(content in repr(e)) + + + @patch('ranger.client.ranger_client.RangerClient.FIND_SERVICES') + def test_unexpected_http_method(self, mock_api): + mock_api.method.return_value = "PATCH" + + try: + RangerClient(TestRangerClient.URL, TestRangerClient.USERNAME, TestRangerClient.PASSWORD).find_services({}) + except Exception as e: + self.assertTrue('Unsupported HTTP Method' in repr(e)) + + + def test_url_missing_format(self): + params = {'arg1': 1, 'arg2': 2} + + try: + API("{arg1}test{arg2}path{arg3}", HttpMethod.GET, HTTPStatus.OK).apply_url_params(params) + + self.fail("Supposed to fail") + except KeyError as e: + self.assertTrue('KeyError' in repr(e)) + + + def test_url_invalid_format(self): + params = {'1', '2'} + + try: + API("{}test{}path{}", HttpMethod.GET, HTTPStatus.OK).apply_url_params(params) + + self.fail("Supposed to fail") + except TypeError as e: + self.assertTrue('TypeError' in repr(e)) + + +if __name__ == '__main__': + unittest.main() diff --git a/pom.xml b/pom.xml index 4e7c922..b8d6141 100644 --- a/pom.xml +++ b/pom.xml @@ -158,6 +158,8 @@ <libpam4j.version>1.10</libpam4j.version> <local.lib.dir>${project.basedir}/../lib/local</local.lib.dir> <log4j.version>1.2.17</log4j.version> + <maven.exec.plugin.version>1.6.0</maven.exec.plugin.version> + <maven.pmd.plugin.version>3.7</maven.pmd.plugin.version> <metrics.core.version>3.0.2</metrics.core.version> <mockito.version>3.0.0</mockito.version> <mockito.all.version>1.10.19</mockito.all.version> @@ -948,7 +950,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-pmd-plugin</artifactId> - <version>3.7</version> + <version>${maven.pmd.plugin.version}</version> <executions> <execution> <phase>verify</phase> @@ -1030,6 +1032,7 @@ <exclude>**/package.json</exclude> <exclude>**/package-lock.json</exclude> <exclude>**/ranger_es_schema.json</exclude> + <exclude>**/venv/**</exclude> </excludes> </configuration> </plugin> diff --git a/ranger-examples/distro/src/main/assembly/sample-client.xml b/ranger-examples/distro/src/main/assembly/sample-client.xml index cde39f1..e3fa1bb 100644 --- a/ranger-examples/distro/src/main/assembly/sample-client.xml +++ b/ranger-examples/distro/src/main/assembly/sample-client.xml @@ -78,10 +78,10 @@ <directory>${project.parent.basedir}/sample-client/scripts</directory> <includes> <include>*.sh</include> + <include>*.py</include> </includes> <fileMode>755</fileMode> </fileSet> -<!-- only for testing --> <fileSet> <outputDirectory></outputDirectory> <directory>${project.parent.basedir}/sample-client/conf</directory> @@ -99,5 +99,24 @@ <include>*.properties</include> </includes> </fileSet> + <fileSet> + <outputDirectory>venv/pylib</outputDirectory> + <directory>../../intg/src/main/python</directory> + </fileSet> + <fileSet> + <outputDirectory>venv/resources</outputDirectory> + <directory>../../intg/src/main/resources</directory> + </fileSet> + <fileSet> + <outputDirectory>venv/pylib</outputDirectory> + <directory>../sample-client/src/main/python</directory> + <includes> + <include>sample_client.py</include> + </includes> + </fileSet> + <fileSet> + <outputDirectory>venv</outputDirectory> + <directory>../sample-client/venv</directory> + </fileSet> </fileSets> </assembly> diff --git a/ranger-examples/sample-client/.gitignore b/ranger-examples/sample-client/.gitignore index a6f89c2..897593c 100644 --- a/ranger-examples/sample-client/.gitignore +++ b/ranger-examples/sample-client/.gitignore @@ -1 +1,2 @@ -/target/ \ No newline at end of file +/target/ +/venv/ \ No newline at end of file diff --git a/ranger-examples/sample-client/conf/config.properties b/ranger-examples/sample-client/conf/config.properties new file mode 100644 index 0000000..5be772a --- /dev/null +++ b/ranger-examples/sample-client/conf/config.properties @@ -0,0 +1,21 @@ +# 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. +# +ranger.client.url=https://localhost:6182 +# Authentication properties +ranger.client.authentication.type=kerberos +ranger.client.kerberos.principal= +ranger.client.kerberos.keytab= +ranger.client.ssl.config.filename= \ No newline at end of file diff --git a/ranger-examples/sample-client/pom.xml b/ranger-examples/sample-client/pom.xml index b102e38..d112c6f 100644 --- a/ranger-examples/sample-client/pom.xml +++ b/ranger-examples/sample-client/pom.xml @@ -28,6 +28,44 @@ <modelVersion>4.0.0</modelVersion> <artifactId>sample-client</artifactId> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-clean-plugin</artifactId> + <version>2.6.1</version> + <configuration> + <filesets> + <fileset> + <directory>venv</directory> + </fileset> + </filesets> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>${maven.exec.plugin.version}</version> + <executions> + <execution> + <configuration> + <executable>python3</executable> + <arguments> + <argument>-m</argument> + <argument>venv</argument> + <argument>venv</argument> + </arguments> + </configuration> + <id>create-venv</id> + <phase>prepare-package</phase> + <goals> + <goal>exec</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> <dependencies> <dependency> <groupId>org.apache.ranger</groupId> diff --git a/ranger-examples/sample-client/scripts/run-pyclient.sh b/ranger-examples/sample-client/scripts/run-pyclient.sh new file mode 100644 index 0000000..8649f0b --- /dev/null +++ b/ranger-examples/sample-client/scripts/run-pyclient.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# 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. + +usage() { + echo "usage: run-pyclient.sh + -n <arg> url to connect to + -h show help." + exit 1 +} + +cd venv || exit +source bin/activate +INSTALL="python3 ./../setup.py install" +$INSTALL >> build.log +PYTHON_CMD="python3 build/lib/pylib/sample_client.py" +while getopts "n:h" opt; do + case $opt in + n) URL=$OPTARG + PYTHON_CMD="$PYTHON_CMD --url $URL" + ;; + h) usage + ;; + \?) echo -e \\n"Option -$OPTARG not allowed." + usage + ;; + esac +done + +prompt="Sample Authentication User Name:" +read -p "$prompt" userName +prompt="Sample Authentication User Password:" +read -p "$prompt" -s password +printf "\n" +PYTHON_CMD="$PYTHON_CMD --username $userName --password $password" +printf "Python command : %s\n" "$PYTHON_CMD" +$PYTHON_CMD \ No newline at end of file diff --git a/ranger-examples/sample-client/scripts/setup.py b/ranger-examples/sample-client/scripts/setup.py new file mode 100644 index 0000000..c4e7407 --- /dev/null +++ b/ranger-examples/sample-client/scripts/setup.py @@ -0,0 +1,30 @@ +#!/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. + +from setuptools import setup, find_packages + +# External dependencies +requirements = ['requests>=2.24'] + +setup( + name='sample_pyclient', + packages=['pylib', 'pylib/ranger/client', 'pylib/ranger/model'], + data_files=[('../../lib/resources', ['resources/logging.conf'])], + install_requires=requirements, + zip_safe=False +) diff --git a/ranger-examples/sample-client/src/main/python/sample_client.py b/ranger-examples/sample-client/src/main/python/sample_client.py new file mode 100644 index 0000000..7ff6e70 --- /dev/null +++ b/ranger-examples/sample-client/src/main/python/sample_client.py @@ -0,0 +1,110 @@ +#!/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 argparse +import logging.config + +from ranger.model.ranger_service import RangerService +from ranger.model.ranger_role import RangerRole, RoleMember +from ranger.client.ranger_client import RangerClient, LOG_CONFIG +from ranger.model.ranger_policy import RangerPolicy, RangerPolicyResource +from ranger.model.ranger_service_def import RangerServiceConfigDef, RangerAccessTypeDef, RangerResourceDef, RangerServiceDef + +logging.config.fileConfig(LOG_CONFIG, disable_existing_loggers=False) +log = logging.getLogger(__name__) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Parameters required for connection to Ranger Admin!') + parser.add_argument('--url', default='http://localhost:6080') + parser.add_argument('--username') + parser.add_argument('--password') + args = parser.parse_args() + + service_def_name = "sampleServiceDef" + service_name = "sampleService" + policy_name = "samplePolicy" + role_name = "sampleRole" + + ranger_client = RangerClient(args.url, args.username, args.password) + + # create a new service definition + config = RangerServiceConfigDef(itemId=1, name='sampleConfig', type='string') + access_type = RangerAccessTypeDef(itemId=1, name='sampleAccess') + resource_def = RangerResourceDef(itemId=1, name='root', type='string') + service_def = RangerServiceDef(name=service_def_name, configs=[config], accessTypes=[access_type], + resources=[resource_def]) + + created_service_def = ranger_client.create_service_def(service_def) + log.info('New Service Definition created successfully {}'.format(created_service_def)) + + # create a new service + service = RangerService(name=service_name, type=service_def_name) + + created_service = ranger_client.create_service(service) + log.info('New Service created successfully {}'.format(created_service)) + + # create a new policy + resource = RangerPolicyResource(['/path/to/sample/resource'], False, False) + policy = RangerPolicy(service=service_name, name=policy_name, resources={'root': resource}) + created_policy = ranger_client.create_policy(policy) + log.info('New Ranger Policy created successfully {}'.format(created_policy)) + + # update an existing policy + policy = RangerPolicy(service=service_name, name=policy_name, description='Policy Updated!') + updated_policy = ranger_client.update_policy(service_name, policy_name, policy) + log.info('Ranger Policy updated successfully {}'.format(updated_policy)) + + # get a policy by name + fetched_policy = ranger_client.get_policy(service_name, policy_name) + log.info('Policy {} fetched {}'.format(policy_name, fetched_policy)) + + # get all policies + all_policies = ranger_client.find_policies({}) + for id, policy in enumerate(all_policies): + log.info('Policy #{}: {}'.format(id, RangerPolicy(**policy))) + + # delete a policy by name + ranger_client.delete_policy(service_name, policy_name) + log.info('Policy {} successfully deleted'.format(policy_name)) + + # create a role in ranger + sample_role = RangerRole(name=role_name, description='Sample Role', users=[RoleMember(isAdmin=True)]) + created_role = ranger_client.create_role(service_name, sample_role) + log.info('New Role successfully created {}'.format(created_role)) + + # update a role in ranger + sample_role = RangerRole(name=role_name, description='Updated Sample Role!') + updated_role = ranger_client.update_role(created_role.id, sample_role) + log.info('Role {} successfully updated {}'.format(role_name, updated_role)) + + # get all roles in ranger + all_roles = ranger_client.find_roles({}) + log.info('List of Roles {}'.format(all_roles)) if all_roles is not None else log.info('No roles found!') + + # delete a role in ranger + ranger_client.delete_role(role_name, ranger_client.username, service_name) + log.info('Role {} successfully deleted'.format(role_name)) + + # delete a service + ranger_client.delete_service(service_name) + log.info('Service {} successfully deleted'.format(service_name)) + + # delete a service definition + ranger_client.delete_service_def(service_def_name) + log.info('Service Definition {} successfully deleted'.format(service_def_name)) +
