Skip to content

Commit 300227e

Browse files
authored
Merge pull request #4669 from atlanhq/featarpit1
POLICY-295 - Added a v2 for unlink policy
2 parents 52483a6 + 3dc8f2c commit 300227e

File tree

5 files changed

+145
-96
lines changed

5 files changed

+145
-96
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
* <p>
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
* <p>
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.atlas.model.instance;
19+
20+
import com.fasterxml.jackson.annotation.JsonAutoDetect;
21+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
22+
import com.fasterxml.jackson.annotation.JsonInclude;
23+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
24+
25+
import javax.xml.bind.annotation.XmlAccessType;
26+
import javax.xml.bind.annotation.XmlAccessorType;
27+
import javax.xml.bind.annotation.XmlRootElement;
28+
import java.io.Serializable;
29+
import java.util.Set;
30+
31+
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
32+
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.PUBLIC_ONLY;
33+
34+
/**
35+
* Request to link/unlink policies from asset.
36+
*/
37+
@JsonAutoDetect(getterVisibility = PUBLIC_ONLY, setterVisibility = PUBLIC_ONLY, fieldVisibility = NONE)
38+
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
39+
@JsonIgnoreProperties(ignoreUnknown = true)
40+
@JsonInclude(JsonInclude.Include.NON_NULL)
41+
@XmlRootElement
42+
@XmlAccessorType(XmlAccessType.PROPERTY)
43+
public class UnlinkBusinessPolicyRequest implements Serializable {
44+
private static final long serialVersionUID = 1L;
45+
46+
private Set<String> unlinkGuids;
47+
48+
private Set<String> assetGuids;
49+
50+
public Set<String> getUnlinkGuids() {
51+
return unlinkGuids;
52+
}
53+
54+
public void setUnlinkGuids(Set<String> unlinkGuids) {
55+
this.unlinkGuids = unlinkGuids;
56+
}
57+
58+
public Set<String> getAssetGuids() {
59+
return assetGuids;
60+
}
61+
62+
public void setAssetGuids(Set<String> assetGuids) {
63+
this.assetGuids = assetGuids;
64+
}
65+
66+
@Override
67+
public String toString() {
68+
final StringBuilder sb = new StringBuilder("UnLinkBusinessPolicyRequest{");
69+
sb.append("unlinkGuids=").append(unlinkGuids);
70+
sb.append(", assetGuids=").append(assetGuids);
71+
sb.append('}');
72+
return sb.toString();
73+
}
74+
}

repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,6 @@ EntityMutationResponse deleteByUniqueAttributes(List<AtlasObjectId> objectIds)
373373

374374
void unlinkBusinessPolicy(String policyId, Set<String> unlinkGuids) throws AtlasBaseException;
375375

376-
void moveBusinessPolicies(Set<String> policyId, String assetId, String type) throws AtlasBaseException;
377-
378376
/**
379377
*
380378
* @param entities
@@ -383,4 +381,6 @@ EntityMutationResponse deleteByUniqueAttributes(List<AtlasObjectId> objectIds)
383381
* For evaluations of policies
384382
*/
385383
List<AtlasEvaluatePolicyResponse> evaluatePolicies(List<AtlasEvaluatePolicyRequest> entities) throws AtlasBaseException;
384+
385+
void unlinkBusinessPolicyV2(Set<String> assetGuids, Set<String> unlinkGuids) throws AtlasBaseException;
386386
}

repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java

+9-14
Original file line numberDiff line numberDiff line change
@@ -3040,26 +3040,21 @@ private void handleEntityMutation(List<AtlasVertex> vertices) throws AtlasBaseEx
30403040

