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