10ab6243922de6e613b4475842ffec268b11d892
[oam/tr069-adapter.git] / netconf-server / src / main / java / org / commscope / tr069adapter / netconf / server / NetconfServerStarter.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.io.BufferedReader;\r
22 import java.io.File;\r
23 import java.io.FileReader;\r
24 import java.io.IOException;\r
25 import java.util.Arrays;\r
26 import java.util.Collections;\r
27 import java.util.HashMap;\r
28 import java.util.List;\r
29 import java.util.Map;\r
30 import java.util.concurrent.TimeUnit;\r
31 import java.util.regex.Matcher;\r
32 import java.util.regex.Pattern;\r
33 import org.apache.commons.io.FileUtils;\r
34 import org.commscope.tr069adapter.common.deviceversion.DeviceVersionManager;\r
35 import org.commscope.tr069adapter.netconf.config.NetConfServerProperties;\r
36 import org.commscope.tr069adapter.netconf.operations.CustomOperationsCreator;\r
37 import org.opendaylight.netconf.test.tool.NetconfDeviceSimulator;\r
38 import org.opendaylight.netconf.test.tool.config.Configuration;\r
39 import org.opendaylight.netconf.test.tool.config.ConfigurationBuilder;\r
40 import org.opendaylight.netconf.test.tool.operations.OperationsCreator;\r
41 import org.slf4j.Logger;\r
42 import org.slf4j.LoggerFactory;\r
43 import org.springframework.beans.factory.annotation.Autowired;\r
44 import org.springframework.context.annotation.Scope;\r
45 import org.springframework.stereotype.Component;\r
46 import com.google.common.base.Preconditions;\r
47 \r
48 \r
49 @Component\r
50 @Scope("singleton")\r
51 public class NetconfServerStarter {\r
52 \r
53   private static final Logger LOG = LoggerFactory.getLogger(NetconfServerStarter.class);\r
54 \r
55   private static Map<String, NetconfDevice> serversMap = new HashMap<>();\r
56 \r
57   @Autowired\r
58   NetConfServerProperties config;\r
59 \r
60   @Autowired\r
61   DeviceVersionManager versionManager;\r
62 \r
63   public boolean startServer(String netConfPort, String macID, String swVersion, String hwVersion) {\r
64 \r
65     if (netConfPort == null) {\r
66       LOG.error("Invalid NETCONF port for deviceID: {}, port is null.", macID);\r
67       return false;\r
68     }\r
69 \r
70     LOG.debug(\r
71         "Starting Netconf server for MACID :{}, on port :{}, softwareVersion {}, hardwareVersion {}",\r
72         macID, netConfPort, swVersion, hwVersion);\r
73     boolean result =\r
74         startServer(netConfPort, config.getSchemaDirPath(), macID, swVersion, hwVersion);\r
75     LOG.debug("Completed starting Netconf server for MACID :{} , on port :{}, server status={}",\r
76         macID, netConfPort, result);\r
77 \r
78     return result;\r
79   }\r
80 \r
81   @SuppressWarnings({"resource", "deprecation"})\r
82   private boolean startServer(String portStr, String schemaDirPath, String macID, String swVersion,\r
83       String hwVersion) {\r
84 \r
85     // creating configuration for the netconf instance\r
86     final Configuration configuration = new ConfigurationBuilder().build();\r
87     OperationsCreator operationsCreator = new CustomOperationsCreator(macID, swVersion, hwVersion);\r
88     configuration.setOperationsCreator(operationsCreator);\r
89     configuration.setGenerateConfigsTimeout((int) TimeUnit.MINUTES.toMillis(30));\r
90     if (portStr != null) {\r
91       try {\r
92         int port = Integer.parseInt(portStr);\r
93         configuration.setStartingPort(port);\r
94       } catch (Exception e) {\r
95         LOG.error("Failed to get netconf service instance port for parameters {}", e.toString());\r
96         return false;\r
97       }\r
98     }\r
99     configuration.setDeviceCount(1);\r
100     configuration.setSsh(Boolean.TRUE);\r
101     configuration.setCapabilities(Configuration.DEFAULT_BASE_CAPABILITIES_EXI);\r
102     configuration.setIp("0.0.0.0");\r
103     \r
104     String versionPath = versionManager.getNetconfYangSchemaPath(swVersion, hwVersion);\r
105     if (versionPath == null && swVersion != null) {\r
106       LOG.error("Failed to get version path for software version {}, calling base version",\r
107           swVersion);\r
108       versionPath = versionManager.getBaseNetconfYangSchemaPath();\r
109     } else if (swVersion == null) {\r
110       LOG.error("Software version is null {}", swVersion);\r
111       return false;\r
112     }\r
113     String schemaVerPath = schemaDirPath + File.separator + versionPath;\r
114     File schemaVerDir = new File(schemaVerPath);\r
115     configuration.setSchemasDir(schemaVerDir);\r
116 \r
117     try (final NetconfDevice netconfDevice = new NetconfDevice(configuration)) {\r
118       final List<Integer> openDevices = netconfDevice.start();\r
119       if (openDevices.isEmpty()) {\r
120         LOG.debug("Failed to start netconf server instance {}", macID);\r
121         return false;\r
122       }\r
123       netconfDevice.setAutoClose(false);\r
124       serversMap.put(macID, netconfDevice);\r
125     } catch (RuntimeException e) {\r
126       LOG.error("Unhandled exception. Failed to start the server", e);\r
127       return false;\r
128     }\r
129 \r
130     return true;\r
131   }\r
132 \r
133   public boolean stopServer(String macID) {\r
134     try {\r
135       LOG.debug("Stopping Netconf server for MACID {}", macID);\r
136       NetconfDevice netconf = serversMap.get(macID);\r
137       netconf.setAutoClose(true);\r
138       netconf.close();\r
139       LOG.debug("Completed stopping Netconf server for MACID {}", macID);\r
140       return true;\r
141     } catch (Exception e) {\r
142       LOG.debug("Error while stopping Netconf server for MACID {}; error message {}", macID,\r
143           e.getMessage());\r
144     }\r
145 \r
146     return false;\r
147   }\r
148 \r
149   protected boolean loadSchemas(File schemasDir) {\r
150     if (schemasDir != null) {\r
151       if (!schemasDir.exists() || !schemasDir.isDirectory() || !schemasDir.canRead()) {\r
152         LOG.error("Failed to load schema. schema location is not valid.");\r
153         return false;\r
154       }\r
155 \r
156       Pattern yangregex = Pattern.compile("(?<name>.*)@(?<revision>\\d{4}-\\d{2}-\\d{2})\\.yang");\r
157       Pattern revisionregex = Pattern.compile("revision\\s+\"?(\\d{4}-\\d{2}-\\d{2})\"?");\r
158 \r
159       final File[] filesArray = schemasDir.listFiles();\r
160       final List<File> files =\r
161           filesArray != null ? Arrays.asList(filesArray) : Collections.emptyList();\r
162       for (final File file : files) {\r
163         final Matcher yangMatcher = yangregex.matcher(file.getName());\r
164         if (!yangMatcher.matches()) {\r
165           try (BufferedReader reader = new BufferedReader(new FileReader(file))) {\r
166             String line = reader.readLine();\r
167             while (line != null && !revisionregex.matcher(line).find()) {\r
168               line = reader.readLine();\r
169             }\r
170             loadSchemaPattren(line, file, revisionregex);\r
171           } catch (final IOException e) {\r
172             LOG.error("Unhandled exception. Failed to load the schema.{}", e.toString());\r
173             return false;\r
174           }\r
175         }\r
176       }\r
177     }\r
178     return true;\r
179   }\r
180 \r
181   private void loadSchemaPattren(String line, File file, Pattern revisionregex) {\r
182     if (line != null) {\r
183       final Matcher m = revisionregex.matcher(line);\r
184       Preconditions.checkState(m.find());\r
185       String moduleName = file.getAbsolutePath();\r
186       if (file.getName().endsWith(".yang")) {\r
187         moduleName = moduleName.substring(0, moduleName.length() - 5);\r
188       }\r
189       final String revision = m.group(1);\r
190       final String correctName = moduleName + "@" + revision + ".yang";\r
191       final File correctNameFile = new File(correctName);\r
192       if (!file.renameTo(correctNameFile)) {\r
193         throw new IllegalStateException("Failed to rename '%s'." + file);\r
194       }\r
195     }\r
196   }\r
197 \r
198 }\r
199 \r
200 \r
201 class NetconfDevice extends NetconfDeviceSimulator {\r
202   boolean autoClose = true;\r
203 \r
204   public NetconfDevice(Configuration configuration) {\r
205     super(configuration);\r
206   }\r
207 \r
208   @Override\r
209   public void close() {\r
210     if (autoClose)\r
211       super.close();\r
212   }\r
213 \r
214   public void setAutoClose(boolean autoClose) {\r
215     this.autoClose = autoClose;\r
216   }\r
217 \r
218 }\r