30413041
@Override
30423042
@GraphTransaction
3043-
public void moveBusinessPolicies(Set<String> policyIds, String assetId, String type) throws AtlasBaseException {
3044-
// Start performance metric recording
3045-
AtlasPerfMetrics.MetricRecorder metric = RequestContext.get().startMetricRecord("moveBusinessPolicy.GraphTransaction");
3046-
3043+
public void unlinkBusinessPolicyV2(Set<String> assetGuids, Set<String> unlinkGuids) throws AtlasBaseException {
3044+
AtlasPerfMetrics.MetricRecorder metric = RequestContext.get().startMetricRecord("unlinkBusinessPolicy.GraphTransaction");
30473045
try {
3048-
// Attempt to move the business policy using the entityGraphMapper
3049-
AtlasVertex vertex = entityGraphMapper.moveBusinessPolicies(policyIds, assetId, type);
3050-
3051-
if (vertex == null) {
3052-
LOG.warn("No vertex found for assetId: {}", assetId);
3046+
List<AtlasVertex> vertices = this.entityGraphMapper.unlinkBusinessPolicyV2(assetGuids, unlinkGuids);
3047+
if (CollectionUtils.isEmpty(vertices)) {
30533048
return;
30543049
}
3055-
handleEntityMutation(Collections.singletonList(vertex));
3050+
3051+
handleEntityMutation(vertices);
30563052
} catch (Exception e) {
3057-
// Log the error with context and rethrow it wrapped in an AtlasBaseException
3058-
LOG.error("Error during moveBusinessPolicy for assetId: {}", assetId, e);
3059-
throw new AtlasBaseException(e);
3053+
LOG.error("Error during unlinkBusinessPolicy", e);
3054+
throw e;
30603055
} finally {
3061-
// End the performance metric recording
30623056
RequestContext.get().endMetricRecord(metric);
30633057
}
30643058
}
3059+
30653060
}

repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphMapper.java

+36-56
Original file line numberDiff line numberDiff line change
@@ -5183,62 +5183,6 @@ private void updateDomainAttribute(AtlasVertex vertex, Set<String> existingValue
51835183
existingValues.forEach(existingValue -> vertex.removePropertyValue(DOMAIN_GUIDS_ATTR, existingValue));
51845184
vertex.setProperty(DOMAIN_GUIDS_ATTR, meshEntityId);
51855185
}
5186-
public AtlasVertex moveBusinessPolicies(Set<String> policyIds, String assetId, String type) throws AtlasBaseException {
5187-
// Retrieve the AtlasVertex for the given assetId
5188-
AtlasVertex assetVertex = AtlasGraphUtilsV2.findByGuid(graph, assetId);
5189-
5190-
if (assetVertex == null) {
5191-
throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "Asset with guid not found");
5192-
}
5193-
5194-
// Get the sets of governed and non-compliant policy GUIDs
5195-
Set<String> governedPolicies = assetVertex.getMultiValuedSetProperty(ASSET_POLICY_GUIDS, String.class);
5196-
Set<String> nonCompliantPolicies = assetVertex.getMultiValuedSetProperty(NON_COMPLIANT_ASSET_POLICY_GUIDS, String.class);
5197-
5198-
// Determine if the type is governed or non-compliant
5199-
boolean isGoverned = MoveBusinessPolicyRequest.Type.GOVERNED.getDescription().equals(type);
5200-
Set<String> currentPolicies = isGoverned ? new HashSet<>(governedPolicies) : new HashSet<>(nonCompliantPolicies);
5201-
policyIds.removeAll(currentPolicies);
5202-
5203-
// Check if the asset already has the given policy IDs
5204-
if (policyIds.isEmpty()) {
5205-
return assetVertex;
5206-
}
5207-
5208-
// Move policies to the appropriate set
5209-
policyIds.forEach(policyId -> {
5210-
if (isGoverned) {
5211-
assetVertex.setProperty(ASSET_POLICY_GUIDS, policyId);
5212-
removeItemFromListPropertyValue(assetVertex, NON_COMPLIANT_ASSET_POLICY_GUIDS, policyId);
5213-
} else {
5214-
assetVertex.setProperty(NON_COMPLIANT_ASSET_POLICY_GUIDS, policyId);
5215-
removeItemFromListPropertyValue(assetVertex, ASSET_POLICY_GUIDS, policyId);
5216-
}
5217-
});
5218-
5219-
// Update the sets after processing
5220-
if (isGoverned) {
5221-
governedPolicies.addAll(policyIds);
5222-
nonCompliantPolicies.removeAll(policyIds);
5223-
} else {
5224-
nonCompliantPolicies.addAll(policyIds);
5225-
governedPolicies.removeAll(policyIds);
5226-
}
5227-
5228-
// Update the modification metadata
5229-
updateModificationMetadata(assetVertex);
5230-
5231-
// Create a differential AtlasEntity to reflect the changes
5232-
AtlasEntity diffEntity = new AtlasEntity(assetVertex.getProperty(TYPE_NAME_PROPERTY_KEY, String.class));
5233-
setEntityCommonAttributes(assetVertex, diffEntity);
5234-
diffEntity.setAttribute(ASSET_POLICY_GUIDS, governedPolicies);
5235-
diffEntity.setAttribute(NON_COMPLIANT_ASSET_POLICY_GUIDS, nonCompliantPolicies);
5236-
5237-
// Cache the differential entity for further processing
5238-
RequestContext.get().cacheDifferentialEntity(diffEntity);
5239-
5240-
return assetVertex;
5241-
}
52425186

