392b69388e75c6fbcc7bb080b2b94fe17d75dfcd
[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.commscope.tr069adapter.common.deviceversion.DeviceVersionManager;\r
34 import org.commscope.tr069adapter.netconf.config.NetConfServerProperties;\r
35 import org.commscope.tr069adapter.netconf.operations.CustomOperationsCreator;\r
36 import org.opendaylight.netconf.test.tool.NetconfDeviceSimulator;\r
37 import org.opendaylight.netconf.test.tool.config.Configuration;\r
38 import org.opendaylight.netconf.test.tool.config.ConfigurationBuilder;\r
39 import org.opendaylight.netconf.test.tool.operations.OperationsCreator;\r
40 import org.slf4j.Logger;\r
41 import org.slf4j.LoggerFactory;\r
42 import org.springframework.beans.factory.annotation.Autowired;\r
43 import org.springframework.context.annotation.Scope;\r
44 import org.springframework.stereotype.Component;\r
45 import com.google.common.base.Preconditions;\r
46 \r
47 \r
48 @Component\r
49 @Scope("singleton")\r
50 public class NetconfServerStarter {\r
51 \r
52   private static final Logger LOG = LoggerFactory.getLogger(NetconfServerStarter.class);\r
53 \r
54   private static Map<String, NetconfDevice> serversMap = new HashMap<>();\r
55 \r
56   @Autowired\r
57   NetConfServerProperties config;\r
58 \r
59   @Autowired\r
60   DeviceVersionManager versionManager;\r
61 \r
62   public boolean startServer(String netConfPort, String macID, String swVersion, String hwVersion) {\r
63 \r
64     if (netConfPort == null) {\r
65       LOG.error("Invalid NETCONF port for deviceID: {}, port is null.", macID);\r
66       return false;\r
67     }\r
68 \r
69     LOG.debug(\r
70         "Starting Netconf server for MACID :{}, on port :{}, softwareVersion {}, hardwareVersion {}",\r
71         macID, netConfPort, swVersion, hwVersion);\r
72     boolean result =\r
73         startServer(netConfPort, config.getSchemaDirPath(), macID, swVersion, hwVersion);\r
74     LOG.debug("Completed starting Netconf server for MACID :{} , on port :{}, server status={}",\r
75         macID, netConfPort, result);\r
76 \r
77     return result;\r
78   }\r
79 \r
80   @SuppressWarnings({"resource", "deprecation"})\r
81   private boolean startServer(String portStr, String schemaDirPath, String macID, String swVersion,\r
82       String hwVersion) {\r
83 \r
84     // creating configuration for the netconf instance\r
85     final Configuration configuration = new ConfigurationBuilder().build();\r
86     OperationsCreator operationsCreator = new CustomOperationsCreator(macID, swVersion, hwVersion);\r
87     configuration.setOperationsCreator(operationsCreator);\r
88     configuration.setGenerateConfigsTimeout((int) TimeUnit.MINUTES.toMillis(30));\r
89     if (portStr != null) {\r
90       try {\r
91         int port = Integer.parseInt(portStr);\r
92         configuration.setStartingPort(port);\r
93       } catch (Exception e) {\r
94         LOG.error("Failed to get netconf service instance port for parameters {}", e.toString());\r
95         return false;\r
96       }\r
97     }\r
98     configuration.setDeviceCount(1);\r
99     configuration.setSsh(Boolean.TRUE);\r
100     configuration.setCapabilities(Configuration.DEFAULT_BASE_CAPABILITIES_EXI);\r
101     configuration.setIp("0.0.0.0");\r
102 \r
103     String versionPath = versionManager.getNetconfYangSchemaPath(swVersion, hwVersion);\r
104     if (versionPath == null && swVersion != null) {\r
105       LOG.error("Failed to get version path for software version {}, calling base version",\r
106           swVersion);\r
107       versionPath = versionManager.getBaseNetconfYangSchemaPath();\r
108     } else if (swVersion == null) {\r
109       LOG.error("Software version is null {}", swVersion);\r
110       return false;\r
111     }\r
112     String schemaVerPath = schemaDirPath + File.separator + versionPath;\r
113     File schemaVerDir = new File(schemaVerPath);\r
114     configuration.setSchemasDir(schemaVerDir);\r
115 \r
116     try (final NetconfDevice netconfDevice = new NetconfDevice(configuration)) {\r
117       final List<Integer> openDevices = netconfDevice.start();\r
118       if (openDevices.isEmpty()) {\r
119         LOG.debug("Failed to start netconf server instance {}", macID);\r
120         return false;\r
121       }\r
122       netconfDevice.setAutoClose(false);\r
123       serversMap.put(macID, netconfDevice);\r
124     } catch (RuntimeException e) {\r
125       LOG.error("Unhandled exception. Failed to start the server", e);\r
126       return false;\r
127     }\r
128 \r
129     return true;\r
130   }\r
131 \r
132   public boolean stopServer(String macID) {\r
133     try {\r
134       LOG.debug("Stopping Netconf server for MACID {}", macID);\r
135       NetconfDevice netconf = serversMap.get(macID);\r
136       netconf.setAutoClose(true);\r
137       netconf.close();\r
138       serversMap.remove(macID);\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   public boolean isNetConfServerRunning(String deviceId) {\r
182     NetconfDevice nc = serversMap.get(deviceId);\r
183     if (null != nc)\r
184       return true;\r
185     else\r
186       return false;\r
187   }\r
188 \r
189   private void loadSchemaPattren(String line, File file, Pattern revisionregex) {\r
190     if (line != null) {\r
191       final Matcher m = revisionregex.matcher(line);\r
192       Preconditions.checkState(m.find());\r
193       String moduleName = file.getAbsolutePath();\r
194       if (file.getName().endsWith(".yang")) {\r
195         moduleName = moduleName.substring(0, moduleName.length() - 5);\r
196       }\r
197       final String revision = m.group(1);\r
198       final String correctName = moduleName + "@" + revision + ".yang";\r
199       final File correctNameFile = new File(correctName);\r
200       if (!file.renameTo(correctNameFile)) {\r
201         throw new IllegalStateException("Failed to rename '%s'." + file);\r
202       }\r
203     }\r
204   }\r
205 \r
206 }\r
207 \r
208 \r
209 class NetconfDevice extends NetconfDeviceSimulator {\r
210   boolean autoClose = true;\r
211 \r
212   public NetconfDevice(Configuration configuration) {\r
213     super(configuration);\r
214   }\r
215 \r
216   @Override\r
217   public void close() {\r
218     if (autoClose)\r
219       super.close();\r
220   }\r
221 \r
222   public void setAutoClose(boolean autoClose) {\r
223     this.autoClose = autoClose;\r
224   }\r
225 \r
226 }\r