You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ma...@apache.org on 2023/06/18 17:21:21 UTC

[ranger] branch RANGER-3923 updated: RANGER-4267: link resource-based services with gds-service

This is an automated email from the ASF dual-hosted git repository.

madhan pushed a commit to branch RANGER-3923
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/RANGER-3923 by this push:
     new 043180fa5 RANGER-4267: link resource-based services with gds-service
043180fa5 is described below

commit 043180fa5d53cd1654cef189a644481b3d131a8f
Author: Madhan Neethiraj <ma...@apache.org>
AuthorDate: Fri Jun 16 23:35:29 2023 -0700

    RANGER-4267: link resource-based services with gds-service
---
 .../apache/ranger/plugin/model/RangerService.java  |  66 +++++-
 .../plugin/model/RangerServiceHeaderInfo.java      |  19 +-
 .../model/validation/RangerServiceValidator.java   |  78 ++++++-
 .../ranger/plugin/store/AbstractPredicateUtil.java |  34 +++
 .../ranger/plugin/store/ServicePredicateUtil.java  |  77 +++++++
 .../apache/ranger/plugin/util/SearchFilter.java    |   2 +
 .../python/apache_ranger/model/ranger_service.py   |   4 +
 .../optimized/current/ranger_core_db_mysql.sql     |   6 +-
 .../optimized/current/ranger_core_db_oracle.sql    |   6 +-
 .../optimized/current/ranger_core_db_postgres.sql  |   6 +-
 .../current/ranger_core_db_sqlanywhere.sql         |   5 +
 .../optimized/current/ranger_core_db_sqlserver.sql |   5 +
 .../java/org/apache/ranger/biz/ServiceDBStore.java |  47 ++++-
 .../org/apache/ranger/entity/XXServiceBase.java    | 133 ++++--------
 .../apache/ranger/entity/XXServiceVersionInfo.java |  85 ++++----
 .../java/org/apache/ranger/rest/ServiceREST.java   | 231 +++++++++++----------
 .../ranger/service/RangerServiceService.java       |  10 +-
 .../ranger/service/RangerServiceServiceBase.java   |  21 ++
 18 files changed, 572 insertions(+), 263 deletions(-)

diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerService.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerService.java
index 326c91cfb..f5ab21c9a 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerService.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerService.java
@@ -55,13 +55,16 @@ public class RangerService extends RangerBaseModelObject implements java.io.Seri
 	private Date                policyUpdateTime;
 	private Long                tagVersion;
 	private Date                tagUpdateTime;
+	private String              gdsService;
+	private Long                gdsVersion;
+	private Date                gdsUpdateTime;
 
 
 	/**
 	 * @param
 	 */
 	public RangerService() {
-		this(null, null, null, null, null);
+		this(null, null, null, null, null, null);
 	}
 
 	/**
@@ -72,12 +75,24 @@ public class RangerService extends RangerBaseModelObject implements java.io.Seri
 	 * @param tagService
 	 */
 	public RangerService(String type, String name, String description, String tagService, Map<String, String> configs) {
+		this(type, name, description, tagService, null, configs);
+	}
+
+	/**
+	 * @param type
+	 * @param name
+	 * @param description
+	 * @param configs
+	 * @param tagService
+	 */
+	public RangerService(String type, String name, String description, String tagService, String gdsService, Map<String, String> configs) {
 		super();
 
 		setType(type);
 		setName(name);
 		setDescription(description);
 		setTagService(tagService);
+		setGdsService(gdsService);
 		setConfigs(configs);
 	}
 
@@ -97,6 +112,9 @@ public class RangerService extends RangerBaseModelObject implements java.io.Seri
 		setPolicyUpdateTime(other.getPolicyUpdateTime());
 		setTagVersion(other.getTagVersion());
 		setTagUpdateTime(other.getTagUpdateTime());
+		setGdsService(other.getGdsService());
+		setGdsVersion(other.getGdsVersion());
+		setGdsUpdateTime(other.getGdsUpdateTime());
 	}
 
 	/**
@@ -248,6 +266,49 @@ public class RangerService extends RangerBaseModelObject implements java.io.Seri
 		this.tagUpdateTime = tagUpdateTime;
 	}
 
+	/**
+	 * @return the gdsService
+	 */
+	public String getGdsService() {
+		return gdsService;
+	}
+
+	/**
+	 * @param gdsService the gdsServiceName to set
+	 */
+	public void setGdsService(String gdsService) {
+		this.gdsService = gdsService;
+	}
+
+	/**
+	 * @return the gdsVersion
+	 */
+	public Long getGdsVersion() {
+		return gdsVersion;
+	}
+
+	/**
+	 * @param gdsVersion the gdsVersion to set
+	 */
+	public void setGdsVersion(Long gdsVersion) {
+		this.gdsVersion = gdsVersion;
+	}
+
+
+	/**
+	 * @return the gdsUpdateTime
+	 */
+	public Date getGdsUpdateTime() {
+		return gdsUpdateTime;
+	}
+
+	/**
+	 * @param gdsUpdateTime the gdsUpdateTime to set
+	 */
+	public void setGdsUpdateTime(Date gdsUpdateTime) {
+		this.gdsUpdateTime = gdsUpdateTime;
+	}
+
 	@Override
 	public String toString( ) {
 		StringBuilder sb = new StringBuilder();
@@ -283,6 +344,9 @@ public class RangerService extends RangerBaseModelObject implements java.io.Seri
 
 		sb.append("tagVersion={").append(tagVersion).append("} ");
 		sb.append("tagUpdateTime={").append(tagUpdateTime).append("} ");
+		sb.append("gdsService={").append(gdsService).append("} ");
+		sb.append("gdsVersion={").append(gdsVersion).append("} ");
+		sb.append("gdsUpdateTime={").append(gdsUpdateTime).append("} ");
 
 		sb.append("}");
 
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceHeaderInfo.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceHeaderInfo.java
index 9891c06c2..5db395a96 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceHeaderInfo.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerServiceHeaderInfo.java
@@ -34,19 +34,22 @@ public class RangerServiceHeaderInfo extends RangerBaseModelObject implements ja
 
     private String  name;
     private Boolean isTagService;
+    private Boolean isGdsService;
 
     public RangerServiceHeaderInfo() {
-        super();
-        setId(-1L);
-        setName("");
-        setIsTagService(false);
+        this(-1L, "", false, false);
     }
 
     public RangerServiceHeaderInfo(Long id, String name, boolean isTagService) {
+        this(id, name, isTagService, false);
+    }
+
+    public RangerServiceHeaderInfo(Long id, String name, boolean isTagService, boolean isGdsService) {
         super();
         setId(id);
         setName(name);
         setIsTagService(isTagService);
+        setIsGdsService(isGdsService);
     }
 
     public String getName() {
@@ -64,4 +67,12 @@ public class RangerServiceHeaderInfo extends RangerBaseModelObject implements ja
     public void setIsTagService(Boolean isTagService) {
         this.isTagService = isTagService;
     }
+
+    public Boolean getIsGdsService() {
+        return isGdsService;
+    }
+
+    public void setIsGdsService(Boolean isGdsService) {
+        this.isGdsService = isGdsService;
+    }
 }
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceValidator.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceValidator.java
index 6ae6b6610..a9ad08a48 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceValidator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerServiceValidator.java
@@ -268,32 +268,76 @@ public class RangerServiceValidator extends RangerValidator {
 				}
 			}
 			String tagServiceName = service.getTagService();
+			String gdsServiceName = service.getGdsService();
 
