diff options
author | Maros Marsalek <mmarsale@cisco.com> | 2016-05-18 15:05:51 +0200 |
---|---|---|
committer | Maros Marsalek <mmarsale@cisco.com> | 2016-05-24 08:36:34 +0000 |
commit | f9b2551eae7b4410b6910a05f19413b9b83137d4 (patch) | |
tree | 476f11bd2fdf611083ffe5e6363620046f37eca8 /v3po | |
parent | d421438681e97ef7213a5cb925c49755cd9fb4b6 (diff) |
HONEYCOMB-61: Restore configuration and context from persisted files
Change-Id: I6edce127f8895f5d65998b4be71a0a111ca2e8bb
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'v3po')
31 files changed, 886 insertions, 281 deletions
diff --git a/v3po/data-api/src/main/yang/data-api.yang b/v3po/data-api/src/main/yang/data-api.yang index 11d963e4b..693a73acd 100644 --- a/v3po/data-api/src/main/yang/data-api.yang +++ b/v3po/data-api/src/main/yang/data-api.yang @@ -29,4 +29,10 @@ module data-api { config:java-class io.fd.honeycomb.v3po.data.ModifiableDataManager; } + typedef datatree-type { + type enumeration { + enum config; + enum oper; + } + } }
\ No newline at end of file diff --git a/v3po/data-impl/pom.xml b/v3po/data-impl/pom.xml index 46faab7a2..1d716a6d9 100644 --- a/v3po/data-impl/pom.xml +++ b/v3po/data-impl/pom.xml @@ -49,10 +49,6 @@ <artifactId>mdsal-binding-dom-codec</artifactId> </dependency> <dependency> - <groupId>org.opendaylight.yangtools</groupId> - <artifactId>yang-data-codec-gson</artifactId> - </dependency> - <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-core-api</artifactId> <version>1.3.0-Beryllium</version> <!-- FIXME use dependency management --> diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java index a54b7f148..df5bbee4b 100644 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java @@ -18,33 +18,22 @@ package io.fd.honeycomb.v3po.data.impl; import static com.google.common.base.Preconditions.checkArgument; -import com.google.common.base.Charsets; import com.google.common.base.Optional; -import com.google.gson.stream.JsonWriter; +import io.fd.honeycomb.v3po.translate.util.JsonUtils; import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import javax.annotation.Nonnull; import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; -import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; -import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactory; -import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter; -import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,17 +71,16 @@ public class PersistingDataTreeAdapter implements org.opendaylight.yangtools.yan private Path testPersistPath(final Path persistPath) { try { checkArgument(!Files.isDirectory(persistPath), "Path %s points to a directory", persistPath); + if(Files.exists(persistPath)) { + checkArgument(Files.isReadable(persistPath), + "Provided path %s points to existing, but non-readable file", persistPath); + return persistPath; + } Files.createDirectories(persistPath.getParent()); Files.write(persistPath, new byte[]{}, StandardOpenOption.CREATE); } catch (IOException | UnsupportedOperationException e) { LOG.warn("Provided path for persistence: {} is not usable", persistPath, e); throw new IllegalArgumentException("Path " + persistPath + " cannot be used as "); - } finally { - try { - Files.delete(persistPath); - } catch (IOException e) { - LOG.warn("Unable to delete file at {}", persistPath, e); - } } return persistPath; @@ -131,17 +119,8 @@ public class PersistingDataTreeAdapter implements org.opendaylight.yangtools.yan if(Files.exists(path)) { Files.delete(path); } - // TODO once we are in static environment, do the writer, streamWriter and NNWriter initialization only once - final JsonWriter - jsonWriter = createJsonWriter(Files.newOutputStream(path, StandardOpenOption.CREATE), true); - final NormalizedNodeStreamWriter streamWriter = JSONNormalizedNodeStreamWriter - .createNestedWriter(JSONCodecFactory.create(schemaServiceDependency.getGlobalContext()), SchemaPath.ROOT, null, jsonWriter); - final NormalizedNodeWriter normalizedNodeWriter = - NormalizedNodeWriter.forStreamWriter(streamWriter, true); - jsonWriter.beginObject(); - writeChildren(normalizedNodeWriter,(ContainerNode) currentRoot.get()); - jsonWriter.endObject(); - jsonWriter.flush(); + JsonUtils.writeJsonRoot(currentRoot.get(), schemaServiceDependency.getGlobalContext(), + Files.newOutputStream(path, StandardOpenOption.CREATE)); LOG.trace("Data persisted successfully in {}", path); } catch (IOException e) { throw new IllegalStateException("Unable to persist current data", e); @@ -151,20 +130,6 @@ public class PersistingDataTreeAdapter implements org.opendaylight.yangtools.yan } } - private void writeChildren(final NormalizedNodeWriter nnWriter, final ContainerNode data) throws IOException { - for(final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> child : data.getValue()) { - nnWriter.write(child); - } - } - - private JsonWriter createJsonWriter(final OutputStream entityStream, boolean prettyPrint) { - if (prettyPrint) { - return JsonWriterFactory.createJsonWriter(new OutputStreamWriter(entityStream, Charsets.UTF_8), 2); - } else { - return JsonWriterFactory.createJsonWriter(new OutputStreamWriter(entityStream, Charsets.UTF_8)); - } - } - @Override public YangInstanceIdentifier getRootPath() { return delegateDependency.getRootPath(); diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java index 3644a9fe7..ac4ba9049 100644 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java @@ -77,11 +77,11 @@ final class WriteTransaction implements DOMDataWriteTransaction { final java.util.function.Consumer<DataModification> r) { switch (store) { case CONFIGURATION: - checkArgument(configModification != null, "Modification of {} is not supported", store); + checkArgument(configModification != null, "Modification of %s is not supported", store); r.accept(configModification); break; case OPERATIONAL: - checkArgument(operationalModification != null, "Modification of {} is not supported", store); + checkArgument(operationalModification != null, "Modification of %s is not supported", store); r.accept(operationalModification); break; } diff --git a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java index 54c830ec0..956aa90f4 100644 --- a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java +++ b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java @@ -1,5 +1,6 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.api.rev160411.DatatreeType; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.tree.*; import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; diff --git a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java index aa57f4d9b..145fc4345 100644 --- a/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java +++ b/v3po/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java @@ -1,6 +1,8 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411; +import java.nio.file.InvalidPathException; import java.nio.file.Paths; +import org.opendaylight.controller.config.api.JmxAttributeValidationException; public class PersistingDataTreeAdapterModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.AbstractPersistingDataTreeAdapterModule { @@ -18,7 +20,11 @@ public class PersistingDataTreeAdapterModule extends @Override public void customValidation() { - // add custom validation form module attributes here. + try { + Paths.get(getPersistFilePath()); + } catch (InvalidPathException e) { + throw new JmxAttributeValidationException("Invalid persist path", e, persistFilePathJmxAttribute); + } } @Override diff --git a/v3po/data-impl/src/main/yang/data-impl.yang b/v3po/data-impl/src/main/yang/data-impl.yang index 3af9d8d3f..a6b217a84 100644 --- a/v3po/data-impl/src/main/yang/data-impl.yang +++ b/v3po/data-impl/src/main/yang/data-impl.yang @@ -24,13 +24,6 @@ module data-impl { config:java-name-prefix InMemoryDataTree; } - typedef datatree-type { - type enumeration { - enum config; - enum oper; - } - } - augment "/config:modules/config:module/config:configuration" { case inmemory-data-tree { when "/config:modules/config:module/config:type = 'inmemory-data-tree'"; @@ -45,7 +38,7 @@ module data-impl { } leaf type { - type datatree-type; + type dapi:datatree-type; } } } diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java index 986d7cfb1..523d9dd70 100644 --- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java @@ -16,17 +16,12 @@ package io.fd.honeycomb.v3po.data.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import com.google.common.io.ByteStreams; import java.nio.file.Files; import java.nio.file.Path; import org.junit.Before; @@ -34,28 +29,12 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; -import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.EffectiveSchemaContext; public class PersistingDataTreeAdapterTest { - public static final String NAMESPACE = "urn:opendaylight:params:xml:ns:yang:test:persistence"; - - // The root QNAME can be anything, onyl its children are iterated - private static final QName ROOT_QNAME = QName.create("random", "data"); - private static final QName TOP_CONTAINER_NAME = QName.create(NAMESPACE, "2015-01-05", "top-container"); - private static final QName STRING_LEAF_QNAME = QName.create(TOP_CONTAINER_NAME, "string"); - @Mock private DataTree delegatingDataTree; @Mock @@ -71,47 +50,10 @@ public class PersistingDataTreeAdapterTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); tmpPersistFile = Files.createTempFile("testing-hc-persistence", "json"); - - // Build test yang schemas - final CrossSourceStatementReactor.BuildAction buildAction = YangInferencePipeline.RFC6020_REACTOR.newBuild(); - buildAction.addSource(new YangStatementSourceImpl(getClass().getResourceAsStream("/test-persistence.yang"))); - final EffectiveSchemaContext effectiveSchemaContext = buildAction.buildEffective(); - doReturn(effectiveSchemaContext).when(schemaService).getGlobalContext(); - persistingDataTreeAdapter = new PersistingDataTreeAdapter(delegatingDataTree, schemaService, tmpPersistFile); } @Test - public void testPersist() throws Exception { - doReturn(snapshot).when(delegatingDataTree).takeSnapshot(); - - NormalizedNode<?, ?> data = getData("testing"); - doReturn(com.google.common.base.Optional.of(data)).when(snapshot).readNode(YangInstanceIdentifier.EMPTY); - persistingDataTreeAdapter.commit(null); - assertTrue(Files.exists(tmpPersistFile)); - - String persisted = new String(Files.readAllBytes(tmpPersistFile)); - String expected = - new String(ByteStreams.toByteArray(getClass().getResourceAsStream("/expected-persisted-output.txt"))); - - assertEquals(expected, persisted); - - data = getData("testing2"); - doReturn(com.google.common.base.Optional.of(data)).when(snapshot).readNode(YangInstanceIdentifier.EMPTY); - persistingDataTreeAdapter.commit(null); - - verify(delegatingDataTree, times(2)).commit(null); - - persisted = new String(Files.readAllBytes(tmpPersistFile)); - assertEquals(expected.replace("testing", "testing2"), persisted); - - persistingDataTreeAdapter.close(); - - // File has to stay even after close - assertTrue(Files.exists(tmpPersistFile)); - } - - @Test public void testNoPersistOnFailure() throws Exception { doThrow(new IllegalStateException("testing errors")).when(delegatingDataTree).commit(any(DataTreeCandidate.class)); @@ -119,19 +61,9 @@ public class PersistingDataTreeAdapterTest { persistingDataTreeAdapter.commit(null); fail("Exception expected"); } catch (IllegalStateException e) { - assertFalse(Files.exists(tmpPersistFile)); verify(delegatingDataTree, times(0)).takeSnapshot(); verify(delegatingDataTree).commit(any(DataTreeCandidate.class)); } } - private NormalizedNode<?, ?> getData(final String stringValue) { - return Builders.containerBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(ROOT_QNAME)) - .withChild(Builders.containerBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_NAME)) - .withChild(ImmutableNodes.leafNode(STRING_LEAF_QNAME, stringValue)) - .build()) - .build(); - } }
\ No newline at end of file diff --git a/v3po/data-impl/src/test/resources/expected-persisted-output.txt b/v3po/data-impl/src/test/resources/expected-persisted-output.txt deleted file mode 100644 index fb21d61e8..000000000 --- a/v3po/data-impl/src/test/resources/expected-persisted-output.txt +++ /dev/null @@ -1,5 +0,0 @@ -{ - "test-persistence:top-container": { - "string": "testing" - } -}
\ No newline at end of file diff --git a/v3po/features/pom.xml b/v3po/features/pom.xml index 1233f7d96..b79e62d92 100644 --- a/v3po/features/pom.xml +++ b/v3po/features/pom.xml @@ -133,6 +133,13 @@ <artifactId>v3po-impl</artifactId> <version>${project.version}</version> <type>xml</type> + <classifier>init</classifier> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>v3po-impl</artifactId> + <version>${project.version}</version> + <type>xml</type> <classifier>context</classifier> </dependency> <dependency> diff --git a/v3po/features/src/main/features/features.xml b/v3po/features/src/main/features/features.xml index 66e57fce5..1e5f28f8c 100644 --- a/v3po/features/src/main/features/features.xml +++ b/v3po/features/src/main/features/features.xml @@ -49,6 +49,7 @@ <configfile finalname="${configfile.directory}/vpp-jvpp.xml">mvn:io.fd.honeycomb.v3po/vpp-jvpp-cfg/${project.version}/xml/config</configfile> <configfile finalname="${configfile.directory}/v3po-context.xml">mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/context</configfile> <configfile finalname="${configfile.directory}/v3po.xml">mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/config</configfile> + <configfile finalname="${configfile.directory}/v3po-init.xml">mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/init</configfile> <configfile finalname="${configfile.directory}/v3po-netconf.xml">mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/netconf</configfile> <configfile finalname="${configfile.directory}/v3po-restconf.xml">mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/restconf</configfile> <configfile finalname="${configfile.directory}/v3po2vpp.xml">mvn:io.fd.honeycomb.v3po/v3po2vpp/${project.version}/xml/config</configfile> diff --git a/v3po/impl/pom.xml b/v3po/impl/pom.xml index 6db420bef..6f4f4e172 100644 --- a/v3po/impl/pom.xml +++ b/v3po/impl/pom.xml @@ -111,6 +111,11 @@ <classifier>netconf</classifier> </artifact> <artifact> + <file>src/main/config/initializer-config.xml</file> + <type>xml</type> + <classifier>init</classifier> + </artifact> + <artifact> <file>src/main/config/context-datatree-config.xml</file> <type>xml</type> <classifier>context</classifier> diff --git a/v3po/impl/src/main/config/default-config.xml b/v3po/impl/src/main/config/default-config.xml index 7106c78ce..961ca72c0 100644 --- a/v3po/impl/src/main/config/default-config.xml +++ b/v3po/impl/src/main/config/default-config.xml @@ -19,7 +19,6 @@ <capability>urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&revision=2014-12-10</capability> <capability>urn:honeycomb:params:xml:ns:yang:translate:utils?module=translate-utils&revision=2016-04-06</capability> <capability>urn:honeycomb:params:xml:ns:yang:vpp:jvpp:cfg?module=vpp-jvpp-cfg&revision=2016-04-06</capability> - <capability>urn:honeycomb:params:xml:ns:yang:vpp:data:init?module=vpp-cfg-init&revision=2016-04-07</capability> <capability>urn:honeycomb:params:xml:ns:yang:data:api?module=data-api&revision=2016-04-11</capability> <capability>urn:honeycomb:params:xml:ns:yang:data:impl?module=data-impl&revision=2016-04-11</capability> <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability> @@ -209,85 +208,6 @@ <name>honeycomb-dom-data-broker</name> </honeycomb-dom-data-broker> </module> - - <!-- Config initialization --> - <!-- Empty registry which does not pass data to VPP --> - <module> - <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:utils">prefix:noop-writer-registry</type> - <name>noop-writer-registry</name> - </module> - <!-- Config data tree which does not pass data to translation layer (uses noop-write-registry) --> - <module> - <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:honeycomb-config-data-tree</type> - <name>cfg-init-config-data-tree</name> - - <!--FIXME do we need/want persistence here ? Do initializers only merge the data ? --> - <!-- Without persistence --> - <!--<data-tree>--> - <!--<type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:data-tree</type>--> - <!--<name>inmemory-config-data-tree</name>--> - <!--</data-tree>--> - <!-- With persistence --> - <data-tree> - <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type> - <name>inmemory-persisted-config-data-tree</name> - </data-tree> - - <serializer> - <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</type> - <name>runtime-mapping-singleton</name> - </serializer> - <writer-registry> - <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry</type> - <name>noop-writer-registry</name> - </writer-registry> - <context-binding-broker> - <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type> - <name>honeycomb-context-binding-data-broker</name> - </context-binding-broker> - </module> - <!-- DOM data broker for config initialization --> - <module> - <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:honeycomb-dom-data-broker</type> - <name>cfg-init-dom-data-broker</name> - <config-data-tree> - <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type> - <name>cfg-init-config-data-tree</name> - </config-data-tree> - <operational-data-tree> - <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-readable-data-tree</type> - <name>operational-data-tree</name> - </operational-data-tree> - </module> - <!-- Binding data broker for config initialization --> - <module> - <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type> - <name>cfg-init-binding-data-broker</name> - <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl"> - <dom-async-broker> - <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type> - <name>cfg-init-dom-data-broker</name> - </dom-async-broker> - <schema-service> - <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type> - <name>yang-schema-service</name> - </schema-service> - <binding-mapping-service> - <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type> - <name>runtime-mapping-singleton</name> - </binding-mapping-service> - </binding-forwarded-data-broker> - </module> - <!-- Config initializer --> - <module> - <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:vpp-cfg-initializer-impl</type> - <name>vpp-cfg-initializer</name> - <binding-data-broker> - <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-async-data-broker</type> - <name>cfg-init-binding-data-broker</name> - </binding-data-broker> - </module>noop-writer-registry - <!-- END: Config initialization --> </modules> <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config"> @@ -388,46 +308,6 @@ </instance> </service> - <!-- Config initialization --> - <service> - <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry</type> - <instance> - <name>noop-writer-registry</name> - <provider>/modules/module[type='noop-writer-registry'][name='noop-writer-registry']</provider> - </instance> - </service> - <service> - <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type> - <instance> - <name>cfg-init-config-data-tree</name> - <provider>/modules/module[type='honeycomb-config-data-tree'][name='cfg-init-config-data-tree'] - </provider> - </instance> - </service> - <service> - <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type> - <instance> - <name>cfg-init-dom-data-broker</name> - <provider>/modules/module[type='honeycomb-dom-data-broker'][name='cfg-init-dom-data-broker']</provider> - </instance> - </service> - <service> - <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type> - <instance> - <name>cfg-init-binding-data-broker</name> - <provider>/modules/module[type='binding-forwarded-data-broker'][name='cfg-init-binding-data-broker']</provider> - </instance> - </service> - <service> - <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:vpp-cfg-initializer</type> - <instance> - <name>vpp-cfg-initializer</name> - <provider>/modules/module[type='vpp-cfg-initializer-impl'][name='vpp-cfg-initializer'] - </provider> - </instance> - </service> - <!-- END: Config initialization --> - </services> </data> </configuration> diff --git a/v3po/impl/src/main/config/initializer-config.xml b/v3po/impl/src/main/config/initializer-config.xml new file mode 100644 index 000000000..c5ee10f91 --- /dev/null +++ b/v3po/impl/src/main/config/initializer-config.xml @@ -0,0 +1,224 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (c) 2016 Cisco and/or its affiliates. + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at: + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<!-- vi: set et smarttab sw=4 tabstop=4: --> + +<snapshot> + <required-capabilities> + <capability>urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&revision=2014-12-10</capability> + <capability>urn:honeycomb:params:xml:ns:yang:translate:utils?module=translate-utils&revision=2016-04-06</capability> + <capability>urn:honeycomb:params:xml:ns:yang:vpp:jvpp:cfg?module=vpp-jvpp-cfg&revision=2016-04-06</capability> + <capability>urn:honeycomb:params:xml:ns:yang:vpp:data:init?module=vpp-cfg-init&revision=2016-04-07</capability> + <capability>urn:honeycomb:params:xml:ns:yang:data:api?module=data-api&revision=2016-04-11</capability> + <capability>urn:honeycomb:params:xml:ns:yang:data:impl?module=data-impl&revision=2016-04-11</capability> + <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability> + </required-capabilities> + <configuration> + + <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> + <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config"> + <!-- Config initialization --> + <!-- Empty registry which does not pass data to VPP --> + <module> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:utils">prefix:noop-writer-registry</type> + <name>noop-writer-registry</name> + </module> + <!-- Config data tree which does not pass data to translation layer (uses noop-write-registry) --> + <module> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:honeycomb-config-data-tree</type> + <name>cfg-init-config-data-tree</name> + <!-- Without persistence --> + <data-tree> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type> + <name>inmemory-config-data-tree</name> + </data-tree> + <serializer> + <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</type> + <name>runtime-mapping-singleton</name> + </serializer> + <writer-registry> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry</type> + <name>noop-writer-registry</name> + </writer-registry> + <context-binding-broker> + <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type> + <name>honeycomb-context-binding-data-broker</name> + </context-binding-broker> + </module> + <!-- DOM data broker for config initialization --> + <module> + <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:honeycomb-dom-data-broker</type> + <name>cfg-init-dom-data-broker</name> + <config-data-tree> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type> + <name>cfg-init-config-data-tree</name> + </config-data-tree> + <operational-data-tree> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-readable-data-tree</type> + <name>operational-data-tree</name> + </operational-data-tree> + </module> + <!-- Binding data broker for config initialization --> + <module> + <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type> + <name>cfg-init-binding-data-broker</name> + <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl"> + <dom-async-broker> + <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type> + <name>cfg-init-dom-data-broker</name> + </dom-async-broker> + <schema-service> + <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type> + <name>yang-schema-service</name> + </schema-service> + <binding-mapping-service> + <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type> + <name>runtime-mapping-singleton</name> + </binding-mapping-service> + </binding-forwarded-data-broker> + </module> + <!-- Config initializer for VPP subtree--> + <module> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:vpp-cfg-initializer</type> + <name>vpp-cfg-initializer</name> + <binding-data-broker> + <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-async-data-broker</type> + <name>cfg-init-binding-data-broker</name> + </binding-data-broker> + </module> + <!-- Config initializer for Interfaces subtree--> + <module> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:interfaces-cfg-initializer</type> + <name>interfaces-cfg-initializer</name> + <binding-data-broker> + <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-async-data-broker</type> + <name>cfg-init-binding-data-broker</name> + </binding-data-broker> + </module> + <module> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:persisted-file-initializer</type> + <name>persisted-context-initializer</name> + <dom-data-broker> + <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type> + <name>honeycomb-context-data-broker</name> + </dom-data-broker> + <schema-service> + <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type> + <name>yang-schema-service</name> + </schema-service> + <persist-file-path>etc/opendaylight/honeycomb/context.json</persist-file-path> + <restoration-type>merge</restoration-type> + <datastore-type>oper</datastore-type> + </module> + <module> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:persisted-file-initializer</type> + <name>persisted-config-initializer</name> + <dom-data-broker> + <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-async-data-broker</type> + <name>honeycomb-dom-data-broker</name> + </dom-data-broker> + <schema-service> + <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type> + <name>yang-schema-service</name> + </schema-service> + <persist-file-path>etc/opendaylight/honeycomb/config.json</persist-file-path> + <restoration-type>merge</restoration-type> + <datastore-type>config</datastore-type> + </module> + + <module> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer-registry</type> + <name>initializer-registry</name> + <persisted-context-initializer> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type> + <name>persisted-context-initializer</name> + </persisted-context-initializer> + <initializers> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type> + <name>vpp-cfg-initializer</name> + </initializers> + <initializers> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type> + <name>interfaces-cfg-initializer</name> + </initializers> + <persisted-config-initializer> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type> + <name>persisted-config-initializer</name> + </persisted-config-initializer> + </module> + <!-- END: Config initialization --> + </modules> + + <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config"> + <!-- Config initialization --> + <service> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry</type> + <instance> + <name>noop-writer-registry</name> + <provider>/modules/module[type='noop-writer-registry'][name='noop-writer-registry']</provider> + </instance> + </service> + <service> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type> + <instance> + <name>cfg-init-config-data-tree</name> + <provider>/modules/module[type='honeycomb-config-data-tree'][name='cfg-init-config-data-tree'] + </provider> + </instance> + </service> + <service> + <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type> + <instance> + <name>cfg-init-dom-data-broker</name> + <provider>/modules/module[type='honeycomb-dom-data-broker'][name='cfg-init-dom-data-broker']</provider> + </instance> + </service> + <service> + <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type> + <instance> + <name>cfg-init-binding-data-broker</name> + <provider>/modules/module[type='binding-forwarded-data-broker'][name='cfg-init-binding-data-broker']</provider> + </instance> + </service> + + <service> + <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type> + <instance> + <name>vpp-cfg-initializer</name> + <provider>/modules/module[type='vpp-cfg-initializer'][name='vpp-cfg-initializer'] + </provider> + </instance> + <instance> + <name>interfaces-cfg-initializer</name> + <provider>/modules/module[type='interfaces-cfg-initializer'][name='interfaces-cfg-initializer'] + </provider> + </instance> + <instance> + <name>persisted-context-initializer</name> + <provider>/modules/module[type='persisted-file-initializer'][name='persisted-context-initializer'] + </provider> + </instance> + <instance> + <name>persisted-config-initializer</name> + <provider>/modules/module[type='persisted-file-initializer'][name='persisted-config-initializer'] + </provider> + </instance> + </service> + </services> + </data> + </configuration> +</snapshot> diff --git a/v3po/translate-utils/pom.xml b/v3po/translate-utils/pom.xml index 346757cc2..9cb6590d8 100644 --- a/v3po/translate-utils/pom.xml +++ b/v3po/translate-utils/pom.xml @@ -66,6 +66,10 @@ <groupId>org.opendaylight.mdsal</groupId> <artifactId>mdsal-binding-dom-codec</artifactId> </dependency> + <dependency> + <groupId>org.opendaylight.yangtools</groupId> + <artifactId>yang-data-codec-gson</artifactId> + </dependency> <!-- Testing Dependencies --> <dependency> diff --git a/v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/JsonUtils.java b/v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/JsonUtils.java new file mode 100644 index 000000000..be6ffa235 --- /dev/null +++ b/v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/JsonUtils.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.util; + +import com.google.common.base.Charsets; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter; +import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactory; +import org.opendaylight.yangtools.yang.data.codec.gson.JSONNormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream; +import org.opendaylight.yangtools.yang.data.codec.gson.JsonWriterFactory; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; + +public class JsonUtils { + + private JsonUtils() {} + + /** + * Serialize normalized node root structure into provided output stream + * + * @throws IOException if serialized data cannot be written into provided output stream + */ + public static void writeJsonRoot(@Nonnull final NormalizedNode<?, ?> rootData, + @Nonnull final SchemaContext schemaContext, + @Nonnull final OutputStream outputStream) throws IOException { + final JsonWriter + jsonWriter = createJsonWriter(outputStream, true); + final NormalizedNodeStreamWriter streamWriter = JSONNormalizedNodeStreamWriter + .createNestedWriter(JSONCodecFactory.create(schemaContext), SchemaPath.ROOT, null, jsonWriter); + final NormalizedNodeWriter normalizedNodeWriter = + NormalizedNodeWriter.forStreamWriter(streamWriter, true); + jsonWriter.beginObject(); + writeChildren(normalizedNodeWriter,(ContainerNode) rootData); + jsonWriter.endObject(); + jsonWriter.flush(); + } + + /** + * Read json serialized normalized node root structure and parse them into normalized nodes + * + * @return artificial normalized node holding all the top level nodes from provided stream as children. In case + * the stream is empty, empty artificial normalized node is returned + * + * @throws IllegalArgumentException if content in the provided input stream is not restore-able + */ + public static ContainerNode readJsonRoot(@Nonnull final SchemaContext schemaContext, + @Nonnull final InputStream stream) { + final DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> builder = + Builders.containerBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(schemaContext.getQName())); + final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(builder); + + final JsonParserStream jsonParser = JsonParserStream.create(writer, schemaContext); + final JsonReader reader = new JsonReader(new InputStreamReader(stream)); + jsonParser.parse(reader); + + return builder.build(); + } + + private static void writeChildren(final NormalizedNodeWriter nnWriter, final ContainerNode data) throws IOException { + for(final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> child : data.getValue()) { + nnWriter.write(child); + } + } + + private static JsonWriter createJsonWriter(final OutputStream entityStream, boolean prettyPrint) { + if (prettyPrint) { + return JsonWriterFactory.createJsonWriter(new OutputStreamWriter(entityStream, Charsets.UTF_8), 2); + } else { + return JsonWriterFactory.createJsonWriter(new OutputStreamWriter(entityStream, Charsets.UTF_8)); + } + } +} diff --git a/v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/JsonUtilsTest.java b/v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/JsonUtilsTest.java new file mode 100644 index 000000000..bd48cb446 --- /dev/null +++ b/v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/JsonUtilsTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.translate.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.google.common.io.ByteStreams; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.EffectiveSchemaContext; + +public class JsonUtilsTest { + + public static final String NAMESPACE = "urn:opendaylight:params:xml:ns:yang:test:persistence"; + + private static final QName ROOT_QNAME = QName.create("urn:ietf:params:xml:ns:netconf:base:1.0", "data"); + private static final QName TOP_CONTAINER_NAME = QName.create(NAMESPACE, "2015-01-05", "top-container"); + private static final QName TOP_CONTAINER2_NAME = QName.create(NAMESPACE, "2015-01-05", "top-container2"); + private static final QName STRING_LEAF_QNAME = QName.create(TOP_CONTAINER_NAME, "string"); + + private Path tmpPersistFile; + private EffectiveSchemaContext effectiveSchemaContext; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + tmpPersistFile = Files.createTempFile("testing-hc-persistence", "json"); + + final CrossSourceStatementReactor.BuildAction buildAction = YangInferencePipeline.RFC6020_REACTOR.newBuild(); + buildAction.addSource(new YangStatementSourceImpl(getClass().getResourceAsStream("/test-persistence.yang"))); + effectiveSchemaContext = buildAction.buildEffective(); + } + + @Test + public void testPersist() throws Exception { + + NormalizedNode<?, ?> data = getData("testing"); + JsonUtils.writeJsonRoot(data, effectiveSchemaContext, Files.newOutputStream(tmpPersistFile, StandardOpenOption.CREATE)); + assertTrue(Files.exists(tmpPersistFile)); + + String persisted = new String(Files.readAllBytes(tmpPersistFile)); + String expected = + new String(ByteStreams.toByteArray(getClass().getResourceAsStream("/expected-persisted-output.txt"))); + + assertEquals(expected, persisted); + + data = getData("testing2"); + JsonUtils.writeJsonRoot(data, effectiveSchemaContext, Files.newOutputStream(tmpPersistFile, StandardOpenOption.CREATE)); + persisted = new String(Files.readAllBytes(tmpPersistFile)); + assertEquals(expected.replace("testing", "testing2"), persisted); + + // File has to stay even after close + assertTrue(Files.exists(tmpPersistFile)); + } + + @Test + public void testRestore() throws Exception { + final ContainerNode normalizedNodeOptional = JsonUtils + .readJsonRoot(effectiveSchemaContext, getClass().getResourceAsStream("/expected-persisted-output.txt")); + assertEquals(getData("testing"), normalizedNodeOptional); + } + + @Test(expected = IllegalArgumentException.class) + public void testRestoreInvalidFile() throws Exception { + JsonUtils.readJsonRoot(effectiveSchemaContext, getClass().getResourceAsStream("/test-persistence.yang")); + } + + private ContainerNode getData(final String stringValue) { + return Builders.containerBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(ROOT_QNAME)) + .withChild(Builders.containerBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_NAME)) + .withChild(ImmutableNodes.leafNode(STRING_LEAF_QNAME, stringValue)) + .build()) + .withChild(Builders.containerBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER2_NAME)) + .withChild(ImmutableNodes.leafNode(STRING_LEAF_QNAME, stringValue)) + .build()) + .build(); + } +}
\ No newline at end of file diff --git a/v3po/translate-utils/src/test/resources/expected-persisted-output.txt b/v3po/translate-utils/src/test/resources/expected-persisted-output.txt new file mode 100644 index 000000000..f0f5902e2 --- /dev/null +++ b/v3po/translate-utils/src/test/resources/expected-persisted-output.txt @@ -0,0 +1,8 @@ +{ + "test-persistence:top-container": { + "string": "testing" + }, + "test-persistence:top-container2": { + "string": "testing" + } +}
\ No newline at end of file diff --git a/v3po/data-impl/src/test/resources/test-persistence.yang b/v3po/translate-utils/src/test/resources/test-persistence.yang index b7dbbb1bc..6dca9f2d5 100644 --- a/v3po/data-impl/src/test/resources/test-persistence.yang +++ b/v3po/translate-utils/src/test/resources/test-persistence.yang @@ -13,4 +13,10 @@ module test-persistence { } } + container top-container2 { + leaf string { + type string; + } + } + } diff --git a/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java b/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java index 3cb6f14e4..d760401f9 100644 --- a/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java +++ b/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java @@ -43,5 +43,9 @@ public interface DataTreeInitializer extends AutoCloseable { public InitializeException(final String message, final Throwable cause) { super(message, cause); } + + public InitializeException(final String msg) { + super(msg); + } } } diff --git a/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InterfacesInitializer.java b/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InterfacesInitializer.java index fde2a2893..9ecbe0c13 100644 --- a/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InterfacesInitializer.java +++ b/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InterfacesInitializer.java @@ -43,6 +43,8 @@ public class InterfacesInitializer extends AbstractDataTreeConverter<InterfacesS InstanceIdentifier.create(Interfaces.class)); } + // TODO move to v3po2vpp + @Override protected Interfaces convert(final InterfacesState operationalData) { LOG.debug("InterfacesInitializer.convert()"); diff --git a/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java b/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java new file mode 100644 index 000000000..eed22313c --- /dev/null +++ b/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.vpp.data.init; + +import static com.google.common.base.Preconditions.checkArgument; + +import io.fd.honeycomb.v3po.translate.util.JsonUtils; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.RestorationType; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; + +public class RestoringInitializer implements DataTreeInitializer { + + private final SchemaService schemaService; + private final Path path; + private final DOMDataBroker dataTree; + private final RestorationType restorationType; + private final LogicalDatastoreType datastoreType; + + public RestoringInitializer(@Nonnull final SchemaService schemaService, + @Nonnull final Path path, + @Nonnull final DOMDataBroker dataTree, + @Nonnull final RestorationType restorationType, + @Nonnull final LogicalDatastoreType datastoreType) { + this.schemaService = schemaService; + this.datastoreType = datastoreType; + this.path = checkStorage(path); + this.dataTree = dataTree; + this.restorationType = restorationType; + } + + private Path checkStorage(final Path path) { + try { + if(Files.exists(path)) { + checkArgument(!Files.isDirectory(path), "File %s is a directory", path); + checkArgument(Files.isReadable(path), "File %s is not readable", path); + } else { + return checkStorage(Files.createFile(path)); + } + } catch (IOException e) { + throw new IllegalArgumentException("Cannot use " + path + " for restoring data", e); + } + + return path; + } + + @Override + public void initialize() throws InitializeException { + if(!Files.exists(path)) { + return; + } + + try { + final ContainerNode containerNode = JsonUtils + .readJsonRoot(schemaService.getGlobalContext(), Files.newInputStream(path, StandardOpenOption.READ)); + + final DOMDataWriteTransaction domDataWriteTransaction = dataTree.newWriteOnlyTransaction(); + for (DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> dataContainerChild : containerNode + .getValue()) { + final YangInstanceIdentifier iid = YangInstanceIdentifier.create(dataContainerChild.getIdentifier()); + switch (restorationType) { + case Merge: + domDataWriteTransaction.merge(datastoreType, iid, dataContainerChild); + break; + case Put: + domDataWriteTransaction.put(datastoreType, iid, dataContainerChild); + break; + default: + throw new InitializeException( + "Unable to initialize data using " + restorationType + " restoration strategy. Unsupported"); + } + } + + // Block here to prevent subsequent initializers processing before context is fully restored + domDataWriteTransaction.submit().checkedGet(); + + } catch (IOException | TransactionCommitFailedException e) { + throw new InitializeException("Unable to restore data from " + path, e); + } + } + + @Override + public void close() {} +} diff --git a/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/VppInitializer.java b/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/VppInitializer.java index 77bb3a563..d7a67870a 100644 --- a/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/VppInitializer.java +++ b/v3po/vpp-cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/VppInitializer.java @@ -42,6 +42,8 @@ public class VppInitializer extends AbstractDataTreeConverter<VppState, Vpp> { super(bindingDataBroker, InstanceIdentifier.create(VppState.class), InstanceIdentifier.create(Vpp.class)); } + // TODO move to v3po2vpp + @Override protected Vpp convert(final VppState operationalData) { LOG.debug("VppInitializer.convert()"); diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java new file mode 100644 index 000000000..d80b9ed30 --- /dev/null +++ b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java @@ -0,0 +1,55 @@ +package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407; + +import io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistry; +import io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistryImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** +* Initializer registry, delegating initialization to a list of initializers +*/ +public class ConfigurationInitializerRegistryModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractConfigurationInitializerRegistryModule { + + private static final Logger LOG = LoggerFactory.getLogger(ConfigurationInitializerRegistryModule.class); + + public ConfigurationInitializerRegistryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public ConfigurationInitializerRegistryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.ConfigurationInitializerRegistryModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void customValidation() { + // add custom validation form module attributes here. + } + + @Override + public java.lang.AutoCloseable createInstance() { + LOG.info("VppConfigurationInitializerModule.createInstance(): initialization started"); + + final InitializerRegistry initializer = new InitializerRegistryImpl(getInitializersDependency()); + + try { + // Initialize contexts first so that other initializers can find any relevant mapping before initializing + // configuration to what is already in VPP + getPersistedContextInitializerDependency().initialize(); + LOG.info("Persisted context restored successfully"); + // Initialize all registered initializers + initializer.initialize(); + LOG.info("VPP configuration initialized successfully from VPP"); + // Initialize stored configuration on top + // FIXME uncomment and test +// getPersistedConfigInitializerDependency().initialize(); + LOG.info("Persisted configuration restored successfully"); + } catch (Exception e) { + LOG.warn("Failed to initialize config", e); + } + + LOG.info("Honeycomb initialized"); + + return initializer; + } + +} diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java new file mode 100644 index 000000000..f07be953e --- /dev/null +++ b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java @@ -0,0 +1,13 @@ +/* +* Generated file +* +* Generated from: yang module name: vpp-cfg-init yang module local name: cfg-initializer-registry +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed May 18 14:43:49 CEST 2016 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407; +public class ConfigurationInitializerRegistryModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractConfigurationInitializerRegistryModuleFactory { + +} diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModule.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModule.java new file mode 100644 index 000000000..51a7c482a --- /dev/null +++ b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModule.java @@ -0,0 +1,24 @@ +package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407; + +import io.fd.honeycomb.v3po.vpp.data.init.InterfacesInitializer; + +public class InterfacesConfigurationInitializerModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractInterfacesConfigurationInitializerModule { + public InterfacesConfigurationInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public InterfacesConfigurationInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.InterfacesConfigurationInitializerModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void customValidation() { + // add custom validation form module attributes here. + } + + @Override + public java.lang.AutoCloseable createInstance() { + return new InterfacesInitializer(getBindingDataBrokerDependency()); + } + +} diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModuleFactory.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModuleFactory.java new file mode 100644 index 000000000..b74947917 --- /dev/null +++ b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/InterfacesConfigurationInitializerModuleFactory.java @@ -0,0 +1,13 @@ +/* +* Generated file +* +* Generated from: yang module name: vpp-cfg-init yang module local name: interfaces-cfg-initializer +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed May 18 14:43:49 CEST 2016 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407; +public class InterfacesConfigurationInitializerModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractInterfacesConfigurationInitializerModuleFactory { + +} diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java new file mode 100644 index 000000000..188d1641c --- /dev/null +++ b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java @@ -0,0 +1,38 @@ +package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407; + +import io.fd.honeycomb.v3po.vpp.data.init.RestoringInitializer; +import java.nio.file.InvalidPathException; +import java.nio.file.Paths; +import org.opendaylight.controller.config.api.JmxAttributeValidationException; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.api.rev160411.DatatreeType; + +/** +* Initializer restoring data from a persisted file +*/ +public class PersistedFileInitializerModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractPersistedFileInitializerModule { + public PersistedFileInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public PersistedFileInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.PersistedFileInitializerModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void customValidation() { + try { + Paths.get(getPersistFilePath()); + } catch (InvalidPathException e) { + throw new JmxAttributeValidationException("Invalid persist path", e, persistFilePathJmxAttribute); + } + } + + @Override + public java.lang.AutoCloseable createInstance() { + return new RestoringInitializer(getSchemaServiceDependency(), Paths.get(getPersistFilePath()), + getDomDataBrokerDependency(), getRestorationType(), + getDatastoreType() == DatatreeType.Config ? LogicalDatastoreType.CONFIGURATION : LogicalDatastoreType.OPERATIONAL); + } + +} diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java new file mode 100644 index 000000000..1d7a3c9c6 --- /dev/null +++ b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java @@ -0,0 +1,13 @@ +/* +* Generated file +* +* Generated from: yang module name: vpp-cfg-init yang module local name: persisted-file-initializer +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed May 18 13:48:52 CEST 2016 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407; +public class PersistedFileInitializerModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractPersistedFileInitializerModuleFactory { + +} diff --git a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/VppConfigurationInitializerModule.java b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/VppConfigurationInitializerModule.java index ae83cb3fe..cc4f183fc 100644 --- a/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/VppConfigurationInitializerModule.java +++ b/v3po/vpp-cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/VppConfigurationInitializerModule.java @@ -1,12 +1,6 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407; -import io.fd.honeycomb.v3po.vpp.data.init.DataTreeInitializer; -import io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistry; -import io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistryImpl; -import io.fd.honeycomb.v3po.vpp.data.init.InterfacesInitializer; import io.fd.honeycomb.v3po.vpp.data.init.VppInitializer; -import java.util.Arrays; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,24 +28,7 @@ public class VppConfigurationInitializerModule extends @Override public java.lang.AutoCloseable createInstance() { - LOG.info("VppConfigurationInitializerModule.createInstance(): initialization started"); - final DataBroker bindingDataBroker = getBindingDataBrokerDependency(); - - final VppInitializer vppInitializer = new VppInitializer(bindingDataBroker); - final InterfacesInitializer interfacesInitializer = new InterfacesInitializer(bindingDataBroker); - - // TODO make configurable - final InitializerRegistry initializer = - new InitializerRegistryImpl(Arrays.<DataTreeInitializer>asList(vppInitializer, interfacesInitializer)); - - try { - initializer.initialize(); - } catch (Exception e) { - LOG.warn("Failed to initialize config", e); - } - LOG.info("VppConfigurationInitializerModule.createInstance(): initialization completed"); - - return initializer; + return new VppInitializer(getBindingDataBrokerDependency()); } } diff --git a/v3po/vpp-cfg-init/src/main/yang/vpp-cfg-init.yang b/v3po/vpp-cfg-init/src/main/yang/vpp-cfg-init.yang index e4ce95aea..024c930b7 100644 --- a/v3po/vpp-cfg-init/src/main/yang/vpp-cfg-init.yang +++ b/v3po/vpp-cfg-init/src/main/yang/vpp-cfg-init.yang @@ -5,6 +5,7 @@ module vpp-cfg-init { import config { prefix config; revision-date 2013-04-05; } import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;} + import opendaylight-md-sal-dom {prefix dom;} import translate-api { prefix tapi; revision-date 2016-04-06; } import data-api { prefix dapi; revision-date 2016-04-11; } @@ -16,20 +17,43 @@ module vpp-cfg-init { "Initial revision"; } - identity vpp-cfg-initializer { + identity cfg-initializer { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistry; + config:java-class io.fd.honeycomb.v3po.vpp.data.init.DataTreeInitializer; } - identity vpp-cfg-initializer-impl { + // TODO move to v3po2vpp + identity vpp-cfg-initializer { base config:module-type; - config:provided-service vpp-cfg-initializer; + config:provided-service cfg-initializer; config:java-name-prefix VppConfigurationInitializer; } augment "/config:modules/config:module/config:configuration" { - case vpp-cfg-initializer-impl { - when "/config:modules/config:module/config:type = 'vpp-cfg-initializer-impl'"; + case vpp-cfg-initializer { + when "/config:modules/config:module/config:type = 'vpp-cfg-initializer'"; + + container binding-data-broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity md-sal-binding:binding-async-data-broker; + } + } + } + } + } + + // TODO move to v3po2vpp + identity interfaces-cfg-initializer { + base config:module-type; + config:provided-service cfg-initializer; + config:java-name-prefix InterfacesConfigurationInitializer; + } + + augment "/config:modules/config:module/config:configuration" { + case interfaces-cfg-initializer { + when "/config:modules/config:module/config:type = 'interfaces-cfg-initializer'"; container binding-data-broker { uses config:service-ref { @@ -42,4 +66,95 @@ module vpp-cfg-init { } } + identity cfg-initializer-registry { + base config:module-type; + config:provided-service cfg-initializer; + config:java-name-prefix ConfigurationInitializerRegistry; + description "Initializer registry, delegating initialization to a list of initializers"; + } + + augment "/config:modules/config:module/config:configuration" { + case cfg-initializer-registry { + when "/config:modules/config:module/config:type = 'cfg-initializer-registry'"; + + list initializers { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity cfg-initializer; + } + } + } + + container persisted-context-initializer { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity cfg-initializer; + } + } + } + + container persisted-config-initializer { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity cfg-initializer; + } + } + } + } + } + + identity persisted-file-initializer { + base config:module-type; + config:provided-service cfg-initializer; + description "Initializer restoring data from a persisted file"; + } + + typedef restoration-type { + type enumeration { + enum merge; + enum put; + } + } + + augment "/config:modules/config:module/config:configuration" { + case persisted-file-initializer { + when "/config:modules/config:module/config:type = 'persisted-file-initializer'"; + + container dom-data-broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dom:dom-async-data-broker; + } + } + } + + container schema-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dom:schema-service; + } + } + } + + leaf persist-file-path { + type string; + } + + leaf restoration-type { + type restoration-type; + default merge; + } + + + leaf datastore-type { + type dapi:datatree-type; + } + } + } + }
\ No newline at end of file |