exchanging new version yang models on firmware upgrade
[oam/tr069-adapter.git] / netconf-server / src / main / java / org / commscope / tr069adapter / netconf / server / NetConfServerManagerImpl.java
index eee8db6..852d205 100644 (file)
 \r
 package org.commscope.tr069adapter.netconf.server;\r
 \r
+import java.io.File;\r
+import java.io.IOException;\r
 import java.net.URI;\r
 import java.net.URISyntaxException;\r
 import java.util.ArrayList;\r
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Map.Entry;\r
-\r
+import java.util.concurrent.ExecutorService;\r
+import java.util.concurrent.Executors;\r
+import org.apache.commons.io.FileUtils;\r
+import org.commscope.tr069adapter.acs.common.OperationDetails;\r
+import org.commscope.tr069adapter.acs.common.ParameterDTO;\r
+import org.commscope.tr069adapter.acs.common.dto.TR069OperationCode;\r
+import org.commscope.tr069adapter.common.deviceversion.DeviceVersionManager;\r
+import org.commscope.tr069adapter.common.deviceversion.ProfileDefinition;\r
 import org.commscope.tr069adapter.mapper.model.NetConfServerDetails;\r
 import org.commscope.tr069adapter.mapper.model.NetconfServerManagementError;\r
+import org.commscope.tr069adapter.mapper.model.VESNotification;\r
+import org.commscope.tr069adapter.mapper.model.VESNotificationResponse;\r
 import org.commscope.tr069adapter.netconf.config.NetConfServerProperties;\r
 import org.commscope.tr069adapter.netconf.dao.NetConfServerDetailsRepository;\r
 import org.commscope.tr069adapter.netconf.entity.NetConfServerDetailsEntity;\r
 import org.commscope.tr069adapter.netconf.error.RetryFailedException;\r
 import org.commscope.tr069adapter.netconf.error.ServerPortAllocationException;\r
 import org.commscope.tr069adapter.netconf.server.helper.ServerPortAllocationHelper;\r
+import org.commscope.tr069adapter.netconf.server.utils.NetConfServerConstants;\r
+import org.commscope.tr069adapter.netconf.server.ves.VESNotificationSender;\r
 import org.slf4j.Logger;\r
 import org.slf4j.LoggerFactory;\r
 import org.springframework.beans.factory.annotation.Autowired;\r
