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