Device Software version management
[oam/tr069-adapter.git] / netconf-server / src / main / java / org / commscope / tr069adapter / netconf / server / NetConfServerManagerImpl.java
1 /*\r
2  * ============LICENSE_START========================================================================\r
3  * ONAP : tr-069-adapter\r
4  * =================================================================================================\r
5  * Copyright (C) 2020 CommScope Inc Intellectual Property.\r
6  * =================================================================================================\r
7  * This tr-069-adapter software file is distributed by CommScope Inc under the Apache License,\r
8  * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You\r
9  * may obtain a copy of the License at\r
10  *\r
11  * http://www.apache.org/licenses/LICENSE-2.0\r
12  *\r
13  * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\r
14  * either express or implied. See the License for the specific language governing permissions and\r
15  * limitations under the License.\r
16  * ===============LICENSE_END=======================================================================\r
17  */\r
18 \r
19 package org.commscope.tr069adapter.netconf.server;\r
20 \r
21 import java.net.URI;\r
22 import java.net.URISyntaxException;\r
23 import java.util.ArrayList;\r
24 import java.util.List;\r
25 import java.util.Map;\r
26 import java.util.Map.Entry;\r
27 import java.util.concurrent.ExecutorService;\r
28 import java.util.concurrent.Executors;\r
29 import org.commscope.tr069adapter.acs.common.OperationDetails;\r
30 import org.commscope.tr069adapter.acs.common.ParameterDTO;\r
31 import org.commscope.tr069adapter.acs.common.dto.TR069OperationCode;\r
32 import org.commscope.tr069adapter.mapper.model.NetConfServerDetails;\r
33 import org.commscope.tr069adapter.mapper.model.NetconfServerManagementError;\r
34 import org.commscope.tr069adapter.mapper.model.VESNotification;\r
35 import org.commscope.tr069adapter.mapper.model.VESNotificationResponse;\r
36 import org.commscope.tr069adapter.netconf.config.NetConfServerProperties;\r
37 import org.commscope.tr069adapter.netconf.dao.NetConfServerDetailsRepository;\r
38 import org.commscope.tr069adapter.netconf.entity.NetConfServerDetailsEntity;\r
39 import org.commscope.tr069adapter.netconf.error.RetryFailedException;\r
40 import org.commscope.tr069adapter.netconf.error.ServerPortAllocationException;\r
41 import org.commscope.tr069adapter.netconf.server.helper.ServerPortAllocationHelper;\r
42 import org.commscope.tr069adapter.netconf.server.utils.NetConfServerConstants;\r
43 import org.commscope.tr069adapter.netconf.server.ves.VESNotificationSender;\r
44 import org.slf4j.Logger;\r
45 import org.slf4j.LoggerFactory;\r
46 import org.springframework.beans.factory.annotation.Autowired;\r
47 import org.springframework.http.HttpEntity;\r
48 import org.springframework.http.HttpHeaders;\r
49 import org.springframework.stereotype.Component;\r
50 import org.springframework.web.client.RestTemplate;\r
51 \r
52 @Component\r
53 public class NetConfServerManagerImpl {\r
54 \r
55   private static final Logger LOG = LoggerFactory.getLogger(NetConfServerManagerImpl.class);\r
56 \r
57   @Autowired\r
58   ServerPortAllocationHelper serverPortAllocator;\r
59 \r
60   @Autowired\r
61   NetConfServerDetailsRepository netconfDAO;\r
62 \r
63   @Autowired\r
64   NetConfServerProperties config;\r
65 \r
66   @Autowired\r
67   NetconfServerStarter ncServerStarter;\r
68 \r
69   @Autowired\r
70   RestartNetconfServerHandler restartServersHandler;\r
71 \r
72   @Autowired\r
73   VESNotificationSender vesNotificationSender;\r
74 \r
75   ExecutorService executorService = Executors.newFixedThreadPool(10);\r
76 \r
77   public void restartServers() {\r
78     LOG.debug("Restarting all netconf servers during startup...");\r
79     Iterable<NetConfServerDetailsEntity> entities = netconfDAO.findAll();\r
80 \r
81     for (NetConfServerDetailsEntity entity : entities) {\r
82       boolean isReserved = serverPortAllocator.checkAndReserveServerPort(entity.getListenPort());\r
83       if (isReserved) {\r
84         ServerStartTask task = new ServerStartTask(entity, this);\r
85         executorService.execute(task);\r
86       } else {\r
87         try {\r
88           restartServersHandler.restart(entity);\r
89         } catch (RetryFailedException e) {\r
90           e.printStackTrace();\r
91         }\r
92       }\r
93     }\r
94     LOG.debug("Restarting netconf servers during startup is completed.");\r
95   }\r
96 \r
97   public NetConfServerDetails createServer(String deviceId, String enodeBName, String swVersion,\r
98       String hwVersion) {\r
99     NetConfServerDetails result = new NetConfServerDetails();\r
100     NetConfServerDetailsEntity entity = null;\r
101     if (deviceId != null) {\r
102       entity = netconfDAO.findByDeviceId(deviceId);\r
103     } else if (enodeBName != null) {\r
104       entity = netconfDAO.findByEnodeBName(enodeBName);\r
105     } else {\r
106       // none is specified\r
107       LOG.error(\r
108           "Both deviceID and enodeBName are null. Hence failed to create the netconf server.");\r
109       return null;\r
110     }\r
111 \r
112     if (null != entity) {\r
113       // found the entity. server is already running. double check and run\r
114       // if\r
115       // required. else return the details.\r
116 \r
117       // update the ENB Name if Changed\r
118       entity.setEnodeBName(enodeBName);\r
119       entity.setSwVersion(swVersion);\r
120       entity.setHwVersion(hwVersion);\r
121       netconfDAO.save(entity);\r
122       result = getNetConfServerDetails(deviceId, entity);\r
123       return result;\r
124     }\r
125 \r
126     try {\r
127 \r
128       String port = serverPortAllocator.reserveServerPort();\r
129       if (port == null) {\r
130         result.setError(NetconfServerManagementError.PORT_NOT_AVAILBLE);\r
131         LOG.error(\r
132             "All ports are exhausted. Hence cannot allocate a port to start new netconf server");\r
133         return result;\r
134       } else {\r
135         LOG.debug("Successfully reserved a port for deviceID={} ,port={}", deviceId, port);\r
136 \r
137         // start the server\r
138         boolean isServerStarted = ncServerStarter.startServer(port, deviceId, swVersion, hwVersion);\r
139         boolean isPortInUse = serverPortAllocator.isServerPortInUse(port);\r
140 \r
141         if (!isServerStarted || !isPortInUse) {\r
142           LOG.error(\r
143               "Failed to start netconf server for deviceID: {}, at port:{} , isServerStarted={} ,isPortInUse={}",\r
144               deviceId, port, isServerStarted, isPortInUse);\r
145           result.setError(NetconfServerManagementError.PORT_IN_USE);\r
146           return result;\r
147         }\r
148       }\r
149 \r
150       // save the record in db\r
151       entity = new NetConfServerDetailsEntity();\r
152       entity.setDeviceId(deviceId);\r
153       entity.setListenPort(port);\r
154       entity.setEnodeBName(enodeBName);\r
155       entity.setSwVersion(swVersion);\r
156       entity.setHwVersion(hwVersion);\r
157       netconfDAO.save(entity);\r
158 \r
159       result = getNetConfServerDetails(deviceId, entity);\r
160       LOG.debug("Successfully started netconf server for deviceID= {}, port={}", deviceId, port);\r
161 \r
162     } catch (ServerPortAllocationException e) {\r
163       LOG.error("Failed to allocate a port {}", e.toString());\r
164     }\r
165 \r
166     if (entity != null) {\r
167       result.setDeviceId(deviceId);\r
168       result.setListenPort(entity.getListenPort());\r
169       String netconfListenAddress = getServiceHost();\r
170       if (netconfListenAddress == null) {\r
171         netconfListenAddress = config.getNetconfServerIP();\r
172       }\r
173       result.setListenAddress(netconfListenAddress);\r
174       result.setError(NetconfServerManagementError.SUCCESS);\r
175     }\r
176     return result;\r
177   }\r
178 \r
179   public NetConfServerDetails restartServer(String deviceId, String enodeBName, String swVersion,\r
180       String hwVersion) {\r
181 \r
182     NetConfServerDetailsEntity entity = null;\r
183     if (deviceId != null) {\r
184       entity = netconfDAO.findByDeviceId(deviceId);\r
185     }\r
186     if (entity != null) {\r
187       boolean result = this.ncServerStarter.stopServer(deviceId);\r
188       restartServersOnStartup(entity);\r
189     }\r
190 \r
191     return null;\r
192   }\r
193 \r
194 \r
195   public boolean restartServersOnStartup(NetConfServerDetailsEntity entity) {\r
196     boolean isSuccess = false;\r
197 \r
198     boolean isServerStarted = ncServerStarter.startServer(entity.getListenPort(),\r
199         entity.getDeviceId(), entity.getSwVersion(), entity.getHwVersion());\r
200     if (isServerStarted) {\r
201       LOG.info("Successfully restarted NETCONF server {}  on port {}  upon application startup.",\r
202           entity.getDeviceId(), entity.getListenPort());\r
203       // we need to push the pnfEntry for IP updated\r
204       NetConfServerDetails details = getNetConfServerDetails(entity.getDeviceId(), entity);\r
205 \r
206       final String baseUrl = config.getMapperPath() + "/registerNetconfServer";\r
207       URI uri = null;\r
208       try {\r
209         uri = new URI(baseUrl);\r
210       } catch (URISyntaxException e) {\r
211         LOG.error("error while contructing the URI {}", e.toString());\r
212       }\r
213       RestTemplate restTemplate = new RestTemplate();\r
214       HttpHeaders headers = new HttpHeaders();\r
215       HttpEntity<NetConfServerDetails> httpentity = new HttpEntity<>(details, headers);\r
216       if (uri != null) {\r
217         isSuccess = restTemplate.postForObject(uri, httpentity, Boolean.class);\r
218       }\r
219 \r
220       if (!isSuccess) {\r
221         LOG.error("Netconf Register request is failed update the updated host details..");\r
222       } else {\r
223         LOG.debug("successfully started the server");\r
224       }\r
225     } else {\r
226       LOG.error("Failed to restart NETCONF server {}  on port {}  upon application startup.",\r
227           entity.getDeviceId(), entity.getListenPort());\r
228     }\r
229     return isSuccess;\r
230   }\r
231 \r
232   private NetConfServerDetails getNetConfServerDetails(String deviceId,\r
233       NetConfServerDetailsEntity entity) {\r
234     NetConfServerDetails result = new NetConfServerDetails();\r
235     result.setDeviceId(deviceId);\r
236     result.setListenPort(entity.getListenPort());\r
237     result.setEnodeBName(entity.getEnodeBName());\r
238     result.setSwVersion(entity.getSwVersion());\r
239     result.setHwVersion(entity.getHwVersion());\r
240     String netconfListenAddress = getServiceHost();\r
241     if (netconfListenAddress == null) {\r
242       netconfListenAddress = config.getNetconfServerIP();\r
243     }\r
244     result.setListenAddress(netconfListenAddress);\r
245     result.setError(NetconfServerManagementError.SUCCESS);\r
246     return result;\r
247   }\r
248 \r
249   public String unregister(String deviceId, String enodeBName) {\r
250     String resultMsg = null;\r
251     NetConfServerDetailsEntity entity = null;\r
252     if (deviceId != null) {\r
253       entity = this.netconfDAO.findByDeviceId(deviceId);\r
254     } else if (enodeBName != null) {\r
255       entity = this.netconfDAO.findByEnodeBName(enodeBName);\r
256     } else {\r
257       LOG.error(\r
258           "Both deviceID and enodeBName are null. Hence failed to unregister the netconf server.");\r
259       resultMsg = "Failed to unregister the device " + deviceId + ", enodeBName=" + enodeBName\r
260           + ". Invalid deviceId/enodeBName specified.";\r
261     }\r
262     if (entity == null) {\r
263       resultMsg = "Failed to unregister the device " + deviceId + ", enodeBName=" + enodeBName\r
264           + ". Invalid deviceId/enodeBName specified.";\r
265       LOG.info(resultMsg);\r
266     }\r
267     boolean result = this.ncServerStarter.stopServer(deviceId);\r
268     if (result) {\r
269       resultMsg =\r
270           "Successfully unregistered the device " + deviceId + " and enodeBName=" + enodeBName;\r
271       this.serverPortAllocator.unReserveServerPort(entity.getListenPort());\r
272       this.netconfDAO.delete(entity);\r
273       LOG.info(resultMsg);\r
274       delteHeartBeatTimer(deviceId);\r
275     } else {\r
276       resultMsg = "Failed to unregister the device " + deviceId + ", enodeBName=" + enodeBName;\r
277       LOG.error(resultMsg);\r
278     }\r
279 \r
280     return resultMsg;\r
281   }\r
282 \r
283   private void delteHeartBeatTimer(String deviceId) {\r
284     VESNotification vesNotification = new VESNotification();\r
285 \r
286     vesNotification.seteNodeBName(deviceId);\r
287 \r
288     ParameterDTO paramDTO = new ParameterDTO();\r
289     paramDTO.setParamName(NetConfServerConstants.HEART_BEAT);\r
290 \r
291     List<ParameterDTO> paramDTOList = new ArrayList<>();\r
292     paramDTOList.add(paramDTO);\r
293 \r
294     OperationDetails opDetails = new OperationDetails();\r
295     opDetails.setOpCode(TR069OperationCode.DELETE_OBJECT);\r
296     opDetails.setParmeters(paramDTOList);\r
297 \r
298     vesNotification.setOperationDetails(opDetails);\r
299 \r
300     VESNotificationResponse response =\r
301         vesNotificationSender.sendDeleteConfigNotification(vesNotification);\r
302 \r
303     if (response.getStatusCode() == NetConfServerConstants.SUCCESS) {\r
304       LOG.info("Heart beat timer is deleted successfully for device {}", deviceId);\r
305     } else {\r
306       LOG.error("Failed to delete heart beat timer for device {}. ErrorMsg : {}", deviceId,\r
307           response.getResponseMsg());\r
308     }\r
309 \r
310   }\r
311 \r
312   public List<NetConfServerDetails> getServersInfo() {\r
313     Iterable<NetConfServerDetailsEntity> serverEntities = netconfDAO.findAll();\r
314     String netconfListenAddress = getServiceHost();\r
315     if (netconfListenAddress == null) {\r
316       netconfListenAddress = config.getNetconfServerIP();\r
317     }\r
318     List<NetConfServerDetails> result = new ArrayList<>();\r
319 \r
320     for (NetConfServerDetailsEntity entity : serverEntities) {\r
321       NetConfServerDetails server = new NetConfServerDetails();\r
322       server.setDeviceId(entity.getDeviceId());\r
323       server.setEnodeBName(entity.getEnodeBName());\r
324       server.setError(NetconfServerManagementError.SUCCESS);\r
325       server.setListenAddress(netconfListenAddress);\r
326       server.setListenPort(entity.getListenPort());\r
327       result.add(server);\r
328     }\r
329     return result;\r
330   }\r
331 \r
332   private String getServiceHost() {\r
333     Map<String, String> envs = System.getenv();\r
334     for (Entry<String, String> entry : envs.entrySet()) {\r
335       if (entry.getKey() != null && entry.getKey().endsWith("_NETCONF_SERVICE_SERVICE_HOST")) {\r
336         return entry.getValue();\r
337       }\r
338     }\r
339     return null;\r
340   }\r
341 \r
342   class ServerStartTask implements Runnable {\r
343 \r
344     NetConfServerDetailsEntity entity;\r
345     NetConfServerManagerImpl netconfServerManager;\r
346 \r
347     public ServerStartTask(NetConfServerDetailsEntity entity,\r
348         NetConfServerManagerImpl netconfServerManager) {\r
349       this.entity = entity;\r
350       this.netconfServerManager = netconfServerManager;\r
351     }\r
352 \r
353     @Override\r
354     public void run() {\r
355       boolean isSuccess = netconfServerManager.restartServersOnStartup(entity);\r
356       if (isSuccess) {\r
357         try {\r
358           netconfServerManager.restartServersHandler.restart(entity);\r
359         } catch (RetryFailedException e) {\r
360           e.printStackTrace();// TODO: logg\r
361         }\r
362       }\r
363     }\r
364 \r
365   }\r
366 }\r