Added the new versioning validation for policy and policy type
[policy/api.git] / main / src / main / java / org / onap / policy / api / main / rest / provider / LegacyGuardPolicyProvider.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP Policy API
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.api.main.rest.provider;
24
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import javax.ws.rs.core.Response;
32
33 import org.apache.commons.lang3.tuple.Pair;
34 import org.onap.policy.models.base.PfConceptKey;
35 import org.onap.policy.models.base.PfModelException;
36 import org.onap.policy.models.base.PfModelRuntimeException;
37 import org.onap.policy.models.pdp.concepts.PdpGroup;
38 import org.onap.policy.models.pdp.concepts.PdpGroupFilter;
39 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
40 import org.onap.policy.models.tosca.legacy.concepts.LegacyGuardPolicyInput;
41 import org.onap.policy.models.tosca.legacy.concepts.LegacyGuardPolicyOutput;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * Class to provide all kinds of legacy guard policy operations.
47  *
48  * @author Chenfei Gao (cgao@research.att.com)
49  */
50 public class LegacyGuardPolicyProvider extends CommonModelProvider {
51
52     private static final Logger LOGGER = LoggerFactory.getLogger(LegacyGuardPolicyProvider.class);
53
54     private static final String INVALID_POLICY_VERSION = "legacy policy version is not an integer";
55     private static final String LEGACY_MINOR_PATCH_SUFFIX = ".0.0";
56     private static final Map<String, PfConceptKey> GUARD_POLICY_TYPE_MAP = new LinkedHashMap<>();
57
58     static {
59         GUARD_POLICY_TYPE_MAP.put("guard.frequency.",
60                 new PfConceptKey("onap.policies.controlloop.guard.FrequencyLimiter:1.0.0"));
61         GUARD_POLICY_TYPE_MAP.put("guard.minmax.",
62                 new PfConceptKey("onap.policies.controlloop.guard.MinMax:1.0.0"));
63         GUARD_POLICY_TYPE_MAP.put("guard.blacklist.",
64                 new PfConceptKey("onap.policies.controlloop.guard.Blacklist:1.0.0"));
65     }
66
67     /**
68      * Default constructor.
69      */
70     public LegacyGuardPolicyProvider() throws PfModelException {
71         super();
72     }
73
74     /**
75      * Retrieves a list of guard policies matching specified ID and version.
76      *
77      * @param policyId the ID of policy
78      * @param policyVersion the version of policy
79      *
80      * @return the map of LegacyGuardPolicyOutput objects
81      */
82     public Map<String, LegacyGuardPolicyOutput> fetchGuardPolicy(String policyId, String policyVersion)
83             throws PfModelException {
84
85         if (policyVersion != null) {
86             validNumber(policyVersion, INVALID_POLICY_VERSION);
87         }
88         return modelsProvider.getGuardPolicy(policyId, policyVersion);
89     }
90
91     /**
92      * Retrieves a list of deployed guard policies in each pdp group.
93      *
94      * @param policyId the ID of the policy
95      *
96      * @return a list of deployed policies in each pdp group
97      *
98      * @throws PfModelException the PfModel parsing exception
99      */
100     public Map<Pair<String, String>, Map<String, LegacyGuardPolicyOutput>> fetchDeployedGuardPolicies(String policyId)
101             throws PfModelException {
102
103         return collectDeployedPolicies(
104                 policyId, getGuardPolicyType(policyId), modelsProvider::getGuardPolicy, Map::putAll, new HashMap<>());
105     }
106
107     /**
108      * Creates a new guard policy.
109      *
110      * @param body the entity body of policy
111      *
112      * @return the map of LegacyGuardPolicyOutput objectst
113      */
114     public Map<String, LegacyGuardPolicyOutput> createGuardPolicy(LegacyGuardPolicyInput body)
115             throws PfModelException {
116
117         validateGuardPolicyVersion(body);
118         return modelsProvider.createGuardPolicy(body);
119     }
120
121     /**
122      * Deletes the guard policies matching specified ID and version.
123      *
124      * @param policyId the ID of policy
125      * @param policyVersion the version of policy
126      *
127      * @return the map of LegacyGuardPolicyOutput objects
128      */
129     public Map<String, LegacyGuardPolicyOutput> deleteGuardPolicy(String policyId, String policyVersion)
130             throws PfModelException {
131
132         validNumber(policyVersion, INVALID_POLICY_VERSION);
133         validateDeleteEligibility(policyId, policyVersion);
134
135         return modelsProvider.deleteGuardPolicy(policyId, policyVersion);
136     }
137
138     /**
139      * Validates whether specified policy can be deleted based on the rule that deployed policy cannot be deleted.
140      *
141      * @param policyId the ID of policy
142      * @param policyVersion the version of policy
143      *
144      * @throws PfModelException the PfModel parsing exception
145      */
146     private void validateDeleteEligibility(String policyId, String policyVersion) throws PfModelException {
147
148         List<ToscaPolicyIdentifier> policies = new ArrayList<>();
149         policies.add(new ToscaPolicyIdentifier(policyId, policyVersion + LEGACY_MINOR_PATCH_SUFFIX));
150         PdpGroupFilter pdpGroupFilter = PdpGroupFilter.builder().policyList(policies).build();
151
152         List<PdpGroup> pdpGroups = modelsProvider.getFilteredPdpGroups(pdpGroupFilter);
153
154         if (!pdpGroups.isEmpty()) {
155             throw new PfModelException(Response.Status.CONFLICT,
156                     constructDeletePolicyViolationMessage(policyId, policyVersion, pdpGroups));
157         }
158     }
159
160     /**
161      * Validates the provided guard policy version in the payload.
162      *
163      * @param body the guard policy payload
164      *
165      * @throws PfModelException the PfModel parsing exception
166      */
167     private void validateGuardPolicyVersion(LegacyGuardPolicyInput body) throws PfModelException {
168
169         validateGuardPolicyVersionExist(body);
170         validateNoDuplicateVersionInDb(body);
171     }
172
173     /**
174      * Validates that the guard policy has version specified.
175      *
176      * @param body the guard policy payload
177      *
178      * @throws PfModelException the PfModel parsing exception
179      */
180     private void validateGuardPolicyVersionExist(LegacyGuardPolicyInput body) throws PfModelException {
181
182         if (body.getPolicyVersion() == null) {
183             String errMsg = "mandatory field 'policy-version' is missing in the policy: " + body.getPolicyId();
184             throw new PfModelException(Response.Status.NOT_ACCEPTABLE, errMsg);
185         }
186     }
187
188     /**
189      * Validates that there is no duplicate version already stored in the database.
190      *
191      * @param body the guard policy payload
192      *
193      * @throws PfModelException the PfModel parsing exception
194      */
195     private void validateNoDuplicateVersionInDb(LegacyGuardPolicyInput body) throws PfModelException {
196
197         try {
198             modelsProvider.getGuardPolicy(body.getPolicyId(), body.getPolicyVersion());
199         } catch (PfModelRuntimeException exc) {
200             if (!hasSameGuardPolicyFound(body, exc)) {
201                 return;
202             }
203             throw new PfModelException(exc.getErrorResponse().getResponseCode(), "unexpected runtime error", exc);
204         }
205
206         // If it gets here, there is one duplicate version stored in the DB.
207         // Try to get the latest version and return it to the user.
208         Map<String, LegacyGuardPolicyOutput> latest = modelsProvider.getGuardPolicy(body.getPolicyId(), null);
209         final String[] versionArray = latest.values().iterator().next().getVersion().split("\\.");
210         String errMsg = "guard policy " + body.getPolicyId() + ":" + body.getPolicyVersion()
211             + " already exists; its latest version is " + versionArray[0];
212         throw new PfModelException(Response.Status.NOT_ACCEPTABLE, errMsg);
213     }
214
215     /**
216      * Checks if the same guard policy found in the database.
217      *
218      * @param body the legacy guard policy payload
219      * @param exc the thrown runtime exception from policy model provider
220      *
221      * @return a boolean flag indicating the check result
222      */
223     private boolean hasSameGuardPolicyFound(LegacyGuardPolicyInput body, PfModelRuntimeException exc) {
224
225         if (exc.getErrorResponse().getResponseCode() == Response.Status.BAD_REQUEST
226                 && exc.getErrorResponse().getErrorMessage().contains("no policy found")) {
227             LOGGER.debug("no duplicate policy {}:{} found in the DB", body.getPolicyId(), body.getPolicyVersion());
228             return false;
229         }
230         return true;
231     }
232
233     /**
234      * Retrieves guard policy type given guard policy ID.
235      *
236      * @param policyId the ID of guard policy
237      *
238      * @return the concept key of guard policy type
239      *
240      * @throws PfModelException the PfModel parsing exception
241      */
242     private PfConceptKey getGuardPolicyType(String policyId) throws PfModelException {
243
244         for (Entry<String, PfConceptKey> guardPolicyTypeEntry : GUARD_POLICY_TYPE_MAP.entrySet()) {
245             if (policyId.startsWith(guardPolicyTypeEntry.getKey())) {
246                 return guardPolicyTypeEntry.getValue();
247             }
248         }
249         throw new PfModelException(Response.Status.BAD_REQUEST, "No policy type defined for " + policyId);
250     }
251 }