re base code
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / distribution / engine / DistributionEngine.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 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  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.be.components.distribution.engine;
22
23 import java.io.File;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Optional;
29 import java.util.concurrent.atomic.AtomicBoolean;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32
33 import javax.annotation.PostConstruct;
34 import javax.annotation.PreDestroy;
35 import javax.annotation.Resource;
36
37 import org.apache.commons.collections.CollectionUtils;
38 import org.apache.commons.lang3.StringUtils;
39 import org.openecomp.sdc.be.components.validation.ServiceDistributionValidation;
40 import org.openecomp.sdc.be.config.BeEcompErrorManager;
41 import org.openecomp.sdc.be.config.ConfigurationManager;
42 import org.openecomp.sdc.be.config.DistributionEngineConfiguration;
43 import org.openecomp.sdc.be.dao.api.ActionStatus;
44 import org.openecomp.sdc.be.model.Service;
45 import org.openecomp.sdc.be.model.User;
46 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
47 import org.openecomp.sdc.be.resources.data.OperationalEnvironmentEntry;
48 import org.openecomp.sdc.common.util.YamlToObjectConverter;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51 import org.springframework.beans.factory.annotation.Autowired;
52 import org.springframework.stereotype.Component;
53
54 @Component("distributionEngine")
55 public class DistributionEngine implements IDistributionEngine {
56
57     private static final Logger LOGGER = LoggerFactory.getLogger(DistributionEngine.class);
58     private static final Pattern FQDN_PATTERN = Pattern.compile("^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])(\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]))*(:[0-9]{2,4})*$", Pattern.CASE_INSENSITIVE);
59
60     @Autowired
61     private EnvironmentsEngine environmentsEngine;
62
63     @Resource
64     private DistributionNotificationSender distributionNotificationSender;
65
66     @Resource
67     private ServiceDistributionArtifactsBuilder serviceDistributionArtifactsBuilder;
68
69     @Resource
70     private DistributionEngineClusterHealth distributionEngineClusterHealth;
71
72     @Resource
73     private ServiceDistributionValidation serviceDistributionValidation;
74
75     private Map<String, DistributionEngineInitTask> envNamePerInitTask = new HashMap<>();
76     private Map<String, DistributionEnginePollingTask> envNamePerPollingTask = new HashMap<>();
77     private Map<String, AtomicBoolean> envNamePerStatus = new HashMap<>();
78
79     @Override
80     public boolean isActive() {
81
82         if (envNamePerInitTask.isEmpty()) {
83             return false;
84         }
85
86         for (DistributionEngineInitTask task : envNamePerInitTask.values()) {
87             boolean active = task.isActive();
88             if (!active) {
89                 return false;
90             }
91         }
92         return true;
93     }
94
95     @PostConstruct
96     private void init() {
97
98         LOGGER.trace("Enter init method of DistributionEngine");
99
100         DistributionEngineConfiguration distributionEngineConfiguration = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration();
101
102         boolean startDistributionEngine = distributionEngineConfiguration.isStartDistributionEngine();
103         LOGGER.debug("Distribution engine activation parameter is {}", startDistributionEngine);
104         if (!startDistributionEngine) {
105             LOGGER.info("The disribution engine is disabled");
106
107             this.distributionEngineClusterHealth.setHealthCheckUebIsDisabled();
108
109             return;
110         }
111
112         boolean isValidConfig = validateConfiguration(distributionEngineConfiguration);
113
114         if (!isValidConfig) {
115             BeEcompErrorManager.getInstance().logBeUebSystemError(DistributionEngineInitTask.INIT_DISTRIBUTION_ENGINE_FLOW, "validate distribution configuration in init phase");
116
117             this.distributionEngineClusterHealth.setHealthCheckUebConfigurationError();
118             return;
119         }
120
121         List<String> environments = distributionEngineConfiguration.getEnvironments();
122
123         for (String envName : environments) {
124             LOGGER.debug("init task for environment {}", envName);
125             AtomicBoolean status = new AtomicBoolean(false);
126             envNamePerStatus.put(envName, status);
127             environmentsEngine.connectUebTopicForDistributionConfTopic(envName, status, envNamePerInitTask, envNamePerPollingTask);
128         }
129
130         LOGGER.debug("init UEB health check");
131         distributionEngineClusterHealth.startHealthCheckTask(envNamePerStatus);
132
133         LOGGER.trace("Exit init method of DistributionEngine");
134
135     }
136
137     @PreDestroy
138     public void shutdown() {
139         LOGGER.info("distribution engine shutdown - start");
140         if (envNamePerInitTask != null) {
141             for (DistributionEngineInitTask task : envNamePerInitTask.values()) {
142                 task.destroy();
143             }
144         }
145         if (envNamePerPollingTask != null) {
146             for (DistributionEnginePollingTask task : envNamePerPollingTask.values()) {
147                 task.destroy();
148             }
149         }
150
151     }
152
153     /**
154      * validate mandatory configuration parameters received
155      *
156      * @param deConfiguration
157      * @return
158      */
159     protected boolean validateConfiguration(DistributionEngineConfiguration deConfiguration) {
160
161         String methodName = "validateConfiguration";
162
163         boolean result = true;
164         result = isValidServers(deConfiguration.getUebServers(), methodName, "uebServers") && result;
165         result = isValidParam(deConfiguration.getEnvironments(), methodName, "environments") && result;
166         result = isValidParam(deConfiguration.getUebPublicKey(), methodName, "uebPublicKey") && result;
167         result = isValidParam(deConfiguration.getUebSecretKey(), methodName, "uebSecretKey") && result;
168         result = isValidParam(deConfiguration.getDistributionNotifTopicName(), methodName, "distributionNotifTopicName") && result;
169         result = isValidParam(deConfiguration.getDistributionStatusTopicName(), methodName, "distributionStatusTopicName") && result;
170         result = isValidObject(deConfiguration.getCreateTopic(), methodName, "createTopic") && result;
171         result = isValidObject(deConfiguration.getDistributionStatusTopic(), methodName, "distributionStatusTopic") && result;
172         result = isValidObject(deConfiguration.getInitMaxIntervalSec(), methodName, "initMaxIntervalSec") && result;
173         result = isValidObject(deConfiguration.getInitRetryIntervalSec(), methodName, "initRetryIntervalSec") && result;
174         result = isValidParam(deConfiguration.getDistributionStatusTopic().getConsumerId(), methodName, "consumerId") && result;
175         result = isValidParam(deConfiguration.getDistributionStatusTopic().getConsumerGroup(), methodName, "consumerGroup") && result;
176         result = isValidObject(deConfiguration.getDistributionStatusTopic().getFetchTimeSec(), methodName, "fetchTimeSec") && result;
177         result = isValidObject(deConfiguration.getDistributionStatusTopic().getPollingIntervalSec(), methodName, "pollingIntervalSec") && result;
178
179         return result;
180     }
181
182     private boolean isValidServers(List<String> uebServers, String methodName, String paramName) {
183
184         if (uebServers == null || uebServers.isEmpty()) {
185             BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName);
186             return false;
187         }
188
189         if (uebServers.size() < 2) {
190             BeEcompErrorManager.getInstance().logBeConfigurationInvalidListSizeError(methodName, paramName, 2);
191             return false;
192         }
193
194         for (String serverFqdn : uebServers) {
195             if (!isValidFqdn(serverFqdn)) {
196                 BeEcompErrorManager.getInstance().logBeInvalidConfigurationError(methodName, paramName, serverFqdn);
197                 return false;
198             }
199         }
200
201         return true;
202     }
203
204     private boolean isValidFqdn(String serverFqdn) {
205
206         try {
207             Matcher matcher = FQDN_PATTERN.matcher(serverFqdn);
208             return matcher.matches();
209
210         } catch (Exception e) {
211             LOGGER.debug("Failed to match value of address {}", serverFqdn, e);
212             return false;
213         }
214     }
215
216     private boolean isValidParam(String paramValue, String methodName, String paramName) {
217
218         if (StringUtils.isEmpty(paramValue)) {
219             BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName);
220             return false;
221         }
222         return true;
223     }
224
225     private boolean isValidParam(List<String> paramValue, String methodName, String paramName) {
226
227         if (CollectionUtils.isEmpty(paramValue)) {
228             BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName);
229             return false;
230         }
231         return true;
232     }
233
234     private boolean isValidObject(Object paramValue, String methodName, String paramName) {
235
236         if (paramValue == null) {
237             BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName);
238             return false;
239         }
240         return true;
241
242     }
243
244     private String getEnvironmentErrorDescription(StorageOperationStatus status) {
245
246         switch (status) {
247         case DISTR_ENVIRONMENT_NOT_AVAILABLE:
248             return "environment is unavailable";
249         case DISTR_ENVIRONMENT_NOT_FOUND:
250             return "environment is not configured in our system";
251         case DISTR_ENVIRONMENT_SENT_IS_INVALID:
252             return "environment name is invalid";
253         default:
254             return "unkhown";
255         }
256     }
257
258     @Override
259     public StorageOperationStatus isEnvironmentAvailable(String envName) {
260
261         if (envName == null || envName.isEmpty()) {
262
263             return StorageOperationStatus.DISTR_ENVIRONMENT_SENT_IS_INVALID;
264         }
265
266         AtomicBoolean status = envNamePerStatus.get(envName);
267         if (status == null) {
268             return StorageOperationStatus.DISTR_ENVIRONMENT_NOT_FOUND;
269         }
270
271         if (!status.get()) {
272             return StorageOperationStatus.DISTR_ENVIRONMENT_NOT_AVAILABLE;
273         }
274         return StorageOperationStatus.OK;
275     }
276
277     @Override
278     public StorageOperationStatus isEnvironmentAvailable() {
279
280         String envName = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration().getEnvironments().get(0);
281
282         return isEnvironmentAvailable(envName);
283     }
284
285     @Override
286     public void disableEnvironment(String envName) {
287         AtomicBoolean status = envNamePerStatus.get(envName);
288         status.set(false);
289     }
290
291     @Override
292     public ActionStatus notifyService(String distributionId, Service service, INotificationData notificationData, String envName, User modifier) {
293         return notifyService(distributionId, service, notificationData, envName, envName, modifier);
294     }
295     @Override
296     public ActionStatus notifyService(String distributionId, Service service, INotificationData notificationData, String envId, String envName,  User modifier) {
297         LOGGER.debug("Received notify service request. distributionId = {}, serviceUuid = {} serviceUid = {}, envName = {}, modifier {}", distributionId, service.getUUID(), service.getUniqueId(), envName,  modifier);
298         String topicName = buildTopicName(envName);
299         ActionStatus notifyServiceStatus = Optional.ofNullable(environmentsEngine.getEnvironmentById(envId))
300                 .map(EnvironmentMessageBusData::new)
301                 .map(messageBusData -> distributionNotificationSender.sendNotification(topicName, distributionId, messageBusData, notificationData, service, modifier))
302                 .orElse(ActionStatus.DISTRIBUTION_ENVIRONMENT_NOT_AVAILABLE);
303         LOGGER.debug("Finish notifyService. status is {}", notifyServiceStatus);
304         return notifyServiceStatus;
305     }
306
307     private String buildTopicName(String envName) {
308         DistributionEngineConfiguration deConfiguration = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration();
309         String distributionNotifTopicName = deConfiguration.getDistributionNotifTopicName();
310         return DistributionEngineInitTask.buildTopicName(distributionNotifTopicName, envName);
311     }
312
313     @Override
314     public StorageOperationStatus isReadyForDistribution(String envName) {
315         StorageOperationStatus status = isEnvironmentAvailable(envName);
316         if (status != StorageOperationStatus.OK) {
317             String envErrorDec = getEnvironmentErrorDescription(status);
318             BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(DistributionNotificationSender.DISTRIBUTION_NOTIFICATION_SENDING, "Environment name " + envName + " is not available. Reason : " + envErrorDec);
319         }
320         return status;
321     }
322
323     @Override
324     public OperationalEnvironmentEntry getEnvironmentById(String opEnvId) {
325         return environmentsEngine.getEnvironmentById(opEnvId);
326     }
327
328     @Override
329     public INotificationData buildServiceForDistribution(Service service, String distributionId, String workloadContext) {
330         INotificationData value = serviceDistributionArtifactsBuilder.buildResourceInstanceForDistribution(service, distributionId, workloadContext);
331         value = serviceDistributionArtifactsBuilder.buildServiceForDistribution(value, service);
332         return value;
333     }
334
335 }