From 54a3992118f4455b99fee8f3a648145bcf2b8e65 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Thu, 11 Aug 2016 13:05:32 +0200 Subject: HONEYCOMB-23 Add plugin sample and sample minimal distribution Change-Id: Idbcdc5a52a9bfd3b90c039f1a1e58c258cd01849 Signed-off-by: Maros Marsalek --- samples/interfaces/Readme.adoc | 10 ++ samples/interfaces/mapping/pom.xml | 79 ++++++++++++++++ .../interfaces/mapping/LowerLayerAccess.java | 71 ++++++++++++++ .../interfaces/mapping/SampleInterfaceModule.java | 54 +++++++++++ .../cfgattrs/InterfacesPluginConfiguration.java | 28 ++++++ .../mapping/config/InterfaceWriterCustomizer.java | 80 ++++++++++++++++ .../mapping/config/InterfacesWriterFactory.java | 54 +++++++++++ .../mapping/init/InterfacesInitializer.java | 68 ++++++++++++++ .../InterfaceUpNotificationProducer.java | 96 +++++++++++++++++++ .../mapping/oper/CountersReaderCustomizer.java | 71 ++++++++++++++ .../mapping/oper/InterfaceReaderCustomizer.java | 103 +++++++++++++++++++++ .../mapping/oper/InterfacesReaderFactory.java | 68 ++++++++++++++ .../config/sample-interfaces.json | 3 + samples/interfaces/models/pom.xml | 75 +++++++++++++++ .../yang/openconfig-interfaces-notification.yang | 60 ++++++++++++ samples/interfaces/pom.xml | 57 ++++++++++++ samples/minimal-distribution/pom.xml | 71 ++++++++++++++ .../java/io/fd/honeycomb/samples/distro/Main.java | 33 +++++++ samples/pom.xml | 57 ++++++++++++ 19 files changed, 1138 insertions(+) create mode 100644 samples/interfaces/Readme.adoc create mode 100644 samples/interfaces/mapping/pom.xml create mode 100644 samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/LowerLayerAccess.java create mode 100644 samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/SampleInterfaceModule.java create mode 100644 samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/cfgattrs/InterfacesPluginConfiguration.java create mode 100644 samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/config/InterfaceWriterCustomizer.java create mode 100644 samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/config/InterfacesWriterFactory.java create mode 100644 samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/init/InterfacesInitializer.java create mode 100644 samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/notification/InterfaceUpNotificationProducer.java create mode 100644 samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/CountersReaderCustomizer.java create mode 100644 samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/InterfaceReaderCustomizer.java create mode 100644 samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/InterfacesReaderFactory.java create mode 100644 samples/interfaces/mapping/src/main/resources/honeycomb-minimal-resources/config/sample-interfaces.json create mode 100644 samples/interfaces/models/pom.xml create mode 100644 samples/interfaces/models/src/main/yang/openconfig-interfaces-notification.yang create mode 100644 samples/interfaces/pom.xml create mode 100644 samples/minimal-distribution/pom.xml create mode 100644 samples/minimal-distribution/src/main/java/io/fd/honeycomb/samples/distro/Main.java create mode 100644 samples/pom.xml (limited to 'samples') diff --git a/samples/interfaces/Readme.adoc b/samples/interfaces/Readme.adoc new file mode 100644 index 000000000..6d73df456 --- /dev/null +++ b/samples/interfaces/Readme.adoc @@ -0,0 +1,10 @@ += Openconfig-interfaces sample +This is a sample Honeycomb plugin implementing mapping for openconfig interfaces yang model + +== Data +Only sample data are used, that are not actually handled + +== Notifications +A sample notification was added to the models to showcase notification capabilities + +// TODO provide a groovy version, will be more compact \ No newline at end of file diff --git a/samples/interfaces/mapping/pom.xml b/samples/interfaces/mapping/pom.xml new file mode 100644 index 000000000..5cd903acd --- /dev/null +++ b/samples/interfaces/mapping/pom.xml @@ -0,0 +1,79 @@ + + + + + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + ../../../common/api-parent + + + 4.0.0 + io.fd.honeycomb.samples.interfaces + interfaces-mapping + 1.0.0-SNAPSHOT + bundle + + + 4.1.0 + 1.2.0 + + + + + ${project.groupId} + interfaces-models + ${project.version} + + + + com.google.inject + guice + ${guice.version} + + + net.jmob + guice.conf + ${guice.config.version} + + + com.google.inject.extensions + guice-multibindings + ${guice.version} + + + + io.fd.honeycomb + translate-impl + 1.0.0-SNAPSHOT + + + io.fd.honeycomb + translate-api + 1.0.0-SNAPSHOT + + + io.fd.honeycomb + notification-api + 1.0.0-SNAPSHOT + + + io.fd.honeycomb + cfg-init + 1.0.0-SNAPSHOT + + + diff --git a/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/LowerLayerAccess.java b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/LowerLayerAccess.java new file mode 100644 index 000000000..4b815bf35 --- /dev/null +++ b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/LowerLayerAccess.java @@ -0,0 +1,71 @@ +/* + * 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.samples.interfaces.mapping; + +import com.google.common.collect.Lists; +import com.google.inject.Inject; +import io.fd.honeycomb.samples.interfaces.mapping.cfgattrs.InterfacesPluginConfiguration; +import io.fd.honeycomb.translate.write.WriteContext; +import java.util.ArrayList; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is a sample class representing common resource for readers and writers to access the lower layer + */ +public final class LowerLayerAccess { + + private static final Logger LOG = LoggerFactory.getLogger(LowerLayerAccess.class); + + @Inject + public LowerLayerAccess(@Nonnull final InterfacesPluginConfiguration configuration) { + LOG.info("Creating lower layer access with configuration: {}", configuration); + } + + public void writeInterface(final InstanceIdentifier id, final Interface dataAfter, + final WriteContext writeContext) { + LOG.info("Writing interface: {}. to {}", dataAfter, id); + // This is where actual write/propagation happens + dataAfter.getMtu(); + } + + public void deleteInterface(final InstanceIdentifier id, final Interface dataBefore, + final WriteContext writeContext) { + LOG.info("Deleting interface: {}. to {}", dataBefore, id); + final String ifcToBeDeleted = id.firstKeyOf(Interface.class).getInterfaceId().getValue(); + // This is where actual write/propagation happens + } + + public long getTotalPacketsForInterface(final String ifcName) { + return 500L; + } + + public long getDroppedPacketsForIfc(final String ifcName) { + return 50L; + } + + public ArrayList getAllInterfaceNames() { + return Lists.newArrayList("ifc1", "ifc2"); + } + + public int getMtuForInterface(final String ifcName) { + return 66; + } +} diff --git a/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/SampleInterfaceModule.java b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/SampleInterfaceModule.java new file mode 100644 index 000000000..000113f11 --- /dev/null +++ b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/SampleInterfaceModule.java @@ -0,0 +1,54 @@ +/* + * 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.samples.interfaces.mapping; + +import com.google.inject.AbstractModule; +import com.google.inject.Singleton; +import com.google.inject.multibindings.Multibinder; +import io.fd.honeycomb.data.init.DataTreeInitializer; +import io.fd.honeycomb.notification.ManagedNotificationProducer; +import io.fd.honeycomb.samples.interfaces.mapping.config.InterfacesWriterFactory; +import io.fd.honeycomb.samples.interfaces.mapping.oper.InterfacesReaderFactory; +import io.fd.honeycomb.samples.interfaces.mapping.cfgattrs.InterfacesPluginConfiguration; +import io.fd.honeycomb.samples.interfaces.mapping.init.InterfacesInitializer; +import io.fd.honeycomb.samples.interfaces.mapping.notification.InterfaceUpNotificationProducer; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.write.WriterFactory; +import net.jmob.guice.conf.core.ConfigurationModule; + +/** + * This is some glue code necessary for Honeycomb distribution to pick up the plugin classes + */ +public final class SampleInterfaceModule extends AbstractModule { + + @Override + protected void configure() { + // These are plugin specific config attributes + install(ConfigurationModule.create()); + requestInjection(InterfacesPluginConfiguration.class); + + // These are plugin's internal components + bind(LowerLayerAccess.class).in(Singleton.class); + + // Below are classes picked up by HC framework + Multibinder.newSetBinder(binder(), WriterFactory.class).addBinding().to(InterfacesWriterFactory.class); + Multibinder.newSetBinder(binder(), ReaderFactory.class).addBinding().to(InterfacesReaderFactory.class); + Multibinder.newSetBinder(binder(), DataTreeInitializer.class).addBinding().to(InterfacesInitializer.class); + Multibinder.newSetBinder(binder(), ManagedNotificationProducer.class).addBinding() + .to(InterfaceUpNotificationProducer.class); + } +} diff --git a/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/cfgattrs/InterfacesPluginConfiguration.java b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/cfgattrs/InterfacesPluginConfiguration.java new file mode 100644 index 000000000..881c18aa0 --- /dev/null +++ b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/cfgattrs/InterfacesPluginConfiguration.java @@ -0,0 +1,28 @@ +/* + * 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.samples.interfaces.mapping.cfgattrs; + +import net.jmob.guice.conf.core.BindConfig; +import net.jmob.guice.conf.core.InjectConfig; +import net.jmob.guice.conf.core.Syntax; + +@BindConfig(value = "sample-interfaces", syntax = Syntax.JSON) +public class InterfacesPluginConfiguration { + + @InjectConfig("some-config-attribute") + String someConfigAttribute; +} diff --git a/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/config/InterfaceWriterCustomizer.java b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/config/InterfaceWriterCustomizer.java new file mode 100644 index 000000000..af185d8b0 --- /dev/null +++ b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/config/InterfaceWriterCustomizer.java @@ -0,0 +1,80 @@ +/* + * 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.samples.interfaces.mapping.config; + +import io.fd.honeycomb.samples.interfaces.mapping.LowerLayerAccess; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.Interface; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.InterfaceKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is a customizer responsible for writing(updating and also deleting) Interface config data + */ +public class InterfaceWriterCustomizer implements ListWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(InterfaceWriterCustomizer.class); + + private final LowerLayerAccess access; + + public InterfaceWriterCustomizer(final LowerLayerAccess access) { + this.access = access; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Interface dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + try { + // Context can be used just like the context in ReadCustomizer see InterfaceReaderCustomizer + // + it also provides a window into the entire configuration tree before current transaction and during current transaction + // just in case, some additional data is necessary here + access.writeInterface(id, dataAfter, writeContext); + } catch (Exception e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Interface dataBefore, @Nonnull final Interface dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + // There are cases when lower layer does not support all of the CRUD operations, in which case, the handler + // should look like this (This will reject configuration from upper layers, returning error/rpc-error): + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("Unable to update interface data, unsupported at lower layer")); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Interface dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + try { + // Context can be used just like the context in ReadCustomizer see InterfaceReaderCustomizer + // + it also provides a window into the entire configuration tree before current transaction and during current transaction + // just in case, some additional data is necessary here + access.deleteInterface(id, dataBefore, writeContext); + } catch (Exception e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } +} diff --git a/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/config/InterfacesWriterFactory.java b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/config/InterfacesWriterFactory.java new file mode 100644 index 000000000..d3b22c345 --- /dev/null +++ b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/config/InterfacesWriterFactory.java @@ -0,0 +1,54 @@ +/* + * 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.samples.interfaces.mapping.config; + +import com.google.inject.Inject; +import io.fd.honeycomb.samples.interfaces.mapping.LowerLayerAccess; +import io.fd.honeycomb.translate.impl.write.GenericListWriter; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.Interfaces; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class InterfacesWriterFactory implements WriterFactory { + + @Nonnull + private final LowerLayerAccess access; + + @Inject + public InterfacesWriterFactory(@Nonnull final LowerLayerAccess access) { + this.access = access; + } + + @Override + public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { + // ReaderFactory is intended for registering Writers into HC framework + // Writers handle ONLY config (config "true") data coming from upper layers and propagate them into lower layer/device + // they are triggered when RESTCONF PUT/POST on config is invoked or when NETCONF edit-config + commit operation is executed + + // Our model root for operational data is Interfaces + final InstanceIdentifier root = InstanceIdentifier.create(Interfaces.class); + // But unlike ReaderFactories, there's no need to create a structural writer, we can "ignore" any nodes + // that do not contain actual data (leaves) + + // Next child node is Interface (list) + final InstanceIdentifier ifcListId = root.child(Interface.class); + registry.add(new GenericListWriter<>(ifcListId, new InterfaceWriterCustomizer(access))); + } +} diff --git a/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/init/InterfacesInitializer.java b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/init/InterfacesInitializer.java new file mode 100644 index 000000000..9aea508c7 --- /dev/null +++ b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/init/InterfacesInitializer.java @@ -0,0 +1,68 @@ +/* + * 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.samples.interfaces.mapping.init; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.data.init.AbstractDataTreeConverter; +import java.util.stream.Collectors; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.Interfaces; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.InterfacesBuilder; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.InterfacesState; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.InterfaceBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is an initializer for interfaces plugin. Its main goal is to revers-engineer configuration data (config "true") + * for interfaces model from operational data. In this case, we are trying to recreate Interfaces container from InterfacesState + * container. Thanks to symmetrical nature of the model, it's pretty straightforward. + * + * This is very useful when the lower layer already contains some data that should be revers-engineer to config data + * in honeycomb in order to get HC and lower layer to sync... It makes life of upper layers much easier + * + * However it's not always possible to perform this task so the initializers are optional for plugins + */ +public class InterfacesInitializer extends AbstractDataTreeConverter { + + private static final Logger LOG = LoggerFactory.getLogger(InterfacesInitializer.class); + + @Inject + public InterfacesInitializer(@Named("honeycomb-initializer") final DataBroker bindingDataBroker) { + super(bindingDataBroker, + InstanceIdentifier.create(InterfacesState.class), InstanceIdentifier.create(Interfaces.class)); + } + + @Override + protected Interfaces convert(final InterfacesState operationalData) { + // Just convert operational data into config data + // The operational data are queried from lower layer using readerCustomizers from this plugin + + LOG.info("Initializing interfaces config data from: {}", operationalData); + + return new InterfacesBuilder() + .setInterface(operationalData.getInterface().stream() + .map(oper -> new InterfaceBuilder() + .setMtu(oper.getMtu()) + .setInterfaceId(oper.getInterfaceId()) + .build()) + .collect(Collectors.toList())) + .build(); + } +} diff --git a/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/notification/InterfaceUpNotificationProducer.java b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/notification/InterfaceUpNotificationProducer.java new file mode 100644 index 000000000..76d2c5dc8 --- /dev/null +++ b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/notification/InterfaceUpNotificationProducer.java @@ -0,0 +1,96 @@ +/* + * 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.samples.interfaces.mapping.notification; + +import com.google.inject.Inject; +import io.fd.honeycomb.notification.ManagedNotificationProducer; +import io.fd.honeycomb.notification.NotificationCollector; +import io.fd.honeycomb.samples.interfaces.mapping.LowerLayerAccess; +import java.util.Collection; +import java.util.Collections; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.InterfaceId; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.InterfaceUp; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.InterfaceUpBuilder; +import org.opendaylight.yangtools.yang.binding.Notification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Notification producer for sample interfaces plugin + */ +public class InterfaceUpNotificationProducer implements ManagedNotificationProducer { + + private static final Logger LOG = LoggerFactory.getLogger(InterfaceUpNotificationProducer.class); + + @Nonnull + private final LowerLayerAccess access; + + private Thread thread; + + @Inject + public InterfaceUpNotificationProducer(@Nonnull final LowerLayerAccess access) { + this.access = access; + } + + @Override + public void start(@Nonnull final NotificationCollector collector) { + LOG.info("Starting notification stream for interfaces"); + + // Simulating notification producer + thread = new Thread(() -> { + while(true) { + if (Thread.currentThread().isInterrupted()) { + return; + } + + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + + + final InterfaceUp ifc1 = new InterfaceUpBuilder().setInterfaceId(new InterfaceId("ifc1")).build(); + LOG.info("Emitting notification: {}", ifc1); + collector.onNotification(ifc1); + } + }, "NotificationProducer"); + thread.setDaemon(true); + thread.start(); + } + + @Override + public void stop() { + if(thread != null) { + thread.interrupt(); + } + } + + @Nonnull + @Override + public Collection> getNotificationTypes() { + // Producing only this single type of notification + return Collections.singleton(InterfaceUp.class); + } + + @Override + public void close() throws Exception { + stop(); + } +} diff --git a/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/CountersReaderCustomizer.java b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/CountersReaderCustomizer.java new file mode 100644 index 000000000..b5ec2cbd9 --- /dev/null +++ b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/CountersReaderCustomizer.java @@ -0,0 +1,71 @@ +/* + * 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.samples.interfaces.mapping.oper; + +import io.fd.honeycomb.samples.interfaces.mapping.LowerLayerAccess; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810._interface.state.Counters; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810._interface.state.CountersBuilder; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.state.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.state.InterfaceKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is a customizer responsible for reading Counters operational data + */ +public class CountersReaderCustomizer implements ReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(CountersReaderCustomizer.class); + private final LowerLayerAccess access; + + public CountersReaderCustomizer(final LowerLayerAccess access) { + this.access = access; + } + + + @Nonnull + @Override + public CountersBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new CountersBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final CountersBuilder builder, @Nonnull final ReadContext ctx) + throws ReadFailedException { + // Get the information about which interface to get counters for + final InterfaceKey interfaceKey = id.firstKeyOf(Interface.class); + LOG.info("Reading counters for interface: {} at {}", interfaceKey.getInterfaceId(), id); + + // Set some random data + builder.setDroppedPackets(access.getDroppedPacketsForIfc(interfaceKey.getInterfaceId().getValue())); + builder.setTotalPackets(access.getTotalPacketsForInterface(interfaceKey.getInterfaceId().getValue())); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Counters readValue) { + ((InterfaceBuilder) parentBuilder).setCounters(readValue); + } +} diff --git a/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/InterfaceReaderCustomizer.java b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/InterfaceReaderCustomizer.java new file mode 100644 index 000000000..7b69005e0 --- /dev/null +++ b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/InterfaceReaderCustomizer.java @@ -0,0 +1,103 @@ +/* + * 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.samples.interfaces.mapping.oper; + +import io.fd.honeycomb.samples.interfaces.mapping.LowerLayerAccess; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.InterfaceId; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.InterfacesStateBuilder; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.state.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.state.InterfaceKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is a customizer responsible for reading Interface operational data + */ +public class InterfaceReaderCustomizer implements ListReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(InterfaceReaderCustomizer.class); + private final LowerLayerAccess access; + + public InterfaceReaderCustomizer(final LowerLayerAccess access) { + this.access = access; + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext context) throws ReadFailedException { + // context can be used to access cache (lifetime during a transaction) to store any information for + // subsequent invocations or for other customizers + // context.getModificationCache(); + + // context can also be used to access context data. Context data are stored in a persistent data store + // and usually are additional data required to perform the translation in customizers e.g. if underlying layer + // does not recognize interface-ids as string names, but only indices, the mapping between them can should + // be stored in the context data store + // Note: The context datastore is also YANG drive, so context data must be modeled in YANG prior to using them + // context.getMappingContext(); + + // return some sample IDs + return access.getAllInterfaceNames().stream() + .map(InterfaceId::new) + .map(InterfaceKey::new) + .collect(Collectors.toList()); + } + + @Override + public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { + // Just set the result of this customizers read into parent builder + // Builder has to be cast properly + ((InterfacesStateBuilder) builder).setInterface(readData); + } + + @Nonnull + @Override + public InterfaceBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + // Just providing empty builder + return new InterfaceBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final InterfaceBuilder builder, @Nonnull final ReadContext ctx) + throws ReadFailedException { + // This is where the actual "read" is happening, read attributes for a specific interface + final InterfaceKey k = id.firstKeyOf(Interface.class); + final String ifcId = k.getInterfaceId().getValue(); + LOG.info("Reading data for interface: {} at {}", ifcId, id); + + // Fill in some random values, this is actually the place where communication with lower layer + // would occur to get the real values + builder.setMtu(access.getMtuForInterface(ifcId)); + builder.setInterfaceId(k.getInterfaceId()); + // Counters container is not set here, instead a dedicated customizer is created for it + // It could be set here, if this customizer + its reader were marked as subtree reader in the ReaderFactory + // However its a good practice to provide a dedicated reader+customizer for every complex node + } + +} diff --git a/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/InterfacesReaderFactory.java b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/InterfacesReaderFactory.java new file mode 100644 index 000000000..5e34eea74 --- /dev/null +++ b/samples/interfaces/mapping/src/main/java/io/fd/honeycomb/samples/interfaces/mapping/oper/InterfacesReaderFactory.java @@ -0,0 +1,68 @@ +/* + * 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.samples.interfaces.mapping.oper; + +import com.google.inject.Inject; +import io.fd.honeycomb.samples.interfaces.mapping.LowerLayerAccess; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.impl.read.GenericReader; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.InterfacesState; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.InterfacesStateBuilder; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810._interface.state.Counters; +import org.opendaylight.yang.gen.v1.io.fd.honeycomb.samples.interfaces.rev160810.interfaces.state.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class InterfacesReaderFactory implements ReaderFactory { + + @Nonnull + private final LowerLayerAccess access; + + @Inject + public InterfacesReaderFactory(@Nonnull final LowerLayerAccess access) { + this.access = access; + } + + @Override + public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) { + // ReaderFactory is intended for registering Readers into HC framework + // Readers provide ONLY operational (config "false") data straight from underlying device/layer + // they are triggered when RESTCONF GET on operational is invoked or when NETCONF get operation is executed + + // Our model root for operational data is InterfacesState + final InstanceIdentifier root = InstanceIdentifier.create(InterfacesState.class); + // Since InterfacesState has no direct data children (leaves) only a structural reader is registered + // This reader just fills in the composite hierarchy of readers + // Honeycomb can't automatically instantiate structural readers and plugins have to help it by invoking as: + registry.addStructuralReader(root, InterfacesStateBuilder.class); + + // Next child node is Interface (list) + final InstanceIdentifier ifcListId = root.child(Interface.class); + registry.add(new GenericListReader<>(ifcListId, new InterfaceReaderCustomizer(access))); + + // Next child is a container Counters + final InstanceIdentifier countersId = ifcListId.child(Counters.class); + // By adding the reader with addAfter, we can ensure ordering of execution among the readers + // Useful in cases when a certain read has to be invoked before/after another + // In this case, we are ensuring that Counters are read after Interface is read + // "add" could be used instead, leaving the ordering to "nature" + // Same applies for writers + registry.addAfter(new GenericReader<>(countersId, new CountersReaderCustomizer(access)), ifcListId); + } +} diff --git a/samples/interfaces/mapping/src/main/resources/honeycomb-minimal-resources/config/sample-interfaces.json b/samples/interfaces/mapping/src/main/resources/honeycomb-minimal-resources/config/sample-interfaces.json new file mode 100644 index 000000000..69d527a0e --- /dev/null +++ b/samples/interfaces/mapping/src/main/resources/honeycomb-minimal-resources/config/sample-interfaces.json @@ -0,0 +1,3 @@ +{ + "some-config-attribute": "some-value" +} \ No newline at end of file diff --git a/samples/interfaces/models/pom.xml b/samples/interfaces/models/pom.xml new file mode 100644 index 000000000..d78d6f496 --- /dev/null +++ b/samples/interfaces/models/pom.xml @@ -0,0 +1,75 @@ + + + + + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + ../../../common/api-parent + + + 4.0.0 + io.fd.honeycomb.samples.interfaces + interfaces-models + 1.0.0-SNAPSHOT + bundle + + + + + org.opendaylight.mdsal.model + mdsal-model-artifacts + 0.8.2-Beryllium-SR2 + pom + import + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/interfaces/models/src/main/yang/openconfig-interfaces-notification.yang b/samples/interfaces/models/src/main/yang/openconfig-interfaces-notification.yang new file mode 100644 index 000000000..456fab4df --- /dev/null +++ b/samples/interfaces/models/src/main/yang/openconfig-interfaces-notification.yang @@ -0,0 +1,60 @@ +module sample-interfaces { + + namespace "io:fd:honeycomb:samples:interfaces"; + + prefix "hc-s-if"; + + description "Sample interface model"; + + revision "2016-08-10" { + description "Initial revision"; + } + + typedef interface-id { + type string; + } + + grouping interface-common { + leaf interface-id { + type interface-id; + } + + leaf mtu { + type uint16; + } + } + + grouping interface-state { + container counters { + leaf total-packets { + type uint32; + } + leaf dropped-packets { + type uint32; + } + } + } + + container interfaces { + list interface { + key "interface-id"; + uses interface-common; + } + } + + container interfaces-state { + config false; + + list interface { + key "interface-id"; + uses interface-common; + uses interface-state; + } + } + + notification interface-up { + leaf interface-id { + type interface-id; + } + } +} \ No newline at end of file diff --git a/samples/interfaces/pom.xml b/samples/interfaces/pom.xml new file mode 100644 index 000000000..2f87b10bc --- /dev/null +++ b/samples/interfaces/pom.xml @@ -0,0 +1,57 @@ + + + + + + org.opendaylight.odlparent + odlparent + 1.6.2-Beryllium-SR2 + + + + io.fd.honeycomb.samples.interfaces + interfaces-aggregator + 1.0.0-SNAPSHOT + honeycomb-infra + pom + 4.0.0 + + 3.1.1 + + + models + mapping + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-install-plugin + + true + + + + + diff --git a/samples/minimal-distribution/pom.xml b/samples/minimal-distribution/pom.xml new file mode 100644 index 000000000..c8311aead --- /dev/null +++ b/samples/minimal-distribution/pom.xml @@ -0,0 +1,71 @@ + + + + + + io.fd.honeycomb.common + minimal-distribution-parent + 1.0.0-SNAPSHOT + ../../common/minimal-distro-parent + + + 4.0.0 + io.fd.honeycomb.samples.distro + minimal-distribution + 1.0.0-SNAPSHOT + + + -Xms128m -Xmx128m + io.fd.honeycomb.samples.distro.Main + + + + + + maven-compiler-plugin + + + org.codehaus.gmaven + groovy-maven-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + org.apache.maven.plugins + maven-dependency-plugin + + + maven-assembly-plugin + + + + + + + io.fd.honeycomb.samples.interfaces + interfaces-mapping + 1.0.0-SNAPSHOT + + + io.fd.honeycomb + minimal-distribution + 1.0.0-SNAPSHOT + + + + diff --git a/samples/minimal-distribution/src/main/java/io/fd/honeycomb/samples/distro/Main.java b/samples/minimal-distribution/src/main/java/io/fd/honeycomb/samples/distro/Main.java new file mode 100644 index 000000000..f6b38aa78 --- /dev/null +++ b/samples/minimal-distribution/src/main/java/io/fd/honeycomb/samples/distro/Main.java @@ -0,0 +1,33 @@ +/* + * 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.samples.distro; + +import com.google.common.collect.Lists; +import com.google.inject.Module; +import io.fd.honeycomb.samples.interfaces.mapping.SampleInterfaceModule; +import java.util.List; + +public class Main { + + public static void main(String[] args) { + final List sampleModules = Lists.newArrayList(io.fd.honeycomb.infra.distro.Main.BASE_MODULES); + + sampleModules.add(new SampleInterfaceModule()); + + io.fd.honeycomb.infra.distro.Main.init(sampleModules); + } +} diff --git a/samples/pom.xml b/samples/pom.xml new file mode 100644 index 000000000..ee20f602a --- /dev/null +++ b/samples/pom.xml @@ -0,0 +1,57 @@ + + + + + + org.opendaylight.odlparent + odlparent + 1.6.2-Beryllium-SR2 + + + + io.fd.honeycomb + samples-aggregator + 1.0.0-SNAPSHOT + honeycomb-infra + pom + 4.0.0 + + 3.1.1 + + + interfaces + minimal-distribution + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-install-plugin + + true + + + + + -- cgit 1.2.3-korg