diff options
author | Maros Marsalek <mmarsale@cisco.com> | 2016-08-11 13:05:32 +0200 |
---|---|---|
committer | Maros Marsalek <mmarsale@cisco.com> | 2016-08-19 12:49:56 +0200 |
commit | 2fc8c4514fdf2ae197f3870f75d63d91010befa8 (patch) | |
tree | c809e365755cd8f51d47eb4e9cc6c35ff0ee70b4 /samples/interfaces/mapping | |
parent | a5e47c8e227a1914cd380a993e03c2fe07b0e3d8 (diff) |
HONEYCOMB-23 Add plugin sample and sample minimal distribution
Change-Id: Idbcdc5a52a9bfd3b90c039f1a1e58c258cd01849
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'samples/interfaces/mapping')
12 files changed, 775 insertions, 0 deletions
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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2015 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>io.fd.honeycomb.common</groupId> + <artifactId>api-parent</artifactId> + <version>1.0.0-SNAPSHOT</version> + <relativePath>../../../common/api-parent</relativePath> + </parent> + + <modelVersion>4.0.0</modelVersion> + <groupId>io.fd.honeycomb.samples.interfaces</groupId> + <artifactId>interfaces-mapping</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>bundle</packaging> + + <properties> + <guice.version>4.1.0</guice.version> + <guice.config.version>1.2.0</guice.config.version> + </properties> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>interfaces-models</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>com.google.inject</groupId> + <artifactId>guice</artifactId> + <version>${guice.version}</version> + </dependency> + <dependency> + <groupId>net.jmob</groupId> + <artifactId>guice.conf</artifactId> + <version>${guice.config.version}</version> + </dependency> + <dependency> + <groupId>com.google.inject.extensions</groupId> + <artifactId>guice-multibindings</artifactId> + <version>${guice.version}</version> + </dependency> + + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>translate-impl</artifactId> + <version>1.0.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>translate-api</artifactId> + <version>1.0.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>notification-api</artifactId> + <version>1.0.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>cfg-init</artifactId> + <version>1.0.0-SNAPSHOT</version> + </dependency> + </dependencies> +</project> 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<Interface> 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<Interface> 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<String> 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<Interface, InterfaceKey> { + + 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<Interface> 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<Interface> 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<Interface> 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<Interfaces> 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<Interface> 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<InterfacesState, Interfaces> { + + 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<Class<? extends Notification>> 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<Counters, CountersBuilder> { + + 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<Counters> id) { + return new CountersBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Counters> 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<? extends DataObject> 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<Interface, InterfaceKey, InterfaceBuilder> { + + 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<InterfaceKey> getAllIds(@Nonnull final InstanceIdentifier<Interface> 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<? extends DataObject> builder, @Nonnull final List<Interface> 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<Interface> id) { + // Just providing empty builder + return new InterfaceBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> 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<InterfacesState> 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<Interface> ifcListId = root.child(Interface.class); + registry.add(new GenericListReader<>(ifcListId, new InterfaceReaderCustomizer(access))); + + // Next child is a container Counters + final InstanceIdentifier<Counters> 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 |