blob: d671b73be5776d81aaac9599febf3d3383062a71 [file] [log] [blame]
/*
* 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.plugin.contextenricher;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
import org.apache.ranger.plugin.model.RangerPolicy;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.model.RangerServiceResource;
import org.apache.ranger.plugin.model.RangerTag;
import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper;
import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
import org.apache.ranger.plugin.policyengine.RangerAccessResource;
import org.apache.ranger.plugin.policyresourcematcher.RangerDefaultPolicyResourceMatcher;
import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
import org.apache.ranger.plugin.service.RangerAuthContext;
import org.apache.ranger.plugin.service.RangerBasePlugin;
import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
import org.apache.ranger.plugin.util.RangerPerfTracer;
import org.apache.ranger.plugin.util.RangerResourceTrie;
import org.apache.ranger.plugin.util.RangerServiceNotFoundException;
import org.apache.ranger.plugin.util.ServiceTags;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class RangerTagEnricher extends RangerAbstractContextEnricher {
private static final Log LOG = LogFactory.getLog(RangerTagEnricher.class);
private static final Log PERF_CONTEXTENRICHER_INIT_LOG = RangerPerfTracer.getPerfLogger("contextenricher.init");
private static final Log PERF_TRIE_OP_LOG = RangerPerfTracer.getPerfLogger("resourcetrie.retrieval");
public static final String TAG_REFRESHER_POLLINGINTERVAL_OPTION = "tagRefresherPollingInterval";
public static final String TAG_RETRIEVER_CLASSNAME_OPTION = "tagRetrieverClassName";
public static final String TAG_DISABLE_TRIE_PREFILTER_OPTION = "disableTrieLookupPrefilter";
private RangerTagRefresher tagRefresher;
private RangerTagRetriever tagRetriever;
private boolean disableTrieLookupPrefilter;
private EnrichedServiceTags enrichedServiceTags;
private boolean disableCacheIfServiceNotFound = true;
@Override
public void init() {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerTagEnricher.init()");
}
super.init();
String tagRetrieverClassName = getOption(TAG_RETRIEVER_CLASSNAME_OPTION);
long pollingIntervalMs = getLongOption(TAG_REFRESHER_POLLINGINTERVAL_OPTION, 60 * 1000);
disableTrieLookupPrefilter = getBooleanOption(TAG_DISABLE_TRIE_PREFILTER_OPTION, false);
if (StringUtils.isNotBlank(tagRetrieverClassName)) {
try {
@SuppressWarnings("unchecked")
Class<RangerTagRetriever> tagRetriverClass = (Class<RangerTagRetriever>) Class.forName(tagRetrieverClassName);
tagRetriever = tagRetriverClass.newInstance();
} catch (ClassNotFoundException exception) {
LOG.error("Class " + tagRetrieverClassName + " not found, exception=" + exception);
} catch (ClassCastException exception) {
LOG.error("Class " + tagRetrieverClassName + " is not a type of RangerTagRetriever, exception=" + exception);
} catch (IllegalAccessException exception) {
LOG.error("Class " + tagRetrieverClassName + " illegally accessed, exception=" + exception);
} catch (InstantiationException exception) {
LOG.error("Class " + tagRetrieverClassName + " could not be instantiated, exception=" + exception);
}
if (tagRetriever != null) {
String propertyPrefix = "ranger.plugin." + serviceDef.getName();
disableCacheIfServiceNotFound = RangerConfiguration.getInstance().getBoolean(propertyPrefix + ".disable.cache.if.servicenotfound", true);
String cacheDir = RangerConfiguration.getInstance().get(propertyPrefix + ".policy.cache.dir");
String cacheFilename = String.format("%s_%s_tag.json", appId, serviceName);
cacheFilename = cacheFilename.replace(File.separatorChar, '_');
cacheFilename = cacheFilename.replace(File.pathSeparatorChar, '_');
String cacheFile = cacheDir == null ? null : (cacheDir + File.separator + cacheFilename);
tagRetriever.setServiceName(serviceName);
tagRetriever.setServiceDef(serviceDef);
tagRetriever.setAppId(appId);
tagRetriever.init(enricherDef.getEnricherOptions());
tagRefresher = new RangerTagRefresher(tagRetriever, this, -1L, cacheFile, pollingIntervalMs);
try {
tagRefresher.populateTags();
} catch (Throwable exception) {
LOG.error("Exception when retrieving tag for the first time for this enricher", exception);
}
tagRefresher.setDaemon(true);
tagRefresher.startRefresher();
}
} else {
LOG.error("No value specified for " + TAG_RETRIEVER_CLASSNAME_OPTION + " in the RangerTagEnricher options");
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerTagEnricher.init()");
}
}
@Override
public void enrich(RangerAccessRequest request) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerTagEnricher.enrich(" + request + ")");
}
enrich(request, null);
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerTagEnricher.enrich(" + request + ")");
}
}
@Override
public void enrich(RangerAccessRequest request, Object dataStore) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerTagEnricher.enrich(" + request + ") with dataStore:[" + dataStore + "]");
}
final EnrichedServiceTags enrichedServiceTags;
if (dataStore instanceof EnrichedServiceTags) {
enrichedServiceTags = (EnrichedServiceTags) dataStore;
} else {
enrichedServiceTags = this.enrichedServiceTags;
if (dataStore != null) {
LOG.warn("Incorrect type of dataStore :[" + dataStore.getClass().getName() + "], falling back to original enrich");
}
}
final Set<RangerTagForEval> matchedTags = enrichedServiceTags == null ? null : findMatchingTags(request, enrichedServiceTags);
RangerAccessRequestUtil.setRequestTagsInContext(request.getContext(), matchedTags);
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerTagEnricher.enrich(" + request + ") with dataStore:[" + dataStore + "]): tags count=" + (matchedTags == null ? 0 : matchedTags.size()));
}
}
/*
* This class implements a cache of result of look-up of keyset of policy-resources for each of the collections of hierarchies
* for policy types: access, datamask and rowfilter. If a keyset is examined for validity in a hierarchy of a policy-type,
* then that record is maintained in this cache for later look-up.
*
* The basic idea is that with a large number of tagged service-resources, this cache will speed up performance as well as put
* a cap on the upper bound because it is expected that the cardinality of set of all possible keysets for all resource-def
* combinations in a service-def will be much smaller than the number of service-resources.
*/
static private class ResourceHierarchies {
private final Map<Collection<String>, Boolean> accessHierarchies = new HashMap<>();
private final Map<Collection<String>, Boolean> dataMaskHierarchies = new HashMap<>();
private final Map<Collection<String>, Boolean> rowFilterHierarchies = new HashMap<>();
public Boolean isValidHierarchy(int policyType, Collection<String> resourceKeys) {
switch (policyType) {
case RangerPolicy.POLICY_TYPE_ACCESS:
return accessHierarchies.get(resourceKeys);
case RangerPolicy.POLICY_TYPE_DATAMASK:
return dataMaskHierarchies.get(resourceKeys);
case RangerPolicy.POLICY_TYPE_ROWFILTER:
return rowFilterHierarchies.get(resourceKeys);
default:
return null;
}
}
public void addHierarchy(int policyType, Collection<String> resourceKeys, Boolean isValid) {
switch (policyType) {
case RangerPolicy.POLICY_TYPE_ACCESS:
accessHierarchies.put(resourceKeys, isValid);
break;
case RangerPolicy.POLICY_TYPE_DATAMASK:
dataMaskHierarchies.put(resourceKeys, isValid);
break;
case RangerPolicy.POLICY_TYPE_ROWFILTER:
rowFilterHierarchies.put(resourceKeys, isValid);
break;
default:
LOG.error("unknown policy-type " + policyType);
break;
}
}
}
public void setServiceTags(final ServiceTags serviceTags) {
if (serviceTags == null || CollectionUtils.isEmpty(serviceTags.getServiceResources())) {
LOG.info("ServiceTags is null or there are no tagged resources for service " + serviceName);
enrichedServiceTags = null;
} else {
List<RangerServiceResourceMatcher> resourceMatchers = new ArrayList<>();
RangerServiceDefHelper serviceDefHelper = new RangerServiceDefHelper(serviceDef, false);
List<RangerServiceResource> serviceResources = serviceTags.getServiceResources();
ResourceHierarchies hierarchies = new ResourceHierarchies();
for (RangerServiceResource serviceResource : serviceResources) {
final Collection<String> resourceKeys = serviceResource.getResourceElements().keySet();
for (int policyType : RangerPolicy.POLICY_TYPES) {
Boolean isValidHierarchy = hierarchies.isValidHierarchy(policyType, resourceKeys);
if (isValidHierarchy == null) { // hierarchy not yet validated
isValidHierarchy = Boolean.FALSE;
for (List<RangerServiceDef.RangerResourceDef> hierarchy : serviceDefHelper.getResourceHierarchies(policyType)) {
if (serviceDefHelper.hierarchyHasAllResources(hierarchy, resourceKeys)) {
isValidHierarchy = Boolean.TRUE;
break;
}
}
hierarchies.addHierarchy(policyType, resourceKeys, isValidHierarchy);
}
if (isValidHierarchy) {
RangerDefaultPolicyResourceMatcher matcher = new RangerDefaultPolicyResourceMatcher();
matcher.setServiceDef(this.serviceDef);
matcher.setPolicyResources(serviceResource.getResourceElements(), policyType);
if (LOG.isDebugEnabled()) {
LOG.debug("RangerTagEnricher.setServiceTags() - Initializing matcher with (resource=" + serviceResource
+ ", serviceDef=" + this.serviceDef.getName() + ")");
}
matcher.setServiceDefHelper(serviceDefHelper);
matcher.init();
RangerServiceResourceMatcher serviceResourceMatcher = new RangerServiceResourceMatcher(serviceResource, matcher);
resourceMatchers.add(serviceResourceMatcher);
}
}
}
Map<String, RangerResourceTrie<RangerServiceResourceMatcher>> serviceResourceTrie = null;
if (!disableTrieLookupPrefilter) {
serviceResourceTrie = new HashMap<>();
for (RangerServiceDef.RangerResourceDef resourceDef : serviceDef.getResources()) {
serviceResourceTrie.put(resourceDef.getName(), new RangerResourceTrie<RangerServiceResourceMatcher>(resourceDef, resourceMatchers));
}
}
Set<RangerTagForEval> tagsForEmptyResourceAndAnyAccess = new HashSet<>();
for (Map.Entry<Long, RangerTag> entry : serviceTags.getTags().entrySet()) {
tagsForEmptyResourceAndAnyAccess.add(new RangerTagForEval(entry.getValue(), RangerPolicyResourceMatcher.MatchType.DESCENDANT));
}
enrichedServiceTags = new EnrichedServiceTags(serviceTags, resourceMatchers, serviceResourceTrie, tagsForEmptyResourceAndAnyAccess);
Map<String, RangerBasePlugin> servicePluginMap = RangerBasePlugin.getServicePluginMap();
RangerBasePlugin plugin = servicePluginMap != null ? servicePluginMap.get(getServiceName()) : null;
if (plugin != null) {
RangerAuthContext currentAuthContext = plugin.getCurrentRangerAuthContext();
if (currentAuthContext != null) {
currentAuthContext.addOrReplaceRequestContextEnricher(this, enrichedServiceTags);
plugin.contextChanged();
}
}
}
}
protected Long getServiceTagsVersion() {
return enrichedServiceTags != null ? enrichedServiceTags.getServiceTags().getTagVersion() : null;
}
@Override
public boolean preCleanup() {
boolean ret = true;
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerTagEnricher.preCleanup()");
}
if (tagRefresher != null) {
tagRefresher.cleanup();
tagRefresher = null;
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerTagEnricher.preCleanup() : result=" + ret);
}
return ret;
}
private Set<RangerTagForEval> findMatchingTags(final RangerAccessRequest request, EnrichedServiceTags dataStore) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerTagEnricher.findMatchingTags(" + request + ")");
}
// To minimize chance for race condition between Tag-Refresher thread and access-evaluation thread
final EnrichedServiceTags enrichedServiceTags = dataStore != null ? dataStore : this.enrichedServiceTags;
Set<RangerTagForEval> ret = null;
RangerAccessResource resource = request.getResource();
if ((resource == null || resource.getKeys() == null || resource.getKeys().isEmpty()) && request.isAccessTypeAny()) {
ret = enrichedServiceTags.getTagsForEmptyResourceAndAnyAccess();
} else {
final List<RangerServiceResourceMatcher> serviceResourceMatchers = getEvaluators(resource, enrichedServiceTags);
if (CollectionUtils.isNotEmpty(serviceResourceMatchers)) {
for (RangerServiceResourceMatcher resourceMatcher : serviceResourceMatchers) {
final RangerPolicyResourceMatcher.MatchType matchType = resourceMatcher.getMatchType(resource, request.getContext());
final boolean isMatched;
if (request.isAccessTypeAny()) {
isMatched = matchType != RangerPolicyResourceMatcher.MatchType.NONE;
} else if (request.getResourceMatchingScope() == RangerAccessRequest.ResourceMatchingScope.SELF_OR_DESCENDANTS) {
isMatched = matchType != RangerPolicyResourceMatcher.MatchType.NONE;
} else {
isMatched = matchType == RangerPolicyResourceMatcher.MatchType.SELF || matchType == RangerPolicyResourceMatcher.MatchType.ANCESTOR;
}
if (isMatched) {
if (ret == null) {
ret = new HashSet<>();
}
ret.addAll(getTagsForServiceResource(enrichedServiceTags.getServiceTags(), resourceMatcher.getServiceResource(), matchType));
}
}
}
}
if (CollectionUtils.isEmpty(ret)) {
if (LOG.isDebugEnabled()) {
LOG.debug("RangerTagEnricher.findMatchingTags(" + resource + ") - No tags Found ");
}
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("RangerTagEnricher.findMatchingTags(" + resource + ") - " + ret.size() + " tags Found ");
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerTagEnricher.findMatchingTags(" + request + ")");
}
return ret;
}
private List<RangerServiceResourceMatcher> getEvaluators(RangerAccessResource resource, EnrichedServiceTags enrichedServiceTags) {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerTagEnricher.getEvaluators(" + (resource != null ? resource.getAsString() : null) + ")");
}
List<RangerServiceResourceMatcher> ret = null;
final Map<String, RangerResourceTrie<RangerServiceResourceMatcher>> serviceResourceTrie = enrichedServiceTags.getServiceResourceTrie();
if (resource == null || resource.getKeys() == null || resource.getKeys().isEmpty() || serviceResourceTrie == null) {
ret = enrichedServiceTags.getServiceResourceMatchers();
} else {
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_TRIE_OP_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_TRIE_OP_LOG, "RangerTagEnricher.getEvaluators(resource=" + resource.getAsString() + ")");
}
Set<String> resourceKeys = resource.getKeys();
List<List<RangerServiceResourceMatcher>> serviceResourceMatchersList = null;
List<RangerServiceResourceMatcher> smallestList = null;
if (CollectionUtils.isNotEmpty(resourceKeys)) {
for (String resourceName : resourceKeys) {
RangerResourceTrie<RangerServiceResourceMatcher> trie = serviceResourceTrie.get(resourceName);
if (trie == null) { // if no trie exists for this resource level, ignore and continue to next level
continue;
}
List<RangerServiceResourceMatcher> serviceResourceMatchers = trie.getEvaluatorsForResource(resource.getValue(resourceName));
if (CollectionUtils.isEmpty(serviceResourceMatchers)) { // no policies for this resource, bail out
serviceResourceMatchersList = null;
smallestList = null;
break;
}
if (smallestList == null) {
smallestList = serviceResourceMatchers;
} else {
if (serviceResourceMatchersList == null) {
serviceResourceMatchersList = new ArrayList<>();
serviceResourceMatchersList.add(smallestList);
}
serviceResourceMatchersList.add(serviceResourceMatchers);
if (smallestList.size() > serviceResourceMatchers.size()) {
smallestList = serviceResourceMatchers;
}
}
}
if (serviceResourceMatchersList != null) {
ret = new ArrayList<>(smallestList);
for (List<RangerServiceResourceMatcher> serviceResourceMatchers : serviceResourceMatchersList) {
if (serviceResourceMatchers != smallestList) {
// remove policies from ret that are not in serviceResourceMatchers
ret.retainAll(serviceResourceMatchers);
if (CollectionUtils.isEmpty(ret)) { // if no policy exists, bail out and return empty list
ret = null;
break;
}
}
}
} else {
ret = smallestList;
}
}
RangerPerfTracer.logAlways(perf);
}
if(ret == null) {
ret = Collections.emptyList();
}
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerTagEnricher.getEvaluators(" + (resource != null ? resource.getAsString() : null) + "): evaluatorCount=" + ret.size());
}
return ret;
}
private static Set<RangerTagForEval> getTagsForServiceResource(final ServiceTags serviceTags, final RangerServiceResource serviceResource, final RangerPolicyResourceMatcher.MatchType matchType) {
Set<RangerTagForEval> ret = new HashSet<>();
final Long resourceId = serviceResource.getId();
final Map<Long, List<Long>> resourceToTagIds = serviceTags.getResourceToTagIds();
final Map<Long, RangerTag> tags = serviceTags.getTags();
if (resourceId != null && MapUtils.isNotEmpty(resourceToTagIds) && MapUtils.isNotEmpty(tags)) {
List<Long> tagIds = resourceToTagIds.get(resourceId);
if (CollectionUtils.isNotEmpty(tagIds)) {
for (Long tagId : tagIds) {
RangerTag tag = tags.get(tagId);
if (tag != null) {
ret.add(new RangerTagForEval(tag, matchType));
}
}
}
}
return ret;
}
static private final class EnrichedServiceTags {
final private ServiceTags serviceTags;
final private List<RangerServiceResourceMatcher> serviceResourceMatchers;
final private Map<String, RangerResourceTrie<RangerServiceResourceMatcher>> serviceResourceTrie;
final private Set<RangerTagForEval> tagsForEmptyResourceAndAnyAccess; // Used only when accessed resource is empty and access type is 'any'
EnrichedServiceTags(ServiceTags serviceTags, List<RangerServiceResourceMatcher> serviceResourceMatchers,
Map<String, RangerResourceTrie<RangerServiceResourceMatcher>> serviceResourceTrie, Set<RangerTagForEval> tagsForEmptyResourceAndAnyAccess) {
this.serviceTags = serviceTags;
this.serviceResourceMatchers = serviceResourceMatchers;
this.serviceResourceTrie = serviceResourceTrie;
this.tagsForEmptyResourceAndAnyAccess = tagsForEmptyResourceAndAnyAccess;
}
ServiceTags getServiceTags() {return serviceTags;}
List<RangerServiceResourceMatcher> getServiceResourceMatchers() { return serviceResourceMatchers;}
Map<String, RangerResourceTrie<RangerServiceResourceMatcher>> getServiceResourceTrie() { return serviceResourceTrie;}
Set<RangerTagForEval> getTagsForEmptyResourceAndAnyAccess() { return tagsForEmptyResourceAndAnyAccess;}
}
static class RangerTagRefresher extends Thread {
private static final Log LOG = LogFactory.getLog(RangerTagRefresher.class);
private final RangerTagRetriever tagRetriever;
private final RangerTagEnricher tagEnricher;
private long lastKnownVersion = -1L;
private long lastActivationTimeInMillis;
private final long pollingIntervalMs;
private final String cacheFile;
private boolean hasProvidedTagsToReceiver;
private Gson gson;
final long getPollingIntervalMs() {
return pollingIntervalMs;
}
RangerTagRefresher(RangerTagRetriever tagRetriever, RangerTagEnricher tagEnricher, long lastKnownVersion, String cacheFile, long pollingIntervalMs) {
this.tagRetriever = tagRetriever;
this.tagEnricher = tagEnricher;
this.lastKnownVersion = lastKnownVersion;
this.cacheFile = cacheFile;
this.pollingIntervalMs = pollingIntervalMs;
try {
gson = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").setPrettyPrinting().create();
} catch(Throwable excp) {
LOG.fatal("failed to create GsonBuilder object", excp);
}
}
public long getLastActivationTimeInMillis() {
return lastActivationTimeInMillis;
}
public void setLastActivationTimeInMillis(long lastActivationTimeInMillis) {
this.lastActivationTimeInMillis = lastActivationTimeInMillis;
}
@Override
public void run() {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerTagRefresher(pollingIntervalMs=" + pollingIntervalMs + ").run()");
}
while (true) {
try {
// Sleep first and then fetch tags
if (pollingIntervalMs > 0) {
Thread.sleep(pollingIntervalMs);
} else {
break;
}
RangerPerfTracer perf = null;
if(RangerPerfTracer.isPerfTraceEnabled(PERF_CONTEXTENRICHER_INIT_LOG)) {
perf = RangerPerfTracer.getPerfTracer(PERF_CONTEXTENRICHER_INIT_LOG, "RangerTagRefresher.populateTags(serviceName=" + tagRetriever.getServiceName() + ",lastKnownVersion=" + lastKnownVersion + ")");
}
populateTags();
RangerPerfTracer.log(perf);
} catch (InterruptedException excp) {
LOG.debug("RangerTagRefresher(pollingIntervalMs=" + pollingIntervalMs + ").run() : interrupted! Exiting thread", excp);
break;
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerTagRefresher().run()");
}
}
private void populateTags() throws InterruptedException {
if (tagEnricher != null) {
ServiceTags serviceTags = null;
try {
serviceTags = tagRetriever.retrieveTags(lastKnownVersion, lastActivationTimeInMillis);
if (serviceTags == null) {
if (!hasProvidedTagsToReceiver) {
serviceTags = loadFromCache();
}
} else {
saveToCache(serviceTags);
}
if (serviceTags != null) {
tagEnricher.setServiceTags(serviceTags);
LOG.info("RangerTagRefresher.populateTags() - Updated tags-cache to new version of tags, lastKnownVersion=" + lastKnownVersion + "; newVersion="
+ (serviceTags.getTagVersion() == null ? -1L : serviceTags.getTagVersion()));
hasProvidedTagsToReceiver = true;
lastKnownVersion = serviceTags.getTagVersion() == null ? -1L : serviceTags.getTagVersion();
setLastActivationTimeInMillis(System.currentTimeMillis());
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("RangerTagRefresher.populateTags() - No need to update tags-cache. lastKnownVersion=" + lastKnownVersion);
}
}
} catch (RangerServiceNotFoundException snfe) {
LOG.error("Caught ServiceNotFound exception :", snfe);
// Need to clean up local tag cache
if (tagEnricher.disableCacheIfServiceNotFound) {
disableCache();
tagEnricher.setServiceTags(null);
setLastActivationTimeInMillis(System.currentTimeMillis());
lastKnownVersion = -1L;
}
} catch (InterruptedException interruptedException) {
throw interruptedException;
} catch (Exception e) {
LOG.error("Encountered unexpected exception. Ignoring", e);
}
} else {
LOG.error("RangerTagRefresher.populateTags() - no tag receiver to update tag-cache");
}
}
void cleanup() {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerTagRefresher.cleanup()");
}
stopRefresher();
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerTagRefresher.cleanup()");
}
}
final void startRefresher() {
try {
super.start();
} catch (Exception excp) {
LOG.error("RangerTagRefresher.startRetriever() - failed to start, exception=" + excp);
}
}
private void stopRefresher() {
if (super.isAlive()) {
super.interrupt();
try {
super.join();
} catch (InterruptedException excp) {
LOG.error("RangerTagRefresher(): error while waiting for thread to exit", excp);
}
}
}
final ServiceTags loadFromCache() {
ServiceTags serviceTags = null;
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerTagRetriever(serviceName=" + tagEnricher.getServiceName() + ").loadFromCache()");
}
File cacheFile = StringUtils.isEmpty(this.cacheFile) ? null : new File(this.cacheFile);
if (cacheFile != null && cacheFile.isFile() && cacheFile.canRead()) {
Reader reader = null;
try {
reader = new FileReader(cacheFile);
serviceTags = gson.fromJson(reader, ServiceTags.class);
if (serviceTags != null && !StringUtils.equals(tagEnricher.getServiceName(), serviceTags.getServiceName())) {
LOG.warn("ignoring unexpected serviceName '" + serviceTags.getServiceName() + "' in cache file '" + cacheFile.getAbsolutePath() + "'");
serviceTags.setServiceName(tagEnricher.getServiceName());
}
} catch (Exception excp) {
LOG.error("failed to load service-tags from cache file " + cacheFile.getAbsolutePath(), excp);
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception excp) {
LOG.error("error while closing opened cache file " + cacheFile.getAbsolutePath(), excp);
}
}
}
} else {
LOG.warn("cache file does not exist or not readable '" + (cacheFile == null ? null : cacheFile.getAbsolutePath()) + "'");
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerTagRetriever(serviceName=" + tagEnricher.getServiceName() + ").loadFromCache()");
}
return serviceTags;
}
final void saveToCache(ServiceTags serviceTags) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerTagRetriever(serviceName=" + tagEnricher.getServiceName() + ").saveToCache()");
}
if (serviceTags != null) {
File cacheFile = StringUtils.isEmpty(this.cacheFile) ? null : new File(this.cacheFile);
if (cacheFile != null) {
Writer writer = null;
try {
writer = new FileWriter(cacheFile);
gson.toJson(serviceTags, writer);
} catch (Exception excp) {
LOG.error("failed to save service-tags to cache file '" + cacheFile.getAbsolutePath() + "'", excp);
} finally {
if (writer != null) {
try {
writer.close();
} catch (Exception excp) {
LOG.error("error while closing opened cache file '" + cacheFile.getAbsolutePath() + "'", excp);
}
}
}
}
} else {
LOG.info("service-tags is null. Nothing to save in cache");
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerTagRetriever(serviceName=" + tagEnricher.getServiceName() + ").saveToCache()");
}
}
final void disableCache() {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerTagRetriever.disableCache(serviceName=" + tagEnricher.getServiceName() + ")");
}
File cacheFile = StringUtils.isEmpty(this.cacheFile) ? null : new File(this.cacheFile);
if (cacheFile != null && cacheFile.isFile() && cacheFile.canRead()) {
LOG.warn("Cleaning up local tags cache");
String renamedCacheFile = cacheFile.getAbsolutePath() + "_" + System.currentTimeMillis();
if (!cacheFile.renameTo(new File(renamedCacheFile))) {
LOG.error("Failed to move " + cacheFile.getAbsolutePath() + " to " + renamedCacheFile);
} else {
LOG.warn("moved " + cacheFile.getAbsolutePath() + " to " + renamedCacheFile);
}
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("No local TAGS cache found. No need to disable it!");
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== RangerTagRetriever.disableCache(serviceName=" + tagEnricher.getServiceName() + ")");
}
}
}
}