52435187
private void cacheDifferentialEntity(AtlasVertex ev, Set<String> complaint, Set<String> nonComplaint) {
52445188
AtlasEntity diffEntity = new AtlasEntity(ev.getProperty(TYPE_NAME_PROPERTY_KEY, String.class));
@@ -5277,4 +5221,40 @@ private void isAuthorizedToLink(AtlasVertex vertex) throws AtlasBaseException {
52775221
"read on source Entity, link/unlink operation denied: ", sourceEntity.getAttribute(NAME));
52785222

52795223
}
5224+
5225+
public List<AtlasVertex> unlinkBusinessPolicyV2(Set<String> assetGuids, Set<String> unlinkGuids) {
5226+
5227+
if (CollectionUtils.isEmpty(assetGuids) || CollectionUtils.isEmpty(unlinkGuids)) {
5228+
throw new IllegalArgumentException("assets and unlinkGuids must not be empty");
5229+
}
5230+
5231+
return assetGuids.stream()
5232+
.map(guid -> AtlasGraphUtilsV2.findByGuid(graph, guid))
5233+
.filter(Objects::nonNull)
5234+
.map(vertex -> updateVertexPolicyV2(vertex, unlinkGuids))
5235+
.collect(Collectors.toList());
5236+
}
5237+
5238+
5239+
private AtlasVertex updateVertexPolicyV2(AtlasVertex vertex, Set<String> policyIds) {
5240+
Set<String> compliantPolicies = getMultiValuedSetProperty(vertex, ASSET_POLICY_GUIDS);
5241+
Set<String> nonCompliantPolicies = getMultiValuedSetProperty(vertex, NON_COMPLIANT_ASSET_POLICY_GUIDS);
5242+
policyIds.forEach(policyId -> {
5243+
vertex.removePropertyValue(ASSET_POLICY_GUIDS, policyId);
5244+
vertex.removePropertyValue(NON_COMPLIANT_ASSET_POLICY_GUIDS, policyId);
5245+
});
5246+
5247+
int compliantPolicyCount = countPoliciesExcluding(compliantPolicies, "rule");
5248+
int nonCompliantPolicyCount = countPoliciesExcluding(nonCompliantPolicies, "rule");
5249+
int totalPolicyCount = compliantPolicyCount + nonCompliantPolicyCount;
5250+
vertex.setProperty(ASSET_POLICIES_COUNT, totalPolicyCount);
5251+
5252+
updateModificationMetadata(vertex);
5253+
cacheDifferentialEntity(vertex, compliantPolicies, nonCompliantPolicies);
5254+
5255+
return vertex;
5256+
}
5257+
5258+
5259+
52805260
}

webapp/src/main/java/org/apache/atlas/web/rest/BusinessPolicyREST.java

+24-24
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.apache.atlas.exception.AtlasBaseException;
77
import org.apache.atlas.model.instance.BusinessPolicyRequest;
88
import org.apache.atlas.model.instance.LinkBusinessPolicyRequest;
9+
import org.apache.atlas.model.instance.UnlinkBusinessPolicyRequest;
910
import org.apache.atlas.model.instance.MoveBusinessPolicyRequest;
1011
import org.apache.atlas.repository.store.graph.AtlasEntityStore;
1112
import org.apache.atlas.utils.AtlasPerfMetrics;
@@ -120,48 +121,47 @@ public void unlinkBusinessPolicy(@PathParam("policyId") final String policyGuid,
120121
}
121122
}
122123

