Add health check to vLBMS
[demo.git] / vnfs / vLBMS / apis / health-vnf-onap-plugin / health-vnf-onap-plugin-impl / src / main / java / org / onap / vnf / health / read / ElementStateCustomizer.java
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17  /*
18  * Modifications copyright (c) 2018 AT&T Intellectual Property
19  */
20
21 package org.onap.vnf.health.read;
22
23 import org.onap.vnf.health.CrudService;
24 import org.onap.vnf.health.RESTManager;
25 import org.onap.vnf.health.RESTManager.Pair;
26
27 import io.fd.honeycomb.translate.read.ReadContext;
28 import io.fd.honeycomb.translate.read.ReadFailedException;
29 import io.fd.honeycomb.translate.spi.read.Initialized;
30 import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
31
32 import java.io.BufferedReader;
33 import java.io.FileInputStream;
34 import java.io.FileReader;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.text.SimpleDateFormat;
38 import java.util.ArrayList;
39 import java.util.Date;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Properties;
44
45 import javax.annotation.Nonnull;
46
47 import org.onap.vnf.health.CrudService;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.health.vnf.onap.plugin.rev160918.HealthVnfOnapPluginStateBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.health.vnf.onap.plugin.rev160918.health.vnf.onap.plugin.params.HealthCheckBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.health.vnf.onap.plugin.rev160918.health.vnf.onap.plugin.params.health.check.FaultsBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.health.vnf.onap.plugin.rev160918.health.vnf.onap.plugin.params.health.check.faults.Fault;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.health.vnf.onap.plugin.rev160918.health.vnf.onap.plugin.params.health.check.faults.FaultBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.health.vnf.onap.plugin.rev160918.health.vnf.onap.plugin.params.health.check.faults.FaultKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.health.vnf.onap.plugin.rev160918.health.vnf.onap.plugin.params.HealthCheck;
55 import org.opendaylight.yangtools.concepts.Builder;
56 import org.opendaylight.yangtools.yang.binding.DataObject;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62
63 /**
64  * Reader for {@link Element} list node from our YANG model.
65  */
66 public final class ElementStateCustomizer implements InitializingReaderCustomizer<HealthCheck, HealthCheckBuilder> {
67
68     private final CrudService<HealthCheck> crudService;
69     private static final Logger LOG = LoggerFactory.getLogger(ElementStateCustomizer.class);
70     private final String SCRIPT;
71     private final String OUTPUT;
72     private final String VNFC;
73     private final Boolean PRIMARY;
74     private static SimpleDateFormat SDF;
75
76     public ElementStateCustomizer(final CrudService<HealthCheck> crudService) throws IOException {
77         this.crudService = crudService;
78
79         // initialize data format
80         SDF = new SimpleDateFormat("MM-dd-yyyy:HH.mm.ss");
81
82         // read properties from file
83         String path = "/opt/config/properties.conf";
84                 Properties prop = new Properties();
85                 InputStream prop_file = new FileInputStream(path);
86                 prop.load(prop_file);
87                 SCRIPT = prop.getProperty("script");
88                 OUTPUT = prop.getProperty("output");
89                 VNFC = prop.getProperty("vnfc");
90                 PRIMARY = Boolean.parseBoolean(prop.getProperty("primary"));
91         prop_file.close();
92     }
93     
94     @Override
95     public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final HealthCheck readData) {
96         // merge children data to parent builder
97         // used by infrastructure to merge data loaded in separated customizers
98         ((HealthVnfOnapPluginStateBuilder) builder).setHealthCheck(readData);
99     }
100
101     @Nonnull
102     @Override
103     public HealthCheckBuilder getBuilder(@Nonnull final InstanceIdentifier<HealthCheck> id) {
104         // return new builder for this data node
105         return new HealthCheckBuilder();
106     }
107
108     @Override
109     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<HealthCheck> id,
110                                       @Nonnull final HealthCheckBuilder builder,
111                                       @Nonnull final ReadContext ctx) throws ReadFailedException {
112
113         List<String> ipAddr = new ArrayList<String>();
114         if(PRIMARY) {
115                 String ret = readFromFile("/opt/config/oam_vpktgen_ip.txt");
116                 if(ret != null) {
117                         ipAddr.add(ret);
118                 }
119                 ret = readFromFile("/opt/config/oam_vdns_ip.txt");
120                 if(ret != null) {
121                         ipAddr.add(ret);
122                 }
123         }
124
125         // assess the health status of the local service (try at most three times, otherwise return an error).
126         String healthStatus;
127         String [] cmdArgs = {"/bin/bash", "-c", SCRIPT};
128         int ret = -1;
129         int attempts = 0;
130         
131         do {
132                 try {
133                         Process child = Runtime.getRuntime().exec(cmdArgs);
134                         // wait for child process to terminate
135                         ret = child.waitFor();
136                         attempts++;
137                 }
138                 catch (IOException e) {
139                         LOG.error("Command: [" + SCRIPT + "] returned an error.");
140                         e.printStackTrace();
141                 }
142                 catch (InterruptedException e) {
143                         LOG.error("Child process: [" + SCRIPT + "] returned an error. Error code: " + ret);
144                         e.printStackTrace();
145                 }
146         } while(ret != 0 && attempts < 3);
147
148         if(ret == 0) {
149                 healthStatus = readFromFile(OUTPUT);
150                 if(healthStatus == null) {
151                         healthStatus = "unhealthy";
152                 }
153                 LOG.info("Assessing the health status of the local component... Return status = \"" + healthStatus + "\"");
154         }
155         else {
156                 healthStatus = "unhealthy";
157                 LOG.info("Failed to assess the health status of the local component. Return status = \"unhealthy\"");
158         }
159
160         // perform read of details of data specified by key of Element in id
161         // final HealthCheck data = crudService.readSpecific(id);
162
163         // check the status of other VNF components, if any
164         if(PRIMARY) {
165                 for(int i = 0; i < ipAddr.size(); i++) {
166                         if(!getRemoteVnfcHealthStatus(ipAddr.get(i))) {
167                                 healthStatus = "unhealthy";
168                         }
169                 }
170         }
171
172         // and sets it to builder
173         builder.setState(healthStatus);
174         builder.setVnfName(VNFC);
175         builder.setTime(SDF.format(new Date().getTime()));
176
177         if(healthStatus.equals("unhealthy")) {
178                 List<Fault> faultList = new ArrayList<Fault>();
179             // build a FaultBuilder object in case of one or more VNF components are reporting faults
180             FaultBuilder faultBuilder = new FaultBuilder();
181             faultBuilder.setVnfComponent(VNFC);
182             faultBuilder.setMessage("The VNF is not running correctly");
183             faultBuilder.setKey(new FaultKey(faultBuilder.getVnfComponent()));
184             faultList.add(faultBuilder.build());
185
186             // build a FaultsBuilder object that contains a list of Fault instances
187             FaultsBuilder faultsBuilder = new FaultsBuilder();
188             faultsBuilder.setInfo("One or more VNF components are unreachable");
189             faultsBuilder.setFault(faultList);
190
191             // add the Faults object to HealthCheckBuilder
192             builder.setFaults(faultsBuilder.build());
193         }
194
195         // create the final HealthCheck object
196         builder.build();
197     }
198     /**
199      *
200      * Initialize configuration data based on operational data.
201      * <p/>
202      * Very useful when a plugin is initiated but the underlying layer already contains some operation state.
203      * Deriving the configuration from existing operational state enables reconciliation in case when
204      * Honeycomb's persistence is not available to do the work for us.
205      */
206     @Nonnull
207     @Override
208     public Initialized<? extends DataObject> init(@Nonnull final InstanceIdentifier<HealthCheck> id,
209                                                   @Nonnull final HealthCheck readValue,
210                                                   @Nonnull final ReadContext ctx) {
211         return Initialized.create(id, readValue);
212     }
213     
214     private String readFromFile(String path) {
215         // auto close the file reader
216         try (BufferedReader br = new BufferedReader(new FileReader(path))) {
217                 String line;
218                         while ((line = br.readLine()) != null) {
219                                 return line;
220                         }
221                 } catch (IOException e) {
222                         e.printStackTrace();
223                 }
224                 return null;
225     }
226
227     private boolean getRemoteVnfcHealthStatus(String ipAddr) {
228         // set up the REST manager
229         RESTManager mgr = new RESTManager();
230                 Map<String, String> headers = new HashMap<String, String>();
231                 headers.put("Content-Type", "application/json");
232                 headers.put("Accept", "application/json");
233
234                 // execute the request
235                 String URI = "http://" + ipAddr + ":8183/restconf/operational/health-vnf-onap-plugin:health-vnf-onap-plugin-state/health-check";
236         Pair<Integer, String> result = mgr.get(URI, "admin", "admin", headers);
237
238         return (!result.b.contains("unhealthy"));
239     }
240 }