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