Add DME Participant
[nonrtric/plt/rappmanager.git] / participants / participant-impl-dme / src / main / java / org / oransc / participant / dme / handler / AutomationCompositionElementHandler.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2023 Nordix Foundation.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.oransc.participant.dme.handler;
22
23 import com.fasterxml.jackson.core.JsonProcessingException;
24 import jakarta.validation.Validation;
25 import jakarta.validation.ValidationException;
26 import java.lang.invoke.MethodHandles;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.UUID;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.stream.Collectors;
32 import lombok.AccessLevel;
33 import lombok.Getter;
34 import lombok.RequiredArgsConstructor;
35 import org.apache.http.HttpStatus;
36 import org.onap.policy.clamp.acm.participant.intermediary.api.AutomationCompositionElementListener;
37 import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
38 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
39 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
40 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
41 import org.onap.policy.clamp.models.acm.concepts.DeployState;
42 import org.onap.policy.clamp.models.acm.concepts.LockState;
43 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
44 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
45 import org.onap.policy.common.utils.coder.Coder;
46 import org.onap.policy.common.utils.coder.CoderException;
47 import org.onap.policy.common.utils.coder.StandardCoder;
48 import org.onap.policy.models.base.PfModelException;
49 import org.oransc.participant.dme.exception.DmeException;
50 import org.oransc.participant.dme.models.ConfigurationEntity;
51 import org.oransc.participant.dme.models.DataConsumerEntity;
52 import org.oransc.participant.dme.models.DataProducerEntity;
53 import org.oransc.participant.dme.models.InfoTypeEntity;
54 import org.oransc.participant.dme.restclient.AcDmeClient;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57 import org.springframework.stereotype.Component;
58
59 @Component
60 @RequiredArgsConstructor
61 public class AutomationCompositionElementHandler implements AutomationCompositionElementListener {
62
63     private static final Coder CODER = new StandardCoder();
64
65     private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
66
67     private final ParticipantIntermediaryApi intermediaryApi;
68
69     private final AcDmeClient acDmeClient;
70
71     // Map of acElement Id and DME services
72     @Getter(AccessLevel.PACKAGE)
73     private final Map<UUID, ConfigurationEntity> configRequestMap = new ConcurrentHashMap<>();
74
75     @Override
76     public void undeploy(UUID automationCompositionId, UUID automationCompositionElementId) throws DmeException {
77         var configurationEntity = configRequestMap.get(automationCompositionElementId);
78         if (configurationEntity != null && acDmeClient.isDmeHealthy()) {
79             if (configurationEntity.getDataConsumerEntities() != null) {
80                 acDmeClient.deleteDataConsumer(configurationEntity.getDataConsumerEntities().stream()
81                                                        .map(DataConsumerEntity::getDataConsumerId)
82                                                        .collect(Collectors.toSet()));
83             }
84             if (configurationEntity.getDataProducerEntities() != null) {
85                 acDmeClient.deleteDataProducer(configurationEntity.getDataProducerEntities().stream()
86                                                        .map(DataProducerEntity::getDataProducerId)
87                                                        .collect(Collectors.toSet()));
88             }
89             configRequestMap.remove(automationCompositionElementId);
90             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
91                     automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR,
92                     "Undeployed");
93         } else {
94             LOGGER.warn("Failed to connect with DME. Service configuration is: {}", configurationEntity);
95             throw new DmeException(HttpStatus.SC_SERVICE_UNAVAILABLE, "Unable to connect with DME");
96         }
97     }
98
99     @Override
100     public void deploy(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
101             throws DmeException {
102         try {
103             var configurationEntity = CODER.convert(properties, ConfigurationEntity.class);
104             var violations = Validation.buildDefaultValidatorFactory().getValidator().validate(configurationEntity);
105             if (violations.isEmpty()) {
106                 if ((configurationEntity.getInfoTypeEntities() != null
107                              || configurationEntity.getDataProducerEntities() != null
108                              || configurationEntity.getDataConsumerEntities() != null) && acDmeClient.isDmeHealthy()) {
109                     if (configurationEntity.getInfoTypeEntities() != null) {
110                         acDmeClient.createInfoType(configurationEntity.getInfoTypeEntities().stream().collect(
111                                 Collectors.toMap(InfoTypeEntity::getInfoTypeId, InfoTypeEntity::getPayload)));
112                     }
113                     if (configurationEntity.getDataProducerEntities() != null) {
114                         acDmeClient.createDataProducer(configurationEntity.getDataProducerEntities().stream().collect(
115                                 Collectors.toMap(DataProducerEntity::getDataProducerId,
116                                         DataProducerEntity::getPayload)));
117                     }
118                     if (configurationEntity.getDataConsumerEntities() != null) {
119                         acDmeClient.createDataConsumer(configurationEntity.getDataConsumerEntities().stream().collect(
120                                 Collectors.toMap(DataConsumerEntity::getDataConsumerId,
121                                         DataConsumerEntity::getPayload)));
122                     }
123
124                     configRequestMap.put(element.getId(), configurationEntity);
125                     intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
126                             DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
127                 } else {
128                     intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
129                             DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Unable to connect with DME ");
130                     throw new DmeException(HttpStatus.SC_SERVICE_UNAVAILABLE, "Unable to connect with DME");
131                 }
132             } else {
133                 LOGGER.error("Violations found in the config request parameters: {}", violations);
134                 throw new ValidationException("Constraint violations in the config request");
135             }
136         } catch (JsonProcessingException | ValidationException | CoderException | DmeException e) {
137             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
138                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, e.getMessage());
139             throw new DmeException(HttpStatus.SC_BAD_REQUEST, "Invalid Configuration", e);
140         }
141     }
142
143     @Override
144     public void lock(UUID instanceId, UUID elementId) {
145         intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, null, LockState.LOCKED,
146                 StateChangeResult.NO_ERROR, "Locked");
147     }
148
149     @Override
150     public void unlock(UUID instanceId, UUID elementId) {
151         intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, null, LockState.UNLOCKED,
152                 StateChangeResult.NO_ERROR, "Unlocked");
153     }
154
155     @Override
156     public void delete(UUID instanceId, UUID elementId) {
157         intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, DeployState.DELETED, null,
158                 StateChangeResult.NO_ERROR, "Deleted");
159     }
160
161     @Override
162     public void update(UUID instanceId, AcElementDeploy element, Map<String, Object> properties) {
163         intermediaryApi.updateAutomationCompositionElementState(instanceId, element.getId(), DeployState.DEPLOYED, null,
164                 StateChangeResult.NO_ERROR, "Update not supported");
165     }
166
167     @Override
168     public void prime(UUID compositionId, List<AutomationCompositionElementDefinition> elementDefinitionList) {
169         intermediaryApi.updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.NO_ERROR, "Primed");
170     }
171
172     @Override
173     public void deprime(UUID compositionId) {
174         intermediaryApi.updateCompositionState(compositionId, AcTypeState.COMMISSIONED, StateChangeResult.NO_ERROR,
175                 "Deprimed");
176     }
177
178     @Override
179     public void handleRestartComposition(UUID compositionId,
180             List<AutomationCompositionElementDefinition> elementDefinitionList, AcTypeState state) {
181         var finalState = AcTypeState.PRIMED.equals(state) || AcTypeState.PRIMING.equals(state) ? AcTypeState.PRIMED
182                                  : AcTypeState.COMMISSIONED;
183         intermediaryApi.updateCompositionState(compositionId, finalState, StateChangeResult.NO_ERROR, "Restarted");
184     }
185
186     @Override
187     public void handleRestartInstance(UUID automationCompositionId, AcElementDeploy element,
188             Map<String, Object> properties, DeployState deployState, LockState lockState) throws PfModelException {
189         if (DeployState.DEPLOYING.equals(deployState)) {
190             deploy(automationCompositionId, element, properties);
191             return;
192         }
193         if (DeployState.UNDEPLOYING.equals(deployState) || DeployState.DEPLOYED.equals(deployState)
194                     || DeployState.UPDATING.equals(deployState)) {
195             try {
196                 var configurationEntity = CODER.convert(properties, ConfigurationEntity.class);
197                 configRequestMap.put(element.getId(), configurationEntity);
198             } catch (ValidationException | CoderException e) {
199                 throw new DmeException(HttpStatus.SC_BAD_REQUEST, "Invalid Configuration", e);
200             }
201         }
202         if (DeployState.UNDEPLOYING.equals(deployState)) {
203             undeploy(automationCompositionId, element.getId());
204             return;
205         }
206         deployState = AcmUtils.deployCompleted(deployState);
207         lockState = AcmUtils.lockCompleted(deployState, lockState);
208         intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(), deployState,
209                 lockState, StateChangeResult.NO_ERROR, "Restarted");
210     }
211
212     @Override
213     public void migrate(UUID automationCompositionId, AcElementDeploy element, UUID compositionTargetId,
214             Map<String, Object> properties) {
215         intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
216                 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
217     }
218 }