ee1ccdceaf552e37e10eafb417d57aeeddcef6b0
[policy/xacml-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.xacml.pdp.application.optimization;
24
25 import com.att.research.xacml.api.Advice;
26 import com.att.research.xacml.api.AttributeAssignment;
27 import com.att.research.xacml.api.Decision;
28 import com.att.research.xacml.api.Request;
29 import com.att.research.xacml.api.Response;
30 import com.att.research.xacml.api.Result;
31 import java.nio.file.Path;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.List;
37 import java.util.Map;
38 import org.apache.commons.lang3.tuple.Pair;
39 import org.onap.policy.common.endpoints.parameters.RestServerParameters;
40 import org.onap.policy.models.decisions.concepts.DecisionRequest;
41 import org.onap.policy.models.decisions.concepts.DecisionResponse;
42 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
43 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
44 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
45 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
46 import org.onap.policy.pdp.xacml.application.common.std.StdXacmlApplicationServiceProvider;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 public class OptimizationPdpApplication extends StdXacmlApplicationServiceProvider {
51
52     private static final Logger LOGGER = LoggerFactory.getLogger(OptimizationPdpApplication.class);
53     private static final String STRING_VERSION100 = "1.0.0";
54     private static final String RESOURCE_SUBSCRIBERNAME = "subscriberName";
55     private static final String RESOURCE_POLICYTYPE = "policy-type";
56     private static final String RESOURCE_SCOPE = "scope";
57
58     public static final String POLICYTYPE_AFFINITY = "onap.policies.optimization.resource.AffinityPolicy";
59     public static final String POLICYTYPE_SUBSCRIBER = "onap.policies.optimization.service.SubscriberPolicy";
60     public static final String POLICYTYPE_DISTANCE = "onap.policies.optimization.resource.DistancePolicy";
61     public static final String POLICYTYPE_HPA = "onap.policies.optimization.resource.HpaPolicy";
62     public static final String POLICYTYPE_OPTIMIZATION = "onap.policies.optimization.resource.OptimizationPolicy";
63     public static final String POLICYTYPE_PCI = "onap.policies.optimization.resource.PciPolicy";
64     public static final String POLICYTYPE_QUERY = "onap.policies.optimization.service.QueryPolicy";
65     public static final String POLICYTYPE_VIMFIT = "onap.policies.optimization.resource.Vim_fit";
66     public static final String POLICYTYPE_VNF = "onap.policies.optimization.resource.VnfPolicy";
67
68     private OptimizationPdpApplicationTranslator translator = new OptimizationPdpApplicationTranslator();
69     private List<ToscaPolicyTypeIdentifier> supportedPolicyTypes = new ArrayList<>();
70
71     /**
72      * Constructor.
73      */
74     public OptimizationPdpApplication() {
75         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_AFFINITY, STRING_VERSION100));
76         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_DISTANCE, STRING_VERSION100));
77         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_HPA, STRING_VERSION100));
78         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_OPTIMIZATION, STRING_VERSION100));
79         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_PCI, STRING_VERSION100));
80         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_QUERY, STRING_VERSION100));
81         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_SUBSCRIBER, STRING_VERSION100));
82         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_VIMFIT, STRING_VERSION100));
83         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_VNF, STRING_VERSION100));
84     }
85
86     @Override
87     public String applicationName() {
88         return "optimization";
89     }
90
91     @Override
92     public List<String> actionDecisionsSupported() {
93         return Arrays.asList("optimize");
94     }
95
96     @Override
97     public void initialize(Path pathForData, RestServerParameters policyApiParameters)
98             throws XacmlApplicationException {
99         //
100         // Store our API parameters and path for translator so it
101         // can go get Policy Types
102         //
103         this.translator.setPathForData(pathForData);
104         this.translator.setApiRestParameters(policyApiParameters);
105         //
106         // Let our super class do its thing
107         //
108         super.initialize(pathForData, policyApiParameters);
109     }
110
111     @Override
112     public synchronized List<ToscaPolicyTypeIdentifier> supportedPolicyTypes() {
113         return Collections.unmodifiableList(supportedPolicyTypes);
114     }
115
116     @Override
117     public boolean canSupportPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
118         //
119         // For the time being, restrict this if the version isn't known.
120         // Could be too difficult to support changing of versions dynamically.
121         //
122         //
123         // For the time being, restrict this if the version isn't known.
124         // Could be too difficult to support changing of versions dynamically.
125         //
126         for (ToscaPolicyTypeIdentifier supported : this.supportedPolicyTypes) {
127             if (policyTypeId.equals(supported)) {
128                 LOGGER.info("optimization can support {}", supported);
129                 return true;
130             }
131         }
132         return false;
133     }
134
135     @Override
136     public Pair<DecisionResponse, Response> makeDecision(DecisionRequest request,
137             Map<String, String[]> requestQueryParams) {
138         //
139         // In case we have a subcriber policy
140         //
141         Response xacmlSubscriberResponse = null;
142         //
143         // Check if there are subject attributes for subscriber
144         //
145         if (hasSubscriberAttributes(request)) {
146             //
147             // We must do an initial request to pull subscriber attributes
148             //
149             LOGGER.info("Request Subscriber attributes");
150             //
151             // Convert the request
152             //
153             DecisionRequest subscriberRequest = new DecisionRequest(request);
154             //
155             // Override the PolicyType to ensure we are only looking at Subscriber Policies
156             //
157             if (subscriberRequest.getResource().containsKey(RESOURCE_POLICYTYPE)) {
158                 subscriberRequest.getResource().remove(RESOURCE_POLICYTYPE);
159             }
160             subscriberRequest.getResource().put(RESOURCE_POLICYTYPE, POLICYTYPE_SUBSCRIBER);
161             //
162             // Convert to a XacmlRequest and get a decision
163             //
164             try {
165                 xacmlSubscriberResponse =
166                         this.xacmlDecision(OptimizationSubscriberRequest.createInstance(subscriberRequest));
167             } catch (XacmlApplicationException e) {
168                 LOGGER.error("Could not create subscriberName request", e);
169             }
170             //
171             // Check the response for subscriber attributes and add them
172             // to the initial request.
173             //
174             if (xacmlSubscriberResponse != null && ! addSubscriberAttributes(xacmlSubscriberResponse, request)) {
175                 LOGGER.error("Failed to get subscriber role attributes");
176                 //
177                 // Convert to a DecisionResponse
178                 //
179                 return Pair.of(this.getTranslator().convertResponse(xacmlSubscriberResponse), xacmlSubscriberResponse);
180             }
181         }
182         //
183         // Convert to a XacmlRequest
184         //
185         Request xacmlRequest = this.getTranslator().convertRequest(request);
186         //
187         // Now get a decision
188         //
189         Response xacmlResponse = this.xacmlDecision(xacmlRequest);
190         //
191         // Convert to a DecisionResponse
192         //
193         Pair<DecisionResponse, Response> returnPair = Pair.of(this.getTranslator().convertResponse(xacmlResponse),
194                 xacmlResponse);
195         //
196         // Add back in advice from subscriber
197         //
198         if (xacmlSubscriberResponse != null) {
199             addSubscriberAdvice(xacmlSubscriberResponse, returnPair.getLeft());
200         }
201         return returnPair;
202     }
203
204     @Override
205     protected ToscaPolicyTranslator getTranslator(String type) {
206         //
207         // Return translator
208         //
209         return translator;
210     }
211
212     @SuppressWarnings("unchecked")
213     private boolean hasSubscriberAttributes(DecisionRequest request) {
214         return request.getContext() != null
215                 && request.getContext().containsKey(RESOURCE_SUBSCRIBERNAME)
216                 && request.getContext().get(RESOURCE_SUBSCRIBERNAME) instanceof List
217                 && ! ((List<String>) request.getContext().get(RESOURCE_SUBSCRIBERNAME)).isEmpty();
218     }
219
220     private boolean addSubscriberAttributes(Response xacmlResponse, DecisionRequest initialRequest) {
221         //
222         // This has multiple results right now because of how the attributes were added to the
223         // request. That will have to be fixed in the future, for now find the Permit result
224         // and add the role attributes as they will be used in the next request.
225         //
226         for (Result result : xacmlResponse.getResults()) {
227             //
228             // Check the result
229             //
230             if (result.getStatus().isOk() && result.getDecision().equals(Decision.PERMIT)) {
231                 //
232                 // Pull out the advice which has attributes
233                 //
234                 scanAdvice(result.getAssociatedAdvice(), initialRequest);
235                 //
236                 // PLD this is an assumption that all is good
237                 //
238                 return true;
239             } else {
240                 LOGGER.error("XACML result not ok {} or Permit {}", result.getStatus(), result.getDecision());
241             }
242         }
243         return false;
244     }
245
246     private void addSubscriberAdvice(Response xacmlResponse, DecisionResponse response) {
247         //
248         // Again find the Permit result
249         //
250         for (Result result : xacmlResponse.getResults()) {
251             //
252             // Check the result
253             //
254             if (result.getStatus().isOk() && Decision.PERMIT.equals(result.getDecision())) {
255                 this.translator.scanAdvice(result.getAssociatedAdvice(), response);
256             }
257         }
258     }
259
260
261     @SuppressWarnings("unchecked")
262     private void scanAdvice(Collection<Advice> adviceCollection, DecisionRequest initialRequest) {
263         //
264         // There really should only be one advice object
265         //
266         for (Advice advice : adviceCollection) {
267             //
268             // Look for the optimization specific advice
269             //
270             if (! ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER.equals(advice.getId())) {
271                 LOGGER.error("Unsupported advice id {}", advice.getId());
272                 continue;
273             }
274             //
275             // Get the attributes and add them
276             //
277             for (AttributeAssignment attribute : advice.getAttributeAssignments()) {
278                 //
279                 // If this is subscriber role
280                 //
281                 if (ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER_ROLE.equals(attribute.getAttributeId())) {
282                     ((List<String>) initialRequest.getResource().get(RESOURCE_SCOPE))
283                             .add(attribute.getAttributeValue().getValue().toString());
284                 }
285             }
286         }
287     }
288
289 }