ed1164e41ce3f9e1e69890d4d7b1deb729cf1956
[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 \r
30 import org.commscope.tr069adapter.acs.common.OperationDetails;\r
31 import org.commscope.tr069adapter.acs.common.ParameterDTO;\r
32 import org.commscope.tr069adapter.acs.common.dto.TR069OperationCode;\r
33 import org.commscope.tr069adapter.mapper.model.NetConfServerDetails;\r
34 import org.commscope.tr069adapter.mapper.model.NetconfServerManagementError;\r
35 import org.commscope.tr069adapter.mapper.model.VESNotification;\r
36 import org.commscope.tr069adapter.mapper.model.VESNotificationResponse;\r
37 import org.commscope.tr069adapter.netconf.config.NetConfServerProperties;\r
38 import org.commscope.tr069adapter.netconf.dao.NetConfServerDetailsRepository;\r
39 import org.commscope.tr069adapter.netconf.entity.NetConfServerDetailsEntity;\r
40 import org.commscope.tr069adapter.netconf.error.RetryFailedException;\r
41 import org.commscope.tr069adapter.netconf.error.ServerPortAllocationException;\r
42 import org.commscope.tr069adapter.netconf.server.helper.ServerPortAllocationHelper;\r
43 import org.commscope.tr069adapter.netconf.server.utils.NetConfServerConstants;\r
44 import org.commscope.tr069adapter.netconf.server.ves.VESNotificationSender;\r
45 import org.slf4j.Logger;\r
46 import org.slf4j.LoggerFactory;\r
47 import org.springframework.beans.factory.annotation.Autowired;\r
48 import org.springframework.http.HttpEntity;\r
49 import org.springframework.http.HttpHeaders;\r
50 import org.springframework.stereotype.Component;\r
51 import org.springframework.web.client.RestTemplate;\r
52 \r
53 @Component\r
54 public class NetConfServerManagerImpl {\r
55 \r
56   private static final Logger LOG = LoggerFactory.getLogger(NetConfServerManagerImpl.class);\r
57 \r
58   @Autowired\r
59   ServerPortAllocationHelper serverPortAllocator;\r
60 \r
61   @Autowired\r
62   NetConfServerDetailsRepository netconfDAO;\r
63 \r
64   @Autowired\r
65   NetConfServerProperties config;\r
66 \r
67   @Autowired\r
68   NetconfServerStarter ncServerStarter;\r
69 \r
70   @Autowired\r
71   RestartNetconfServerHandler restartServersHandler;\r
72 \r
73   @Autowired\r
74   VESNotificationSender vesNotificationSender;\r
75 \r
76   ExecutorService executorService = Executors.newFixedThreadPool(10);\r
77 \r
78   public void restartServers() {\r
79     LOG.debug("Restarting all netconf servers during startup...");\r
80     Iterable<NetConfServerDetailsEntity> entities = netconfDAO.findAll();\r
81 \r
82     for (NetConfServerDetailsEntity entity : entities) {\r
83       boolean isReserved = serverPortAllocator.checkAndReserveServerPort(entity.getListenPort());\r
84       if (isReserved) {\r
85         ServerStartTask task = new ServerStartTask(entity, this);\r
86         executorService.execute(task);\r
87       } else {\r
88         try {\r
89           restartServersHandler.restart(entity);\r
90         } catch (RetryFailedException e) {\r
91           e.printStackTrace();\r
92         }\r
93       }\r
94     }\r
95     LOG.debug("Restarting netconf servers during startup is completed.");\r
96   }\r
97 \r
98   public NetConfServerDetails createServer(String deviceId, String enodeBName) {\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       netconfDAO.save(entity);\r
120       result = getNetConfServerDetails(deviceId, entity);\r
121       return result;\r
122     }\r
123 \r
124     try {\r
125 \r
126       String port = serverPortAllocator.reserveServerPort();\r
127       if (port == null) {\r
128         result.setError(NetconfServerManagementError.PORT_NOT_AVAILBLE);\r
129         LOG.error(\r
130             "All ports are exhausted. Hence cannot allocate a port to start new netconf server");\r
131         return result;\r
132       } else {\r
133         LOG.debug("Successfully reserved a port for deviceID={} ,port={}", deviceId, port);\r
134 \r
135         // start the server\r
136         boolean isServerStarted = ncServerStarter.startServer(port, deviceId);\r
137         boolean isPortInUse = serverPortAllocator.isServerPortInUse(port);\r
138 \r
139         if (!isServerStarted || !isPortInUse) {\r
140           LOG.error(\r
141               "Failed to start netconf server for deviceID: {}, at port:{} , isServerStarted={} ,isPortInUse={}",\r
142               deviceId, port, isServerStarted, isPortInUse);\r
143           result.setError(NetconfServerManagementError.PORT_IN_USE);\r
144           return result;\r
145         }\r
146       }\r
147 \r
148       // save the record in db\r
149       entity = new NetConfServerDetailsEntity();\r
150       entity.setDeviceId(deviceId);\r
151       entity.setListenPort(port);\r
152       entity.setEnodeBName(enodeBName);\r
153       netconfDAO.save(entity);\r
154 \r
155       result = getNetConfServerDetails(deviceId, entity);\r
156       LOG.debug("Successfully started netconf server for deviceID= {}, port={}", deviceId, port);\r
157 \r
158     } catch (ServerPortAllocationException e) {\r
159       LOG.error("Failed to allocate a port {}", e.toString());\r
160     }\r
161 \r
162     if (entity != null) {\r
163       result.setDeviceId(deviceId);\r
164       result.setListenPort(entity.getListenPort());\r
165       String netconfListenAddress = getServiceHost();\r
166       if (netconfListenAddress == null) {\r
167         netconfListenAddress = config.getNetconfServerIP();\r
168       }\r
169       result.setListenAddress(netconfListenAddress);\r
170       result.setError(NetconfServerManagementError.SUCCESS);\r
171     }\r
172     return result;\r
173   }\r
174 \r
175   public boolean restartServersOnStartup(NetConfServerDetailsEntity entity) {\r
176     boolean isSuccess = false;\r
177 \r
178     boolean isServerStarted =\r
179         ncServerStarter.startServer(entity.getListenPort(), entity.getDeviceId());\r
180     if (isServerStarted) {\r
181       LOG.info("Successfully restarted NETCONF server {}  on port {}  upon application startup.",\r
182           entity.getDeviceId(), entity.getListenPort());\r
183       // we need to push the pnfEntry for IP updated\r
184       NetConfServerDetails details = getNetConfServerDetails(entity.getDeviceId(), entity);\r
185 \r
186       final String baseUrl = config.getMapperPath() + "/registerNetconfServer";\r
187       URI uri = null;\r
188       try {\r
189         uri = new URI(baseUrl);\r
190       } catch (URISyntaxException e) {\r
191         LOG.error("error while contructing the URI {}", e.toString());\r
192       }\r
193       RestTemplate restTemplate = new RestTemplate();\r
194       HttpHeaders headers = new HttpHeaders();\r
195       HttpEntity<NetConfServerDetails> httpentity = new HttpEntity<>(details, headers);\r
196       if (uri != null) {\r
197         isSuccess = restTemplate.postForObject(uri, httpentity, Boolean.class);\r
198       }\r
199 \r
200       if (!isSuccess) {\r
201         LOG.error("Netconf Register request is failed update the updated host details..");\r
202       } else {\r
203         LOG.debug("successfully started the server");\r
204       }\r
205     } else {\r
206       LOG.error("Failed to restart NETCONF server {}  on port {}  upon application startup.",\r
207           entity.getDeviceId(), entity.getListenPort());\r
208     }\r
209     return isSuccess;\r
210   }\r
211 \r
212   private NetConfServerDetails getNetConfServerDetails(String deviceId,\r
213       NetConfServerDetailsEntity entity) {\r
214     NetConfServerDetails result = new NetConfServerDetails();\r
215     result.setDeviceId(deviceId);\r
216     result.setListenPort(entity.getListenPort());\r
217     result.setEnodeBName(entity.getEnodeBName());\r
218     String netconfListenAddress = getServiceHost();\r
219     if (netconfListenAddress == null) {\r
220       netconfListenAddress = config.getNetconfServerIP();\r
221     }\r
222     result.setListenAddress(netconfListenAddress);\r
223     result.setError(NetconfServerManagementError.SUCCESS);\r
224     return result;\r
225   }\r
226 \r
227   public String unregister(String deviceId, String enodeBName) {\r
228     String resultMsg = null;\r
229     NetConfServerDetailsEntity entity = null;\r
230     if (deviceId != null) {\r
231       entity = this.netconfDAO.findByDeviceId(deviceId);\r
232     } else if (enodeBName != null) {\r
233       entity = this.netconfDAO.findByEnodeBName(enodeBName);\r
234     } else {\r
235       LOG.error(\r
236           "Both deviceID and enodeBName are null. Hence failed to unregister the netconf server.");\r
237       resultMsg = "Failed to unregister the device " + deviceId + ", enodeBName=" + enodeBName\r
238           + ". Invalid deviceId/enodeBName specified.";\r
239     }\r
240     if (entity == null) {\r
241       resultMsg = "Failed to unregister the device " + deviceId + ", enodeBName=" + enodeBName\r
242           + ". Invalid deviceId/enodeBName specified.";\r
243       LOG.info(resultMsg);\r
244     }\r
245     boolean result = this.ncServerStarter.stopServer(deviceId);\r
246     if (result) {\r
247       resultMsg =\r
248           "Successfully unregistered the device " + deviceId + " and enodeBName=" + enodeBName;\r
249       this.serverPortAllocator.unReserveServerPort(entity.getListenPort());\r
250       this.netconfDAO.delete(entity);\r
251       LOG.info(resultMsg);\r
252       delteHeartBeatTimer(deviceId);\r
253     } else {\r
254       resultMsg = "Failed to unregister the device " + deviceId + ", enodeBName=" + enodeBName;\r
255       LOG.error(resultMsg);\r
256     }\r
257 \r
258     return resultMsg;\r
259   }\r
260 \r
261   private void delteHeartBeatTimer(String deviceId) {\r
262     VESNotification vesNotification = new VESNotification();\r
263 \r
264     vesNotification.seteNodeBName(deviceId);\r
265 \r
266     ParameterDTO paramDTO = new ParameterDTO();\r
267     paramDTO.setParamName(NetConfServerConstants.HEART_BEAT);\r
268 \r
269     List<ParameterDTO> paramDTOList = new ArrayList<>();\r
270     paramDTOList.add(paramDTO);\r
271 \r
272     OperationDetails opDetails = new OperationDetails();\r
273     opDetails.setOpCode(TR069OperationCode.DELETE_OBJECT);\r
274     opDetails.setParmeters(paramDTOList);\r
275 \r
276     vesNotification.setOperationDetails(opDetails);\r
277 \r
278     VESNotificationResponse response =\r
279         vesNotificationSender.sendDeleteConfigNotification(vesNotification);\r
280 \r
281     if (response.getStatusCode() == NetConfServerConstants.SUCCESS) {\r
282       LOG.info("Heart beat timer is deleted successfully for device {}", deviceId);\r
283     } else {\r
284       LOG.error("Failed to delete heart beat timer for device {}. ErrorMsg : {}", deviceId,\r
285           response.getResponseMsg());\r
286     }\r
287 \r
288   }\r
289 \r
290   public List<NetConfServerDetails> getServersInfo() {\r
291     Iterable<NetConfServerDetailsEntity> serverEntities = netconfDAO.findAll();\r
292     String netconfListenAddress = getServiceHost();\r
293     if (netconfListenAddress == null) {\r
294       netconfListenAddress = config.getNetconfServerIP();\r
295     }\r
296     List<NetConfServerDetails> result = new ArrayList<>();\r
297 \r
298     for (NetConfServerDetailsEntity entity : serverEntities) {\r
299       NetConfServerDetails server = new NetConfServerDetails();\r
300       server.setDeviceId(entity.getDeviceId());\r
301       server.setEnodeBName(entity.getEnodeBName());\r
302       server.setError(NetconfServerManagementError.SUCCESS);\r
303       server.setListenAddress(netconfListenAddress);\r
304       server.setListenPort(entity.getListenPort());\r
305       result.add(server);\r
306     }\r
307     return result;\r
308   }\r
309 \r
310   private String getServiceHost() {\r
311     Map<String, String> envs = System.getenv();\r
312     for (Entry<String, String> entry : envs.entrySet()) {\r
313       if (entry.getKey() != null && entry.getKey().endsWith("_NETCONF_SERVICE_SERVICE_HOST")) {\r
314         return entry.getValue();\r
315       }\r
316     }\r
317     return null;\r
318   }\r
319 \r
320   class ServerStartTask implements Runnable {\r
321 \r
322     NetConfServerDetailsEntity entity;\r
323     NetConfServerManagerImpl netconfServerManager;\r
324 \r
325     public ServerStartTask(NetConfServerDetailsEntity entity,\r
326         NetConfServerManagerImpl netconfServerManager) {\r
327       this.entity = entity;\r
328       this.netconfServerManager = netconfServerManager;\r
329     }\r
330 \r
331     @Override\r
332     public void run() {\r
333       boolean isSuccess = netconfServerManager.restartServersOnStartup(entity);\r
334       if (isSuccess) {\r
335         try {\r
336           netconfServerManager.restartServersHandler.restart(entity);\r
337         } catch (RetryFailedException e) {\r
338           e.printStackTrace();// TODO: logg\r
339         }\r
340       }\r
341     }\r
342 \r
343   }\r
344 }\r