123-
124124
@POST
125-
@Path("/move/{assetId}")
125+
@Path("/unlink-business-policy/v2")
126126
@Timed
127-
public void moveBusinessPolicies(
128-
@PathParam("assetId") String assetId,
129-
final MoveBusinessPolicyRequest request
130-
) throws AtlasBaseException {
131-
if (isInvalidRequest(request, assetId)) {
132-
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Request is missing required parameters.");
127+
public void unlinkBusinessPolicyV2(final UnlinkBusinessPolicyRequest request) throws AtlasBaseException {
128+
AtlasPerfMetrics.MetricRecorder metric = RequestContext.get().startMetricRecord("unlinkBusinessPolicyV2");
129+
// Ensure the current user is authorized to unlink policies
130+
if (!ARGO_SERVICE_USER_NAME.equals(RequestContext.getCurrentUser())) {
131+
throw new AtlasBaseException(AtlasErrorCode.UNAUTHORIZED_ACCESS, RequestContext.getCurrentUser(), "Policy unlinking");
133132
}
134-
// Start performance metric recording
135-
AtlasPerfMetrics.MetricRecorder metric = RequestContext.get().startMetricRecord("moveBusinessPolicy");
136133

137-
// Ensure the current user is authorized to move the policy
138-
String currentUser = RequestContext.getCurrentUser();
139-
if (!ARGO_SERVICE_USER_NAME.equals(currentUser)) {
140-
throw new AtlasBaseException(AtlasErrorCode.UNAUTHORIZED_ACCESS, currentUser, "moveBusinessPolicy");
134+
if(CollectionUtils.isEmpty(request.getAssetGuids()) || CollectionUtils.isEmpty(request.getUnlinkGuids())) {
135+
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Asset GUIDs or Unlink GUIDs cannot be empty");
141136
}
142137

143-
// Set request context parameters for the current operation
144-
RequestContext requestContext = RequestContext.get();
145-
requestContext.setIncludeClassifications(false);
146-
requestContext.setIncludeMeanings(false);
147-
requestContext.getRequestContextHeaders().put("x-atlan-route", "business-policy-rest");
138+
if(request.getAssetGuids().size() > 50 || request.getUnlinkGuids().size() > 50) {
139+
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Asset GUIDs and Unlink GUIDs should not exceed 50");
140+
}
141+
142+
// Set request context parameters
143+
RequestContext.get().setIncludeClassifications(false);
144+
RequestContext.get().setIncludeMeanings(false);
145+
RequestContext.get().getRequestContextHeaders().put("x-atlan-route", "business-policy-rest");
148146

149147
AtlasPerfTracer perf = null;
150148
try {
151149
// Start performance tracing if enabled
152150
if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
153-
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "BusinessPolicyREST.moveBusinessPolicy(" + assetId + ")");
151+
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "BusinessPolicyREST.unlinkBusinessPolicyV2()");
154152
}
155153

156-
// Move the business policy using the entitiesStore
157-
entitiesStore.moveBusinessPolicies(request.getPolicyIds(), assetId, request.getType());
154+
// Unlink the business policy from the specified entities
155+
entitiesStore.unlinkBusinessPolicyV2(request.getAssetGuids(), request.getUnlinkGuids());
158156
} finally {
159-
// Log performance trace and end metric recording
157+
// Log performance metrics
160158
AtlasPerfTracer.log(perf);
161-
requestContext.endMetricRecord(metric);
159+
RequestContext.get().endMetricRecord(metric);
162160
}
163161
}
164162

163+
164+
165165
private boolean isInvalidRequest(MoveBusinessPolicyRequest request, String assetId) {
166166
return Objects.isNull(request) ||
167167
CollectionUtils.isEmpty(request.getPolicyIds()) ||

0 commit comments

Comments
 (0)