@@ -61,27 +74,73 @@ public class NetConfServerManagerImpl {
   @Autowired\r
   RestartNetconfServerHandler restartServersHandler;\r
 \r
+  @Autowired\r
+  VESNotificationSender vesNotificationSender;\r
+\r
+  @Autowired\r
+  DeviceVersionManager versionManager;\r
+\r
+  ExecutorService executorService = Executors.newFixedThreadPool(10);\r
+\r
+  public boolean loadSchemas() {\r
+    LOG.debug("Loading yang schema started");\r
+    List<ProfileDefinition> profiles = versionManager.getSupportedProfileDefinitions();\r
+    try {\r
+      String commonSchemaPath = config.getSchemaDirPath() + "/common";\r
+\r
+      for (ProfileDefinition profile : profiles) {\r
+        String verSpecificSchemaPath =\r
+            config.getSchemaDirPath() + File.separator + profile.getNetConfSchemaPath();\r
+        File schemaDir = new File(commonSchemaPath);\r
+        File schemaVerDir = new File(verSpecificSchemaPath);\r
+\r
+        if (!schemaVerDir.isDirectory()) {\r
+          LOG.error("No folder path found for given version path {}",\r
+              schemaVerDir.getAbsolutePath());\r
+          return false;\r
+        }\r
+\r
+        try {\r
+          FileUtils.copyDirectory(schemaDir, schemaVerDir);\r
+        } catch (IOException e) {\r
+          LOG.error("Failed to copy directory " + e.getMessage());\r
+        }\r
+        boolean isSchemaLoaded = ncServerStarter.loadSchemas(schemaVerDir);\r
+        if (!isSchemaLoaded) {\r
+          LOG.debug("Failed to load schema for profile {}", profile.getProfileId());\r
+          return false;\r
+        }\r
+      }\r
+    } catch (Exception e) {\r
+      LOG.error("Load schema's failed in netconf server {}", e.getMessage());\r
+      return false;\r
+    }\r
+    LOG.debug("Loading yang schema completed");\r
+    return true;\r
+  }\r
+\r
   public void restartServers() {\r
     LOG.debug("Restarting all netconf servers during startup...");\r
     Iterable<NetConfServerDetailsEntity> entities = netconfDAO.findAll();\r
-    List<NetConfServerDetailsEntity> serverDetailsList = new ArrayList<>();\r
-    for (NetConfServerDetailsEntity entity : entities) {\r
-      serverDetailsList.add(entity);\r
-    }\r
-    restartServersOnStartup(serverDetailsList);\r
 \r
-    if (!serverDetailsList.isEmpty()) {\r
-      LOG.debug("Attempting to start failed netconf servers {}", serverDetailsList);\r
-      try {\r
-        restartServersHandler.restart(serverDetailsList);\r
-      } catch (RetryFailedException e) {\r
-        LOG.error("Failed to restart all netconf servers. {}", e.toString());\r
+    for (NetConfServerDetailsEntity entity : entities) {\r
+      boolean isReserved = serverPortAllocator.checkAndReserveServerPort(entity.getListenPort());\r
+      if (isReserved) {\r
+        ServerStartTask task = new ServerStartTask(entity, this);\r
+        executorService.execute(task);\r
+      } else {\r
+        try {\r
+          restartServersHandler.restart(entity);\r
+        } catch (RetryFailedException e) {\r
+          LOG.error("submit task for restarting is failed {}", e.toString());\r
+        }\r
       }\r
     }\r
     LOG.debug("Restarting netconf servers during startup is completed.");\r
   }\r
 \r
-  public NetConfServerDetails createServer(String deviceId, String enodeBName) {\r
+  public NetConfServerDetails createServer(String deviceId, String enodeBName, String swVersion,\r
+      String hwVersion) {\r
     NetConfServerDetails result = new NetConfServerDetails();\r
     NetConfServerDetailsEntity entity = null;\r
     if (deviceId != null) {\r
@@ -95,7 +154,11 @@ public class NetConfServerManagerImpl {
       return null;\r
     }\r
 \r
-    if (null != entity) {\r
+    if (null != entity && ncServerStarter.isNetConfServerRunning(deviceId)) {\r
+      if (isVersionChanged(entity, swVersion, hwVersion)) {\r
+        return restartOnVersionChange(deviceId, enodeBName, swVersion, hwVersion);\r
+      }\r
+\r
       // found the entity. server is already running. double check and run\r
       // if\r
       // required. else return the details.\r
@@ -110,17 +173,25 @@ public class NetConfServerManagerImpl {
     try {\r
 \r
       String port = serverPortAllocator.reserveServerPort();\r
-      LOG.debug("Successfully reserved a port for deviceID={} ,port={}", deviceId, port);\r
-\r
-      // start the server\r
-      boolean isServerStarted = ncServerStarter.startServer(port, deviceId);\r
-      boolean isPortInUse = serverPortAllocator.isServerPortInUse(port);\r
-\r
-      if (!isServerStarted || !isPortInUse) {\r
+      if (port == null) {\r
+        result.setError(NetconfServerManagementError.PORT_NOT_AVAILBLE);\r
         LOG.error(\r
-            "Failed to start netconf server for deviceID: {}, at port:{} , isServerStarted={} ,isPortInUse={}",\r
-            deviceId, port, isServerStarted, isPortInUse);\r
-        return null;\r
+            "All ports are exhausted. Hence cannot allocate a port to start new netconf server");\r
+        return result;\r
+      } else {\r
+        LOG.debug("Successfully reserved a port for deviceID={} ,port={}", deviceId, port);\r
+\r
+        // start the server\r
+        boolean isServerStarted = ncServerStarter.startServer(port, deviceId, swVersion, hwVersion);\r
+        boolean isPortInUse = serverPortAllocator.isServerPortInUse(port);\r
+\r
+        if (!isServerStarted || !isPortInUse) {\r
+          LOG.error(\r
+              "Failed to start netconf server for deviceID: {}, at port:{} , isServerStarted={} ,isPortInUse={}",\r
+              deviceId, port, isServerStarted, isPortInUse);\r
+          result.setError(NetconfServerManagementError.PORT_IN_USE);\r
+          return result;\r
+        }\r
       }\r
 \r
       // save the record in db\r
@@ -128,6 +199,8 @@ public class NetConfServerManagerImpl {
       entity.setDeviceId(deviceId);\r
       entity.setListenPort(port);\r
       entity.setEnodeBName(enodeBName);\r
+      entity.setSwVersion(swVersion);\r
+      entity.setHwVersion(hwVersion);\r
       netconfDAO.save(entity);\r
 \r
       result = getNetConfServerDetails(deviceId, entity);\r
@@ -150,52 +223,78 @@ public class NetConfServerManagerImpl {
     return result;\r
   }\r
 \r
-  public void restartServersOnStartup(List<NetConfServerDetailsEntity> serverDetailsList) {\r
-\r
-    List<NetConfServerDetailsEntity> startedServers = new ArrayList<>();\r
-    for (NetConfServerDetailsEntity entity : serverDetailsList) {\r
-\r
-      serverPortAllocator.checkAndReserveServerPort(entity.getListenPort());\r
+  public NetConfServerDetails restartOnVersionChange(String deviceId, String enodeBName,\r
+      String swVersion, String hwVersion) {\r
 \r
-      serverPortAllocator.isServerPortInUse(entity.getListenPort());\r
-      boolean isServerStarted =\r
-          ncServerStarter.startServer(entity.getListenPort(), entity.getDeviceId());\r
+    NetConfServerDetailsEntity entity = null;\r
+    if (deviceId != null) {\r
+      entity = netconfDAO.findByDeviceId(deviceId);\r
+    }\r
+    if (entity == null) {\r
+      return null;\r
+    }\r
 \r
-      if (isServerStarted) {\r
-        LOG.info("Successfully restarted NETCONF server {}  on port {}  upon application startup.",\r
-            entity.getDeviceId(), entity.getListenPort());\r
-        // we need to push the pnfEntry for IP updated\r
-        NetConfServerDetails details = getNetConfServerDetails(entity.getDeviceId(), entity);\r
+    boolean isVersionChanged = isVersionChanged(entity, swVersion, hwVersion);\r
+    if (isVersionChanged) {\r
+      LOG.debug("software version changed, stopping the the existing netconf instance");\r
+      boolean result = this.ncServerStarter.stopServer(deviceId);\r
+      if (result) {\r
+        LOG.debug(\r
+            "successfully stopped the netconf instance; trying to start with new version yang models");\r
+        entity.setSwVersion(swVersion);\r
+        entity.setHwVersion(hwVersion);\r
+        netconfDAO.save(entity);\r
 \r
-        final String baseUrl = config.getMapperPath() + "/registerNetconfServer";\r
-        URI uri = null;\r
-        try {\r
-          uri = new URI(baseUrl);\r
-        } catch (URISyntaxException e) {\r
-          LOG.error("error while contructing the URI {}", e.toString());\r
-        }\r
-        RestTemplate restTemplate = new RestTemplate();\r
-        HttpHeaders headers = new HttpHeaders();\r
-        HttpEntity<NetConfServerDetails> httpentity = new HttpEntity<>(details, headers);\r
-        boolean isSuccess = false;\r
-        if (uri != null) {\r
-          isSuccess = restTemplate.postForObject(uri, httpentity, Boolean.class);\r
-        }\r
+        boolean isSuccess = startNetConfServerInstance(entity);\r
 \r
         if (!isSuccess) {\r
-          LOG.error("Netconf Register request is failed update the updated host details..");\r
-        } else {\r
-          LOG.debug("successfully started the server");\r
+          try {\r
+            restartServersHandler.restart(entity);\r
+          } catch (RetryFailedException e) {\r
+            LOG.debug("");\r
+          }\r
         }\r
-        startedServers.add(entity);\r
-      } else {\r
-        LOG.error("Failed to restart NETCONF server {}  on port {}  upon application startup.",\r
-            entity.getDeviceId(), entity.getListenPort());\r
       }\r
     }\r
-    if (!serverDetailsList.isEmpty()) {\r
-      serverDetailsList.removeAll(startedServers);\r
+    return getNetConfServerDetails(deviceId, entity);\r
+  }\r
+\r
+\r
+  public boolean startNetConfServerInstance(NetConfServerDetailsEntity entity) {\r
+    boolean isSuccess = false;\r
+\r
+    boolean isServerStarted = ncServerStarter.startServer(entity.getListenPort(),\r
+        entity.getDeviceId(), entity.getSwVersion(), entity.getHwVersion());\r
+    if (isServerStarted) {\r
+      LOG.info("Successfully restarted NETCONF server {}  on port {} .",\r
+          entity.getDeviceId(), entity.getListenPort());\r
+      // we need to push the pnfEntry for IP updated\r
+      NetConfServerDetails details = getNetConfServerDetails(entity.getDeviceId(), entity);\r
+\r
+      final String baseUrl = config.getMapperPath() + "/registerNetconfServer";\r
+      URI uri = null;\r
+      try {\r
+        uri = new URI(baseUrl);\r
+      } catch (URISyntaxException e) {\r
+        LOG.error("error while contructing the URI {}", e.toString());\r
+      }\r
+      RestTemplate restTemplate = new RestTemplate();\r
+      HttpHeaders headers = new HttpHeaders();\r
+      HttpEntity<NetConfServerDetails> httpentity = new HttpEntity<>(details, headers);\r
+      if (uri != null) {\r
+        isSuccess = restTemplate.postForObject(uri, httpentity, Boolean.class);\r
+      }\r
+\r
+      if (!isSuccess) {\r
+        LOG.error("Netconf Register request is failed update the updated host details..");\r
+      } else {\r
+        LOG.debug("successfully started the server");\r
+      }\r
+    } else {\r
+      LOG.error("Failed to restart NETCONF server {}  on port {}  upon application startup.",\r
+          entity.getDeviceId(), entity.getListenPort());\r
     }\r
+    return isSuccess;\r
   }\r
 \r
   private NetConfServerDetails getNetConfServerDetails(String deviceId,\r
@@ -204,6 +303,8 @@ public class NetConfServerManagerImpl {
     result.setDeviceId(deviceId);\r
     result.setListenPort(entity.getListenPort());\r
     result.setEnodeBName(entity.getEnodeBName());\r
+    result.setSwVersion(entity.getSwVersion());\r
+    result.setHwVersion(entity.getHwVersion());\r
     String netconfListenAddress = getServiceHost();\r
     if (netconfListenAddress == null) {\r
       netconfListenAddress = config.getNetconfServerIP();\r
@@ -213,9 +314,68 @@ public class NetConfServerManagerImpl {
     return result;\r
   }\r
 \r
-  public boolean unregister(String deviceId, String enodeBName) {\r
-    LOG.debug("Unregister is not yet supported deviceId={} enodeBName={}", deviceId, enodeBName);\r
-    return false;\r
+  public String unregister(String deviceId, String enodeBName) {\r
+    String resultMsg = null;\r
+    NetConfServerDetailsEntity entity = null;\r
+    if (deviceId != null) {\r
+      entity = this.netconfDAO.findByDeviceId(deviceId);\r
+    } else if (enodeBName != null) {\r
+      entity = this.netconfDAO.findByEnodeBName(enodeBName);\r
+    } else {\r
+      LOG.error(\r
+          "Both deviceID and enodeBName are null. Hence failed to unregister the netconf server.");\r
+      resultMsg = "Failed to unregister the device " + deviceId + ", enodeBName=" + enodeBName\r
+          + ". Invalid deviceId/enodeBName specified.";\r
+    }\r
+    if (entity == null) {\r
+      resultMsg = "Failed to unregister the device " + deviceId + ", enodeBName=" + enodeBName\r
+          + ". Invalid deviceId/enodeBName specified.";\r
+      LOG.info(resultMsg);\r
+      return resultMsg;\r
+    }\r
+    boolean result = this.ncServerStarter.stopServer(deviceId);\r
+    if (result) {\r
+      resultMsg =\r
+          "Successfully unregistered the device " + deviceId + " and enodeBName=" + enodeBName;\r
+      this.serverPortAllocator.unReserveServerPort(entity.getListenPort());\r
+      this.netconfDAO.delete(entity);\r
+      LOG.info(resultMsg);\r
+      delteHeartBeatTimer(deviceId);\r
+    } else {\r
+      resultMsg = "Failed to unregister the device " + deviceId + ", enodeBName=" + enodeBName;\r
+      LOG.error(resultMsg);\r
+    }\r
+\r
+    return resultMsg;\r
+  }\r
+\r
+  private void delteHeartBeatTimer(String deviceId) {\r
+    VESNotification vesNotification = new VESNotification();\r
+\r
+    vesNotification.seteNodeBName(deviceId);\r
+\r
+    ParameterDTO paramDTO = new ParameterDTO();\r
+    paramDTO.setParamName(NetConfServerConstants.HEART_BEAT);\r
+\r
+    List<ParameterDTO> paramDTOList = new ArrayList<>();\r
+    paramDTOList.add(paramDTO);\r
+\r
+    OperationDetails opDetails = new OperationDetails();\r
+    opDetails.setOpCode(TR069OperationCode.DELETE_OBJECT);\r
+    opDetails.setParmeters(paramDTOList);\r
+\r
+    vesNotification.setOperationDetails(opDetails);\r
+\r
+    VESNotificationResponse response =\r
+        vesNotificationSender.sendDeleteConfigNotification(vesNotification);\r
+\r
+    if (response.getStatusCode() == NetConfServerConstants.SUCCESS) {\r
+      LOG.info("Heart beat timer is deleted successfully for device {}", deviceId);\r
+    } else {\r
+      LOG.error("Failed to delete heart beat timer for device {}. ErrorMsg : {}", deviceId,\r
+          response.getResponseMsg());\r
+    }\r
+\r
   }\r
 \r
   public List<NetConfServerDetails> getServersInfo() {\r
@@ -233,6 +393,8 @@ public class NetConfServerManagerImpl {
       server.setError(NetconfServerManagementError.SUCCESS);\r
       server.setListenAddress(netconfListenAddress);\r
       server.setListenPort(entity.getListenPort());\r
+      server.setSwVersion(entity.getSwVersion());\r
+      server.setHwVersion(entity.getHwVersion());\r
       result.add(server);\r
     }\r
     return result;\r
@@ -247,4 +409,37 @@ public class NetConfServerManagerImpl {
     }\r
     return null;\r
   }\r
+\r
+  private boolean isVersionChanged(NetConfServerDetailsEntity entity, String swVersion,\r
+      String hwVersion) {\r
+    String existingProfileId =\r
+        versionManager.getAssociatedProfileId(entity.getSwVersion(), entity.getHwVersion());\r
+    String newProfiled = versionManager.getAssociatedProfileId(swVersion, hwVersion);\r
+    return !existingProfileId.equalsIgnoreCase(newProfiled) ? true : false;\r
+  }\r
+\r
+  class ServerStartTask implements Runnable {\r
+\r
+    NetConfServerDetailsEntity entity;\r
+    NetConfServerManagerImpl netconfServerManager;\r
+\r
+    public ServerStartTask(NetConfServerDetailsEntity entity,\r
+        NetConfServerManagerImpl netconfServerManager) {\r
+      this.entity = entity;\r
+      this.netconfServerManager = netconfServerManager;\r
+    }\r
+\r
+    @Override\r
+    public void run() {\r
+      boolean isSuccess = netconfServerManager.startNetConfServerInstance(entity);\r
+      if (!isSuccess) {\r
+        try {\r
+          netconfServerManager.restartServersHandler.restart(entity);\r
+        } catch (RetryFailedException e) {\r
+          LOG.debug("");\r
+        }\r
+      }\r
+    }\r
+\r
+  }\r
 }\r