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