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