2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2021 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
11 * http://www.apache.org/licenses/LICENSE-2.0
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 * ============LICENSE_END=========================================================
21 package org.onap.policy.pap.main.notification;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.List;
29 import java.util.Map.Entry;
31 import java.util.function.BiPredicate;
32 import java.util.stream.Collectors;
33 import lombok.AccessLevel;
35 import org.onap.policy.models.base.PfModelException;
36 import org.onap.policy.models.pap.concepts.PolicyNotification;
37 import org.onap.policy.models.pdp.concepts.PdpPolicyStatus;
38 import org.onap.policy.models.pdp.concepts.PdpPolicyStatus.State;
39 import org.onap.policy.models.provider.PolicyModelsProvider;
40 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
41 import org.onap.policy.pap.main.notification.StatusAction.Action;
44 * Collection of Policy Deployment Status records. The sequence of method invocations
45 * should be as follows:
47 * <li>{@link #loadByGroup(String)}</li>
48 * <li>various other methods</li>
49 * <li>repeat the previous steps as appropriate</li>
50 * <li>{@link #flush(PolicyNotification)}</li>
53 public class DeploymentStatus {
55 * Tracks the groups that have been loaded.
57 private final Set<String> pdpGroupLoaded = new HashSet<>();
60 * Records, mapped by PDP/Policy pair.
62 @Getter(AccessLevel.PROTECTED)
63 private final Map<StatusKey, StatusAction> recordMap = new HashMap<>();
66 * Records the policy status so that notifications can be generated. When
67 * {@link #loadByGroup(String)} is invoked, records are added to this. Other than
68 * that, this is not updated until {@link #addNotifications(PolicyNotification)} is
71 private DeploymentTracker tracker = new DeploymentTracker();
73 private PolicyModelsProvider provider;
77 * Constructs the object.
79 * @param provider the provider to use to access the DB
81 public DeploymentStatus(PolicyModelsProvider provider) {
82 this.provider = provider;
86 * Adds new policy status to a notification.
88 * @param notif notification to which to add policy status
90 protected void addNotifications(PolicyNotification notif) {
91 var newTracker = new DeploymentTracker();
92 recordMap.values().forEach(newTracker::add);
94 tracker.addNotifications(notif, newTracker);
100 * Loads policy deployment status associated with the given PDP group.
102 * @param pdpGroup group whose records are to be loaded
103 * @throws PfModelException if an error occurs
105 public void loadByGroup(String pdpGroup) throws PfModelException {
106 if (pdpGroupLoaded.contains(pdpGroup)) {
110 pdpGroupLoaded.add(pdpGroup);
112 for (PdpPolicyStatus status : provider.getGroupPolicyStatus(pdpGroup)) {
113 var status2 = new StatusAction(Action.UNCHANGED, status);
114 recordMap.put(new StatusKey(status), status2);
115 tracker.add(status2);
120 * Flushes changes to the DB, adding policy status to the notification.
122 * @param notif notification to which to add policy status
124 public void flush(PolicyNotification notif) {
125 // must add notifications BEFORE deleting undeployments
126 addNotifications(notif);
127 deleteUndeployments();
132 * Flushes changes to the DB.
134 protected void flush() {
135 // categorize the records
136 List<PdpPolicyStatus> created = new ArrayList<>();
137 List<PdpPolicyStatus> updated = new ArrayList<>();
138 List<PdpPolicyStatus> deleted = new ArrayList<>();
140 for (StatusAction status : recordMap.values()) {
141 switch (status.getAction()) {
143 created.add(status.getStatus());
146 updated.add(status.getStatus());
149 deleted.add(status.getStatus());
156 provider.cudPolicyStatus(created, updated, deleted);
159 * update the records to indicate everything is now unchanged (i.e., matches what
163 Iterator<StatusAction> iter = recordMap.values().iterator();
164 while (iter.hasNext()) {
165 StatusAction status = iter.next();
167 if (status.getAction() == Action.DELETED) {
170 status.setAction(Action.UNCHANGED);
176 * Deletes records for any policies that have been completely undeployed.
178 protected void deleteUndeployments() {
179 // identify the incomplete policies
182 Set<ToscaConceptIdentifier> incomplete = recordMap.values().stream()
183 .filter(status -> status.getAction() != Action.DELETED)
184 .map(StatusAction::getStatus)
185 .filter(status -> status.getState() == State.WAITING)
186 .map(PdpPolicyStatus::getPolicy)
187 .collect(Collectors.toSet());
190 // delete if UNDEPLOYED and not incomplete
191 deleteDeployment((key, status) -> !status.getStatus().isDeploy() && !incomplete.contains(key.getPolicy()));
195 * Delete deployment records for a PDP.
197 * @param pdpId PDP whose records are to be deleted
199 public void deleteDeployment(String pdpId) {
200 deleteDeployment((key, status) -> key.getPdpId().equals(pdpId));
204 * Delete deployment records for a policy.
206 * @param policy policy whose records are to be deleted
207 * @param deploy {@code true} to delete deployment records, {@code false} to delete
208 * undeployment records
210 public void deleteDeployment(ToscaConceptIdentifier policy, boolean deploy) {
211 deleteDeployment((key, status) -> status.getStatus().isDeploy() == deploy && key.getPolicy().equals(policy));
215 * Delete deployment records for a policy.
217 * @param filter filter to identify records to be deleted
219 private void deleteDeployment(BiPredicate<StatusKey, StatusAction> filter) {
220 Iterator<Entry<StatusKey, StatusAction>> iter = recordMap.entrySet().iterator();
221 while (iter.hasNext()) {
222 Entry<StatusKey, StatusAction> entry = iter.next();
223 StatusKey key = entry.getKey();
224 StatusAction value = entry.getValue();
226 if (filter.test(key, value)) {
227 if (value.getAction() == Action.CREATED) {
228 // it's a new record - just remove it
231 // it's an existing record - mark it for deletion
232 value.setAction(Action.DELETED);
239 * Deploys/undeploys a policy to a PDP. Assumes that
240 * {@link #deleteDeployment(ToscaConceptIdentifier, boolean)} has already been invoked
241 * to delete any records having the wrong "deploy" value.
243 * @param pdpId PDP to which the policy is to be deployed
244 * @param policy policy to be deployed
245 * @param policyType policy's type
246 * @param pdpGroup PdpGroup containing the PDP of interest
247 * @param pdpType PDP type (i.e., PdpSubGroup) containing the PDP of interest
248 * @param deploy {@code true} if the policy is being deployed, {@code false} if
251 public void deploy(String pdpId, ToscaConceptIdentifier policy, ToscaConceptIdentifier policyType, String pdpGroup,
252 String pdpType, boolean deploy) {
254 recordMap.compute(new StatusKey(pdpId, policy), (key, status) -> {
256 if (status == null) {
257 // no record yet - create one
260 return new StatusAction(Action.CREATED, PdpPolicyStatus.builder()
265 .policyType(policyType)
267 .state(State.WAITING)
272 PdpPolicyStatus status2 = status.getStatus();
274 // record already exists - see if the deployment flag should be changed
276 if (status2.isDeploy() != deploy) {
277 // deployment flag has changed
279 status2.setDeploy(deploy);
280 status2.setState(State.WAITING);
283 } else if (status.getAction() == Action.DELETED) {
284 // deployment flag is unchanged
285 status.setAction(Action.UPDATED);
293 * Indicates the deployment/undeployment of a set of policies to a PDP has completed.
295 * @param pdpId PDP of interest
296 * @param expectedPolicies policies that we expected to be deployed to the PDP
297 * @param actualPolicies policies that were actually deployed to the PDP
299 public void completeDeploy(String pdpId, Set<ToscaConceptIdentifier> expectedPolicies,
300 Set<ToscaConceptIdentifier> actualPolicies) {
302 for (StatusAction status : recordMap.values()) {
303 PdpPolicyStatus status2 = status.getStatus();
305 if (!status.getStatus().getPdpId().equals(pdpId)
306 || expectedPolicies.contains(status2.getPolicy()) != status2.isDeploy()) {
308 * The policy is "expected" to be deployed, but the record is not marked
309 * for deployment (or vice versa), which means the expected policy is out
310 * of date with the DB, thus we'll ignore this policy for now.
316 if (actualPolicies.contains(status2.getPolicy())) {
317 state = (status.getStatus().isDeploy() ? State.SUCCESS : State.FAILURE);
319 state = (status.getStatus().isDeploy() ? State.FAILURE : State.SUCCESS);
322 if (status2.getState() != state) {
324 status2.setState(state);