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