bug fix
[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.operations.api.StorageOperationStatus;
46 import org.openecomp.sdc.be.resources.data.OperationalEnvironmentEntry;
47 import org.openecomp.sdc.common.util.YamlToObjectConverter;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50 import org.springframework.beans.factory.annotation.Autowired;
51 import org.springframework.stereotype.Component;
52
53 @Component("distributionEngine")
54 public class DistributionEngine implements IDistributionEngine {
55
56     private static final Logger LOGGER = LoggerFactory.getLogger(DistributionEngine.class);
57     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);
58
59     @Autowired
60     private EnvironmentsEngine environmentsEngine;
61
62     @Resource
63     private DistributionNotificationSender distributionNotificationSender;
64
65     @Resource
66     private ServiceDistributionArtifactsBuilder serviceDistributionArtifactsBuilder;
67
68     @Resource
69     private DistributionEngineClusterHealth distributionEngineClusterHealth;
70
71     @Resource
72     private ServiceDistributionValidation serviceDistributionValidation;
73
74     private Map<String, DistributionEngineInitTask> envNamePerInitTask = new HashMap<>();
75     private Map<String, DistributionEnginePollingTask> envNamePerPollingTask = new HashMap<>();
76     private Map<String, AtomicBoolean> envNamePerStatus = new HashMap<>();
77
78     @Override
79     public boolean isActive() {
80
81         if (envNamePerInitTask.isEmpty()) {
82             return false;
83         }
84
85         for (DistributionEngineInitTask task : envNamePerInitTask.values()) {
86             boolean active = task.isActive();
87             if (!active) {
88                 return false;
89             }
90         }
91         return true;
92     }
93
94     @PostConstruct
95     private void init() {
96
97         LOGGER.trace("Enter init method of DistributionEngine");
98
99         DistributionEngineConfiguration distributionEngineConfiguration = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration();
100
101         boolean startDistributionEngine = distributionEngineConfiguration.isStartDistributionEngine();
102         LOGGER.debug("Distribution engine activation parameter is {}", startDistributionEngine);
103         if (!startDistributionEngine) {
104             LOGGER.info("The disribution engine is disabled");
105
106             this.distributionEngineClusterHealth.setHealthCheckUebIsDisabled();
107
108             return;
109         }
110
111         boolean isValidConfig = validateConfiguration(distributionEngineConfiguration);
112
113         if (!isValidConfig) {
114             BeEcompErrorManager.getInstance().logBeUebSystemError(DistributionEngineInitTask.INIT_DISTRIBUTION_ENGINE_FLOW, "validate distribution configuration in init phase");
115
116             this.distributionEngineClusterHealth.setHealthCheckUebConfigurationError();
117             return;
118         }
119
120         List<String> environments = distributionEngineConfiguration.getEnvironments();
121
122         for (String envName : environments) {
123             LOGGER.debug("init task for environment {}", envName);
124             AtomicBoolean status = new AtomicBoolean(false);
125             envNamePerStatus.put(envName, status);
126             environmentsEngine.connectUebTopicForDistributionConfTopic(envName, status, envNamePerInitTask, envNamePerPollingTask);
127         }
128
129         LOGGER.debug("init UEB health check");
130         distributionEngineClusterHealth.startHealthCheckTask(envNamePerStatus);
131
132         LOGGER.trace("Exit init method of DistributionEngine");
133
134     }
135
136     @PreDestroy
137     public void shutdown() {
138         LOGGER.info("distribution engine shutdown - start");
139         if (envNamePerInitTask != null) {
140             for (DistributionEngineInitTask task : envNamePerInitTask.values()) {
141                 task.destroy();
142             }
143         }
144         if (envNamePerPollingTask != null) {
145             for (DistributionEnginePollingTask task : envNamePerPollingTask.values()) {
146                 task.destroy();
147             }
148         }
149
150     }
151
152     /**
153      * validate mandatory configuration parameters received
154      *
155      * @param deConfiguration
156      * @return
157      */
158     protected boolean validateConfiguration(DistributionEngineConfiguration deConfiguration) {
159
160         String methodName = "validateConfiguration";
161
162         boolean result = true;
163         result = isValidServers(deConfiguration.getUebServers(), methodName, "uebServers") && result;
164         result = isValidParam(deConfiguration.getEnvironments(), methodName, "environments") && result;
165         result = isValidParam(deConfiguration.getUebPublicKey(), methodName, "uebPublicKey") && result;
166         result = isValidParam(deConfiguration.getUebSecretKey(), methodName, "uebSecretKey") && result;
167         result = isValidParam(deConfiguration.getDistributionNotifTopicName(), methodName, "distributionNotifTopicName") && result;
168         result = isValidParam(deConfiguration.getDistributionStatusTopicName(), methodName, "distributionStatusTopicName") && result;
169         result = isValidObject(deConfiguration.getCreateTopic(), methodName, "createTopic") && result;
170         result = isValidObject(deConfiguration.getDistributionStatusTopic(), methodName, "distributionStatusTopic") && result;
171         result = isValidObject(deConfiguration.getInitMaxIntervalSec(), methodName, "initMaxIntervalSec") && result;
172         result = isValidObject(deConfiguration.getInitRetryIntervalSec(), methodName, "initRetryIntervalSec") && result;
173         result = isValidParam(deConfiguration.getDistributionStatusTopic().getConsumerId(), methodName, "consumerId") && result;
174         result = isValidParam(deConfiguration.getDistributionStatusTopic().getConsumerGroup(), methodName, "consumerGroup") && result;
175         result = isValidObject(deConfiguration.getDistributionStatusTopic().getFetchTimeSec(), methodName, "fetchTimeSec") && result;
176         result = isValidObject(deConfiguration.getDistributionStatusTopic().getPollingIntervalSec(), methodName, "pollingIntervalSec") && result;
177
178         return result;
179     }
180
181     private boolean isValidServers(List<String> uebServers, String methodName, String paramName) {
182
183         if (uebServers == null || uebServers.isEmpty()) {
184             BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName);
185             return false;
186         }
187
188         if (uebServers.size() < 2) {
189             BeEcompErrorManager.getInstance().logBeConfigurationInvalidListSizeError(methodName, paramName, 2);
190             return false;
191         }
192
193         for (String serverFqdn : uebServers) {
194             if (!isValidFqdn(serverFqdn)) {
195                 BeEcompErrorManager.getInstance().logBeInvalidConfigurationError(methodName, paramName, serverFqdn);
196                 return false;
197             }
198         }
199
200         return true;
201     }
202
203     private boolean isValidFqdn(String serverFqdn) {
204
205         try {
206             Matcher matcher = FQDN_PATTERN.matcher(serverFqdn);
207             return matcher.matches();
208
209         } catch (Exception e) {
210             LOGGER.debug("Failed to match value of address {}", serverFqdn, e);
211             return false;
212         }
213     }
214
215     private boolean isValidParam(String paramValue, String methodName, String paramName) {
216
217         if (StringUtils.isEmpty(paramValue)) {
218             BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName);
219             return false;
220         }
221         return true;
222     }
223
224     private boolean isValidParam(List<String> paramValue, String methodName, String paramName) {
225
226         if (CollectionUtils.isEmpty(paramValue)) {
227             BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName);
228             return false;
229         }
230         return true;
231     }
232
233     private boolean isValidObject(Object paramValue, String methodName, String paramName) {
234
235         if (paramValue == null) {
236             BeEcompErrorManager.getInstance().logBeMissingConfigurationError(methodName, paramName);
237             return false;
238         }
239         return true;
240
241     }
242
243     private String getEnvironmentErrorDescription(StorageOperationStatus status) {
244
245         switch (status) {
246         case DISTR_ENVIRONMENT_NOT_AVAILABLE:
247             return "environment is unavailable";
248         case DISTR_ENVIRONMENT_NOT_FOUND:
249             return "environment is not configured in our system";
250         case DISTR_ENVIRONMENT_SENT_IS_INVALID:
251             return "environment name is invalid";
252         default:
253             return "unkhown";
254         }
255     }
256
257     @Override
258     public StorageOperationStatus isEnvironmentAvailable(String envName) {
259
260         if (envName == null || envName.isEmpty()) {
261
262             return StorageOperationStatus.DISTR_ENVIRONMENT_SENT_IS_INVALID;
263         }
264
265         AtomicBoolean status = envNamePerStatus.get(envName);
266         if (status == null) {
267             return StorageOperationStatus.DISTR_ENVIRONMENT_NOT_FOUND;
268         }
269
270         if (!status.get()) {
271             return StorageOperationStatus.DISTR_ENVIRONMENT_NOT_AVAILABLE;
272         }
273         return StorageOperationStatus.OK;
274     }
275
276     @Override
277     public StorageOperationStatus isEnvironmentAvailable() {
278
279         String envName = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration().getEnvironments().get(0);
280
281         return isEnvironmentAvailable(envName);
282     }
283
284     @Override
285     public void disableEnvironment(String envName) {
286         AtomicBoolean status = envNamePerStatus.get(envName);
287         status.set(false);
288     }
289
290     @Override
291     public ActionStatus notifyService(String distributionId, Service service, INotificationData notificationData, String envName, String userId, String modifierName) {
292         return notifyService(distributionId, service, notificationData, envName, envName, userId, modifierName);
293     }
294
295     @Override
296     public ActionStatus notifyService(String distributionId, Service service, INotificationData notificationData, String envId, String envName, String userId, String modifierName) {
297         LOGGER.debug("Received notify service request. distributionId = {}, serviceUuid = {} serviceUid = {}, envName = {}, userId = {}, modifierName {}", distributionId, service.getUUID(), service.getUniqueId(), envName, userId, modifierName);
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, userId, modifierName))
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(Service service, 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             return status;
320         }
321
322         return verifyServiceHasDeploymentArtifacts(service);
323     }
324
325     @Override
326     public StorageOperationStatus verifyServiceHasDeploymentArtifacts(Service service) {
327          if (!serviceDistributionArtifactsBuilder.verifyServiceContainsDeploymentArtifacts(service)) {
328              return StorageOperationStatus.DISTR_ARTIFACT_NOT_FOUND;
329          }
330         return StorageOperationStatus.OK;
331     }
332
333     @Override
334     public OperationalEnvironmentEntry getEnvironmentById(String opEnvId) {
335         return environmentsEngine.getEnvironmentById(opEnvId);
336     }
337
338     @Override
339     public INotificationData buildServiceForDistribution(Service service, String distributionId, String workloadContext) {
340         INotificationData value = serviceDistributionArtifactsBuilder.buildResourceInstanceForDistribution(service, distributionId, workloadContext);
341         value = serviceDistributionArtifactsBuilder.buildServiceForDistribution(value, service);
342         return value;
343     }
344
345 }