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