Refactor persister: require only capabilities referenced by the xml snapshot.
[controller.git] / opendaylight / netconf / netconf-it / src / test / java / org / opendaylight / controller / netconf / it / NetconfITTest.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.netconf.it;
10
11 import ch.ethz.ssh2.Connection;
12 import ch.ethz.ssh2.Session;
13 import com.google.common.base.Optional;
14 import com.google.common.collect.Lists;
15 import com.google.common.collect.Sets;
16 import io.netty.channel.ChannelFuture;
17 import io.netty.channel.EventLoopGroup;
18 import io.netty.channel.nio.NioEventLoopGroup;
19 import io.netty.util.HashedWheelTimer;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.lang.management.ManagementFactory;
23 import java.net.InetSocketAddress;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.List;
28 import java.util.Set;
29 import java.util.concurrent.TimeUnit;
30 import java.util.regex.Pattern;
31 import javax.management.ObjectName;
32 import javax.net.ssl.SSLContext;
33 import javax.xml.parsers.ParserConfigurationException;
34 import junit.framework.Assert;
35 import org.junit.After;
36 import org.junit.Before;
37 import org.junit.Ignore;
38 import org.junit.Test;
39 import org.opendaylight.controller.config.api.ModuleIdentifier;
40 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
41 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
42 import org.opendaylight.controller.config.manager.impl.jmx.BaseJMXRegistrator;
43 import org.opendaylight.controller.config.manager.impl.jmx.RootRuntimeBeanRegistratorImpl;
44 import org.opendaylight.controller.config.persist.api.Persister;
45 import org.opendaylight.controller.config.spi.ModuleFactory;
46 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
47 import org.opendaylight.controller.config.yang.store.api.YangStoreException;
48 import org.opendaylight.controller.config.yang.store.impl.HardcodedYangStoreService;
49 import org.opendaylight.controller.config.yang.test.impl.Asdf;
50 import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
51 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
52 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
53 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplRuntimeMXBean;
54 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplRuntimeRegistrator;
55 import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
56 import org.opendaylight.controller.netconf.api.NetconfMessage;
57 import org.opendaylight.controller.netconf.client.NetconfClient;
58 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
59 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
60 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
61 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
62 import org.opendaylight.controller.netconf.impl.NetconfServerSessionListenerFactory;
63 import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
64 import org.opendaylight.controller.netconf.impl.SessionIdProvider;
65 import org.opendaylight.controller.netconf.impl.mapping.ExiDecoderHandler;
66 import org.opendaylight.controller.netconf.impl.mapping.ExiEncoderHandler;
67 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
68 import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
69 import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
70 import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
71 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
72 import org.opendaylight.controller.netconf.util.xml.ExiParameters;
73 import org.opendaylight.controller.netconf.util.xml.XmlElement;
74 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
77 import org.w3c.dom.Document;
78 import org.w3c.dom.Element;
79 import org.w3c.dom.NamedNodeMap;
80 import org.w3c.dom.Node;
81 import org.xml.sax.SAXException;
82 import static java.util.Collections.emptyList;
83 import static junit.framework.Assert.assertEquals;
84 import static junit.framework.Assert.assertNotNull;
85 import static junit.framework.Assert.assertTrue;
86 import static org.mockito.Mockito.doReturn;
87 import static org.mockito.Mockito.mock;
88
89 public class NetconfITTest extends AbstractConfigTest {
90
91      private static final Logger logger =  LoggerFactory.getLogger(NetconfITTest.class);
92     //
93
94     private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
95     private static final InetSocketAddress sshAddress = new InetSocketAddress("127.0.0.1", 10830);
96     private static final String USERNAME = "netconf";
97     private static final String PASSWORD = "netconf";
98
99     private NetconfMessage getConfig, getConfigCandidate, editConfig,
100             closeSession, startExi, stopExi;
101     private DefaultCommitNotificationProducer commitNot;
102     private NetconfServerDispatcher dispatch;
103     private EventLoopGroup nettyThreadgroup;
104
105     private NetconfClientDispatcher clientDispatcher;
106
107
108     @Before
109     public void setUp() throws Exception {
110         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(getModuleFactories().toArray(
111                 new ModuleFactory[0])));
112
113         loadMessages();
114
115         NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
116         factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
117
118         nettyThreadgroup = new NioEventLoopGroup();
119
120         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
121
122         dispatch = createDispatcher(Optional.<SSLContext> absent(), factoriesListener);
123         ChannelFuture s = dispatch.createServer(tcpAddress);
124         s.await();
125
126         clientDispatcher = new NetconfClientDispatcher(Optional.<SSLContext>absent(), nettyThreadgroup, nettyThreadgroup);
127     }
128
129     private NetconfServerDispatcher createDispatcher(Optional<SSLContext> sslC,
130             NetconfOperationServiceFactoryListenerImpl factoriesListener) {
131         SessionIdProvider idProvider = new SessionIdProvider();
132         NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
133                 new HashedWheelTimer(5000, TimeUnit.MILLISECONDS), factoriesListener, idProvider);
134
135         NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
136                 factoriesListener, commitNot, idProvider);
137
138         NetconfServerDispatcher.ServerSslChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerSslChannelInitializer(
139                 sslC, serverNegotiatorFactory, listenerFactory);
140         return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
141     }
142
143     @After
144     public void tearDown() throws Exception {
145         commitNot.close();
146         nettyThreadgroup.shutdownGracefully();
147         clientDispatcher.close();
148     }
149
150     private void loadMessages() throws IOException, SAXException, ParserConfigurationException {
151         this.editConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/edit_config.xml");
152         this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
153         this.getConfigCandidate = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig_candidate.xml");
154         this.startExi = XmlFileLoader
155                 .xmlFileToNetconfMessage("netconfMessages/startExi.xml");
156         this.stopExi = XmlFileLoader
157                 .xmlFileToNetconfMessage("netconfMessages/stopExi.xml");
158         this.closeSession = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/closeSession.xml");
159     }
160
161     private HardcodedYangStoreService getYangStore() throws YangStoreException, IOException {
162         final Collection<InputStream> yangDependencies = getBasicYangs();
163         return new HardcodedYangStoreService(yangDependencies);
164     }
165
166     static Collection<InputStream> getBasicYangs() throws IOException {
167         List<String> paths = Arrays.asList("/META-INF/yang/config.yang", "/META-INF/yang/rpc-context.yang",
168                 "/META-INF/yang/config-test.yang", "/META-INF/yang/config-test-impl.yang",
169                 "/META-INF/yang/ietf-inet-types.yang");
170         final Collection<InputStream> yangDependencies = new ArrayList<>();
171         List<String> failedToFind = new ArrayList<>();
172         for (String path : paths) {
173             InputStream resourceAsStream = NetconfITTest.class.getResourceAsStream(path);
174             if (resourceAsStream == null) {
175                 failedToFind.add(path);
176             } else {
177                 yangDependencies.add(resourceAsStream);
178             }
179         }
180         assertEquals("Some yang files were not found",emptyList(), failedToFind);
181         return yangDependencies;
182     }
183
184     protected List<ModuleFactory> getModuleFactories() {
185         return getModuleFactoriesS();
186     }
187     static List<ModuleFactory> getModuleFactoriesS() {
188         return Lists.newArrayList(new TestImplModuleFactory(), new DepTestImplModuleFactory(),
189                 new NetconfTestImplModuleFactory());
190     }
191
192     @Test
193     public void testNetconfClientDemonstration() throws Exception {
194         try (NetconfClient netconfClient = new NetconfClient("client", tcpAddress, 4000, clientDispatcher)) {
195
196             Set<String> capabilitiesFromNetconfServer = netconfClient.getCapabilities();
197             long sessionId = netconfClient.getSessionId();
198
199             // NetconfMessage can be created :
200             // new NetconfMessage(XmlUtil.readXmlToDocument("<xml/>"));
201
202             NetconfMessage response = netconfClient.sendMessage(getConfig);
203             response.getDocument();
204         }
205     }
206
207     @Test
208     public void testTwoSessions() throws Exception {
209         try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 10000, clientDispatcher))  {
210             try (NetconfClient netconfClient2 = new NetconfClient("2", tcpAddress, 10000, clientDispatcher))  {
211             }
212         }
213     }
214
215     @Test(timeout = 10000)
216     public void testPersister() throws Exception {
217         Persister persister = mock(Persister.class);
218         doReturn("mockPersister").when(persister).toString();
219         doReturn(Optional.absent()).when(persister).loadLastConfig();
220         ConfigPersisterNotificationHandler h =
221                 new ConfigPersisterNotificationHandler(persister, tcpAddress, ManagementFactory.getPlatformMBeanServer(), Pattern.compile(ConfigPersisterActivator.DEFAULT_IGNORED_REGEX));
222         h.init();
223     }
224
225     @Ignore
226     @Test
227     public void waitingTest() throws Exception {
228         final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
229         transaction.createModule(DepTestImplModuleFactory.NAME, "eb");
230         transaction.commit();
231         Thread.currentThread().suspend();
232     }
233
234     @Test
235     public void rpcReplyContainsAllAttributesTest() throws Exception {
236         try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
237             final String rpc = "<rpc message-id=\"5\" a=\"a\" b=\"44\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
238                     + "<get/>" + "</rpc>";
239             final Document doc = XmlUtil.readXmlToDocument(rpc);
240             final NetconfMessage message = netconfClient.sendMessage(new NetconfMessage(doc));
241             assertNotNull(message);
242             final NamedNodeMap expectedAttributes = doc.getDocumentElement().getAttributes();
243             final NamedNodeMap returnedAttributes = message.getDocument().getDocumentElement().getAttributes();
244
245             assertSameAttributes(expectedAttributes, returnedAttributes);
246         }
247     }
248
249     private void assertSameAttributes(final NamedNodeMap expectedAttributes, final NamedNodeMap returnedAttributes) {
250         assertNotNull("Expecting 4 attributes", returnedAttributes);
251         assertEquals(expectedAttributes.getLength(), returnedAttributes.getLength());
252
253         for (int i = 0; i < expectedAttributes.getLength(); i++) {
254             final Node expAttr = expectedAttributes.item(i);
255             final Node attr = returnedAttributes.item(i);
256             assertEquals(expAttr.getNodeName(), attr.getNodeName());
257             assertEquals(expAttr.getNamespaceURI(), attr.getNamespaceURI());
258             assertEquals(expAttr.getTextContent(), attr.getTextContent());
259         }
260     }
261
262     @Test
263     public void rpcReplyErrorContainsAllAttributesTest() throws Exception {
264         try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
265             final String rpc = "<rpc message-id=\"1\" a=\"adada\" b=\"4\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
266                     + "<commit/>" + "</rpc>";
267             final Document doc = XmlUtil.readXmlToDocument(rpc);
268             final NetconfMessage message = netconfClient.sendMessage(new NetconfMessage(doc));
269             final NamedNodeMap expectedAttributes = doc.getDocumentElement().getAttributes();
270             final NamedNodeMap returnedAttributes = message.getDocument().getDocumentElement().getAttributes();
271
272             assertSameAttributes(expectedAttributes, returnedAttributes);
273         }
274     }
275
276     @Test
277     public void rpcOutputContainsCorrectNamespace() throws Exception {
278         final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
279         ObjectName dep = transaction.createModule(DepTestImplModuleFactory.NAME, "instanceD");
280         ObjectName impl = transaction.createModule(NetconfTestImplModuleFactory.NAME, "instance");
281         NetconfTestImplModuleMXBean proxy = configRegistryClient
282                 .newMXBeanProxy(impl, NetconfTestImplModuleMXBean.class);
283         proxy.setTestingDep(dep);
284         registerRuntimeBean();
285
286         transaction.commit();
287
288         try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
289             final String expectedNamespace = "urn:opendaylight:params:xml:ns:yang:controller:test:impl";
290
291             final String rpc = "<rpc message-id=\"5\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
292                     + "<no-arg xmlns=\""
293                     + expectedNamespace
294                     + "\">    "
295                     + "<context-instance>/modules/module[type='impl-netconf'][name='instance']</context-instance>"
296                     + "<arg1>argument1</arg1>" + "</no-arg>" + "</rpc>";
297             final Document doc = XmlUtil.readXmlToDocument(rpc);
298             final NetconfMessage message = netconfClient.sendMessage(new NetconfMessage(doc));
299
300             final Element rpcReply = message.getDocument().getDocumentElement();
301             final XmlElement resultElement = XmlElement.fromDomElement(rpcReply).getOnlyChildElement();
302             assertEquals("result", resultElement.getName());
303
304             final String namespace = resultElement.getNamespaceAttribute();
305             assertEquals(expectedNamespace, namespace);
306         }
307     }
308
309     private void registerRuntimeBean() {
310         BaseJMXRegistrator baseJMXRegistrator = new BaseJMXRegistrator(ManagementFactory.getPlatformMBeanServer());
311         RootRuntimeBeanRegistratorImpl runtimeBeanRegistrator = baseJMXRegistrator
312                 .createRuntimeBeanRegistrator(new ModuleIdentifier(NetconfTestImplModuleFactory.NAME, "instance"));
313         NetconfTestImplRuntimeRegistrator reg = new NetconfTestImplRuntimeRegistrator(runtimeBeanRegistrator);
314         reg.register(new NetconfTestImplRuntimeMXBean() {
315             @Override
316             public Asdf getAsdf() {
317                 return null;
318             }
319
320             @Override
321             public Long getCreatedSessions() {
322                 return null;
323             }
324
325             @Override
326             public String noArg(String arg1) {
327                 return "from no arg";
328             }
329         });
330     }
331
332     @Test
333 //    @Ignore
334     public void testStartExi() throws Exception {
335         try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
336
337
338             Document rpcReply = netconfClient.sendMessage(this.startExi)
339                     .getDocument();
340             assertIsOK(rpcReply);
341
342             ExiParameters exiParams = new ExiParameters();
343             exiParams.setParametersFromXmlElement(XmlElement.fromDomDocument(this.startExi.getDocument()));
344
345             netconfClient.getClientSession().addExiDecoder(ExiDecoderHandler.HANDLER_NAME, new ExiDecoderHandler(exiParams));
346             netconfClient.getClientSession().addExiEncoder(ExiEncoderHandler.HANDLER_NAME, new ExiEncoderHandler(exiParams));
347
348             rpcReply = netconfClient.sendMessage(this.editConfig)
349                     .getDocument();
350             assertIsOK(rpcReply);
351
352             rpcReply = netconfClient.sendMessage(this.stopExi)
353                     .getDocument();
354             assertIsOK(rpcReply);
355
356         }
357     }
358
359     @Test
360     public void testCloseSession() throws Exception {
361         try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
362
363             // edit config
364             Document rpcReply = netconfClient.sendMessage(this.editConfig)
365                     .getDocument();
366             assertIsOK(rpcReply);
367
368             rpcReply = netconfClient.sendMessage(this.closeSession)
369                     .getDocument();
370
371             assertIsOK(rpcReply);
372         }
373     }
374
375     @Test
376     public void testEditConfig() throws Exception {
377         try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
378             // send edit_config.xml
379             final Document rpcReply = netconfClient.sendMessage(this.editConfig).getDocument();
380             assertIsOK(rpcReply);
381         }
382     }
383
384     @Test
385     public void testValidate() throws Exception {
386         try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
387             // begin transaction
388             Document rpcReply = netconfClient.sendMessage(getConfigCandidate).getDocument();
389             assertEquals("data", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
390
391             // operations empty
392             rpcReply = netconfClient.sendMessage(XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/validate.xml"))
393                     .getDocument();
394             assertIsOK(rpcReply);
395         }
396     }
397
398     private void assertIsOK(final Document rpcReply) {
399         assertEquals("rpc-reply", rpcReply.getDocumentElement().getLocalName());
400         assertEquals("ok", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
401     }
402
403     @Ignore
404     @Test
405     // TODO can only send NetconfMessage - it must be valid xml
406     public void testClientHelloWithAuth() throws Exception {
407         final String fileName = "netconfMessages/client_hello_with_auth.xml";
408         // final InputStream resourceAsStream =
409         // AbstractListenerTest.class.getResourceAsStream(fileName);
410         // assertNotNull(resourceAsStream);
411         try (NetconfClient netconfClient = new NetconfClient("test", tcpAddress, 5000, clientDispatcher)) {
412             // IOUtils.copy(resourceAsStream, netconfClient.getStream());
413             // netconfClient.getOutputStream().write(NetconfMessageFactory.endOfMessage);
414             // server should not write anything back
415             // assertEquals(null, netconfClient.readMessage());
416             assertGetConfigWorks(netconfClient);
417         }
418     }
419
420     private Document assertGetConfigWorks(final NetconfClient netconfClient) throws InterruptedException {
421         return assertGetConfigWorks(netconfClient, this.getConfig);
422     }
423
424     private Document assertGetConfigWorks(final NetconfClient netconfClient, final NetconfMessage getConfigMessage)
425             throws InterruptedException {
426         final NetconfMessage rpcReply = netconfClient.sendMessage(getConfigMessage);
427         assertNotNull(rpcReply);
428         assertEquals("data", XmlElement.fromDomDocument(rpcReply.getDocument()).getOnlyChildElement().getName());
429         return rpcReply.getDocument();
430     }
431
432     @Test
433     public void testGetConfig() throws Exception {
434         try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
435             assertGetConfigWorks(netconfClient);
436         }
437     }
438
439     @Test
440     public void createYangTestBasedOnYuma() throws Exception {
441         try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
442             Document rpcReply = netconfClient.sendMessage(
443                     XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_yang-test.xml"))
444                     .getDocument();
445             assertEquals("rpc-reply", rpcReply.getDocumentElement().getTagName());
446             assertIsOK(rpcReply);
447             assertGetConfigWorks(netconfClient, this.getConfigCandidate);
448             rpcReply = netconfClient.sendMessage(XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/commit.xml"))
449                     .getDocument();
450             assertIsOK(rpcReply);
451
452             final ObjectName on = new ObjectName(
453                     "org.opendaylight.controller:instanceName=impl-dep-instance,type=Module,moduleFactoryName=impl-dep");
454             Set<ObjectName> cfgBeans = configRegistryClient.lookupConfigBeans();
455             assertEquals(cfgBeans, Sets.newHashSet(on));
456         }
457     }
458
459     private NetconfClient createSession(final InetSocketAddress address, final String expected) throws Exception {
460         final NetconfClient netconfClient = new NetconfClient("test " + address.toString(), address, 5000, clientDispatcher);
461         assertEquals(expected, Long.toString(netconfClient.getSessionId()));
462         return netconfClient;
463     }
464
465     private void startSSHServer() throws Exception{
466         logger.info("Creating SSH server");
467         Thread sshServerThread = new Thread(NetconfSSHServer.start(10830,tcpAddress));
468         sshServerThread.setDaemon(true);
469         sshServerThread.start();
470         logger.info("SSH server on");
471     }
472
473     @Test
474     public void sshTest() throws Exception {
475         startSSHServer();
476         logger.info("creating connection");
477         Connection conn = new Connection(sshAddress.getHostName(),sshAddress.getPort());
478         Assert.assertNotNull(conn);
479         logger.info("connection created");
480         conn.connect();
481         boolean isAuthenticated = conn.authenticateWithPassword(USERNAME,PASSWORD);
482         assertTrue(isAuthenticated);
483         logger.info("user authenticated");
484         final Session sess = conn.openSession();
485         sess.startSubSystem("netconf");
486         logger.info("user authenticated");
487         sess.getStdin().write(XmlUtil.toString(this.getConfig.getDocument()).getBytes());
488
489         new Thread(){
490            public void run(){
491                while (true){
492                  byte[] bytes = new byte[1024];
493                    int c = 0;
494                    try {
495                        c = sess.getStdout().read(bytes);
496                    } catch (IOException e) {
497                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
498                    }
499                    logger.info("got data:"+bytes);
500                  if (c == 0) break;
501                }
502            }
503         }.join();
504     }
505
506
507 }