-			if (StringUtils.isNotBlank(tagServiceName) && StringUtils.equals(type, EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_TAG_NAME)) {
-				failures.add(new ValidationFailureDetailsBuilder()
-						.field("tag_service")
-						.isSemanticallyIncorrect()
-						.becauseOf("tag service cannot be part of any other service")
-						.build());
-				valid = false;
+			if (StringUtils.equals(type, EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_TAG_NAME)) {
+				if (StringUtils.isNotBlank(tagServiceName)) {
+					failures.add(new ValidationFailureDetailsBuilder()
+							.field("tag_service")
+							.isSemanticallyIncorrect()
+							.becauseOf("tag service cannot be part of a tag service")
+							.build());
+					valid = false;
+				}
+
+				if (StringUtils.isNotBlank(gdsServiceName)) {
+					failures.add(new ValidationFailureDetailsBuilder()
+							.field("gds_service")
+							.isSemanticallyIncorrect()
+							.becauseOf("tag service cannot be part of a gds service")
+							.build());
+					valid = false;
+				}
+			}
+
+			if (StringUtils.equals(type, EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_GDS_NAME)) {
+				if (StringUtils.isNotBlank(tagServiceName)) {
+					failures.add(new ValidationFailureDetailsBuilder()
+							.field("tag_service")
+							.isSemanticallyIncorrect()
+							.becauseOf("gds service cannot be linked to a tag service")
+							.build());
+					valid = false;
+				}
+
+				if (StringUtils.isNotBlank(gdsServiceName)) {
+					failures.add(new ValidationFailureDetailsBuilder()
+							.field("gds_service")
+							.isSemanticallyIncorrect()
+							.becauseOf("gds service cannot be linked to a gds service")
+							.build());
+					valid = false;
+				}
 			}
 
-			boolean needToEnsureServiceType = false;
+			boolean needToEnsureTagServiceType = false;
+			boolean needToEnsureGdsServiceType = false;
 			if (action == Action.UPDATE) {
 				RangerService otherService = getService(name);
 				String otherTagServiceName = otherService == null ? null : otherService.getTagService();
+				String otherGdsServiceName = otherService == null ? null : otherService.getGdsService();
 
 				if (StringUtils.isNotBlank(tagServiceName)) {
 					if (!StringUtils.equals(tagServiceName, otherTagServiceName)) {
-						needToEnsureServiceType = true;
+						needToEnsureTagServiceType = true;
+					}
+				}
+
+				if (StringUtils.isNotBlank(gdsServiceName)) {
+					if (!StringUtils.equals(gdsServiceName, otherGdsServiceName)) {
+						needToEnsureGdsServiceType = true;
 					}
 				}
 			} else {    // action == Action.CREATE
 				if (StringUtils.isNotBlank(tagServiceName)) {
-					needToEnsureServiceType = true;
+					needToEnsureTagServiceType = true;
+				}
+
+				if (StringUtils.isNotBlank(gdsServiceName)) {
+					needToEnsureGdsServiceType = true;
 				}
 			}
-			if (needToEnsureServiceType) {
+			if (needToEnsureTagServiceType) {
 				RangerService maybeTagService = getService(tagServiceName);
 				if (maybeTagService == null || !StringUtils.equals(maybeTagService.getType(), EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_TAG_NAME)) {
 					failures.add(new ValidationFailureDetailsBuilder()
@@ -304,6 +348,18 @@ public class RangerServiceValidator extends RangerValidator {
 					valid = false;
 				}
 			}
+
+			if (needToEnsureGdsServiceType) {
+				RangerService gdsService = getService(gdsServiceName);
+				if (gdsService == null || !StringUtils.equals(gdsService.getType(), EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_GDS_NAME)) {
+					failures.add(new ValidationFailureDetailsBuilder()
+							.field("gds_service")
+							.isSemanticallyIncorrect()
+							.becauseOf("gds service name does not refer to existing gds service:" + gdsServiceName)
+							.build());
+					valid = false;
+				}
+			}
 		}
 
 		if(LOG.isDebugEnabled()) {
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/AbstractPredicateUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/AbstractPredicateUtil.java
index 07c561506..0c47515ef 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/store/AbstractPredicateUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/AbstractPredicateUtil.java
@@ -91,6 +91,7 @@ public class AbstractPredicateUtil {
 		addPredicateForIsEnabled(filter.getParam(SearchFilter.IS_ENABLED), predicates);
 		addPredicateForIsRecursive(filter.getParam(SearchFilter.IS_RECURSIVE), predicates);
 		addPredicateForTagServiceName(filter.getParam(SearchFilter.TAG_SERVICE_NAME), predicates);
+		addPredicateForGdsServiceName(filter.getParam(SearchFilter.GDS_SERVICE_NAME), predicates);
 		// addPredicateForTagServiceId(filter.getParam(SearchFilter.TAG_SERVICE_ID), predicates); // not supported
 		addPredicateForUserName(filter.getParam(SearchFilter.USER), predicates);
 		addPredicateForGroupName(filter.getParam(SearchFilter.GROUP), predicates);
@@ -857,6 +858,39 @@ public class AbstractPredicateUtil {
 		return ret;
 	}
 
+	private Predicate addPredicateForGdsServiceName(final String gdsServiceName, List<Predicate> predicates) {
+		if(StringUtils.isEmpty(gdsServiceName)) {
+			return null;
+		}
+
+		Predicate ret = new Predicate() {
+			@Override
+			public boolean evaluate(Object object) {
+				if(object == null) {
+					return false;
+				}
+
+				boolean ret = false;
+
+				if(object instanceof RangerService) {
+					RangerService service = (RangerService)object;
+
+					ret = StringUtils.equals(gdsServiceName, service.getGdsService());
+				} else {
+					ret = true;
+				}
+
+				return ret;
+			}
+		};
+
+		if(ret != null) {
+			predicates.add(ret);
+		}
+
+		return ret;
+	}
+
 	private Predicate addPredicateForResourceSignature(String signature, List<Predicate> predicates) {
 
 		Predicate ret = createPredicateForResourceSignature(signature);
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/ServicePredicateUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/ServicePredicateUtil.java
index 757dc6719..26c5dd7e3 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/store/ServicePredicateUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/ServicePredicateUtil.java
@@ -44,6 +44,8 @@ public class ServicePredicateUtil extends AbstractPredicateUtil {
 		addPredicateForServiceId(filter.getParam(SearchFilter.SERVICE_ID), predicates);
 		addPredicateForTagSeviceName(filter.getParam(SearchFilter.TAG_SERVICE_NAME), predicates);
 		addPredicateForTagSeviceId(filter.getParam(SearchFilter.TAG_SERVICE_ID), predicates);
+		addPredicateForGdsSeviceName(filter.getParam(SearchFilter.GDS_SERVICE_NAME), predicates);
+		addPredicateForGdsSeviceId(filter.getParam(SearchFilter.GDS_SERVICE_ID), predicates);
 	}
 
 	private String getServiceType(String serviceName) {
@@ -230,4 +232,79 @@ public class ServicePredicateUtil extends AbstractPredicateUtil {
 
 		return ret;
 	}
+
+	private Predicate addPredicateForGdsSeviceName(final String gdsServiceName, List<Predicate> predicates) {
+		if(StringUtils.isEmpty(gdsServiceName)) {
+			return null;
+		}
+
+		Predicate ret = new Predicate() {
+			@Override
+			public boolean evaluate(Object object) {
+				if(object == null) {
+					return false;
+				}
+
+				boolean ret = false;
+
+				if(object instanceof RangerService) {
+					RangerService service = (RangerService)object;
+
+					ret = StringUtils.equals(gdsServiceName, service.getGdsService());
+				} else {
+					ret = true;
+				}
+
+				return ret;
+			}
+		};
+
+		if(predicates != null) {
+			predicates.add(ret);
+		}
+
+		return ret;
+	}
+
+	private Predicate addPredicateForGdsSeviceId(final String gdsServiceId, List<Predicate> predicates) {
+		if(StringUtils.isEmpty(gdsServiceId)) {
+			return null;
+		}
+
+		Predicate ret = new Predicate() {
+			@Override
+			public boolean evaluate(Object object) {
+				if(object == null) {
+					return false;
+				}
+
+				boolean ret = false;
+
+				if(object instanceof RangerService) {
+					RangerService service = (RangerService)object;
+
+					if(! StringUtils.isEmpty(service.getGdsService())) {
+						RangerService gdsService = null;
+
+						try {
+							gdsService = serviceStore.getServiceByName(service.getGdsService());
+						} catch(Exception excp) {
+						}
+
+						ret = gdsService != null && gdsService.getId() != null && StringUtils.equals(gdsServiceId, gdsService.getId().toString());
+					}
+				} else {
+					ret = true;
+				}
+
+				return ret;
+			}
+		};
+
+		if(predicates != null) {
+			predicates.add(ret);
+		}
+
+		return ret;
+	}
 }
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
index ea8dec8c2..440bb4c24 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
@@ -38,6 +38,8 @@ public class SearchFilter {
 	public static final String IS_RECURSIVE    = "isRecursive";   // search
 	public static final String TAG_SERVICE_NAME = "tagServiceName";  // search
 	public static final String TAG_SERVICE_ID  = "tagServiceId";  // search
+	public static final String GDS_SERVICE_NAME = "gdsServiceName";  // search
+	public static final String GDS_SERVICE_ID   = "gdsServiceId";  // search
 	public static final String USER            = "user";          // search
 	public static final String GROUP           = "group";         // search
 	public static final String ROLE            = "role";         // search
diff --git a/intg/src/main/python/apache_ranger/model/ranger_service.py b/intg/src/main/python/apache_ranger/model/ranger_service.py
index a1346d5b5..e9b69ba5a 100644
--- a/intg/src/main/python/apache_ranger/model/ranger_service.py
+++ b/intg/src/main/python/apache_ranger/model/ranger_service.py
@@ -36,6 +36,9 @@ class RangerService(RangerBaseModelObject):
         self.policyUpdateTime = attrs.get('policyUpdateTime')
         self.tagVersion       = attrs.get('tagVersion')
         self.tagUpdateTime    = attrs.get('tagUpdateTime')
+        self.gdsService       = attrs.get('gdsService')
+        self.gdsVersion       = attrs.get('gdsVersion')
+        self.gdsUpdateTime    = attrs.get('gdsUpdateTime')
 
 
 class RangerServiceHeaderInfo(RangerBaseModelObject):
@@ -47,3 +50,4 @@ class RangerServiceHeaderInfo(RangerBaseModelObject):
 
         self.name         = attrs.get('name')
         self.isTagService = attrs.get('isTagService')
+        self.isGdsService = attrs.get('isGdsService')
diff --git a/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql b/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
index de9512624..12262dfc5 100644
--- a/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
+++ b/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
@@ -563,6 +563,7 @@ CREATE TABLE `x_service` (
 `tag_service` BIGINT DEFAULT NULL NULL,
 `tag_version` BIGINT DEFAULT 0 NOT NULL,
 `tag_update_time` DATETIME DEFAULT NULL NULL,
+`gds_service` BIGINT DEFAULT NULL NULL,
 primary key (`id`),
 UNIQUE KEY `X_service_name` (`name`),
 KEY `x_service_added_by_id` (`added_by_id`),
@@ -573,7 +574,8 @@ KEY `x_service_type` (`type`),
 CONSTRAINT `x_service_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
 CONSTRAINT `x_service_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`),
 CONSTRAINT `x_service_FK_type` FOREIGN KEY (`type`) REFERENCES `x_service_def` (`id`),
-CONSTRAINT `x_service_FK_tag_service` FOREIGN KEY (`tag_service`) REFERENCES `x_service` (`id`)
+CONSTRAINT `x_service_FK_tag_service` FOREIGN KEY (`tag_service`) REFERENCES `x_service` (`id`),
+CONSTRAINT `x_service_FK_gds_service` FOREIGN KEY (`gds_service`) REFERENCES `x_service` (`id`)
 )ROW_FORMAT=DYNAMIC;
 
 CREATE TABLE IF NOT EXISTS `x_security_zone`(
@@ -1246,6 +1248,8 @@ CREATE TABLE `x_service_version_info` (
 `tag_update_time` datetime NULL DEFAULT NULL,
 `role_version` bigint(20) NOT NULL DEFAULT 0,
 `role_update_time` datetime NULL DEFAULT NULL,
+`gds_version` bigint(20) DEFAULT 0 NOT NULL,
+`gds_update_time` datetime DEFAULT NULL NULL,
 `version` bigint(20) NOT NULL DEFAULT '1',
 primary key (`id`),
 CONSTRAINT `x_service_version_info_FK_service_id` FOREIGN KEY (`service_id`) REFERENCES `x_service` (`id`)
diff --git a/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql b/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
index 91ec963ed..c36ca4c7f 100644
--- a/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
+++ b/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
@@ -662,12 +662,14 @@ is_enabled NUMBER(1) DEFAULT '0' NOT NULL,
 tag_service NUMBER(20) DEFAULT NULL NULL,
 tag_version NUMBER(20) DEFAULT 0 NOT NULL,
 tag_update_time DATE DEFAULT NULL NULL,
+gds_service NUMBER(20) DEFAULT NULL NULL,
 primary key (id),
 CONSTRAINT x_service_name UNIQUE (name),
 CONSTRAINT x_service_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
 CONSTRAINT x_service_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
 CONSTRAINT x_service_FK_type FOREIGN KEY (type) REFERENCES x_service_def (id),
-CONSTRAINT x_service_FK_tag_service FOREIGN KEY (tag_service) REFERENCES x_service(id)
+CONSTRAINT x_service_FK_tag_service FOREIGN KEY (tag_service) REFERENCES x_service(id),
+CONSTRAINT x_service_FK_gds_service FOREIGN KEY (gds_service) REFERENCES x_service(id)
 );
 
 CREATE TABLE x_security_zone (
@@ -1325,6 +1327,8 @@ tag_version NUMBER(20) DEFAULT 0 NOT NULL,
 tag_update_time DATE DEFAULT NULL NULL,
 role_version NUMBER(20) DEFAULT 0 NOT NULL,
 role_update_time DATE DEFAULT NULL NULL,
+gds_version NUMBER(20) DEFAULT 0 NOT NULL,
+gds_update_time DATE DEFAULT NULL NULL,
 version NUMBER(20) DEFAULT 1 NOT NULL,
 primary key (id),
 CONSTRAINT x_svc_ver_info_FK_service_id FOREIGN KEY (service_id) REFERENCES x_service(id)
diff --git a/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql b/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
index c12832d38..31ed661e4 100644
--- a/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
+++ b/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
@@ -575,12 +575,14 @@ is_enabled BOOLEAN DEFAULT '0' NOT NULL,
 tag_service BIGINT DEFAULT NULL NULL,
 tag_version BIGINT DEFAULT 0 NOT NULL,
 tag_update_time TIMESTAMP DEFAULT NULL NULL,
+gds_service NUMBER(20) DEFAULT NULL NULL,
 primary key(id),
 CONSTRAINT x_service_name UNIQUE(name),
 CONSTRAINT x_service_FK_added_by_id FOREIGN KEY(added_by_id) REFERENCES x_portal_user(id),
 CONSTRAINT x_service_FK_upd_by_id FOREIGN KEY(upd_by_id) REFERENCES x_portal_user(id),
 CONSTRAINT x_service_FK_type FOREIGN KEY(type) REFERENCES x_service_def(id),
-CONSTRAINT x_service_FK_tag_service FOREIGN KEY (tag_service) REFERENCES x_service(id)
+CONSTRAINT x_service_FK_tag_service FOREIGN KEY (tag_service) REFERENCES x_service(id),
+CONSTRAINT x_service_FK_gds_service FOREIGN KEY (gds_service) REFERENCES x_service(id)
 );
 
 CREATE SEQUENCE x_security_zone_seq;
@@ -1194,6 +1196,8 @@ tag_version bigint NOT NULL DEFAULT '0',
 tag_update_time TIMESTAMP DEFAULT NULL,
 role_version bigint NOT NULL DEFAULT '0',
 role_update_time TIMESTAMP DEFAULT NULL,
+gds_version bigint NOT NULL DEFAULT '0',
+gds_update_time TIMESTAMP DEFAULT NULL,
 version bigint NOT NULL DEFAULT '1',
 primary key (id),
 CONSTRAINT x_service_version_info_service_id FOREIGN KEY (service_id) REFERENCES x_service (id)
diff --git a/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql b/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
index cbae01f82..e99ffa29e 100644
--- a/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
+++ b/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
@@ -525,6 +525,7 @@ create table dbo.x_service (
 	tag_service bigint DEFAULT NULL NULL,
 	tag_version bigint DEFAULT 0 NOT NULL,
 	tag_update_time datetime DEFAULT NULL NULL,
+	gds_service bigint DEFAULT NULL NULL,
 	CONSTRAINT x_service_def_PK_id PRIMARY KEY CLUSTERED(id),
 	CONSTRAINT x_service_UK_name UNIQUE NONCLUSTERED (name)
 )
@@ -1021,6 +1022,8 @@ CREATE TABLE dbo.x_service_version_info(
 	tag_update_time datetime DEFAULT NULL NULL,
 	role_version bigint NOT NULL DEFAULT 0,
 	role_update_time datetime DEFAULT NULL NULL,
+	gds_version bigint NOT NULL DEFAULT 0,
+	gds_update_time datetime DEFAULT NULL NULL,
 	version bigint NOT NULL DEFAULT 1,
 	CONSTRAINT x_service_version_info_PK_id PRIMARY KEY CLUSTERED(id)
 )
@@ -1583,6 +1586,8 @@ ALTER TABLE dbo.x_tag_resource_map ADD CONSTRAINT x_tag_res_map_FK_upd_by_id FOR
 GO
 ALTER TABLE dbo.x_service ADD CONSTRAINT x_service_FK_tag_service FOREIGN KEY(tag_service) REFERENCES dbo.x_service (id)
 GO
+ALTER TABLE dbo.x_service ADD CONSTRAINT x_service_FK_gds_service FOREIGN KEY(gds_service) REFERENCES dbo.x_service (id)
+GO
 ALTER TABLE dbo.x_datamask_type_def ADD CONSTRAINT x_datamask_type_def_FK_def_id FOREIGN KEY(def_id) REFERENCES dbo.x_service_def (id)
 GO
 ALTER TABLE dbo.x_datamask_type_def ADD CONSTRAINT x_datamask_type_def_FK_added_by_id FOREIGN KEY(added_by_id) REFERENCES dbo.x_portal_user (id)
diff --git a/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql b/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
index 583464890..5e763ca11 100644
--- a/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
+++ b/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
@@ -1403,6 +1403,7 @@ CREATE TABLE [dbo].[x_service] (
         [tag_service] [bigint] DEFAULT NULL NULL,
         [tag_version] [bigint] DEFAULT 0 NOT NULL,
         [tag_update_time] [datetime2] DEFAULT NULL NULL,
+        [gds_service] [bigint] DEFAULT NULL NULL,
 PRIMARY KEY CLUSTERED
 (
         [id] ASC
@@ -2083,6 +2084,8 @@ CREATE TABLE [dbo].[x_service_version_info](
         [tag_update_time] [datetime2] DEFAULT NULL NULL,
         [role_version] [bigint] NOT NULL DEFAULT 0,
         [role_update_time] [datetime2] DEFAULT NULL NULL,
+        [gds_version] [bigint] NOT NULL DEFAULT 0,
+        [gds_update_time] [datetime2] DEFAULT NULL NULL,
         [version] [bigint] NOT NULL DEFAULT 1,
         PRIMARY KEY CLUSTERED
 (
@@ -2843,6 +2846,8 @@ REFERENCES [dbo].[x_service_def] ([id])
 ALTER TABLE [dbo].[x_service] CHECK CONSTRAINT [x_service_FK_type]
 ALTER TABLE [dbo].[x_service]  WITH CHECK ADD  CONSTRAINT [x_service_FK_tag_service] FOREIGN KEY([tag_service])
 REFERENCES [dbo].[x_service] ([id])
+ALTER TABLE [dbo].[x_service]  WITH CHECK ADD  CONSTRAINT [x_service_FK_gds_service] FOREIGN KEY([gds_service])
+REFERENCES [dbo].[x_service] ([id])
 ALTER TABLE [dbo].[x_policy]  WITH CHECK ADD  CONSTRAINT [x_policy_FK_added_by_id] FOREIGN KEY([added_by_id])
 REFERENCES [dbo].[x_portal_user] ([id])
 ALTER TABLE [dbo].[x_policy] CHECK CONSTRAINT [x_policy_FK_added_by_id]
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java b/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java
index 6265b8d37..ecef3dc1e 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java
@@ -1690,6 +1690,43 @@ public class ServiceDBStore extends AbstractServiceStore {
 			hasTagServiceValueChanged = true;
 		}
 
+		boolean hasGdsServiceValueChanged = false;
+		Long    existingGdsServiceId      = existing.getGdsService();
+		String  newGdsServiceName         = service.getGdsService(); // null/empty for old clients; blank string to remove existing association
+		Long    newGdsServiceId           = null;
+
+		if (StringUtils.isEmpty(newGdsServiceName)) { // old client; don't update existing gdsService
+			if (existingGdsServiceId != null) {
+				newGdsServiceName = getServiceName(existingGdsServiceId);
+
+				service.setGdsService(newGdsServiceName);
+
+				LOG.info("ServiceDBStore.updateService(id=" + service.getId() + "; name=" + service.getName() + "): gdsService is null; using existing gdsService '" + newGdsServiceName + "'");
+			}
+		}
+
+		if (StringUtils.isNotBlank(newGdsServiceName)) {
+			RangerService tmp = getServiceByName(newGdsServiceName);
+
+			if (tmp == null || !EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_GDS_NAME.equals(tmp.getType())) {
+				if (LOG.isDebugEnabled()) {
+					LOG.debug("ServiceDBStore.updateService() - " + newGdsServiceName + " does not refer to a valid gds service.(" + service + ")");
+				}
+
+				throw restErrorUtil.createRESTException("Invalid gds service name " + newGdsServiceName, MessageEnums.ERROR_CREATING_OBJECT);
+			} else {
+				newGdsServiceId = tmp.getId();
+			}
+		}
+
+		if (existingGdsServiceId == null) {
+			if (newGdsServiceId != null) {
+				hasGdsServiceValueChanged = true;
+			}
+		} else if (!existingGdsServiceId.equals(newGdsServiceId)) {
+			hasGdsServiceValueChanged = true;
+		}
+
 		boolean hasIsEnabledChanged = !existing.getIsenabled().equals(service.getIsEnabled());
 
 		List<XXServiceConfigMap> dbConfigMaps = daoMgr.getXXServiceConfigMap().findByServiceId(service.getId());
@@ -1707,7 +1744,7 @@ public class ServiceDBStore extends AbstractServiceStore {
 			service.setVersion(existing.getVersion());
 			service = svcService.update(service);
 
-			if (hasTagServiceValueChanged || hasIsEnabledChanged || hasServiceConfigForPluginChanged) {
+			if (hasTagServiceValueChanged || hasGdsServiceValueChanged || hasIsEnabledChanged || hasServiceConfigForPluginChanged) {
 				updatePolicyVersion(service, RangerPolicyDelta.CHANGE_TYPE_SERVICE_CHANGE, null,false);
 			}
 		}
@@ -3684,11 +3721,13 @@ public class ServiceDBStore extends AbstractServiceStore {
 				serviceVersionInfoDbObj = new XXServiceVersionInfo();
 				serviceVersionInfoDbObj.setServiceId(service.getId());
 				serviceVersionInfoDbObj.setPolicyVersion(nextVersion);
-				serviceVersionInfoDbObj.setPolicyUpdateTime(new Date());
+				serviceVersionInfoDbObj.setPolicyUpdateTime(now);
 				serviceVersionInfoDbObj.setTagVersion(nextVersion);
-				serviceVersionInfoDbObj.setTagUpdateTime(new Date());
+				serviceVersionInfoDbObj.setTagUpdateTime(now);
 				serviceVersionInfoDbObj.setRoleVersion(nextVersion);
-				serviceVersionInfoDbObj.setRoleUpdateTime(new Date());
+				serviceVersionInfoDbObj.setRoleUpdateTime(now);
+				serviceVersionInfoDbObj.setGdsVersion(nextVersion);
+				serviceVersionInfoDbObj.setGdsUpdateTime(now);
 
 				serviceVersionUpdater.version = nextVersion;
 				serviceVersionInfoDao.create(serviceVersionInfoDbObj);
diff --git a/security-admin/src/main/java/org/apache/ranger/entity/XXServiceBase.java b/security-admin/src/main/java/org/apache/ranger/entity/XXServiceBase.java
index 85ce53cae..d1e991994 100644
--- a/security-admin/src/main/java/org/apache/ranger/entity/XXServiceBase.java
+++ b/security-admin/src/main/java/org/apache/ranger/entity/XXServiceBase.java
@@ -18,6 +18,7 @@
 package org.apache.ranger.entity;
 
 import java.util.Date;
+import java.util.Objects;
 
 import javax.persistence.Column;
 import javax.persistence.MappedSuperclass;
@@ -86,6 +87,9 @@ public abstract class XXServiceBase extends XXDBBase {
 	@Column(name = "tag_service")
 	protected Long tagService;
 
+	@Column(name = "gds_service")
+	protected Long gdsService;
+
 	/**
 	 * policyVersion of the XXService
 	 * <ul>
@@ -244,6 +248,24 @@ public abstract class XXServiceBase extends XXDBBase {
 		return this.tagService;
 	}
 
+	/**
+	 * This method sets the value to the member attribute <b> gdsService</b> .
+	 *
+	 * @param gdsService - Value to set member attribute <b> gdsService</b>
+	 */
+	public void setGdsService(Long gdsService) {
+		this.gdsService = gdsService;
+	}
+
+	/**
+	 * Returns the value for the member attribute <b>gdsService</b>
+	 *
+	 * @return Long - value of member attribute <b>gdsService</b> .
+	 */
+	public Long getGdsService() {
+		return this.gdsService;
+	}
+
 	/**
 	 * This method sets the value to the member attribute <b> policyVersion</b>
 	 * . You cannot set null to the attribute.
@@ -371,94 +393,31 @@ public abstract class XXServiceBase extends XXDBBase {
 	 */
 	@Override
 	public boolean equals(Object obj) {
-		if (!super.equals(obj)) {
-			return false;
-		}
+		final boolean ret;
+
 		if (this == obj) {
-			return true;
+			ret = true;
+		} else if (obj == null || getClass() != obj.getClass()) {
+			ret = false;
+		} else {
+			XXServiceBase other = (XXServiceBase) obj;
+
+			ret = super.equals(obj) &&
+				  Objects.equals(description, other.description) &&
+				  Objects.equals(isEnabled, other.isEnabled) &&
+				  Objects.equals(name, other.name) &&
+				  Objects.equals(policyUpdateTime, other.policyUpdateTime) &&
+				  Objects.equals(policyVersion, other.policyVersion) &&
+				  Objects.equals(tagService, other.tagService) &&
+				  Objects.equals(tagVersion, other.tagVersion) &&
+				  Objects.equals(tagUpdateTime, other.tagUpdateTime) &&
+				  Objects.equals(gdsService, other.gdsService) &&
+				  Objects.equals(type, other.type) &&
+				  Objects.equals(version, other.version) &&
+				  Objects.equals(guid, other.guid);
 		}
-		if (getClass() != obj.getClass()) {
-			return false;
-		}
-		XXServiceBase other = (XXServiceBase) obj;
-		if (description == null) {
-			if (other.description != null) {
-				return false;
-			}
-		} else if (!description.equals(other.description)) {
-			return false;
-		}
-		if (isEnabled == null) {
-			if (other.isEnabled != null) {
-				return false;
-			}
-		} else if (!isEnabled.equals(other.isEnabled)) {
-			return false;
-		}
-		if (name == null) {
-			if (other.name != null) {
-				return false;
-			}
-		} else if (!name.equals(other.name)) {
-			return false;
-		}
-		if (tagService == null) {
-			if (other.tagService != null) {
-				return false;
-			}
-		} else if (!tagService.equals(other.tagService)) {
-			return false;
-		}
-		if (policyUpdateTime == null) {
-			if (other.policyUpdateTime != null) {
-				return false;
-			}
-		} else if (!policyUpdateTime.equals(other.policyUpdateTime)) {
-			return false;
-		}
-		if (policyVersion == null) {
-			if (other.policyVersion != null) {
-				return false;
-			}
-		} else if (!policyVersion.equals(other.policyVersion)) {
-			return false;
-		}
-		if (tagUpdateTime == null) {
-			if (other.tagUpdateTime != null) {
-				return false;
-			}
-		} else if (!tagUpdateTime.equals(other.tagUpdateTime)) {
-			return false;
-		}
-		if (tagVersion == null) {
-			if (other.tagVersion != null) {
-				return false;
-			}
-		} else if (!tagVersion.equals(other.tagVersion)) {
-			return false;
-		}
-		if (type == null) {
-			if (other.type != null) {
-				return false;
-			}
-		} else if (!type.equals(other.type)) {
-			return false;
-		}
-		if (version == null) {
-			if (other.version != null) {
-				return false;
-			}
-		} else if (!version.equals(other.version)) {
-			return false;
-		}
-		if (guid == null) {
-			if (other.guid != null) {
-				return false;
-			}
-		} else if (!guid.equals(other.guid)) {
-			return false;
-		}
-		return true;
+
+		return ret;
 	}
 
 	/*
@@ -469,7 +428,7 @@ public abstract class XXServiceBase extends XXDBBase {
 	@Override
 	public String toString() {
 		return "XXServiceBase [" + super.toString() + " guid=" + guid + ", version=" + version + ", type=" + type
-				+ ", name=" + name +", displayName=" + displayName + ", tagService=" + tagService + ", policyVersion=" + policyVersion + ", policyUpdateTime=" + policyUpdateTime
+				+ ", name=" + name +", displayName=" + displayName + ", tagService=" + tagService + ", gdsService=" + gdsService + ", policyVersion=" + policyVersion + ", policyUpdateTime=" + policyUpdateTime
 				+ ", tagVersion=" + tagVersion + ", tagUpdateTime=" + tagUpdateTime
 				+ ", description=" + description + ", isEnabled=" + isEnabled + "]";
 	}
diff --git a/security-admin/src/main/java/org/apache/ranger/entity/XXServiceVersionInfo.java b/security-admin/src/main/java/org/apache/ranger/entity/XXServiceVersionInfo.java
index cfb0137b9..9edca0a87 100644
--- a/security-admin/src/main/java/org/apache/ranger/entity/XXServiceVersionInfo.java
+++ b/security-admin/src/main/java/org/apache/ranger/entity/XXServiceVersionInfo.java
@@ -20,6 +20,7 @@
 package org.apache.ranger.entity;
 
 import java.util.Date;
+import java.util.Objects;
 
 import javax.persistence.Cacheable;
 import javax.persistence.Entity;
@@ -77,6 +78,13 @@ public class XXServiceVersionInfo implements java.io.Serializable {
 	@Column(name="role_update_time"   )
 	protected Date roleUpdateTime = DateUtil.getUTCDate();
 
+	@Column(name = "gds_version")
+	protected Long gdsVersion;
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name = "gds_update_time")
+	protected Date gdsUpdateTime;
+
 	@Version
 	@Column(name = "version")
 	protected Long version;
@@ -167,6 +175,22 @@ public class XXServiceVersionInfo implements java.io.Serializable {
 		return this.roleUpdateTime;
 	}
 
+	public void setGdsVersion(Long gdsVersion) {
+		this.gdsVersion = gdsVersion;
+	}
+
+	public Long getGdsVersion() {
+		return this.gdsVersion;
+	}
+
+	public void setGdsUpdateTime(Date gdsUpdateTime) {
+		this.gdsUpdateTime = gdsUpdateTime;
+	}
+
+	public Date getGdsUpdateTime() {
+		return this.gdsUpdateTime;
+	}
+
 	/**
 	 * This return the bean content in string format
 	 * @return formatedStr
@@ -183,6 +207,8 @@ public class XXServiceVersionInfo implements java.io.Serializable {
 		str += "tagUpdateTime={" + tagUpdateTime + "} ";
 		str += "setRoleVersion={" + roleVersion + "}" ;
 		str += "setRoleUpdateTime={" + roleUpdateTime + "}" ;
+		str += "gdsVersion={" + gdsVersion + "}" ;
+		str += "gdsUpdateTime={" + gdsUpdateTime + "}" ;
 		str += "}";
 		return str;
 	}
@@ -193,43 +219,30 @@ public class XXServiceVersionInfo implements java.io.Serializable {
 	*/
 	@Override
 	public boolean equals( Object obj) {
-		if (obj == null)
-			return false;
-		if (this == obj)
-			return true;
-		if (!super.equals(obj))
-			return false;
-		if (getClass() != obj.getClass())
-			return false;
-		XXServiceVersionInfo other = (XXServiceVersionInfo) obj;
-		if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
-			return false;
+		final boolean ret;
+
+		if (this == obj) {
+			ret = true;
+		} else if (obj == null || getClass() != obj.getClass()) {
+			ret = false;
+		} else {
+			XXServiceVersionInfo other = (XXServiceVersionInfo) obj;
+
+			ret = super.equals(obj) &&
+				  Objects.equals(id, other.id) &&
+				  Objects.equals(version, other.version) &&
+				  Objects.equals(serviceId, other.serviceId) &&
+				  Objects.equals(policyVersion, other.policyVersion) &&
+				  Objects.equals(policyUpdateTime, other.policyUpdateTime) &&
+				  Objects.equals(tagVersion, other.tagVersion) &&
+				  Objects.equals(tagUpdateTime, other.tagUpdateTime) &&
+				  Objects.equals(roleVersion, other.roleVersion) &&
+				  Objects.equals(roleUpdateTime, other.roleUpdateTime) &&
+				  Objects.equals(gdsVersion, other.gdsVersion) &&
+				  Objects.equals(gdsUpdateTime, other.gdsUpdateTime);
 		}
-		if ((version == null && other.version != null) || (this.version != null && !this.version.equals(other.version))) {
-			return false;
-		}
-		if ((this.serviceId == null && other.serviceId != null) || (this.serviceId != null && !this.serviceId.equals(other.serviceId))) {
-			return false;
-		}
-		if ((this.policyVersion == null && other.policyVersion != null) || (this.policyVersion != null && !this.policyVersion.equals(other.policyVersion))) {
-			return false;
-		}
-		if ((this.policyUpdateTime == null && other.policyUpdateTime != null) || (this.policyUpdateTime != null && !this.policyUpdateTime.equals(other.policyUpdateTime))) {
-			return false;
-		}
-		if ((this.tagVersion == null && other.tagVersion != null) || (this.tagVersion != null && !this.tagVersion.equals(other.tagVersion))) {
-			return false;
-		}
-		if ((this.tagUpdateTime == null && other.tagUpdateTime != null) || (this.tagUpdateTime != null && !this.tagUpdateTime.equals(other.tagUpdateTime))) {
-			return false;
-		}
-		if ((this.roleVersion == null && other.roleVersion != null) || (this.roleVersion != null && !this.roleVersion.equals(other.roleVersion))) {
-			return false;
-		}
-		if ((this.roleUpdateTime == null && other.roleUpdateTime != null) || (this.roleUpdateTime != null && !this.roleUpdateTime.equals(other.roleUpdateTime))) {
-			return false;
-		}
-		return true;
+
+		return ret;
 	}
 
 	public static boolean equals(Object object1, Object object2) {
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
index 6348d0287..2bc3ee4ee 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
@@ -768,14 +768,12 @@ public class ServiceREST {
 			}
                          bizUtil.blockAuditorRoleUser();
 
-			if (StringUtils.isBlank(service.getTagService())
-					&& xxServiceDef != null
-					&& !StringUtils.equals(EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_TAG_NAME, xxServiceDef.getName())
-					&& !StringUtils.equals(EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_KMS_NAME , xxServiceDef.getName())) {
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("Tag service may need to be created and linked with this service:[" + service.getName() + "]");
-				}
-				createOrGetTagService(service);
+			String serviceType = xxServiceDef != null ? xxServiceDef.getName() : null;
+
+			if (!StringUtils.equals(EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_TAG_NAME, serviceType) &&
+				!StringUtils.equals(EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_GDS_NAME, serviceType) &&
+				!StringUtils.equals(EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_KMS_NAME , serviceType)) {
+				createOrGetLinkedServices(service);
 			}
 
 			ret = svcStore.createService(service);
@@ -4210,155 +4208,158 @@ public class ServiceREST {
 		}
 	}
 
-	private void createOrGetTagService(RangerService resourceService) {
+	private void createOrGetLinkedServices(RangerService resourceService) {
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> createOrGetTagService(resourceService=" + resourceService.getName() + ")");
+			LOG.debug("==> createOrGetLinkedServices(resourceService=" + resourceService.getName() + ")");
 		}
-		final boolean isAutoCreateTagService = config.getBoolean("ranger.tagservice.auto.create", true);
 
-		if (isAutoCreateTagService) {
+		Runnable createAndLinkTagServiceTask = new Runnable() {
+			@Override
+			public void run() {
+				final LinkedServiceCreator creator = new LinkedServiceCreator(resourceService.getName(), EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_TAG_NAME);
 
-			String tagServiceName = config.get("ranger.tagservice.auto.name");
-
-			if (StringUtils.isBlank(tagServiceName)) {
-				tagServiceName = getGeneratedTagServiceName(resourceService.getName());
+				creator.doCreateAndLinkService();
 			}
+		};
 
-			if (StringUtils.isNotBlank(tagServiceName)) {
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("Attempting to get/create and possibly link to tag-service:[" + tagServiceName + "]");
-				}
-
-				final boolean isAutoLinkTagService = config.getBoolean("ranger.tagservice.auto.link", true);
-				RangerService tagService = null;
-
-				try {
-					tagService = svcStore.getServiceByName(tagServiceName);
-				} catch (Exception e) {
-					LOG.info("failed to retrieve tag-service [" + tagServiceName + "]. Will attempt to create.", e);
-				}
-
-				if (tagService == null) {
-					final TagServiceOperationContext context = new TagServiceOperationContext(tagServiceName, resourceService.getName(), isAutoLinkTagService);
+		Runnable createAndLinkGdsServiceTask = new Runnable() {
+			@Override
+			public void run() {
+				final LinkedServiceCreator creator = new LinkedServiceCreator(resourceService.getName(), EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_GDS_NAME);
 
-					Runnable createAndLinkTagServiceTask = new Runnable() {
-						@Override
-						public void run() {
-							doCreateAndLinkTagService(context);
-						}
-					};
+				creator.doCreateAndLinkService();
+			}
+		};
 
-					rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(createAndLinkTagServiceTask);
+		rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(createAndLinkTagServiceTask);
+		rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(createAndLinkGdsServiceTask);
 
-				} else if (isAutoLinkTagService) {
-					resourceService.setTagService(tagServiceName);
-				}
-			}
-		}
 		if (LOG.isDebugEnabled()) {
 			LOG.debug("<== createOrGetTagService(resourceService=" + resourceService.getName() + ")");
 		}
 	}
 
-	private String getGeneratedTagServiceName(String resourceServiceName) {
-		int lastIndexOfMarker = StringUtils.lastIndexOf(resourceServiceName, '_');
-		if (lastIndexOfMarker != -1) {
-			return resourceServiceName.substring(0, lastIndexOfMarker) + "_tag";
-		} else {
-			return null;
-		}
-	}
+	private final class LinkedServiceCreator {
+		static final char SEP = '_';
 
-	private final class TagServiceOperationContext {
-		final String tagServiceName;
-		final String resourceServiceName;
-		final boolean isAutoLinkTagService;
+		final String  resourceServiceName;
+		final String  linkedServiceType;
+		final String  linkedServiceName;
+		final boolean isAutoCreate;
+		final boolean isAutoLink;
 
-		TagServiceOperationContext(@Nonnull String tagserviceName, @Nonnull String resourceServiceName, boolean isAutoLinkTagService) {
-			this.tagServiceName = tagserviceName;
+		LinkedServiceCreator(@Nonnull String resourceServiceName, @Nonnull String linkedServiceType) {
 			this.resourceServiceName = resourceServiceName;
-			this.isAutoLinkTagService = isAutoLinkTagService;
-		}
-
-		@Override
-		public String toString() {
-			return "{tagServiceName=" + tagServiceName + ", resourceServiceName=" + resourceServiceName + ", isAutoLinkTagService=" + isAutoLinkTagService + "}";
+			this.linkedServiceType   = linkedServiceType;
+			this.linkedServiceName   = computeLinkedServiceName();
+			this.isAutoCreate        = config.getBoolean("ranger." + linkedServiceType + "service.auto.create", true);
+			this.isAutoLink          = config.getBoolean("ranger." + linkedServiceType + "service.auto.link", true);
 		}
-	}
 
-	private void doCreateAndLinkTagService(final TagServiceOperationContext context) {
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> doCreateAndLinkTagService(context=" + context + ")");
-		}
+		void doCreateAndLinkService() {
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("==> doCreateAndLinkService()");
+			}
 
-		RangerService resourceService = null;
+			RangerService resourceService = null;
 
-		try {
-			resourceService = svcStore.getServiceByName(context.resourceServiceName);
-			LOG.info("Successfully retrieved resource-service:[" + resourceService.getName() + "]");
-		} catch (Exception e) {
-			LOG.error("Resource-service:[" + context.resourceServiceName + "] cannot be retrieved");
-		}
-
-		if (resourceService != null) {
 			try {
-				String tagServiceName = context.tagServiceName;
+				resourceService = svcStore.getServiceByName(resourceServiceName);
+				LOG.info("Successfully retrieved resource-service:[" + resourceService.getName() + "]");
+			} catch (Exception e) {
+				LOG.error("Resource-service:[" + resourceServiceName + "] cannot be retrieved");
+			}
+
+			if (resourceService != null) {
+				try {
+					RangerService linkedService = svcStore.getServiceByName(linkedServiceName);
 
-				RangerService tagService = svcStore.getServiceByName(tagServiceName);
+					if (linkedService == null && isAutoCreate) {
+						linkedService = new RangerService();
 
-				if (tagService == null) {
-					tagService = new RangerService();
+						linkedService.setName(linkedServiceName);
+						linkedService.setDisplayName(linkedServiceName); //set DEFAULT display name
+						linkedService.setType(linkedServiceType);
 
-					tagService.setName(context.tagServiceName);
-					tagService.setDisplayName(context.tagServiceName);//set DEFAULT display name
-					tagService.setType(EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_TAG_NAME);
+						LOG.info("creating service [" + linkedServiceName + "]");
 
-					LOG.info("creating tag-service [" + context.tagServiceName + "]");
+						svcStore.createService(linkedService);
+					}
+				} catch (Exception e) {
+					throw new RuntimeException(e);
+				}
 
-					svcStore.createService(tagService);
+				if (isAutoLink) {
+					doLinkService();
 				}
-			} catch (Exception e) {
-				throw new RuntimeException(e);
-			}
 
-			if (context.isAutoLinkTagService) {
-				doLinkTagService(context);
+			} else {
+				LOG.info("Resource service :[" + resourceServiceName + "] not found! Returning without linking " + linkedServiceType + " service!!");
 			}
 
-		} else {
-			LOG.info("Resource service :[" + context.resourceServiceName + "] not found! Returning without linking tag service!!");
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("<== doCreateAndLinkService()");
+			}
 		}
 
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== doCreateAndLinkTagService(context=" + context + ")");
-		}
-	}
+		private String computeLinkedServiceName() {
+			String ret = config.get("ranger." + linkedServiceType + "service.auto.name");
 
-	private void doLinkTagService(final TagServiceOperationContext context) {
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> doLinkTagService(context=" + context + ")");
+			if (StringUtils.isBlank(ret)) {
+				final int lastIndexOfSep = StringUtils.lastIndexOf(resourceServiceName, SEP);
+
+				ret = (lastIndexOfSep != -1) ? resourceServiceName.substring(0, lastIndexOfSep) + SEP + linkedServiceType : null;
+			}
+
+			return ret;
 		}
-		try {
-			RangerService resourceService = svcStore.getServiceByName(context.resourceServiceName);
-			LOG.info("Successfully retrieved resource-service:[" + resourceService.getName() + "]");
 
-			RangerService tagService = svcStore.getServiceByName(context.tagServiceName);
-			LOG.info("Successfully retrieved tag-service:[" + tagService.getName() + "]");
+		private void doLinkService() {
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("==> doLinkTagService()");
+			}
+
+			try {
+				RangerService resourceService = svcStore.getServiceByName(resourceServiceName);
+				LOG.info("Successfully retrieved resource-service:[" + resourceService.getName() + "]");
+
+				RangerService linkedService = svcStore.getServiceByName(linkedServiceName);
+				LOG.info("Successfully retrieved service:[" + linkedService.getName() + "]");
 
-			if (!StringUtils.equals(tagService.getName(), resourceService.getTagService())) {
-				resourceService.setTagService(tagService.getName());
+				if (linkedService == null) {
+					LOG.error("Failed to link service[" + resourceServiceName + "] with service [" + linkedServiceName + "]: " + linkedServiceName + " not found");
+				} else if (EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_TAG_NAME.equals(linkedServiceType)) {
+					if (!StringUtils.equals(linkedService.getName(), resourceService.getTagService())) {
+						resourceService.setTagService(linkedService.getName());
 
-				LOG.info("Linking resource-service[" + resourceService.getName() + "] with tag-service [" + tagService.getName() + "]");
+						LOG.info("Linking resource-service[" + resourceService.getName() + "] with tag-service [" + linkedService.getName() + "]");
 
-				RangerService service = svcStore.updateService(resourceService, null);
+						RangerService service = svcStore.updateService(resourceService, null);
 
-				LOG.info("Updated resource-service:[" + service.getName() + "]");
+						LOG.info("Updated resource-service:[" + service.getName() + "]");
+					}
+				} else if (EmbeddedServiceDefsUtil.EMBEDDED_SERVICEDEF_GDS_NAME.equals(linkedServiceType)) {
+					if (!StringUtils.equals(linkedService.getName(), resourceService.getGdsService())) {
+						resourceService.setGdsService(linkedService.getName());
+
+						LOG.info("Linking resource-service[" + resourceService.getName() + "] with gds-service [" + linkedService.getName() + "]");
+
+						RangerService service = svcStore.updateService(resourceService, null);
+
+						LOG.info("Updated resource-service:[" + service.getName() + "]");
+					}
+				}
+			} catch (Exception e) {
+				LOG.error("Failed to link service[" + resourceServiceName + "] with service [" + linkedServiceName + "]");
+			}
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("<== doLinkTagService()");
 			}
-		} catch (Exception e) {
-			LOG.error("Failed to link service[" + context.resourceServiceName + "] with tag-service [" + context.tagServiceName + "]");
 		}
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== doLinkTagService(context=" + context + ")");
+
+		@Override
+		public String toString() {
+			return "{resourceServiceName=" + resourceServiceName + ", linkedServiceType=" + linkedServiceType + ", isAutoCreate=" + isAutoCreate + ", isAutoLink=" + isAutoLink + "}";
 		}
 	}
 
diff --git a/security-admin/src/main/java/org/apache/ranger/service/RangerServiceService.java b/security-admin/src/main/java/org/apache/ranger/service/RangerServiceService.java
index e72bd4c10..8ec558881 100644
--- a/security-admin/src/main/java/org/apache/ranger/service/RangerServiceService.java
+++ b/security-admin/src/main/java/org/apache/ranger/service/RangerServiceService.java
@@ -262,12 +262,16 @@ public class RangerServiceService extends RangerServiceServiceBase<XXService, Ra
 					}
 					oldValue = jsonUtil.readMapToString(oldConfig);
 					value = jsonUtil.readMapToString(newConfig);
-				}
-				if ("tagService".equalsIgnoreCase(fieldName)) {
+				} else if ("tagService".equalsIgnoreCase(fieldName)) {
 					if(!StringUtils.isEmpty(oldValue) && !"null".equalsIgnoreCase(oldValue)){
 						RangerService oldService = this.populateViewBean(mObj);
 						oldValue=oldService.getTagService();
 					}
+				} else if ("gdsService".equalsIgnoreCase(fieldName)) {
+					if(!StringUtils.isEmpty(oldValue) && !"null".equalsIgnoreCase(oldValue)){
+						RangerService oldService = this.populateViewBean(mObj);
+						oldValue = oldService.getGdsService();
+					}
 				}
 				if (oldValue == null || value.equalsIgnoreCase(oldValue)) {
 					return null;
@@ -344,6 +348,8 @@ public class RangerServiceService extends RangerServiceServiceBase<XXService, Ra
 		serviceVersionInfo.setPolicyUpdateTime(now);
 		serviceVersionInfo.setTagUpdateTime(now);
 		serviceVersionInfo.setRoleUpdateTime(now);
+		serviceVersionInfo.setGdsVersion(1L);
+		serviceVersionInfo.setGdsUpdateTime(now);
 
 		XXServiceVersionInfoDao serviceVersionInfoDao = daoMgr.getXXServiceVersionInfo();
 
diff --git a/security-admin/src/main/java/org/apache/ranger/service/RangerServiceServiceBase.java b/security-admin/src/main/java/org/apache/ranger/service/RangerServiceServiceBase.java
index fbe5e42d4..5c9591f63 100755
--- a/security-admin/src/main/java/org/apache/ranger/service/RangerServiceServiceBase.java
+++ b/security-admin/src/main/java/org/apache/ranger/service/RangerServiceServiceBase.java
@@ -92,10 +92,27 @@ public abstract class RangerServiceServiceBase<T extends XXServiceBase, V extend
 			tagServiceId = xTagService.getId();
 		}
 
+		Long   gdsServiceId   = null;
+		String gdsServiceName = vObj.getGdsService();
+
+		if (StringUtils.isNotBlank(gdsServiceName)) {
+			XXService xGdsService = daoMgr.getXXService().findByName(gdsServiceName);
+
+			if (xGdsService == null) {
+				throw restErrorUtil.createRESTException(
+						"No Service found with name :" + gdsServiceName,
+						MessageEnums.INVALID_INPUT_DATA);
+			}
+
+			gdsServiceId = xGdsService.getId();
+		}
+
 		xObj.setType(xServiceDef.getId());
 		xObj.setName(vObj.getName());
 		xObj.setDisplayName(vObj.getDisplayName());
 		xObj.setTagService(tagServiceId);
+		xObj.setGdsService(gdsServiceId);
+
 		if (OPERATION_CONTEXT == OPERATION_CREATE_CONTEXT) {
 			xObj.setTagVersion(vObj.getTagVersion());
 		}
@@ -108,6 +125,7 @@ public abstract class RangerServiceServiceBase<T extends XXServiceBase, V extend
 	protected V mapEntityToViewBean(V vObj, T xObj) {
 		XXServiceDef xServiceDef = daoMgr.getXXServiceDef().getById(xObj.getType());
 		XXService    xTagService = xObj.getTagService() != null ? daoMgr.getXXService().getById(xObj.getTagService()) : null;
+		XXService    xGdsService = xObj.getGdsService() != null ? daoMgr.getXXService().getById(xObj.getGdsService()) : null;
 		vObj.setType(xServiceDef.getName());
 		vObj.setGuid(xObj.getGuid());
 		vObj.setVersion(xObj.getVersion());
@@ -115,12 +133,15 @@ public abstract class RangerServiceServiceBase<T extends XXServiceBase, V extend
 		vObj.setDisplayName(xObj.getDisplayName());
 		vObj.setDescription(xObj.getDescription());
 		vObj.setTagService(xTagService != null ? xTagService.getName() : null);
+		vObj.setGdsService(xGdsService != null ? xGdsService.getName() : null);
 		XXServiceVersionInfo versionInfoObj = daoMgr.getXXServiceVersionInfo().findByServiceId(xObj.getId());
 		if (versionInfoObj != null) {
 			vObj.setPolicyVersion(versionInfoObj.getPolicyVersion());
 			vObj.setTagVersion(versionInfoObj.getTagVersion());
 			vObj.setPolicyUpdateTime(versionInfoObj.getPolicyUpdateTime());
 			vObj.setTagUpdateTime(versionInfoObj.getTagUpdateTime());
+			vObj.setGdsVersion(versionInfoObj.getGdsVersion());
+			vObj.setGdsUpdateTime(versionInfoObj.getGdsUpdateTime());
 		} else {
 			vObj.setPolicyVersion(xObj.getPolicyVersion());
 			vObj.setTagVersion(xObj.getTagVersion());