This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch ranger-2.6
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/ranger-2.6 by this push:
new eac0d3f77 RANGER-4889: updated RangerMemSizing to support access
request evaluations
eac0d3f77 is described below
commit eac0d3f779e6788772934f1c667df3a98369e67e
Author: Madhan Neethiraj <[email protected]>
AuthorDate: Mon Aug 5 18:08:53 2024 -0700
RANGER-4889: updated RangerMemSizing to support access request evaluations
(cherry picked from commit 9de9676d5d2100bcba2574e507c9d4ba474ba0f3)
---
.../apache/ranger/sizing/PerfRequestGenerator.java | 160 +++++++++++
.../org/apache/ranger/sizing/RangerMemSizing.java | 307 ++++++++++++++++++++-
2 files changed, 464 insertions(+), 3 deletions(-)
diff --git
a/ranger-tools/src/main/java/org/apache/ranger/sizing/PerfRequestGenerator.java
b/ranger-tools/src/main/java/org/apache/ranger/sizing/PerfRequestGenerator.java
new file mode 100644
index 000000000..a33299312
--- /dev/null
+++
b/ranger-tools/src/main/java/org/apache/ranger/sizing/PerfRequestGenerator.java
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+package org.apache.ranger.sizing;
+
+import org.apache.ranger.plugin.model.RangerPolicy;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
+import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
+import org.apache.ranger.plugin.util.ServicePolicies;
+import org.apache.ranger.plugin.util.ServiceTags;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+public class PerfRequestGenerator {
+ public PerfRequestGenerator() {
+ }
+
+ public Collection<RangerAccessRequest> generate(ServicePolicies policies,
ServiceTags tags) {
+ List<RangerAccessRequest> ret = new ArrayList<>();
+ Set<Map<String, Object>> resources = new HashSet<>();
+ Set<String> accessTypes = new HashSet<>();
+ Set<String> users = new HashSet<>();
+ Set<String> groups = new HashSet<>();
+
+ // collect resources, users, groups referenced in policies
+ // collect accessTypes from serviceDef
+ if (policies != null) {
+ if (policies.getServiceDef() != null &&
policies.getServiceDef().getAccessTypes() != null) {
+ policies.getServiceDef().getAccessTypes().forEach(atd ->
accessTypes.add(atd.getName()));
+ }
+
+ if (policies.getPolicies() != null) {
+ policies.getPolicies().forEach(policy -> {
+ collectResources(policy.getResources(), resources);
+
+ if (policy.getAdditionalResources() != null) {
+ policy.getAdditionalResources().forEach(resource ->
collectResources(resource, resources));
+ }
+
+ collectUsersGroups(policy, users, groups);
+ });
+ }
+
+ if (policies.getTagPolicies() != null &&
policies.getTagPolicies().getPolicies() != null) {
+ policies.getTagPolicies().getPolicies().forEach(policy ->
collectUsersGroups(policy, users, groups));
+ }
+ }
+
+ // collect resources from tagged-resources
+ if (tags != null && tags.getServiceResources() != null) {
+ tags.getServiceResources().forEach(resource ->
collectResources(resource.getResourceElements(), resources));
+ }
+
+ if (accessTypes.isEmpty()) {
+ accessTypes.add("read");
+ }
+
+ if (users.isEmpty()) {
+ users.add("user1");
+ }
+
+ if (groups.isEmpty()) {
+ groups.add("group1");
+ }
+
+ Iterator<String> iterAccessTypes = accessTypes.iterator();
+ Iterator<String> iterUser = users.iterator();
+ Iterator<String> iterGroup = groups.iterator();
+
+ for (Map<String, Object> resource : resources) {
+ ret.add(new RangerAccessRequestImpl(new
RangerAccessResourceImpl(resource), iterAccessTypes.next(), iterUser.next(),
Collections.singleton(iterGroup.next()), null));
+
+ if (!iterAccessTypes.hasNext()) {
+ iterAccessTypes = accessTypes.iterator();
+ }
+
+ if (!iterUser.hasNext()) {
+ iterUser = users.iterator();
+ }
+
+ if (!iterGroup.hasNext()) {
+ iterGroup = groups.iterator();
+ }
+ }
+
+ return ret;
+ }
+
+ private void collectResources(Map<String, RangerPolicyResource>
policyResource, Set<Map<String, Object>> resources) {
+ if (policyResource != null) {
+ int resourceCount = 1;
+
+ for (Map.Entry<String, RangerPolicyResource> entry :
policyResource.entrySet()) {
+ resourceCount *= entry.getValue().getValues().size();
+ }
+
+ List<Map<String, Object>> toAdd = new ArrayList<>(resourceCount);
+
+ for (int i = 0; i < resourceCount; i++) {
+ toAdd.add(new HashMap<>());
+ }
+
+ for (Map.Entry<String, RangerPolicyResource> entry :
policyResource.entrySet()) {
+ String name = entry.getKey();
+ List<String> values = entry.getValue().getValues();
+
+ for (int idxResource = 0; idxResource < resourceCount;
idxResource++) {
+ toAdd.get(idxResource).put(name, values.get(idxResource %
values.size()));
+ }
+ }
+
+ resources.addAll(toAdd);
+ }
+ }
+
+ private void collectUsersGroups(RangerPolicy policy, Set<String> users,
Set<String> groups) {
+ collectUsersGroups(policy.getPolicyItems(), users, groups);
+ collectUsersGroups(policy.getAllowExceptions(), users, groups);
+ collectUsersGroups(policy.getDenyPolicyItems(), users, groups);
+ collectUsersGroups(policy.getDenyExceptions(), users, groups);
+ collectUsersGroups(policy.getDataMaskPolicyItems(), users, groups);
+ collectUsersGroups(policy.getRowFilterPolicyItems(), users, groups);
+ }
+
+ private void collectUsersGroups(List<? extends RangerPolicyItem>
policyItems, Set<String> users, Set<String> groups) {
+ if (policyItems != null) {
+ policyItems.forEach(policyItem -> {
+ users.addAll(policyItem.getUsers());
+ groups.addAll(policyItem.getGroups());
+ });
+ }
+ }
+}
diff --git
a/ranger-tools/src/main/java/org/apache/ranger/sizing/RangerMemSizing.java
b/ranger-tools/src/main/java/org/apache/ranger/sizing/RangerMemSizing.java
index 74f231013..ee9d8b47f 100644
--- a/ranger-tools/src/main/java/org/apache/ranger/sizing/RangerMemSizing.java
+++ b/ranger-tools/src/main/java/org/apache/ranger/sizing/RangerMemSizing.java
@@ -20,14 +20,42 @@
package org.apache.ranger.sizing;
import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
-
-import org.apache.commons.cli.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.Version;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
import org.apache.commons.lang.StringUtils;
import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig;
import org.apache.ranger.authorization.utils.JsonUtils;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
+import org.apache.ranger.plugin.policyengine.RangerAccessResource;
+import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
+import org.apache.ranger.plugin.policyengine.RangerAccessResult;
import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions;
import org.apache.ranger.plugin.service.RangerBasePlugin;
import org.apache.ranger.plugin.util.RangerRoles;
@@ -43,10 +71,15 @@ public class RangerMemSizing {
private final SimpleDateFormat DATE_FORMAT = new
SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
+ private static final TypeReference<List<RangerAccessRequest>>
TYPE_LIST_REQUESTS = new TypeReference<List<RangerAccessRequest>>() {};
+
private final String policyFile;
private final String tagFile;
private final String rolesFile;
private final String userStoreFile;
+ private final String genRequestsFile;
+ private final String evalRequestsFile;
+ private final int evalClientsCount;
private final boolean deDup;
private final boolean deDupStrings;
private final String optimizationMode;
@@ -58,6 +91,9 @@ public class RangerMemSizing {
this.tagFile = cmdLine.getOptionValue('t');
this.rolesFile = cmdLine.getOptionValue('r');
this.userStoreFile = cmdLine.getOptionValue('u');
+ this.genRequestsFile = cmdLine.getOptionValue('q');
+ this.evalRequestsFile = cmdLine.getOptionValue('e');
+ this.evalClientsCount = cmdLine.hasOption('c') ?
Integer.parseInt(cmdLine.getOptionValue('c')) : 1;
this.deDup = Boolean.parseBoolean(cmdLine.getOptionValue("d",
"true"));
this.deDupStrings = this.deDup;
this.optimizationMode =
StringUtils.startsWithIgnoreCase(cmdLine.getOptionValue('o', "space"), "s") ?
OPT_MODE_SPACE : OPT_MODEL_RETRIEVAL;
@@ -71,6 +107,20 @@ public class RangerMemSizing {
RangerRoles roles = loadRoles(rolesFile, tracker);
RangerUserStore userStore = loadUserStore(userStoreFile, tracker);
RangerBasePlugin plugin = createRangerPlugin(policies, tags, roles,
userStore, tracker);
+ int genReqCount = 0;
+ int evalReqCount = 0;
+ int evalAvgTimeNs = 0;
+
+ if (StringUtils.isNotBlank(genRequestsFile)) {
+ genReqCount = generateRequestsFile(policies, tags, genRequestsFile,
tracker);
+ }
+
+ if (StringUtils.isNotBlank(evalRequestsFile)) {
+ int[] res = evaluateRequests(evalRequestsFile, plugin, tracker);
+
+ evalReqCount = res[0];
+ evalAvgTimeNs = res[1];
+ }
tracker.stop();
@@ -92,6 +142,14 @@ public class RangerMemSizing {
out.println(" UserStore: file=" + userStoreFile + ", size=" + new
File(userStoreFile).length() + ", " + toSummaryStr(userStore));
}
+ if (genRequestsFile != null) {
+ out.println(" GenReq: file=" + genRequestsFile + ", requestCount=" +
genReqCount);
+ }
+
+ if (evalRequestsFile != null) {
+ out.println(" EvalReq: file=" + evalRequestsFile + ", requestCount="
+ evalReqCount + ", avgTimeTaken=" + evalAvgTimeNs + "ns, clientCount=" +
evalClientsCount);
+ }
+
out.println(" DeDup: " + deDup);
out.println(" OptMode: " + optimizationMode);
out.println();
@@ -314,13 +372,144 @@ public class RangerMemSizing {
return ret;
}
+ private int generateRequestsFile(ServicePolicies policies, ServiceTags tags,
String fileName, PerfMemTimeTracker parent) {
+ ObjectMapper mapper = JsonUtils.getMapper();
+
+ initMapper(mapper);
+
+ PerfMemTimeTracker tracker = new PerfMemTimeTracker("generateRequests");
+
+ Collection<RangerAccessRequest> requests = new
PerfRequestGenerator().generate(policies, tags);
+
+ log("generateRequestsFile(): saving " + requests.size() + " requests..");
+
+ try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(fileName)))
{
+ writer.write('[');
+
+ boolean isFirst = true;
+
+ for (RangerAccessRequest request : requests) {
+ if (!isFirst) {
+ writer.write(',');
+ } else {
+ isFirst = false;
+ }
+ writer.newLine();
+
+ writer.write(mapper.writeValueAsString(request));
+ }
+
+ writer.newLine();
+ writer.write(']');
+
+ log("generateRequestsFile(): saved " + requests.size() + " requests");
+ } catch (IOException excp) {
+ log("generateRequestsFile(): failed", excp);
+ }
+
+ tracker.stop();
+ parent.addChild(tracker);
+
+ return requests.size();
+ }
+
+ private int[] evaluateRequests(String evalRequestsFile, RangerBasePlugin
plugin, PerfMemTimeTracker parent) {
+ PerfMemTimeTracker tracker = new PerfMemTimeTracker("evaluateRequests");
+
+ final List<RangerAccessRequest> requests =
readRequests(evalRequestsFile, tracker);
+ final Thread[] clients = new
Thread[evalClientsCount];
+ final AtomicInteger idxNextRequest = new AtomicInteger();
+ final AtomicLong totalTimeTakenNs = new AtomicLong();
+
+ for (int idxClient = 0; idxClient < evalClientsCount; idxClient++) {
+ clients[idxClient] = new Thread(() -> {
+ do {
+ int idxReq = idxNextRequest.getAndIncrement();
+
+ if (idxReq >= requests.size()) {
+ break;
+ }
+
+ RangerAccessRequest request = requests.get(idxReq);
+
+ long startTime = System.nanoTime();
+
+ RangerAccessResult result = plugin.isAccessAllowed(request);
+
+ totalTimeTakenNs.getAndAdd(System.nanoTime() - startTime);
+
+ if ((idxReq + 1) % 1000 == 0) {
+ log(" evaluated requests: " + (idxReq + 1) + ", avgTimeTaken=" +
(totalTimeTakenNs.get() / idxReq) + "ns");
+ }
+
+ requests.set(idxReq, null); // so that objects associated with the
request can be freed
+ } while (true);
+ });
+ }
+
+ log("evaluateRequests(): evaluating " + requests.size() + " requests in "
+ clients.length + " clients...");
+
+ for (Thread client : clients) {
+ client.run();
+ }
+
+ log("evaluateRequests(): waiting for " + clients.length + " clients to
complete...");
+ for (Thread client : clients) {
+ try {
+ client.join();
+ } catch (Exception excp) {
+ // ignore
+ }
+ }
+
+ tracker.stop();
+ parent.addChild(tracker);
+
+ int avgTimeTakenNs = (int) (totalTimeTakenNs.get() / idxNextRequest.get());
+
+ log("evaluateRequests(): evaluated " + idxNextRequest.get() + " requests,
avgTimeTaken=" + avgTimeTakenNs + "ns");
+
+ return new int[] { requests.size(), avgTimeTakenNs };
+ }
+
+ private List<RangerAccessRequest> readRequests(String fileName,
PerfMemTimeTracker parent) {
+ PerfMemTimeTracker tracker = new PerfMemTimeTracker("readRequests");
+
+ List<RangerAccessRequest> ret = null;
+
+ ObjectMapper mapper = JsonUtils.getMapper();
+
+ initMapper(mapper);
+
+ try (InputStream inStr =
Files.newInputStream(Paths.get(evalRequestsFile))) {
+ ret = mapper.readValue(inStr, TYPE_LIST_REQUESTS);
+ } catch (IOException excp) {
+ log("readRequests(): failed to read file " + evalRequestsFile, excp);
+ }
+
+ if (ret == null) {
+ ret = Collections.emptyList();
+ }
+
+ tracker.stop();
+ parent.addChild(tracker);
+
+ log("readRequests(file=" + fileName + ", size=" + new
File(evalRequestsFile).length() + "): request count=" + ret.size());
+
+ return ret;
+ }
+
private static CommandLine parseArgs(String[] args) {
Option help = new Option("h", "help", false, "show help");
- Option deDup = new Option("d", "deDup", true, "deDup string/tags");
+ Option deDup = new Option("d", "deDup", true, "deDup string, tags:
true|false");
Option policies = new Option("p", "policies", true, "policies file");
Option tags = new Option("t", "tags", true, "tags file");
Option roles = new Option("r", "roles", true, "roles file");
Option userStore = new Option("u", "userStore", true, "userStore file");
+ Option genRequests = new Option("q", "genRequests", true, "generate
requests file");
+ Option evalRequests = new Option("e", "evalRequests", true, "eval requests
file");
+ Option evalClients = new Option("c", "evalClients", true, "eval clients
count");
+ Option gdsInfo = new Option("g", "gdsInfo", true, "gdsInfo file");
Option optimizeMode = new Option("o", "optMode", true, "optimization mode:
space|retrieval");
Options options = new Options();
@@ -330,6 +519,10 @@ public class RangerMemSizing {
options.addOption(tags);
options.addOption(roles);
options.addOption(userStore);
+ options.addOption(genRequests);
+ options.addOption(evalRequests);
+ options.addOption(evalClients);
+ options.addOption(gdsInfo);
options.addOption(deDup);
options.addOption(optimizeMode);
@@ -454,4 +647,112 @@ public class RangerMemSizing {
return "users=" + userCount + ", groups=" + groupCount + ",
userGroupMappings=" + userGroupCount;
}
+
+ private void initMapper(ObjectMapper mapper) {
+ SimpleModule serDeModule = new SimpleModule("RangerMemSizing", new
Version(1, 0, 0, null, null, null));
+
+ serDeModule.addSerializer(RangerAccessResource.class, new
RangerAccessResourceSerializer());
+ serDeModule.addSerializer(RangerAccessResourceImpl.class, new
RangerAccessResourceImplSerializer());
+ serDeModule.addDeserializer(RangerAccessResource.class, new
RangerAccessResourceDeserializer());
+
+ serDeModule.addSerializer(RangerAccessRequest.class, new
RangerAccessRequestSerializer());
+ serDeModule.addSerializer(RangerAccessRequestImpl.class, new
RangerAccessRequestImplSerializer());
+ serDeModule.addDeserializer(RangerAccessRequest.class, new
RangerAccessRequestDeserializer());
+
+ mapper.registerModule(serDeModule);
+ }
+
+
+ static class TestRangerAccessResourceImpl {
+ private Map<String, Object> elements;
+
+ public TestRangerAccessResourceImpl() {
+ }
+
+ public TestRangerAccessResourceImpl(Map<String, Object> elements) {
+ this.elements = elements;
+ }
+
+ public Map<String, Object> getElements() { return elements; }
+ }
+
+ static class TestRangerAccessRequestImpl {
+ private TestRangerAccessResourceImpl resource;
+ private String accessType;
+ private String user;
+ private Set<String> userGroups;
+
+ public TestRangerAccessRequestImpl() {
+ }
+
+ public TestRangerAccessRequestImpl(RangerAccessResource resource, String
accessType, String user, Set<String> userGroups) {
+ this.resource = new TestRangerAccessResourceImpl(resource.getAsMap());
+ this.accessType = accessType;
+ this.user = user;
+ this.userGroups = userGroups;
+ }
+
+ public TestRangerAccessResourceImpl getResource() {
+ return resource;
+ }
+
+ public String getAccessType() {
+ return accessType;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public Set<String> getUserGroups() {
+ return userGroups;
+ }
+
+ }
+
+ static class RangerAccessResourceSerializer extends
JsonSerializer<RangerAccessResource> {
+ @Override
+ public void serialize(RangerAccessResource value, JsonGenerator gen,
SerializerProvider serializers) throws IOException {
+ JsonUtils.getMapper().writeValue(gen, new
TestRangerAccessResourceImpl(value.getAsMap()));
+ }
+ }
+
+ static class RangerAccessResourceImplSerializer extends
JsonSerializer<RangerAccessResource> {
+ @Override
+ public void serialize(RangerAccessResource value, JsonGenerator gen,
SerializerProvider serializers) throws IOException {
+ JsonUtils.getMapper().writeValue(gen, new
TestRangerAccessResourceImpl(value.getAsMap()));
+ }
+ }
+
+ static class RangerAccessResourceDeserializer extends
JsonDeserializer<RangerAccessResource> {
+ @Override
+ public RangerAccessResource deserialize(JsonParser parser,
DeserializationContext context) throws IOException {
+ TestRangerAccessResourceImpl resource = context.readValue(parser,
TestRangerAccessResourceImpl.class);
+
+ return new RangerAccessResourceImpl(resource.getElements());
+ }
+ }
+
+ static class RangerAccessRequestSerializer extends
JsonSerializer<RangerAccessRequest> {
+ @Override
+ public void serialize(RangerAccessRequest value, JsonGenerator gen,
SerializerProvider serializers) throws IOException {
+ JsonUtils.getMapper().writeValue(gen, new
TestRangerAccessRequestImpl(value.getResource(), value.getAccessType(),
value.getUser(), value.getUserGroups()));
+ }
+ }
+
+ static class RangerAccessRequestImplSerializer extends
JsonSerializer<RangerAccessRequestImpl> {
+ @Override
+ public void serialize(RangerAccessRequestImpl value, JsonGenerator gen,
SerializerProvider serializers) throws IOException {
+ JsonUtils.getMapper().writeValue(gen, new
TestRangerAccessRequestImpl(value.getResource(), value.getAccessType(),
value.getUser(), value.getUserGroups()));
+ }
+ }
+
+ static class RangerAccessRequestDeserializer extends
JsonDeserializer<RangerAccessRequest> {
+ @Override
+ public RangerAccessRequest deserialize(JsonParser parser,
DeserializationContext context) throws IOException {
+ TestRangerAccessRequestImpl req = context.readValue(parser,
TestRangerAccessRequestImpl.class);
+
+ return new RangerAccessRequestImpl(new
RangerAccessResourceImpl(req.resource.getElements()), req.accessType, req.user,
req.userGroups, null);
+ }
+ }
}