From e3c31cee916480b2d9d169c1f5afb1c42efaabe1 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Fri, 29 Jul 2016 16:27:12 +0200 Subject: HONEYCOMB-130: Rename infra packages(remove vpp/v3po) Change-Id: Ic5b90e397e3743623d01b206bc60bc5c7df6b981 Signed-off-by: Maros Marsalek --- .../data/init/AbstractDataTreeConverter.java | 114 ++ .../honeycomb/data/init/DataTreeInitializer.java | 51 + .../honeycomb/data/init/InitializerRegistry.java | 33 + .../data/init/InitializerRegistryImpl.java | 52 + .../honeycomb/data/init/RestoringInitializer.java | 112 ++ .../vpp/data/init/AbstractDataTreeConverter.java | 114 -- .../v3po/vpp/data/init/DataTreeInitializer.java | 51 - .../v3po/vpp/data/init/InitializerRegistry.java | 33 - .../vpp/data/init/InitializerRegistryImpl.java | 52 - .../v3po/vpp/data/init/RestoringInitializer.java | 112 -- .../ConfigurationInitializerRegistryModule.java | 54 + ...figurationInitializerRegistryModuleFactory.java | 14 + .../rev160407/PersistedFileInitializerModule.java | 38 + .../PersistedFileInitializerModuleFactory.java | 13 + .../ConfigurationInitializerRegistryModule.java | 54 - ...figurationInitializerRegistryModuleFactory.java | 13 - .../rev160407/PersistedFileInitializerModule.java | 38 - .../PersistedFileInitializerModuleFactory.java | 13 - infra/cfg-init/src/main/yang/cfg-init.yang | 117 ++ infra/cfg-init/src/main/yang/vpp-cfg-init.yang | 117 -- .../data/init/InitializerRegistryImplTest.java | 66 + .../vpp/data/init/InitializerRegistryImplTest.java | 66 - .../io/fd/honeycomb/data/DataModification.java | 70 + .../fd/honeycomb/data/ModifiableDataManager.java | 33 + .../io/fd/honeycomb/data/ReadableDataManager.java | 40 + .../fd/honeycomb/v3po/data/DataModification.java | 70 - .../honeycomb/v3po/data/ModifiableDataManager.java | 33 - .../honeycomb/v3po/data/ReadableDataManager.java | 40 - infra/data-api/src/main/yang/data-api.yang | 4 +- infra/data-impl/pom.xml | 2 +- .../java/io/fd/honeycomb/data/impl/DataBroker.java | 198 +++ .../data/impl/ModifiableDataTreeDelegator.java | 236 ++++ .../data/impl/ModifiableDataTreeManager.java | 122 ++ .../fd/honeycomb/data/impl/ModificationDiff.java | 278 ++++ .../data/impl/PersistingDataTreeAdapter.java | 151 +++ .../honeycomb/data/impl/ReadOnlyTransaction.java | 119 ++ .../honeycomb/data/impl/ReadWriteTransaction.java | 101 ++ .../data/impl/ReadableDataTreeDelegator.java | 241 ++++ .../fd/honeycomb/data/impl/WriteTransaction.java | 177 +++ .../io/fd/honeycomb/v3po/data/impl/DataBroker.java | 198 --- .../data/impl/ModifiableDataTreeDelegator.java | 236 ---- .../v3po/data/impl/ModifiableDataTreeManager.java | 122 -- .../honeycomb/v3po/data/impl/ModificationDiff.java | 278 ---- .../v3po/data/impl/PersistingDataTreeAdapter.java | 151 --- .../v3po/data/impl/ReadOnlyTransaction.java | 119 -- .../v3po/data/impl/ReadWriteTransaction.java | 101 -- .../v3po/data/impl/ReadableDataTreeDelegator.java | 242 ---- .../honeycomb/v3po/data/impl/WriteTransaction.java | 177 --- .../data/impl/rev160411/ConfigDataTreeModule.java | 6 +- .../impl/rev160411/OperationalDataTreeModule.java | 4 +- .../rev160411/PersistingDataTreeAdapterModule.java | 2 +- .../io/fd/honeycomb/data/impl/DataBrokerTest.java | 111 ++ .../data/impl/ModifiableDataTreeDelegatorTest.java | 269 ++++ .../honeycomb/data/impl/ModificationDiffTest.java | 427 ++++++ .../data/impl/PersistingDataTreeAdapterTest.java | 69 + .../data/impl/ReadOnlyTransactionTest.java | 68 + .../data/impl/ReadWriteTransactionTest.java | 111 ++ .../data/impl/ReadableDataTreeDelegatorTest.java | 192 +++ .../honeycomb/data/impl/WriteTransactionTest.java | 128 ++ .../honeycomb/v3po/data/impl/DataBrokerTest.java | 111 -- .../data/impl/ModifiableDataTreeDelegatorTest.java | 269 ---- .../v3po/data/impl/ModificationDiffTest.java | 427 ------ .../data/impl/PersistingDataTreeAdapterTest.java | 69 - .../v3po/data/impl/ReadOnlyTransactionTest.java | 68 - .../v3po/data/impl/ReadWriteTransactionTest.java | 111 -- .../data/impl/ReadableDataTreeDelegatorTest.java | 192 --- .../v3po/data/impl/WriteTransactionTest.java | 128 -- .../src/main/config/context-datatree-config.xml | 6 +- infra/impl/src/main/config/default-config.xml | 12 +- infra/impl/src/main/config/initializer-config.xml | 18 +- .../impl/src/main/config/netconf-north-config.xml | 80 +- .../impl/src/main/config/restconf-north-config.xml | 2 +- .../impl/NorthboundFacadeHoneycombDOMBroker.java | 206 +++ .../impl/NorthboundFacadeHoneycombDOMBroker.java | 206 --- .../impl/rev141210/ContextDataBrokerModule.java | 26 + .../rev141210/ContextDataBrokerModuleFactory.java | 13 + .../honeycomb/impl/rev141210/DataBrokerModule.java | 34 + .../impl/rev141210/DataBrokerModuleFactory.java | 13 + .../honeycomb/impl/rev141210/HoneycombModule.java | 59 + .../impl/rev141210/HoneycombModuleFactory.java | 28 + .../impl/rev141210/NetconfBindingBrokerModule.java | 117 ++ .../NetconfBindingBrokerModuleFactory.java | 13 + .../rev141210/NetconfMonitoringReaderModule.java | 46 + .../NetconfMonitoringReaderModuleFactory.java | 13 + .../impl/rev141210/ContextDataBrokerModule.java | 26 - .../rev141210/ContextDataBrokerModuleFactory.java | 13 - .../yang/v3po/impl/rev141210/DataBrokerModule.java | 34 - .../impl/rev141210/DataBrokerModuleFactory.java | 13 - .../impl/rev141210/NetconfBindingBrokerModule.java | 117 -- .../NetconfBindingBrokerModuleFactory.java | 13 - .../rev141210/NetconfMonitoringReaderModule.java | 46 - .../NetconfMonitoringReaderModuleFactory.java | 13 - .../ns/yang/v3po/impl/rev141210/V3poModule.java | 60 - .../v3po/impl/rev141210/V3poModuleFactory.java | 28 - infra/impl/src/main/yang/honeycomb-impl.yang | 155 +++ infra/impl/src/main/yang/v3po-impl.yang | 155 --- .../v3po/impl/rev141210/V3poModuleFactoryTest.java | 26 - .../yang/v3po/impl/rev141210/V3poModuleTest.java | 70 - .../fd/honeycomb/data/impl/AbstractInfraTest.java | 106 ++ .../data/impl/HoneycombReadInfraTest.java | 460 +++++++ .../data/impl/HoneycombSubtreeReadInfraTest.java | 150 +++ .../data/impl/HoneycombWriteInfraTest.java | 522 ++++++++ .../test/java/io/fd/honeycomb/data/impl/Ids.java | 62 + .../v3po/data/impl/AbstractInfraTest.java | 106 -- .../v3po/data/impl/HoneycombReadInfraTest.java | 460 ------- .../data/impl/HoneycombSubtreeReadInfraTest.java | 150 --- .../v3po/data/impl/HoneycombWriteInfraTest.java | 521 -------- .../java/io/fd/honeycomb/v3po/data/impl/Ids.java | 62 - .../notification/ManagedNotificationProducer.java | 38 + .../notification/NotificationCollector.java | 35 + .../notification/NotificationProducer.java | 37 + .../notification/ManagedNotificationProducer.java | 38 - .../v3po/notification/NotificationCollector.java | 35 - .../v3po/notification/NotificationProducer.java | 37 - .../api/src/main/yang/notification-api.yang | 4 +- .../main/config/notification-to-netconf-config.xml | 4 +- .../impl/HoneycombNotificationCollector.java | 66 + .../impl/NotificationProducerRegistry.java | 112 ++ .../impl/NotificationProducerTracker.java | 109 ++ .../impl/HoneycombNotificationCollector.java | 66 - .../impl/NotificationProducerRegistry.java | 112 -- .../impl/NotificationProducerTracker.java | 109 -- .../HoneycombNotificationManagerModule.java | 10 +- ...ycombNotificationToNetconfTranslatorModule.java | 4 +- .../impl/HoneycombNotificationCollectorTest.java | 63 + .../impl/NotificationProducerRegistryTest.java | 98 ++ .../impl/NotificationProducerTrackerTest.java | 67 + .../impl/HoneycombNotificationCollectorTest.java | 63 - .../impl/NotificationProducerRegistryTest.java | 98 -- .../impl/NotificationProducerTrackerTest.java | 67 - infra/notification/pom.xml | 1 + infra/postman_rest_collection.json | 1386 -------------------- .../io/fd/honeycomb/translate/MappingContext.java | 66 + .../ModifiableSubtreeManagerRegistryBuilder.java | 77 ++ .../fd/honeycomb/translate/ModificationCache.java | 49 + .../honeycomb/translate/ModificationContext.java | 44 + .../io/fd/honeycomb/translate/SubtreeManager.java | 39 + .../translate/SubtreeManagerRegistryBuilder.java | 22 + .../honeycomb/translate/TranslationException.java | 38 + .../io/fd/honeycomb/translate/read/ListReader.java | 66 + .../fd/honeycomb/translate/read/ReadContext.java | 26 + .../translate/read/ReadFailedException.java | 61 + .../io/fd/honeycomb/translate/read/Reader.java | 76 ++ .../fd/honeycomb/translate/read/ReaderFactory.java | 38 + .../registry/ModifiableReaderRegistryBuilder.java | 41 + .../translate/read/registry/ReaderRegistry.java | 62 + .../read/registry/ReaderRegistryBuilder.java | 27 + .../translate/write/DataObjectUpdate.java | 114 ++ .../fd/honeycomb/translate/write/ListWriter.java | 33 + .../fd/honeycomb/translate/write/WriteContext.java | 50 + .../translate/write/WriteFailedException.java | 166 +++ .../io/fd/honeycomb/translate/write/Writer.java | 48 + .../honeycomb/translate/write/WriterFactory.java | 38 + .../registry/ModifiableWriterRegistryBuilder.java | 31 + .../translate/write/registry/WriterRegistry.java | 213 +++ .../write/registry/WriterRegistryBuilder.java | 27 + .../honeycomb/v3po/translate/MappingContext.java | 66 - .../ModifiableSubtreeManagerRegistryBuilder.java | 77 -- .../v3po/translate/ModificationCache.java | 49 - .../v3po/translate/ModificationContext.java | 44 - .../honeycomb/v3po/translate/SubtreeManager.java | 39 - .../translate/SubtreeManagerRegistryBuilder.java | 22 - .../v3po/translate/TranslationException.java | 38 - .../honeycomb/v3po/translate/read/ListReader.java | 66 - .../honeycomb/v3po/translate/read/ReadContext.java | 26 - .../v3po/translate/read/ReadFailedException.java | 61 - .../fd/honeycomb/v3po/translate/read/Reader.java | 76 -- .../v3po/translate/read/ReaderFactory.java | 38 - .../registry/ModifiableReaderRegistryBuilder.java | 41 - .../translate/read/registry/ReaderRegistry.java | 62 - .../read/registry/ReaderRegistryBuilder.java | 27 - .../v3po/translate/write/DataObjectUpdate.java | 114 -- .../honeycomb/v3po/translate/write/ListWriter.java | 33 - .../v3po/translate/write/WriteContext.java | 50 - .../v3po/translate/write/WriteFailedException.java | 166 --- .../fd/honeycomb/v3po/translate/write/Writer.java | 48 - .../v3po/translate/write/WriterFactory.java | 38 - .../registry/ModifiableWriterRegistryBuilder.java | 31 - .../translate/write/registry/WriterRegistry.java | 213 --- .../write/registry/WriterRegistryBuilder.java | 27 - .../translate-api/src/main/yang/translate-api.yang | 14 +- .../translate/ReadFailedExceptionTest.java | 50 + .../v3po/translate/ReadFailedExceptionTest.java | 50 - infra/translate-impl/pom.xml | 2 +- .../translate/impl/read/GenericListReader.java | 117 ++ .../translate/impl/read/GenericReader.java | 70 + .../translate/impl/write/GenericListWriter.java | 106 ++ .../translate/impl/write/GenericWriter.java | 61 + .../translate/impl/read/GenericListReader.java | 117 -- .../v3po/translate/impl/read/GenericReader.java | 70 - .../translate/impl/write/GenericListWriter.java | 106 -- .../v3po/translate/impl/write/GenericWriter.java | 61 - .../impl/write/GenericListWriterTest.java | 83 ++ .../translate/impl/write/GenericWriterTest.java | 64 + .../impl/write/GenericListWriterTest.java | 83 -- .../translate/impl/write/GenericWriterTest.java | 64 - .../translate/spi/read/ListReaderCustomizer.java | 63 + .../translate/spi/read/ReaderCustomizer.java | 63 + .../translate/spi/write/ListWriterCustomizer.java | 34 + .../translate/spi/write/WriterCustomizer.java | 75 ++ .../translate/spi/read/ListReaderCustomizer.java | 63 - .../v3po/translate/spi/read/ReaderCustomizer.java | 63 - .../translate/spi/write/ListWriterCustomizer.java | 34 - .../v3po/translate/spi/write/WriterCustomizer.java | 75 -- ...stractSubtreeManagerRegistryBuilderBuilder.java | 213 +++ .../io/fd/honeycomb/translate/util/JsonUtils.java | 102 ++ .../io/fd/honeycomb/translate/util/RWUtils.java | 186 +++ .../honeycomb/translate/util/ReflectionUtils.java | 79 ++ .../translate/util/TransactionMappingContext.java | 75 ++ .../translate/util/read/AbstractGenericReader.java | 90 ++ .../translate/util/read/BindingBrokerReader.java | 96 ++ .../util/read/KeepaliveReaderWrapper.java | 173 +++ .../translate/util/read/NoopReaderCustomizer.java | 34 + .../util/read/ReflexiveListReaderCustomizer.java | 65 + .../translate/util/read/ReflexiveReader.java | 57 + .../util/read/ReflexiveReaderCustomizer.java | 103 ++ .../util/read/registry/CompositeReader.java | 202 +++ .../read/registry/CompositeReaderRegistry.java | 117 ++ .../registry/CompositeReaderRegistryBuilder.java | 109 ++ .../util/read/registry/SubtreeReader.java | 250 ++++ .../util/read/registry/TypeHierarchy.java | 101 ++ .../util/write/AbstractGenericWriter.java | 137 ++ .../translate/util/write/NoopWriterRegistry.java | 40 + .../util/write/TransactionWriteContext.java | 121 ++ .../util/write/registry/FlatWriterRegistry.java | 315 +++++ .../write/registry/FlatWriterRegistryBuilder.java | 71 + .../util/write/registry/SubtreeWriter.java | 85 ++ ...stractSubtreeManagerRegistryBuilderBuilder.java | 213 --- .../honeycomb/v3po/translate/util/JsonUtils.java | 102 -- .../fd/honeycomb/v3po/translate/util/RWUtils.java | 186 --- .../v3po/translate/util/ReflectionUtils.java | 79 -- .../translate/util/TransactionMappingContext.java | 75 -- .../translate/util/read/AbstractGenericReader.java | 90 -- .../translate/util/read/BindingBrokerReader.java | 96 -- .../util/read/KeepaliveReaderWrapper.java | 173 --- .../translate/util/read/NoopReaderCustomizer.java | 34 - .../util/read/ReflexiveListReaderCustomizer.java | 65 - .../v3po/translate/util/read/ReflexiveReader.java | 57 - .../util/read/ReflexiveReaderCustomizer.java | 103 -- .../util/read/registry/CompositeReader.java | 202 --- .../read/registry/CompositeReaderRegistry.java | 117 -- .../registry/CompositeReaderRegistryBuilder.java | 109 -- .../util/read/registry/SubtreeReader.java | 250 ---- .../util/read/registry/TypeHierarchy.java | 101 -- .../util/write/AbstractGenericWriter.java | 137 -- .../translate/util/write/NoopWriterRegistry.java | 40 - .../util/write/TransactionWriteContext.java | 121 -- .../util/write/registry/FlatWriterRegistry.java | 315 ----- .../write/registry/FlatWriterRegistryBuilder.java | 71 - .../util/write/registry/SubtreeWriter.java | 85 -- .../rev160406/DelegatingReaderRegistryModule.java | 2 +- .../rev160406/DelegatingWriterRegistryModule.java | 2 +- .../utils/rev160406/NoopWriterRegistryModule.java | 6 +- .../rev160406/RealtimeMappingContextModule.java | 2 +- .../write/util/TransactionWriteContextTest.java | 131 ++ .../fd/honeycomb/translate/util/DataObjects.java | 52 + .../fd/honeycomb/translate/util/JsonUtilsTest.java | 109 ++ .../CompositeReaderRegistryBuilderTest.java | 114 ++ .../util/read/registry/SubtreeReaderTest.java | 124 ++ .../util/read/registry/TypeHierarchyTest.java | 72 + .../registry/FlatWriterRegistryBuilderTest.java | 131 ++ .../write/registry/FlatWriterRegistryTest.java | 265 ++++ .../util/write/registry/SubtreeWriterTest.java | 84 ++ .../write/util/TransactionWriteContextTest.java | 131 -- .../honeycomb/v3po/translate/util/DataObjects.java | 52 - .../v3po/translate/util/JsonUtilsTest.java | 109 -- .../CompositeReaderRegistryBuilderTest.java | 114 -- .../util/read/registry/SubtreeReaderTest.java | 124 -- .../util/read/registry/TypeHierarchyTest.java | 69 - .../registry/FlatWriterRegistryBuilderTest.java | 131 -- .../write/registry/FlatWriterRegistryTest.java | 264 ---- .../util/write/registry/SubtreeWriterTest.java | 84 -- v3po/postman_rest_collection.json | 1386 ++++++++++++++++++++ v3po/v3po2vpp/src/main/config/default-config.xml | 10 +- .../v3po/initializers/InterfacesInitializer.java | 282 ++++ .../SubInterfaceInitializationUtils.java | 92 ++ .../v3po/initializers/VppClasifierInitializer.java | 49 + .../v3po/initializers/VppInitializer.java | 97 ++ .../translate/v3po/interfaces/AclCustomizer.java | 91 ++ .../translate/v3po/interfaces/AclWriter.java | 74 ++ .../v3po/interfaces/EthernetCustomizer.java | 61 + .../v3po/interfaces/InterconnectionWriteUtils.java | 175 +++ .../v3po/interfaces/InterfaceCustomizer.java | 132 ++ .../translate/v3po/interfaces/L2Customizer.java | 89 ++ .../v3po/interfaces/RewriteCustomizer.java | 154 +++ .../v3po/interfaces/RoutingCustomizer.java | 108 ++ .../v3po/interfaces/SubInterfaceAclCustomizer.java | 100 ++ .../v3po/interfaces/SubInterfaceCustomizer.java | 223 ++++ .../v3po/interfaces/SubInterfaceL2Customizer.java | 100 ++ .../translate/v3po/interfaces/TapCustomizer.java | 197 +++ .../v3po/interfaces/VhostUserCustomizer.java | 167 +++ .../translate/v3po/interfaces/VxlanCustomizer.java | 177 +++ .../v3po/interfaces/VxlanGpeCustomizer.java | 176 +++ .../v3po/interfaces/ip/Ipv4AddressCustomizer.java | 135 ++ .../v3po/interfaces/ip/Ipv4Customizer.java | 78 ++ .../interfaces/ip/Ipv4NeighbourCustomizer.java | 133 ++ .../v3po/interfaces/ip/Ipv4WriteUtils.java | 111 ++ .../v3po/interfaces/ip/Ipv6Customizer.java | 57 + .../ip/SubInterfaceIpv4AddressCustomizer.java | 150 +++ .../v3po/interfacesstate/AclCustomizer.java | 96 ++ .../translate/v3po/interfacesstate/AclReader.java | 60 + .../v3po/interfacesstate/EthernetCustomizer.java | 87 ++ .../interfacesstate/InterconnectionReadUtils.java | 131 ++ .../v3po/interfacesstate/InterfaceCustomizer.java | 178 +++ .../v3po/interfacesstate/InterfaceUtils.java | 286 ++++ .../v3po/interfacesstate/L2Customizer.java | 75 ++ .../v3po/interfacesstate/RewriteCustomizer.java | 145 ++ .../interfacesstate/SubInterfaceAclCustomizer.java | 103 ++ .../interfacesstate/SubInterfaceCustomizer.java | 241 ++++ .../interfacesstate/SubInterfaceL2Customizer.java | 77 ++ .../v3po/interfacesstate/TapCustomizer.java | 121 ++ .../v3po/interfacesstate/VhostUserCustomizer.java | 130 ++ .../v3po/interfacesstate/VxlanCustomizer.java | 145 ++ .../v3po/interfacesstate/VxlanGpeCustomizer.java | 148 +++ .../interfacesstate/ip/Ipv4AddressCustomizer.java | 113 ++ .../v3po/interfacesstate/ip/Ipv4Customizer.java | 60 + .../ip/Ipv4NeighbourCustomizer.java | 73 ++ .../v3po/interfacesstate/ip/Ipv4ReadUtils.java | 130 ++ .../v3po/interfacesstate/ip/Ipv6Customizer.java | 64 + .../ip/SubInterfaceIpv4AddressCustomizer.java | 120 ++ .../InterfaceChangeNotificationProducer.java | 153 +++ .../translate/v3po/vpp/BridgeDomainCustomizer.java | 144 ++ .../translate/v3po/vpp/L2FibEntryCustomizer.java | 141 ++ .../v3po/vppclassifier/ClassifySessionReader.java | 202 +++ .../v3po/vppclassifier/ClassifySessionWriter.java | 147 +++ .../v3po/vppclassifier/ClassifyTableReader.java | 147 +++ .../v3po/vppclassifier/ClassifyTableWriter.java | 146 +++ .../v3po/vppclassifier/VppNodeReader.java | 41 + .../v3po/vppstate/BridgeDomainCustomizer.java | 154 +++ .../v3po/vppstate/L2FibEntryCustomizer.java | 154 +++ .../translate/v3po/vppstate/VersionCustomizer.java | 79 ++ .../v3po/initializers/InterfacesInitializer.java | 284 ---- .../SubInterfaceInitializationUtils.java | 92 -- .../v3po/initializers/VppClasifierInitializer.java | 49 - .../v3po/initializers/VppInitializer.java | 97 -- .../translate/v3po/interfaces/AclCustomizer.java | 91 -- .../v3po/translate/v3po/interfaces/AclWriter.java | 74 -- .../v3po/interfaces/EthernetCustomizer.java | 61 - .../v3po/interfaces/InterconnectionWriteUtils.java | 175 --- .../v3po/interfaces/InterfaceCustomizer.java | 132 -- .../translate/v3po/interfaces/L2Customizer.java | 89 -- .../v3po/interfaces/RewriteCustomizer.java | 154 --- .../v3po/interfaces/RoutingCustomizer.java | 108 -- .../v3po/interfaces/SubInterfaceAclCustomizer.java | 102 -- .../v3po/interfaces/SubInterfaceCustomizer.java | 223 ---- .../v3po/interfaces/SubInterfaceL2Customizer.java | 100 -- .../translate/v3po/interfaces/TapCustomizer.java | 197 --- .../v3po/interfaces/VhostUserCustomizer.java | 167 --- .../translate/v3po/interfaces/VxlanCustomizer.java | 177 --- .../v3po/interfaces/VxlanGpeCustomizer.java | 176 --- .../v3po/interfaces/ip/Ipv4AddressCustomizer.java | 137 -- .../v3po/interfaces/ip/Ipv4Customizer.java | 78 -- .../interfaces/ip/Ipv4NeighbourCustomizer.java | 133 -- .../v3po/interfaces/ip/Ipv4WriteUtils.java | 111 -- .../v3po/interfaces/ip/Ipv6Customizer.java | 57 - .../ip/SubInterfaceIpv4AddressCustomizer.java | 152 --- .../v3po/interfacesstate/AclCustomizer.java | 96 -- .../translate/v3po/interfacesstate/AclReader.java | 60 - .../v3po/interfacesstate/EthernetCustomizer.java | 87 -- .../interfacesstate/InterconnectionReadUtils.java | 131 -- .../v3po/interfacesstate/InterfaceCustomizer.java | 178 --- .../v3po/interfacesstate/InterfaceUtils.java | 287 ---- .../v3po/interfacesstate/L2Customizer.java | 75 -- .../v3po/interfacesstate/RewriteCustomizer.java | 145 -- .../interfacesstate/SubInterfaceAclCustomizer.java | 103 -- .../interfacesstate/SubInterfaceCustomizer.java | 242 ---- .../interfacesstate/SubInterfaceL2Customizer.java | 77 -- .../v3po/interfacesstate/TapCustomizer.java | 121 -- .../v3po/interfacesstate/VhostUserCustomizer.java | 130 -- .../v3po/interfacesstate/VxlanCustomizer.java | 145 -- .../v3po/interfacesstate/VxlanGpeCustomizer.java | 148 --- .../interfacesstate/ip/Ipv4AddressCustomizer.java | 113 -- .../v3po/interfacesstate/ip/Ipv4Customizer.java | 60 - .../ip/Ipv4NeighbourCustomizer.java | 73 -- .../v3po/interfacesstate/ip/Ipv4ReadUtils.java | 130 -- .../v3po/interfacesstate/ip/Ipv6Customizer.java | 64 - .../ip/SubInterfaceIpv4AddressCustomizer.java | 120 -- .../InterfaceChangeNotificationProducer.java | 153 --- .../translate/v3po/vpp/BridgeDomainCustomizer.java | 144 -- .../translate/v3po/vpp/L2FibEntryCustomizer.java | 141 -- .../v3po/vppclassifier/ClassifySessionReader.java | 202 --- .../v3po/vppclassifier/ClassifySessionWriter.java | 147 --- .../v3po/vppclassifier/ClassifyTableReader.java | 147 --- .../v3po/vppclassifier/ClassifyTableWriter.java | 146 --- .../v3po/vppclassifier/VppNodeReader.java | 41 - .../v3po/vppstate/BridgeDomainCustomizer.java | 154 --- .../v3po/vppstate/L2FibEntryCustomizer.java | 154 --- .../translate/v3po/vppstate/VersionCustomizer.java | 79 -- .../InterfacesConfigurationInitializerModule.java | 2 +- .../rev160406/InterfacesHoneycombWriterModule.java | 36 +- .../InterfacesStateHoneycombReaderModule.java | 34 +- .../SubinterfaceAugmentationWriterFactory.java | 20 +- ...SubinterfaceStateAugmentationReaderFactory.java | 20 +- ...ppClassifierConfigurationInitializerModule.java | 2 +- .../VppClassifierHoneycombWriterModule.java | 12 +- .../VppClassifierStateHoneycombReaderModule.java | 12 +- .../VppConfigurationInitializerModule.java | 2 +- .../rev160406/VppHoneycombWriterModule.java | 12 +- .../VppInterfaceNotificationProducerModule.java | 2 +- .../rev160406/VppStateHoneycombReaderModule.java | 20 +- v3po/v3po2vpp/src/main/yang/v3po2vpp.yang | 2 +- .../initializers/InterfacesInitializerTest.java | 106 ++ .../v3po/initializers/VppInitializerTest.java | 116 ++ .../v3po/interfaces/AclCustomizerTest.java | 221 ++++ .../v3po/interfaces/InterfaceTypeTestUtils.java | 40 + .../v3po/interfaces/RewriteCustomizerTest.java | 245 ++++ .../interfaces/SubInterfaceCustomizerTest.java | 320 +++++ .../v3po/interfaces/TapCustomizerTest.java | 161 +++ .../v3po/interfaces/VhostUserCustomizerTest.java | 294 +++++ .../v3po/interfaces/VxlanCustomizerTest.java | 253 ++++ .../v3po/interfaces/VxlanGpeCustomizerTest.java | 262 ++++ .../interfaces/ip/Ipv4AddressCustomizerTest.java | 292 +++++ .../interfaces/ip/Ipv4NeighbourCustomizerTest.java | 147 +++ .../v3po/interfacesstate/AclCustomizerTest.java | 132 ++ .../interfacesstate/InterfaceCustomizerTest.java | 212 +++ .../v3po/interfacesstate/InterfaceUtilsTest.java | 55 + .../v3po/interfacesstate/L2CustomizerTest.java | 179 +++ .../interfacesstate/RewriteCustomizerTest.java | 127 ++ .../SubInterfaceCustomizerTest.java | 146 +++ .../v3po/interfacesstate/VxlanCustomizerTest.java | 140 ++ .../interfacesstate/VxlanGpeCustomizerTest.java | 285 ++++ .../ip/Ipv4AddressCustomizerTest.java | 297 +++++ .../InterfaceChangeNotificationProducerTest.java | 130 ++ .../translate/v3po/test/ContextTestUtils.java | 70 + .../translate/v3po/test/InterfaceTestUtils.java | 52 + .../v3po/test/ListReaderCustomizerTest.java | 53 + .../translate/v3po/test/ReaderCustomizerTest.java | 94 ++ .../translate/v3po/test/TestHelperUtils.java | 37 + .../v3po/vpp/BridgeDomainCustomizerTest.java | 327 +++++ .../translate/v3po/vpp/BridgeDomainTestUtils.java | 64 + .../v3po/vpp/L2FibEntryCustomizerTest.java | 224 ++++ .../vppclassifier/ClassifySessionReaderTest.java | 136 ++ .../vppclassifier/ClassifySessionWriterTest.java | 218 +++ .../vppclassifier/ClassifyTableReaderTest.java | 154 +++ .../vppclassifier/ClassifyTableWriterTest.java | 228 ++++ .../v3po/vppstate/BridgeDomainCustomizerTest.java | 61 + .../v3po/vppstate/L2FibEntryCustomizerTest.java | 139 ++ .../v3po/vppstate/VersionCustomizerTest.java | 68 + .../translate/v3po/vppstate/VppStateTest.java | 308 +++++ .../translate/v3po/vppstate/VppStateTestUtils.java | 72 + .../initializers/InterfacesInitializerTest.java | 106 -- .../v3po/initializers/VppInitializerTest.java | 116 -- .../v3po/interfaces/AclCustomizerTest.java | 221 ---- .../v3po/interfaces/InterfaceTypeTestUtils.java | 47 - .../v3po/interfaces/RewriteCustomizerTest.java | 245 ---- .../interfaces/SubInterfaceCustomizerTest.java | 319 ----- .../v3po/interfaces/TapCustomizerTest.java | 157 --- .../v3po/interfaces/VhostUserCustomizerTest.java | 290 ---- .../v3po/interfaces/VxlanCustomizerTest.java | 253 ---- .../v3po/interfaces/VxlanGpeCustomizerTest.java | 259 ---- .../interfaces/ip/Ipv4AddressCustomizerTest.java | 292 ----- .../interfaces/ip/Ipv4NeighbourCustomizerTest.java | 147 --- .../v3po/interfacesstate/AclCustomizerTest.java | 131 -- .../interfacesstate/InterfaceCustomizerTest.java | 209 --- .../v3po/interfacesstate/InterfaceUtilsTest.java | 55 - .../v3po/interfacesstate/L2CustomizerTest.java | 178 --- .../interfacesstate/RewriteCustomizerTest.java | 127 -- .../SubInterfaceCustomizerTest.java | 145 -- .../v3po/interfacesstate/VxlanCustomizerTest.java | 140 -- .../interfacesstate/VxlanGpeCustomizerTest.java | 285 ---- .../ip/Ipv4AddressCustomizerTest.java | 297 ----- .../InterfaceChangeNotificationProducerTest.java | 130 -- .../v3po/translate/v3po/test/ContextTestUtils.java | 70 - .../translate/v3po/test/InterfaceTestUtils.java | 52 - .../v3po/test/ListReaderCustomizerTest.java | 53 - .../translate/v3po/test/ReaderCustomizerTest.java | 94 -- .../v3po/translate/v3po/test/TestHelperUtils.java | 37 - .../v3po/vpp/BridgeDomainCustomizerTest.java | 322 ----- .../translate/v3po/vpp/BridgeDomainTestUtils.java | 64 - .../v3po/vpp/L2FibEntryCustomizerTest.java | 224 ---- .../vppclassifier/ClassifySessionReaderTest.java | 136 -- .../vppclassifier/ClassifySessionWriterTest.java | 218 --- .../vppclassifier/ClassifyTableReaderTest.java | 153 --- .../vppclassifier/ClassifyTableWriterTest.java | 228 ---- .../v3po/vppstate/BridgeDomainCustomizerTest.java | 61 - .../v3po/vppstate/L2FibEntryCustomizerTest.java | 139 -- .../v3po/vppstate/VersionCustomizerTest.java | 68 - .../v3po/translate/v3po/vppstate/VppStateTest.java | 308 ----- .../translate/v3po/vppstate/VppStateTestUtils.java | 72 - .../impl/rev141210/ContextReaderModule.java | 6 +- .../v3po/util/AbstractInterfaceTypeCustomizer.java | 103 ++ .../translate/v3po/util/FutureJVppCustomizer.java | 45 + .../translate/v3po/util/NamingContext.java | 188 +++ .../translate/v3po/util/ReadTimeoutException.java | 33 + .../translate/v3po/util/SubInterfaceUtils.java | 28 + .../translate/v3po/util/TagRewriteOperation.java | 86 ++ .../translate/v3po/util/TranslateUtils.java | 225 ++++ .../translate/v3po/util/WriteTimeoutException.java | 33 + .../v3po/util/cache/DumpCacheManager.java | 2 +- .../v3po/util/AbstractInterfaceTypeCustomizer.java | 103 -- .../translate/v3po/util/FutureJVppCustomizer.java | 45 - .../v3po/translate/v3po/util/NamingContext.java | 188 --- .../translate/v3po/util/ReadTimeoutException.java | 33 - .../translate/v3po/util/SubInterfaceUtils.java | 28 - .../translate/v3po/util/TagRewriteOperation.java | 86 -- .../v3po/translate/v3po/util/TranslateUtils.java | 225 ---- .../translate/v3po/util/WriteTimeoutException.java | 33 - .../util/rev160406/NamingContextImplModule.java | 2 +- .../src/main/yang/vpp-util.yang | 2 +- .../translate/v3po/util/SubinterfaceUtilsTest.java | 32 + .../translate/v3po/util/TranslateUtilsTest.java | 137 ++ .../v3po/util/cache/DumpCacheManagerTest.java | 2 +- .../translate/v3po/util/SubinterfaceUtilsTest.java | 32 - .../translate/v3po/util/TranslateUtilsTest.java | 137 -- 504 files changed, 28848 insertions(+), 28932 deletions(-) create mode 100644 infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/AbstractDataTreeConverter.java create mode 100644 infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/DataTreeInitializer.java create mode 100644 infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/InitializerRegistry.java create mode 100644 infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/InitializerRegistryImpl.java create mode 100644 infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/RestoringInitializer.java delete mode 100644 infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/AbstractDataTreeConverter.java delete mode 100644 infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java delete mode 100644 infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistry.java delete mode 100644 infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImpl.java delete mode 100644 infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java create mode 100644 infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/ConfigurationInitializerRegistryModule.java create mode 100644 infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java create mode 100644 infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/PersistedFileInitializerModule.java create mode 100644 infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/PersistedFileInitializerModuleFactory.java delete mode 100644 infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java delete mode 100644 infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java delete mode 100644 infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java delete mode 100644 infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java create mode 100644 infra/cfg-init/src/main/yang/cfg-init.yang delete mode 100644 infra/cfg-init/src/main/yang/vpp-cfg-init.yang create mode 100644 infra/cfg-init/src/test/java/io/fd/honeycomb/data/init/InitializerRegistryImplTest.java delete mode 100644 infra/cfg-init/src/test/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImplTest.java create mode 100644 infra/data-api/src/main/java/io/fd/honeycomb/data/DataModification.java create mode 100644 infra/data-api/src/main/java/io/fd/honeycomb/data/ModifiableDataManager.java create mode 100644 infra/data-api/src/main/java/io/fd/honeycomb/data/ReadableDataManager.java delete mode 100644 infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataModification.java delete mode 100644 infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataManager.java delete mode 100644 infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableDataManager.java create mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/DataBroker.java create mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java create mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeManager.java create mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java create mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/PersistingDataTreeAdapter.java create mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadOnlyTransaction.java create mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadWriteTransaction.java create mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadableDataTreeDelegator.java create mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/WriteTransaction.java delete mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java delete mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java delete mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java delete mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModificationDiff.java delete mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java delete mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java delete mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java delete mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java delete mode 100644 infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java create mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/DataBrokerTest.java create mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegatorTest.java create mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java create mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/PersistingDataTreeAdapterTest.java create mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadOnlyTransactionTest.java create mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadWriteTransactionTest.java create mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadableDataTreeDelegatorTest.java create mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/WriteTransactionTest.java delete mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java delete mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java delete mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java delete mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java delete mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java delete mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java delete mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java delete mode 100644 infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java create mode 100644 infra/impl/src/main/java/io/fd/honeycomb/impl/NorthboundFacadeHoneycombDOMBroker.java delete mode 100644 infra/impl/src/main/java/io/fd/honeycomb/v3po/impl/NorthboundFacadeHoneycombDOMBroker.java create mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/ContextDataBrokerModule.java create mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/ContextDataBrokerModuleFactory.java create mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/DataBrokerModule.java create mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/DataBrokerModuleFactory.java create mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/HoneycombModule.java create mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/HoneycombModuleFactory.java create mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfBindingBrokerModule.java create mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfBindingBrokerModuleFactory.java create mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfMonitoringReaderModule.java create mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfMonitoringReaderModuleFactory.java delete mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModule.java delete mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModuleFactory.java delete mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModule.java delete mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModuleFactory.java delete mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModule.java delete mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModuleFactory.java delete mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModule.java delete mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModuleFactory.java delete mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java delete mode 100644 infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java create mode 100644 infra/impl/src/main/yang/honeycomb-impl.yang delete mode 100644 infra/impl/src/main/yang/v3po-impl.yang delete mode 100644 infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java delete mode 100644 infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java create mode 100644 infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/AbstractInfraTest.java create mode 100644 infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombReadInfraTest.java create mode 100644 infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombSubtreeReadInfraTest.java create mode 100644 infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java create mode 100644 infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/Ids.java delete mode 100644 infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/AbstractInfraTest.java delete mode 100644 infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombReadInfraTest.java delete mode 100644 infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombSubtreeReadInfraTest.java delete mode 100644 infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombWriteInfraTest.java delete mode 100644 infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/Ids.java create mode 100644 infra/notification/api/src/main/java/io/fd/honeycomb/notification/ManagedNotificationProducer.java create mode 100644 infra/notification/api/src/main/java/io/fd/honeycomb/notification/NotificationCollector.java create mode 100644 infra/notification/api/src/main/java/io/fd/honeycomb/notification/NotificationProducer.java delete mode 100644 infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/ManagedNotificationProducer.java delete mode 100644 infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationCollector.java delete mode 100644 infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationProducer.java create mode 100644 infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/HoneycombNotificationCollector.java create mode 100644 infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/NotificationProducerRegistry.java create mode 100644 infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/NotificationProducerTracker.java delete mode 100644 infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollector.java delete mode 100644 infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistry.java delete mode 100644 infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTracker.java create mode 100644 infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/HoneycombNotificationCollectorTest.java create mode 100644 infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/NotificationProducerRegistryTest.java create mode 100644 infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/NotificationProducerTrackerTest.java delete mode 100644 infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollectorTest.java delete mode 100644 infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistryTest.java delete mode 100644 infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTrackerTest.java delete mode 100644 infra/postman_rest_collection.json create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/MappingContext.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModifiableSubtreeManagerRegistryBuilder.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModificationCache.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModificationContext.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/SubtreeManager.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/SubtreeManagerRegistryBuilder.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/TranslationException.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ListReader.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReadContext.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReadFailedException.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/Reader.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReaderFactory.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ModifiableReaderRegistryBuilder.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ReaderRegistry.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ReaderRegistryBuilder.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/DataObjectUpdate.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/ListWriter.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriteContext.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriteFailedException.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/Writer.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriterFactory.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/ModifiableWriterRegistryBuilder.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/WriterRegistry.java create mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/WriterRegistryBuilder.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java delete mode 100644 infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java create mode 100644 infra/translate-api/src/test/java/io/fd/honeycomb/translate/ReadFailedExceptionTest.java delete mode 100644 infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java create mode 100644 infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/GenericListReader.java create mode 100644 infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/GenericReader.java create mode 100644 infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/GenericListWriter.java create mode 100644 infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/GenericWriter.java delete mode 100644 infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericListReader.java delete mode 100644 infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericReader.java delete mode 100644 infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriter.java delete mode 100644 infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java create mode 100644 infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/GenericListWriterTest.java create mode 100644 infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/GenericWriterTest.java delete mode 100644 infra/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriterTest.java delete mode 100644 infra/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriterTest.java create mode 100644 infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/read/ListReaderCustomizer.java create mode 100644 infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/read/ReaderCustomizer.java create mode 100644 infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/write/ListWriterCustomizer.java create mode 100644 infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/write/WriterCustomizer.java delete mode 100644 infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/ListReaderCustomizer.java delete mode 100644 infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/ReaderCustomizer.java delete mode 100644 infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/write/ListWriterCustomizer.java delete mode 100644 infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/write/WriterCustomizer.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/JsonUtils.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/RWUtils.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/ReflectionUtils.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/TransactionMappingContext.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/AbstractGenericReader.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/BindingBrokerReader.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/KeepaliveReaderWrapper.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/NoopReaderCustomizer.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveListReaderCustomizer.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveReader.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveReaderCustomizer.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReader.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistry.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistryBuilder.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/SubtreeReader.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/TypeHierarchy.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/AbstractGenericWriter.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/NoopWriterRegistry.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/TransactionWriteContext.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistry.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryBuilder.java create mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/SubtreeWriter.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/JsonUtils.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/RWUtils.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/ReflectionUtils.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/TransactionMappingContext.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/AbstractGenericReader.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/BindingBrokerReader.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/KeepaliveReaderWrapper.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/NoopReaderCustomizer.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveListReaderCustomizer.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReader.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReaderCustomizer.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReader.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistry.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilder.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReader.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/TypeHierarchy.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/AbstractGenericWriter.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/NoopWriterRegistry.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/TransactionWriteContext.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistry.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryBuilder.java delete mode 100644 infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/SubtreeWriter.java create mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/translate/impl/write/util/TransactionWriteContextTest.java create mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/DataObjects.java create mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/JsonUtilsTest.java create mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java create mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/SubtreeReaderTest.java create mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/TypeHierarchyTest.java create mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryBuilderTest.java create mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryTest.java create mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/SubtreeWriterTest.java delete mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/util/TransactionWriteContextTest.java delete mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/DataObjects.java delete mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/JsonUtilsTest.java delete mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java delete mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReaderTest.java delete mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/TypeHierarchyTest.java delete mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryBuilderTest.java delete mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryTest.java delete mode 100644 infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/SubtreeWriterTest.java create mode 100644 v3po/postman_rest_collection.json create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/SubInterfaceInitializationUtils.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppClasifierInitializer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclWriter.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/EthernetCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterconnectionWriteUtils.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/L2Customizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2Customizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4Customizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4WriteUtils.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv6Customizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclReader.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/EthernetCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterconnectionReadUtils.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2Customizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/TapCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VhostUserCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4Customizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv6Customizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/InterfacesInitializer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/SubInterfaceInitializationUtils.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppClasifierInitializer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppInitializer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclWriter.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/EthernetCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterconnectionWriteUtils.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/L2Customizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RewriteCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RoutingCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceAclCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceL2Customizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VhostUserCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanGpeCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4Customizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4WriteUtils.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv6Customizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclReader.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/EthernetCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterconnectionReadUtils.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2Customizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/RewriteCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/TapCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VhostUserCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanGpeCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4Customizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv6Customizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/notification/InterfaceChangeNotificationProducer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vpp/L2FibEntryCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReader.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriter.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReader.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriter.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/VppNodeReader.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/L2FibEntryCustomizer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VersionCustomizer.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceTypeTestUtils.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtilsTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2CustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ContextTestUtils.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/InterfaceTestUtils.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ListReaderCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ReaderCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/TestHelperUtils.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainTestUtils.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReaderTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriterTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReaderTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriterTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VppStateTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VppStateTestUtils.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/initializers/InterfacesInitializerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppInitializerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceTypeTestUtils.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RewriteCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VhostUserCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanGpeCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtilsTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2CustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/RewriteCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanGpeCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/notification/InterfaceChangeNotificationProducerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ContextTestUtils.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/InterfaceTestUtils.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ListReaderCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ReaderCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/TestHelperUtils.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainTestUtils.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/L2FibEntryCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReaderTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriterTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReaderTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriterTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/L2FibEntryCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VersionCustomizerTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VppStateTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VppStateTestUtils.java create mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/AbstractInterfaceTypeCustomizer.java create mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/FutureJVppCustomizer.java create mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/NamingContext.java create mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/ReadTimeoutException.java create mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/SubInterfaceUtils.java create mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TagRewriteOperation.java create mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TranslateUtils.java create mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/WriteTimeoutException.java delete mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/AbstractInterfaceTypeCustomizer.java delete mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/FutureJVppCustomizer.java delete mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/NamingContext.java delete mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/ReadTimeoutException.java delete mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/SubInterfaceUtils.java delete mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TagRewriteOperation.java delete mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtils.java delete mode 100644 vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/WriteTimeoutException.java create mode 100644 vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/SubinterfaceUtilsTest.java create mode 100644 vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/TranslateUtilsTest.java delete mode 100644 vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/SubinterfaceUtilsTest.java delete mode 100644 vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtilsTest.java diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/AbstractDataTreeConverter.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/AbstractDataTreeConverter.java new file mode 100644 index 000000000..74cdc3058 --- /dev/null +++ b/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/AbstractDataTreeConverter.java @@ -0,0 +1,114 @@ +/* + * 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.data.init; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Base class for initializers which perform conversion between operational and config YANG model. + * + * @param Config data object + * @param Operational data object + */ +@Beta +public abstract class AbstractDataTreeConverter + implements DataTreeInitializer { + private static final Logger LOG = LoggerFactory.getLogger(AbstractDataTreeConverter.class); + + private final InstanceIdentifier idOper; + private final InstanceIdentifier idConfig; + private final DataBroker bindingDataBroker; + + public AbstractDataTreeConverter(final DataBroker bindingDataBroker, + final InstanceIdentifier operRootId, + final InstanceIdentifier cfgRootId) { + this.bindingDataBroker = checkNotNull(bindingDataBroker, "bindingDataBroker should not be null"); + this.idOper = checkNotNull(operRootId, "operRootId should not be null"); + this.idConfig = checkNotNull(cfgRootId, "cfgRootId should not be null"); + } + + @Override + public void close() throws Exception { + LOG.debug("AbstractDataTreeConverter.close()"); + // Not removing initialized data, since this works in cooperation with persistence, it could remove + // data restored by persistence or remove user configured data when shutting down HC + } + + @Override + public final void initialize() throws InitializeException { + LOG.debug("AbstractDataTreeConverter.initialize() from(oper): {}, to(cfg): {}", idOper, idConfig); + final Optional data = readData(); + + if (data.isPresent()) { + LOG.debug("Config initialization, operational data={}", data); + + final O operationalData = data.get(); + final C configData = convert(operationalData); + + try { + LOG.debug("Initializing config with data={}", configData); + writeData(configData); + LOG.info("Config initialization successful from(oper): {}, to(cfg): {}", idOper, idConfig); + } catch (TransactionCommitFailedException e) { + throw new InitializeException("Failed to perform config initialization", e); + } + } else { + LOG.info("Data is not present under: {}, no initial changes to config at: {}", idOper, idConfig); + } + } + + private Optional readData() { + try (ReadOnlyTransaction readTx = bindingDataBroker.newReadOnlyTransaction()) { + final CheckedFuture, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> + readFuture = readTx.read(LogicalDatastoreType.OPERATIONAL, idOper); + return readFuture.checkedGet(); + } catch (org.opendaylight.controller.md.sal.common.api.data.ReadFailedException e) { + LOG.warn("Failed to read operational state", e); + } + return Optional.absent(); + } + + private void writeData(final C configData) throws TransactionCommitFailedException { + final WriteTransaction writeTx = bindingDataBroker.newWriteOnlyTransaction(); + // Merge(instead of put) has to be used due to dynamic start, this might be executed multiple times + // and might overwrite config restored from persisted file with the same incomplete config. + // Making the entire configuration trigger VPP twice (on second persis ... and VPP does not like that + writeTx.merge(LogicalDatastoreType.CONFIGURATION, idConfig, configData); + writeTx.submit().checkedGet(); + } + + // TODO make this class concrete and use function dependency instead of abstract method + /** + * Converts operational data to config data for given root node + * @param operationalData data object representing operational data + * @return data object representing config data + */ + protected abstract C convert(final O operationalData); +} diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/DataTreeInitializer.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/DataTreeInitializer.java new file mode 100644 index 000000000..c0ff8c2be --- /dev/null +++ b/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/DataTreeInitializer.java @@ -0,0 +1,51 @@ +/* + * 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.data.init; + +import com.google.common.annotations.Beta; + +/** + * Service for config data tree initialization. + * Implementation reads operational data and initializes config data tree. + * Initialization does not cause any change in VPP state, unlike ordinary writes to config. + */ +@Beta +public interface DataTreeInitializer extends AutoCloseable { + + /** + * Initializes config data tree for supported root node. + * @throws InitializeException if initialization failed + */ + void initialize() throws InitializeException; + + /** + * Removes all data managed by the initializer. + */ + @Override + void close() throws Exception; + + class InitializeException extends Exception { + + public InitializeException(final String message, final Throwable cause) { + super(message, cause); + } + + public InitializeException(final String msg) { + super(msg); + } + } +} diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/InitializerRegistry.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/InitializerRegistry.java new file mode 100644 index 000000000..b662a4fae --- /dev/null +++ b/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/InitializerRegistry.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.data.init; + +import com.google.common.annotations.Beta; + +/** + * Data tree initializer suitable as a holder for all other root initializers, providing initializeAll feature. + */ +@Beta +public interface InitializerRegistry extends DataTreeInitializer { + + /** + * Performs initialize on all registered root initializers. + * @throws if initialization failed + */ + @Override + void initialize() throws InitializeException; +} diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/InitializerRegistryImpl.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/InitializerRegistryImpl.java new file mode 100644 index 000000000..b83dd1e04 --- /dev/null +++ b/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/InitializerRegistryImpl.java @@ -0,0 +1,52 @@ +/* + * 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.data.init; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import javax.annotation.Nonnull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class InitializerRegistryImpl implements InitializerRegistry { + private static final Logger LOG = LoggerFactory.getLogger(InitializerRegistryImpl.class); + private final List initializers; + + public InitializerRegistryImpl(@Nonnull List initializers) { + this.initializers = checkNotNull(initializers, "initializers should not be null"); + checkArgument(!initializers.contains(null), "initializers should not contain null elements"); + } + + @Override + public void close() throws Exception { + LOG.debug("InitializerRegistryImpl.close()"); + for (DataTreeInitializer initializer : initializers) { + initializer.close(); + } + } + + @Override + public void initialize() throws InitializeException { + // TODO check if readers are there + LOG.debug("InitializerRegistryImpl.initialize()"); + for (DataTreeInitializer initializer : initializers) { + initializer.initialize(); + } + } +} diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/RestoringInitializer.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/RestoringInitializer.java new file mode 100644 index 000000000..54c3df787 --- /dev/null +++ b/infra/cfg-init/src/main/java/io/fd/honeycomb/data/init/RestoringInitializer.java @@ -0,0 +1,112 @@ +/* + * 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.data.init; + +import static com.google.common.base.Preconditions.checkArgument; + +import io.fd.honeycomb.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.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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RestoringInitializer implements DataTreeInitializer { + + private static final Logger LOG = LoggerFactory.getLogger(RestoringInitializer.class); + + 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) { + if (Files.exists(path)) { + checkArgument(!Files.isDirectory(path), "File %s is a directory", path); + checkArgument(Files.isReadable(path), "File %s is not readable", path); + } + + return path; + } + + @Override + public void initialize() throws InitializeException { + LOG.debug("Starting restoration of {} from {} using {}", dataTree, path, restorationType); + if(!Files.exists(path)) { + LOG.debug("Persist file {} does not exist. Skipping restoration", path); + return; + } + + try { + final ContainerNode containerNode = JsonUtils + .readJsonRoot(schemaService.getGlobalContext(), Files.newInputStream(path, StandardOpenOption.READ)); + + final DOMDataWriteTransaction domDataWriteTransaction = dataTree.newWriteOnlyTransaction(); + for (DataContainerChild dataContainerChild : containerNode + .getValue()) { + final YangInstanceIdentifier iid = YangInstanceIdentifier.create(dataContainerChild.getIdentifier()); + LOG.trace("Restoring {} from {}", iid, path); + + 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(); + LOG.debug("Data from {} restored successfully", path); + + } catch (IOException | TransactionCommitFailedException e) { + throw new InitializeException("Unable to restore data from " + path, e); + } + } + + @Override + public void close() {} +} diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/AbstractDataTreeConverter.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/AbstractDataTreeConverter.java deleted file mode 100644 index f0058264e..000000000 --- a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/AbstractDataTreeConverter.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.checkNotNull; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Base class for initializers which perform conversion between operational and config YANG model. - * - * @param Config data object - * @param Operational data object - */ -@Beta -public abstract class AbstractDataTreeConverter - implements DataTreeInitializer { - private static final Logger LOG = LoggerFactory.getLogger(AbstractDataTreeConverter.class); - - private final InstanceIdentifier idOper; - private final InstanceIdentifier idConfig; - private final DataBroker bindingDataBroker; - - public AbstractDataTreeConverter(final DataBroker bindingDataBroker, - final InstanceIdentifier operRootId, - final InstanceIdentifier cfgRootId) { - this.bindingDataBroker = checkNotNull(bindingDataBroker, "bindingDataBroker should not be null"); - this.idOper = checkNotNull(operRootId, "operRootId should not be null"); - this.idConfig = checkNotNull(cfgRootId, "cfgRootId should not be null"); - } - - @Override - public void close() throws Exception { - LOG.debug("AbstractDataTreeConverter.close()"); - // Not removing initialized data, since this works in cooperation with persistence, it could remove - // data restored by persistence or remove user configured data when shutting down HC - } - - @Override - public final void initialize() throws InitializeException { - LOG.debug("AbstractDataTreeConverter.initialize() from(oper): {}, to(cfg): {}", idOper, idConfig); - final Optional data = readData(); - - if (data.isPresent()) { - LOG.debug("Config initialization, operational data={}", data); - - final O operationalData = data.get(); - final C configData = convert(operationalData); - - try { - LOG.debug("Initializing config with data={}", configData); - writeData(configData); - LOG.info("Config initialization successful from(oper): {}, to(cfg): {}", idOper, idConfig); - } catch (TransactionCommitFailedException e) { - throw new InitializeException("Failed to perform config initialization", e); - } - } else { - LOG.info("Data is not present under: {}, no initial changes to config at: {}", idOper, idConfig); - } - } - - private Optional readData() { - try (ReadOnlyTransaction readTx = bindingDataBroker.newReadOnlyTransaction()) { - final CheckedFuture, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> - readFuture = readTx.read(LogicalDatastoreType.OPERATIONAL, idOper); - return readFuture.checkedGet(); - } catch (org.opendaylight.controller.md.sal.common.api.data.ReadFailedException e) { - LOG.warn("Failed to read operational state", e); - } - return Optional.absent(); - } - - private void writeData(final C configData) throws TransactionCommitFailedException { - final WriteTransaction writeTx = bindingDataBroker.newWriteOnlyTransaction(); - // Merge(instead of put) has to be used due to dynamic start, this might be executed multiple times - // and might overwrite config restored from persisted file with the same incomplete config. - // Making the entire configuration trigger VPP twice (on second persis ... and VPP does not like that - writeTx.merge(LogicalDatastoreType.CONFIGURATION, idConfig, configData); - writeTx.submit().checkedGet(); - } - - // TODO make this class concrete and use function dependency instead of abstract method - /** - * Converts operational data to config data for given root node - * @param operationalData data object representing operational data - * @return data object representing config data - */ - protected abstract C convert(final O operationalData); -} diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java deleted file mode 100644 index d760401f9..000000000 --- a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 com.google.common.annotations.Beta; - -/** - * Service for config data tree initialization. - * Implementation reads operational data and initializes config data tree. - * Initialization does not cause any change in VPP state, unlike ordinary writes to config. - */ -@Beta -public interface DataTreeInitializer extends AutoCloseable { - - /** - * Initializes config data tree for supported root node. - * @throws InitializeException if initialization failed - */ - void initialize() throws InitializeException; - - /** - * Removes all data managed by the initializer. - */ - @Override - void close() throws Exception; - - class InitializeException extends Exception { - - public InitializeException(final String message, final Throwable cause) { - super(message, cause); - } - - public InitializeException(final String msg) { - super(msg); - } - } -} diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistry.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistry.java deleted file mode 100644 index 8760f0f09..000000000 --- a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistry.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 com.google.common.annotations.Beta; - -/** - * Data tree initializer suitable as a holder for all other root initializers, providing initializeAll feature. - */ -@Beta -public interface InitializerRegistry extends DataTreeInitializer { - - /** - * Performs initialize on all registered root initializers. - * @throws if initialization failed - */ - @Override - void initialize() throws InitializeException; -} diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImpl.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImpl.java deleted file mode 100644 index e5220f7e8..000000000 --- a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 static com.google.common.base.Preconditions.checkNotNull; - -import java.util.List; -import javax.annotation.Nonnull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class InitializerRegistryImpl implements InitializerRegistry { - private static final Logger LOG = LoggerFactory.getLogger(InitializerRegistryImpl.class); - private final List initializers; - - public InitializerRegistryImpl(@Nonnull List initializers) { - this.initializers = checkNotNull(initializers, "initializers should not be null"); - checkArgument(!initializers.contains(null), "initializers should not contain null elements"); - } - - @Override - public void close() throws Exception { - LOG.debug("InitializerRegistryImpl.close()"); - for (DataTreeInitializer initializer : initializers) { - initializer.close(); - } - } - - @Override - public void initialize() throws InitializeException { - // TODO check if readers are there - LOG.debug("InitializerRegistryImpl.initialize()"); - for (DataTreeInitializer initializer : initializers) { - initializer.initialize(); - } - } -} diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java deleted file mode 100644 index abc3f54c0..000000000 --- a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RestoringInitializer implements DataTreeInitializer { - - private static final Logger LOG = LoggerFactory.getLogger(RestoringInitializer.class); - - 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) { - if (Files.exists(path)) { - checkArgument(!Files.isDirectory(path), "File %s is a directory", path); - checkArgument(Files.isReadable(path), "File %s is not readable", path); - } - - return path; - } - - @Override - public void initialize() throws InitializeException { - LOG.debug("Starting restoration of {} from {} using {}", dataTree, path, restorationType); - if(!Files.exists(path)) { - LOG.debug("Persist file {} does not exist. Skipping restoration", path); - return; - } - - try { - final ContainerNode containerNode = JsonUtils - .readJsonRoot(schemaService.getGlobalContext(), Files.newInputStream(path, StandardOpenOption.READ)); - - final DOMDataWriteTransaction domDataWriteTransaction = dataTree.newWriteOnlyTransaction(); - for (DataContainerChild dataContainerChild : containerNode - .getValue()) { - final YangInstanceIdentifier iid = YangInstanceIdentifier.create(dataContainerChild.getIdentifier()); - LOG.trace("Restoring {} from {}", iid, path); - - 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(); - LOG.debug("Data from {} restored successfully", path); - - } catch (IOException | TransactionCommitFailedException e) { - throw new InitializeException("Unable to restore data from " + path, e); - } - } - - @Override - public void close() {} -} diff --git a/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/ConfigurationInitializerRegistryModule.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/ConfigurationInitializerRegistryModule.java new file mode 100644 index 000000000..3a90c5303 --- /dev/null +++ b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/ConfigurationInitializerRegistryModule.java @@ -0,0 +1,54 @@ +package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.init.rev160407; + +import io.fd.honeycomb.data.init.InitializerRegistry; +import io.fd.honeycomb.data.init.InitializerRegistryImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** +* Initializer registry, delegating initialization to a list of initializers +*/ +public class ConfigurationInitializerRegistryModule extends 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, 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("Config 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("Configuration initialized successfully"); + // Initialize stored configuration on top + 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/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java new file mode 100644 index 000000000..461c1f01b --- /dev/null +++ b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java @@ -0,0 +1,14 @@ +/* +* 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.data.init.rev160407; +public class ConfigurationInitializerRegistryModuleFactory extends + AbstractConfigurationInitializerRegistryModuleFactory { + +} diff --git a/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/PersistedFileInitializerModule.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/PersistedFileInitializerModule.java new file mode 100644 index 000000000..b57ded9fc --- /dev/null +++ b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/PersistedFileInitializerModule.java @@ -0,0 +1,38 @@ +package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.init.rev160407; + +import io.fd.honeycomb.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 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, 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/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/PersistedFileInitializerModuleFactory.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/init/rev160407/PersistedFileInitializerModuleFactory.java new file mode 100644 index 000000000..7e703d558 --- /dev/null +++ b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/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.data.init.rev160407; +public class PersistedFileInitializerModuleFactory extends AbstractPersistedFileInitializerModuleFactory { + +} diff --git a/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java deleted file mode 100644 index 3fff82e32..000000000 --- a/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java +++ /dev/null @@ -1,54 +0,0 @@ -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 - 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/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java deleted file mode 100644 index f07be953e..000000000 --- a/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java +++ /dev/null @@ -1,13 +0,0 @@ -/* -* 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/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java deleted file mode 100644 index 188d1641c..000000000 --- a/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java +++ /dev/null @@ -1,38 +0,0 @@ -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/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java deleted file mode 100644 index 1d7a3c9c6..000000000 --- a/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java +++ /dev/null @@ -1,13 +0,0 @@ -/* -* 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/infra/cfg-init/src/main/yang/cfg-init.yang b/infra/cfg-init/src/main/yang/cfg-init.yang new file mode 100644 index 000000000..8b1a4d9d1 --- /dev/null +++ b/infra/cfg-init/src/main/yang/cfg-init.yang @@ -0,0 +1,117 @@ +module cfg-init { + yang-version 1; + namespace "urn:honeycomb:params:xml:ns:yang:data:init"; + prefix "init"; + + import config { prefix config; revision-date 2013-04-05; } + 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; } + + description + "This module contains initializers for config data tree"; + + revision "2016-04-07" { + description + "Initial revision"; + } + + identity cfg-initializer { + base "config:service-type"; + config:java-class io.fd.honeycomb.data.init.DataTreeInitializer; + } + + 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; + mandatory true; + } + + leaf restoration-type { + type restoration-type; + default merge; + } + + + leaf datastore-type { + type dapi:datatree-type; + mandatory true; + } + } + } + +} \ No newline at end of file diff --git a/infra/cfg-init/src/main/yang/vpp-cfg-init.yang b/infra/cfg-init/src/main/yang/vpp-cfg-init.yang deleted file mode 100644 index 52750d926..000000000 --- a/infra/cfg-init/src/main/yang/vpp-cfg-init.yang +++ /dev/null @@ -1,117 +0,0 @@ -module vpp-cfg-init { - yang-version 1; - namespace "urn:honeycomb:params:xml:ns:yang:vpp:data:init"; - prefix "init"; - - import config { prefix config; revision-date 2013-04-05; } - 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; } - - description - "This module contains initializers for VPP config data tree"; - - revision "2016-04-07" { - description - "Initial revision"; - } - - identity cfg-initializer { - base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.vpp.data.init.DataTreeInitializer; - } - - 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; - mandatory true; - } - - leaf restoration-type { - type restoration-type; - default merge; - } - - - leaf datastore-type { - type dapi:datatree-type; - mandatory true; - } - } - } - -} \ No newline at end of file diff --git a/infra/cfg-init/src/test/java/io/fd/honeycomb/data/init/InitializerRegistryImplTest.java b/infra/cfg-init/src/test/java/io/fd/honeycomb/data/init/InitializerRegistryImplTest.java new file mode 100644 index 000000000..009b7c9b4 --- /dev/null +++ b/infra/cfg-init/src/test/java/io/fd/honeycomb/data/init/InitializerRegistryImplTest.java @@ -0,0 +1,66 @@ +/* + * 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.data.init; + +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; + +public class InitializerRegistryImplTest { + + @Mock(name="dti1") + private DataTreeInitializer dti1; + @Mock(name="dti2") + private DataTreeInitializer dti2; + @Mock(name="dti3") + private DataTreeInitializer dti3; + + private InitializerRegistryImpl initializerRegistry; + + @Before + public void setUp() throws Exception { + initMocks(this); + initializerRegistry = new InitializerRegistryImpl(Arrays.asList(dti1, dti2, dti3)); + } + + @Test(expected = IllegalArgumentException.class) + public void testConstructorFailed() throws Exception { + new InitializerRegistryImpl(Arrays.asList(dti1, null)); + } + + @Test + public void testInitialize() throws Exception { + initializerRegistry.initialize(); + + verify(dti1).initialize(); + verify(dti2).initialize(); + verify(dti3).initialize(); + } + + @Test + public void testClose() throws Exception { + initializerRegistry.close(); + + verify(dti1).close(); + verify(dti2).close(); + verify(dti3).close(); + } +} \ No newline at end of file diff --git a/infra/cfg-init/src/test/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImplTest.java b/infra/cfg-init/src/test/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImplTest.java deleted file mode 100644 index d562fb60c..000000000 --- a/infra/cfg-init/src/test/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImplTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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 org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import java.util.Arrays; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; - -public class InitializerRegistryImplTest { - - @Mock(name="dti1") - private DataTreeInitializer dti1; - @Mock(name="dti2") - private DataTreeInitializer dti2; - @Mock(name="dti3") - private DataTreeInitializer dti3; - - private InitializerRegistryImpl initializerRegistry; - - @Before - public void setUp() throws Exception { - initMocks(this); - initializerRegistry = new InitializerRegistryImpl(Arrays.asList(dti1, dti2, dti3)); - } - - @Test(expected = IllegalArgumentException.class) - public void testConstructorFailed() throws Exception { - new InitializerRegistryImpl(Arrays.asList(dti1, null)); - } - - @Test - public void testInitialize() throws Exception { - initializerRegistry.initialize(); - - verify(dti1).initialize(); - verify(dti2).initialize(); - verify(dti3).initialize(); - } - - @Test - public void testClose() throws Exception { - initializerRegistry.close(); - - verify(dti1).close(); - verify(dti2).close(); - verify(dti3).close(); - } -} \ No newline at end of file diff --git a/infra/data-api/src/main/java/io/fd/honeycomb/data/DataModification.java b/infra/data-api/src/main/java/io/fd/honeycomb/data/DataModification.java new file mode 100644 index 000000000..6e903a4e2 --- /dev/null +++ b/infra/data-api/src/main/java/io/fd/honeycomb/data/DataModification.java @@ -0,0 +1,70 @@ +/* + * 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.data; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.TranslationException; +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.DataValidationFailedException; + +/** + * Modification of a {@link ModifiableDataManager}. + */ +@Beta +public interface DataModification extends ReadableDataManager { + + /** + * Delete the node at specified path. + * + * @param path Node path + */ + void delete(YangInstanceIdentifier path); + + /** + * Merge the specified data with the currently-present data + * at specified path. + * + * @param path Node path + * @param data Data to be merged + */ + void merge(YangInstanceIdentifier path, NormalizedNode data); + + /** + * Replace the data at specified path with supplied data. + * + * @param path Node path + * @param data New node data + */ + void write(YangInstanceIdentifier path, NormalizedNode data); + + /** + * Alters data tree using this modification. + * + * @throws DataValidationFailedException if modification data is not valid + * @throws TranslationException if failed while updating data tree state + */ + void commit() throws DataValidationFailedException, TranslationException; + + /** + * Validate and prepare modification before commit. Besides commit, no further operation is expected after validate + * and the behaviour is undefined. + * + * @throws DataValidationFailedException if modification data is not valid + */ + void validate() throws DataValidationFailedException; +} diff --git a/infra/data-api/src/main/java/io/fd/honeycomb/data/ModifiableDataManager.java b/infra/data-api/src/main/java/io/fd/honeycomb/data/ModifiableDataManager.java new file mode 100644 index 000000000..7652ccf82 --- /dev/null +++ b/infra/data-api/src/main/java/io/fd/honeycomb/data/ModifiableDataManager.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.data; + +import com.google.common.annotations.Beta; + +/** + * Facade over data tree that allows tree modification. + */ +@Beta +public interface ModifiableDataManager extends ReadableDataManager { + + /** + * Creates read-only snapshot of a ModifiableDataTree. + * + * @return modification + */ + DataModification newModification(); +} diff --git a/infra/data-api/src/main/java/io/fd/honeycomb/data/ReadableDataManager.java b/infra/data-api/src/main/java/io/fd/honeycomb/data/ReadableDataManager.java new file mode 100644 index 000000000..887732ad4 --- /dev/null +++ b/infra/data-api/src/main/java/io/fd/honeycomb/data/ReadableDataManager.java @@ -0,0 +1,40 @@ +/* + * 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.data; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Facade over data tree that allows reading tree nodes. + */ +@Beta +public interface ReadableDataManager { + + /** + * Reads a particular node from the data tree. + * + * @param path Path of the node + * @return a CheckFuture containing the result of the read. + */ + CheckedFuture>, ReadFailedException> read(@Nonnull final YangInstanceIdentifier path); +} diff --git a/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataModification.java b/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataModification.java deleted file mode 100644 index d05c55716..000000000 --- a/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataModification.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.data; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.TranslationException; -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.DataValidationFailedException; - -/** - * Modification of a {@link ModifiableDataManager}. - */ -@Beta -public interface DataModification extends ReadableDataManager { - - /** - * Delete the node at specified path. - * - * @param path Node path - */ - void delete(YangInstanceIdentifier path); - - /** - * Merge the specified data with the currently-present data - * at specified path. - * - * @param path Node path - * @param data Data to be merged - */ - void merge(YangInstanceIdentifier path, NormalizedNode data); - - /** - * Replace the data at specified path with supplied data. - * - * @param path Node path - * @param data New node data - */ - void write(YangInstanceIdentifier path, NormalizedNode data); - - /** - * Alters data tree using this modification. - * - * @throws DataValidationFailedException if modification data is not valid - * @throws TranslationException if failed while updating data tree state - */ - void commit() throws DataValidationFailedException, TranslationException; - - /** - * Validate and prepare modification before commit. Besides commit, no further operation is expected after validate - * and the behaviour is undefined. - * - * @throws DataValidationFailedException if modification data is not valid - */ - void validate() throws DataValidationFailedException; -} diff --git a/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataManager.java b/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataManager.java deleted file mode 100644 index 11cd513ea..000000000 --- a/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataManager.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.data; - -import com.google.common.annotations.Beta; - -/** - * Facade over data tree that allows tree modification. - */ -@Beta -public interface ModifiableDataManager extends ReadableDataManager { - - /** - * Creates read-only snapshot of a ModifiableDataTree. - * - * @return modification - */ - DataModification newModification(); -} diff --git a/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableDataManager.java b/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableDataManager.java deleted file mode 100644 index 0e98c0903..000000000 --- a/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableDataManager.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.data; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -/** - * Facade over data tree that allows reading tree nodes. - */ -@Beta -public interface ReadableDataManager { - - /** - * Reads a particular node from the data tree. - * - * @param path Path of the node - * @return a CheckFuture containing the result of the read. - */ - CheckedFuture>, ReadFailedException> read(@Nonnull final YangInstanceIdentifier path); -} diff --git a/infra/data-api/src/main/yang/data-api.yang b/infra/data-api/src/main/yang/data-api.yang index 693a73acd..d09d1d371 100644 --- a/infra/data-api/src/main/yang/data-api.yang +++ b/infra/data-api/src/main/yang/data-api.yang @@ -21,12 +21,12 @@ module data-api { identity honeycomb-readable-data-tree { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.data.ReadableDataManager; + config:java-class io.fd.honeycomb.data.ReadableDataManager; } identity honeycomb-modifiable-data-tree { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.data.ModifiableDataManager; + config:java-class io.fd.honeycomb.data.ModifiableDataManager; } typedef datatree-type { diff --git a/infra/data-impl/pom.xml b/infra/data-impl/pom.xml index b80c796a5..dc7f6b0d5 100644 --- a/infra/data-impl/pom.xml +++ b/infra/data-impl/pom.xml @@ -95,7 +95,7 @@ ${project.groupId}.${project.artifactId} - io.fd.honeycomb.v3po.data.impl.* + io.fd.honeycomb.data.impl.* diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/DataBroker.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/DataBroker.java new file mode 100644 index 000000000..eb19c9dd1 --- /dev/null +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/DataBroker.java @@ -0,0 +1,198 @@ +/* + * 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.data.impl; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.data.DataModification; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.ReadableDataManager; +import java.io.Closeable; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Data Broker which provides data transaction functionality for YANG capable data provider using {@link NormalizedNode} + * data format. + */ +public class DataBroker implements DOMDataBroker, Closeable { + + private static final Logger LOG = LoggerFactory.getLogger(DataBroker.class); + private final TransactionFactory transactionFactory; + + /** + * Creates DataBroker instance. + * + * @param transactionFactory transaction producing factory + */ + public DataBroker(final TransactionFactory transactionFactory) { + this.transactionFactory = transactionFactory; + } + + @Override + public DOMDataReadOnlyTransaction newReadOnlyTransaction() { + LOG.trace("DataBroker({}).newReadOnlyTransaction()", this); + return transactionFactory.newReadOnlyTransaction(); + } + + @Override + public DOMDataReadWriteTransaction newReadWriteTransaction() { + LOG.trace("DataBroker({}).newReadWriteTransaction()", this); + return transactionFactory.newReadWriteTransaction(); + } + + @Override + public DOMDataWriteTransaction newWriteOnlyTransaction() { + LOG.trace("DataBroker({}).newWriteOnlyTransaction()", this); + return transactionFactory.newWriteOnlyTransaction(); + } + + @Override + public ListenerRegistration registerDataChangeListener(final LogicalDatastoreType store, + final YangInstanceIdentifier path, + final DOMDataChangeListener listener, + final DataChangeScope triggeringScope) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) { + throw new UnsupportedOperationException("Not supported"); + } + + @Nonnull + @Override + public Map, DOMDataBrokerExtension> getSupportedExtensions() { + return Collections.emptyMap(); + } + + /** + * Create DataBroker for a modifiable config DT, but only readable Operational + */ + @Nonnull + public static DataBroker create(@Nonnull final ModifiableDataManager configDataTree, + @Nonnull final ReadableDataManager operationalDataTree) { + checkNotNull(operationalDataTree, "operationalDataTree should not be null"); + checkNotNull(configDataTree, "configDataTree should not be null"); + return new DataBroker(new MainPipelineTxFactory(configDataTree, operationalDataTree)); + } + + /** + * Create DataBroker for modifiable operational DT, but no support for config + */ + @Nonnull + public static DataBroker create(@Nonnull final ModifiableDataManager operationalDataTree) { + checkNotNull(operationalDataTree, "operationalDataTree should not be null"); + return new DataBroker(new ContextPipelineTxFactory(operationalDataTree)); + } + + @Override + public void close() throws IOException { + // NOOP + } + + /** + * Transaction provider factory to be used by {@link DataBroker} + */ + public interface TransactionFactory { + + DOMDataReadOnlyTransaction newReadOnlyTransaction(); + + DOMDataReadWriteTransaction newReadWriteTransaction(); + + DOMDataWriteTransaction newWriteOnlyTransaction(); + } + + /** + * Transaction factory specific for Honeycomb's main pipeline (config: read+write, operational: read-only) + */ + private static class MainPipelineTxFactory implements TransactionFactory { + private final ReadableDataManager operationalDataTree; + private final ModifiableDataManager configDataTree; + + MainPipelineTxFactory(@Nonnull final ModifiableDataManager configDataTree, + @Nonnull final ReadableDataManager operationalDataTree) { + this.operationalDataTree = operationalDataTree; + this.configDataTree = configDataTree; + } + + @Override + public DOMDataReadOnlyTransaction newReadOnlyTransaction() { + return ReadOnlyTransaction.create(configDataTree.newModification(), operationalDataTree); + } + + @Override + public DOMDataReadWriteTransaction newReadWriteTransaction() { + final DataModification configModification = configDataTree.newModification(); + return new ReadWriteTransaction( + ReadOnlyTransaction.create(configModification, operationalDataTree), + WriteTransaction.createConfigOnly(configModification)); + } + + @Override + public DOMDataWriteTransaction newWriteOnlyTransaction() { + return WriteTransaction.createConfigOnly(configDataTree.newModification()); + } + } + + /** + * Transaction factory specific for Honeycomb's context pipeline (config: none, operational: read+write) + */ + private static class ContextPipelineTxFactory implements TransactionFactory { + private final ModifiableDataManager operationalDataTree; + + ContextPipelineTxFactory(@Nonnull final ModifiableDataManager operationalDataTree) { + this.operationalDataTree = operationalDataTree; + } + + @Override + public DOMDataReadOnlyTransaction newReadOnlyTransaction() { + return ReadOnlyTransaction.createOperationalOnly(operationalDataTree); + } + + @Override + public DOMDataReadWriteTransaction newReadWriteTransaction() { + final DataModification dataModification = operationalDataTree.newModification(); + return new ReadWriteTransaction( + ReadOnlyTransaction.createOperationalOnly(dataModification), + WriteTransaction.createOperationalOnly(dataModification)); + } + + @Override + public DOMDataWriteTransaction newWriteOnlyTransaction() { + return WriteTransaction.createOperationalOnly(operationalDataTree.newModification()); + } + } +} + + diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java new file mode 100644 index 000000000..e9a616eea --- /dev/null +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java @@ -0,0 +1,236 @@ +/* + * 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.data.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.util.concurrent.Futures.immediateCheckedFuture; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.data.DataModification; +import io.fd.honeycomb.data.ReadableDataManager; +import io.fd.honeycomb.translate.TranslationException; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.util.TransactionMappingContext; +import io.fd.honeycomb.translate.util.write.TransactionWriteContext; +import io.fd.honeycomb.translate.write.DataObjectUpdate; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +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.DataTreeCandidateNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Extension of {@link ModifiableDataTreeManager} that propagates data changes to underlying writer layer before they + * are fully committed in the backing data tree. Data changes are propagated in BA format. + */ +public final class ModifiableDataTreeDelegator extends ModifiableDataTreeManager { + + private static final Logger LOG = LoggerFactory.getLogger(ModifiableDataTreeDelegator.class); + private static final ReadableDataManager EMPTY_OPERATIONAL = p -> immediateCheckedFuture(Optional.absent()); + + private final WriterRegistry writerRegistry; + private final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker; + // TODO what to use instead of deprecated BindingNormalizedNodeSerializer ? + private final BindingNormalizedNodeSerializer serializer; + + /** + * Creates configuration data tree instance. + * @param serializer service for serialization between Java Binding Data representation and NormalizedNode + * representation. + * @param dataTree data tree for configuration data representation + * @param writerRegistry service for translation between Java Binding Data and data provider, capable of performing + * @param contextBroker BA broker providing full access to mapping context data + */ + public ModifiableDataTreeDelegator(@Nonnull final BindingNormalizedNodeSerializer serializer, + @Nonnull final DataTree dataTree, + @Nonnull final WriterRegistry writerRegistry, + @Nonnull final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker) { + super(dataTree); + this.contextBroker = checkNotNull(contextBroker, "contextBroker should not be null"); + this.serializer = checkNotNull(serializer, "serializer should not be null"); + this.writerRegistry = checkNotNull(writerRegistry, "writerRegistry should not be null"); + } + + @Override + public DataModification newModification() { + return new ConfigSnapshot(super.newModification()); + } + + private final class ConfigSnapshot extends ModifiableDataTreeManager.ConfigSnapshot { + + private final DataModification untouchedModification; + + /** + * @param untouchedModification DataModification captured while this modification/snapshot was created. + * To be used later while invoking writers to provide them with before state + * (state without current modifications). + * It must be captured as close as possible to when current modification started. + */ + ConfigSnapshot(final DataModification untouchedModification) { + this.untouchedModification = untouchedModification; + } + + /** + * Pass the changes to underlying writer layer. + * Transform from BI to BA. + * Revert(Write data before to subtrees that have been successfully modified before failure) in case of failure. + */ + @Override + protected void processCandidate(final DataTreeCandidate candidate) + throws TranslationException { + + final DataTreeCandidateNode rootNode = candidate.getRootNode(); + final YangInstanceIdentifier rootPath = candidate.getRootPath(); + LOG.trace("ConfigDataTree.modify() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}", + rootPath, rootNode, rootNode.getDataBefore(), rootNode.getDataAfter()); + + final ModificationDiff modificationDiff = + ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, rootNode); + LOG.debug("ConfigDataTree.modify() diff: {}", modificationDiff); + + // Distinguish between updates (create + update) and deletes + final WriterRegistry.DataObjectUpdates baUpdates = toBindingAware(modificationDiff.getUpdates()); + LOG.debug("ConfigDataTree.modify() extracted updates={}", baUpdates); + + try (final WriteContext ctx = getTransactionWriteContext()) { + writerRegistry.update(baUpdates, ctx); + + final CheckedFuture contextUpdateResult = + ((TransactionMappingContext) ctx.getMappingContext()).submit(); + // Blocking on context data update + contextUpdateResult.checkedGet(); + + } catch (WriterRegistry.BulkUpdateException e) { + LOG.warn("Failed to apply all changes", e); + LOG.info("Trying to revert successful changes for current transaction"); + + try { + e.revertChanges(); + LOG.info("Changes successfully reverted"); + } catch (WriterRegistry.Reverter.RevertFailedException revertFailedException) { + // fail with failed revert + LOG.error("Failed to revert successful changes", revertFailedException); + throw revertFailedException; + } + + throw e; // fail with success revert + } catch (TransactionCommitFailedException e) { + // FIXME revert should probably occur when context is not written successfully + final String msg = "Error while updating mapping context data"; + LOG.error(msg, e); + throw new TranslationException(msg, e); + } catch (TranslationException e) { + LOG.error("Error while processing data change (updates={})", baUpdates, e); + throw e; + } + } + + private TransactionWriteContext getTransactionWriteContext() { + // Before Tx must use modification + final DOMDataReadOnlyTransaction beforeTx = ReadOnlyTransaction.create(untouchedModification, EMPTY_OPERATIONAL); + // After Tx must use current modification + final DOMDataReadOnlyTransaction afterTx = ReadOnlyTransaction.create(this, EMPTY_OPERATIONAL); + final TransactionMappingContext mappingContext = new TransactionMappingContext( + contextBroker.newReadWriteTransaction()); + return new TransactionWriteContext(serializer, beforeTx, afterTx, mappingContext); + } + + private WriterRegistry.DataObjectUpdates toBindingAware( + final Map biNodes) { + return ModifiableDataTreeDelegator.toBindingAware(biNodes, serializer); + } + } + + @VisibleForTesting + static WriterRegistry.DataObjectUpdates toBindingAware( + final Map biNodes, + final BindingNormalizedNodeSerializer serializer) { + + final Multimap, DataObjectUpdate> dataObjectUpdates = HashMultimap.create(); + final Multimap, DataObjectUpdate.DataObjectDelete> dataObjectDeletes = + HashMultimap.create(); + + for (Map.Entry biEntry : biNodes.entrySet()) { + final InstanceIdentifier unkeyedIid = + RWUtils.makeIidWildcarded(serializer.fromYangInstanceIdentifier(biEntry.getKey())); + + ModificationDiff.NormalizedNodeUpdate normalizedNodeUpdate = biEntry.getValue(); + final DataObjectUpdate dataObjectUpdate = toDataObjectUpdate(normalizedNodeUpdate, serializer); + if (dataObjectUpdate != null) { + if (dataObjectUpdate instanceof DataObjectUpdate.DataObjectDelete) { + dataObjectDeletes.put(unkeyedIid, ((DataObjectUpdate.DataObjectDelete) dataObjectUpdate)); + } else { + dataObjectUpdates.put(unkeyedIid, dataObjectUpdate); + } + } + } + return new WriterRegistry.DataObjectUpdates(dataObjectUpdates, dataObjectDeletes); + } + + @Nullable + private static DataObjectUpdate toDataObjectUpdate( + final ModificationDiff.NormalizedNodeUpdate normalizedNodeUpdate, + final BindingNormalizedNodeSerializer serializer) { + + InstanceIdentifier baId = serializer.fromYangInstanceIdentifier(normalizedNodeUpdate.getId()); + checkNotNull(baId, "Unable to transform instance identifier: %s into BA", normalizedNodeUpdate.getId()); + + DataObject dataObjectBefore = getDataObject(serializer, + normalizedNodeUpdate.getDataBefore(), normalizedNodeUpdate.getId()); + DataObject dataObjectAfter = + getDataObject(serializer, normalizedNodeUpdate.getDataAfter(), normalizedNodeUpdate.getId()); + + return dataObjectBefore == null && dataObjectAfter == null + ? null + : DataObjectUpdate.create(baId, dataObjectBefore, dataObjectAfter); + } + + @Nullable + private static DataObject getDataObject(@Nonnull final BindingNormalizedNodeSerializer serializer, + @Nullable final NormalizedNode data, + @Nonnull final YangInstanceIdentifier id) { + DataObject dataObject = null; + if (data != null) { + final Map.Entry, DataObject> dataObjectEntry = + serializer.fromNormalizedNode(id, data); + if (dataObjectEntry != null) { + dataObject = dataObjectEntry.getValue(); + } + } + return dataObject; + } + +} + + + diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeManager.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeManager.java new file mode 100644 index 000000000..61ccf185c --- /dev/null +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeManager.java @@ -0,0 +1,122 @@ +/* + * 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.data.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.util.concurrent.Futures.immediateCheckedFuture; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.DataModification; +import io.fd.honeycomb.translate.TranslationException; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +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.DataTreeModification; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * DataTree backed implementation for modifiable data manager. + */ +public class ModifiableDataTreeManager implements ModifiableDataManager { + + private static final Logger LOG = LoggerFactory.getLogger(ModifiableDataTreeManager.class); + + private final DataTree dataTree; + + public ModifiableDataTreeManager(@Nonnull final DataTree dataTree) { + this.dataTree = checkNotNull(dataTree, "dataTree should not be null"); + } + + @Override + public DataModification newModification() { + return new ConfigSnapshot(); + } + + @Override + public final CheckedFuture>, ReadFailedException> read(@Nonnull final YangInstanceIdentifier path) { + return newModification().read(path); + } + + protected class ConfigSnapshot implements DataModification { + private final DataTreeModification modification; + private boolean validated = false; + + ConfigSnapshot() { + this(dataTree.takeSnapshot().newModification()); + } + + protected ConfigSnapshot(final DataTreeModification modification) { + this.modification = modification; + } + + @Override + public CheckedFuture>, ReadFailedException> read( + @Nonnull final YangInstanceIdentifier path) { + final Optional> node = modification.readNode(path); + if (LOG.isTraceEnabled() && node.isPresent()) { + LOG.trace("ConfigSnapshot.read: {}", node.get()); + } + return immediateCheckedFuture(node); + } + + @Override + public final void delete(final YangInstanceIdentifier path) { + modification.delete(path); + } + + @Override + public final void merge(final YangInstanceIdentifier path, final NormalizedNode data) { + modification.merge(path, data); + } + + @Override + public final void write(final YangInstanceIdentifier path, final NormalizedNode data) { + modification.write(path, data); + } + + @Override + public final void commit() throws DataValidationFailedException, TranslationException { + if(!validated) { + validate(); + } + final DataTreeCandidate candidate = dataTree.prepare(modification); + processCandidate(candidate); + dataTree.commit(candidate); + } + + protected void processCandidate(final DataTreeCandidate candidate) throws TranslationException { + // NOOP + } + + @Override + public final void validate() throws DataValidationFailedException { + modification.ready(); + dataTree.validate(modification); + validated = true; + } + } +} + + + diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java new file mode 100644 index 000000000..710f8a053 --- /dev/null +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java @@ -0,0 +1,278 @@ +/* + * 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.data.impl; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.collect.ImmutableMap; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; +import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.MixinNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType; + +/** + * Recursively collects and provides all unique and non-null modifications (modified normalized nodes). + */ +final class ModificationDiff { + + private static final ModificationDiff EMPTY_DIFF = new ModificationDiff(Collections.emptyMap()); + private static final EnumSet LEAF_MODIFICATIONS = EnumSet.of(ModificationType.WRITE, ModificationType.DELETE); + + private final Map updates; + + private ModificationDiff(@Nonnull Map updates) { + this.updates = updates; + } + + /** + * Get processed modifications. + * + * @return mapped modifications, where key is keyed {@link YangInstanceIdentifier}. + */ + Map getUpdates() { + return updates; + } + + private ModificationDiff merge(final ModificationDiff other) { + if (this == EMPTY_DIFF) { + return other; + } + + if (other == EMPTY_DIFF) { + return this; + } + + return new ModificationDiff(join(updates, other.updates)); + } + + private static Map join(Map first, + Map second) { + final Map merged = new HashMap<>(); + merged.putAll(first); + merged.putAll(second); + return merged; + } + + private static ModificationDiff create(YangInstanceIdentifier id, DataTreeCandidateNode candidate) { + return new ModificationDiff(ImmutableMap.of(id, NormalizedNodeUpdate.create(id, candidate))); + } + + /** + * Produce an aggregated diff from a candidate node recursively. MixinNodes are ignored as modifications and so + * are complex nodes which direct leaves were not modified. + */ + @Nonnull + static ModificationDiff recursivelyFromCandidate(@Nonnull final YangInstanceIdentifier yangIid, + @Nonnull final DataTreeCandidateNode currentCandidate) { + // recursively process child nodes for exact modifications + return recursivelyChildrenFromCandidate(yangIid, currentCandidate) + // also add modification on current level, if elligible + .merge(isModification(currentCandidate) + ? ModificationDiff.create(yangIid, currentCandidate) + : EMPTY_DIFF); + } + + /** + * Check whether current node was modified. {@link MixinNode}s are ignored + * and only nodes which direct leaves(or choices) are modified are considered a modification. + */ + private static Boolean isModification(@Nonnull final DataTreeCandidateNode currentCandidate) { + // Mixin nodes are not considered modifications + if (isMixin(currentCandidate) && !isAugment(currentCandidate)) { + return false; + } else { + return isCurrentModified(currentCandidate); + } + } + + private static Boolean isCurrentModified(final @Nonnull DataTreeCandidateNode currentCandidate) { + // Check if there are any modified leaves and if so, consider current node as modified + final Boolean directLeavesModified = currentCandidate.getChildNodes().stream() + .filter(ModificationDiff::isLeaf) + // For some reason, we get modifications on unmodified list keys TODO debug and report ODL bug + // and that messes up our modifications collection here, so we need to skip + .filter(ModificationDiff::isBeforeAndAfterDifferent) + .filter(child -> LEAF_MODIFICATIONS.contains(child.getModificationType())) + .findFirst() + .isPresent(); + + return directLeavesModified + // Also check choices (choices do not exist in BA world and if anything within a choice was modified, + // consider its parent as being modified) + || currentCandidate.getChildNodes().stream() + .filter(ModificationDiff::isChoice) + // Recursively check each choice if there was any change to it + .filter(ModificationDiff::isCurrentModified) + .findFirst() + .isPresent(); + } + + /** + * Process all non-leaf child nodes recursively, creating aggregated {@link ModificationDiff}. + */ + private static ModificationDiff recursivelyChildrenFromCandidate(final @Nonnull YangInstanceIdentifier yangIid, + final @Nonnull DataTreeCandidateNode currentCandidate) { + // recursively process child nodes for specific modifications + return currentCandidate.getChildNodes().stream() + // not interested in modifications to leaves + .filter(child -> !isLeaf(child)) + .map(candidate -> recursivelyFromCandidate(yangIid.node(candidate.getIdentifier()), candidate)) + .reduce(ModificationDiff::merge) + .orElse(EMPTY_DIFF); + } + + /** + * Check whether candidate.before and candidate.after is different. If not return false. + */ + private static boolean isBeforeAndAfterDifferent(@Nonnull final DataTreeCandidateNode candidateNode) { + if (candidateNode.getDataBefore().isPresent()) { + return !candidateNode.getDataBefore().get().equals(candidateNode.getDataAfter().orNull()); + } + + // considering not a modification if data after is also null + return candidateNode.getDataAfter().isPresent(); + } + + /** + * Check whether candidate node is for a leaf type node. + */ + private static boolean isLeaf(final DataTreeCandidateNode candidateNode) { + // orNull intentional, some candidate nodes have both data after and data before null + return candidateNode.getDataAfter().orNull() instanceof LeafNode + || candidateNode.getDataBefore().orNull() instanceof LeafNode; + } + + /** + * Check whether candidate node is for a Mixin type node. + */ + private static boolean isMixin(final DataTreeCandidateNode candidateNode) { + // orNull intentional, some candidate nodes have both data after and data before null + return candidateNode.getDataAfter().orNull() instanceof MixinNode + || candidateNode.getDataBefore().orNull() instanceof MixinNode; + } + + /** + * Check whether candidate node is for an Augmentation type node. + */ + private static boolean isAugment(final DataTreeCandidateNode candidateNode) { + // orNull intentional, some candidate nodes have both data after and data before null + return candidateNode.getDataAfter().orNull() instanceof AugmentationNode + || candidateNode.getDataBefore().orNull() instanceof AugmentationNode; + } + + /** + * Check whether candidate node is for a Choice type node. + */ + private static boolean isChoice(final DataTreeCandidateNode candidateNode) { + // orNull intentional, some candidate nodes have both data after and data before null + return candidateNode.getDataAfter().orNull() instanceof ChoiceNode + || candidateNode.getDataBefore().orNull() instanceof ChoiceNode; + } + + @Override + public String toString() { + return "ModificationDiff{updates=" + updates + '}'; + } + + /** + * Update to a normalized node identifiable by its {@link YangInstanceIdentifier}. + */ + static final class NormalizedNodeUpdate { + + @Nonnull + private final YangInstanceIdentifier id; + @Nullable + private final NormalizedNode dataBefore; + @Nullable + private final NormalizedNode dataAfter; + + private NormalizedNodeUpdate(@Nonnull final YangInstanceIdentifier id, + @Nullable final NormalizedNode dataBefore, + @Nullable final NormalizedNode dataAfter) { + this.id = checkNotNull(id); + this.dataAfter = dataAfter; + this.dataBefore = dataBefore; + } + + @Nullable + public NormalizedNode getDataBefore() { + return dataBefore; + } + + @Nullable + public NormalizedNode getDataAfter() { + return dataAfter; + } + + @Nonnull + public YangInstanceIdentifier getId() { + return id; + } + + static NormalizedNodeUpdate create(@Nonnull final YangInstanceIdentifier id, + @Nonnull final DataTreeCandidateNode candidate) { + return create(id, candidate.getDataBefore().orNull(), candidate.getDataAfter().orNull()); + } + + static NormalizedNodeUpdate create(@Nonnull final YangInstanceIdentifier id, + @Nullable final NormalizedNode dataBefore, + @Nullable final NormalizedNode dataAfter) { + checkArgument(!(dataBefore == null && dataAfter == null), "Both before and after data are null"); + return new NormalizedNodeUpdate(id, dataBefore, dataAfter); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + + final NormalizedNodeUpdate that = (NormalizedNodeUpdate) other; + + return id.equals(that.id); + + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public String toString() { + return "NormalizedNodeUpdate{" + "id=" + id + + ", dataBefore=" + dataBefore + + ", dataAfter=" + dataAfter + + '}'; + } + } + +} diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/PersistingDataTreeAdapter.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/PersistingDataTreeAdapter.java new file mode 100644 index 000000000..94c5e4446 --- /dev/null +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/PersistingDataTreeAdapter.java @@ -0,0 +1,151 @@ +/* + * 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.data.impl; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Optional; +import io.fd.honeycomb.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.sal.core.api.model.SchemaService; +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.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.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Adapter for a DataTree that stores current state of data in backing DataTree on each successful commit. + * Uses JSON format. + */ +public class PersistingDataTreeAdapter implements DataTree, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(PersistingDataTreeAdapter.class); + + private final DataTree delegateDependency; + private final SchemaService schemaServiceDependency; + private final Path path; + + /** + * Create new Persisting DataTree adapter + * + * @param delegate backing data tree that actually handles all the operations + * @param persistPath path to a file (existing or not) to be used as storage for persistence. Full control over + * a file at peristPath is expected + * @param schemaService schemaContext provier + */ + public PersistingDataTreeAdapter(@Nonnull final DataTree delegate, + @Nonnull final SchemaService schemaService, + @Nonnull final Path persistPath) { + this.path = testPersistPath(checkNotNull(persistPath, "persistPath is null")); + this.delegateDependency = checkNotNull(delegate, "delegate is null"); + this.schemaServiceDependency = checkNotNull(schemaService, "schemaService is null"); + } + + /** + * Test whether file at persistPath exists and is readable or create it along with its parent structure + */ + 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 "); + } + + return persistPath; + } + + @Override + public DataTreeSnapshot takeSnapshot() { + return delegateDependency.takeSnapshot(); + } + + @Override + public void setSchemaContext(final SchemaContext schemaContext) { + delegateDependency.setSchemaContext(schemaContext); + } + + @Override + public void commit(final DataTreeCandidate dataTreeCandidate) { + LOG.trace("Commit detected"); + delegateDependency.commit(dataTreeCandidate); + LOG.debug("Delegate commit successful. Persisting data"); + + // FIXME doing full read and full write might not be the fastest way of persisting data here + final DataTreeSnapshot dataTreeSnapshot = delegateDependency.takeSnapshot(); + + // TODO this can be handled in background by a dedicated thread + a limited blocking queue + // TODO enable configurable granularity for persists. Maybe doing write on every modification is too much + // and we could do bulk persist + persistCurrentData(dataTreeSnapshot.readNode(YangInstanceIdentifier.EMPTY)); + } + + private void persistCurrentData(final Optional> currentRoot) { + if(currentRoot.isPresent()) { + try { + LOG.trace("Persisting current data: {} into: {}", currentRoot.get(), path); + JsonUtils.writeJsonRoot(currentRoot.get(), schemaServiceDependency.getGlobalContext(), + Files.newOutputStream(path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)); + LOG.trace("Data persisted successfully in {}", path); + } catch (IOException e) { + throw new IllegalStateException("Unable to persist current data", e); + } + } else { + LOG.debug("Skipping persistence, since there's no data to persist"); + } + } + + @Override + public YangInstanceIdentifier getRootPath() { + return delegateDependency.getRootPath(); + } + + @Override + public void validate(final DataTreeModification dataTreeModification) throws DataValidationFailedException { + delegateDependency.validate(dataTreeModification); + } + + @Override + public DataTreeCandidate prepare( + final DataTreeModification dataTreeModification) { + return delegateDependency.prepare(dataTreeModification); + } + + @Override + public void close() throws Exception { + LOG.trace("Closing {} for {}", getClass().getSimpleName(), path); + // NOOP + } +} diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadOnlyTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadOnlyTransaction.java new file mode 100644 index 000000000..00d105e26 --- /dev/null +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadOnlyTransaction.java @@ -0,0 +1,119 @@ +/* + * 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.data.impl; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import io.fd.honeycomb.data.ReadableDataManager; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class ReadOnlyTransaction implements DOMDataReadOnlyTransaction { + + private static final Logger LOG = LoggerFactory.getLogger(ReadOnlyTransaction.class); + + @Nullable + private ReadableDataManager operationalData; + @Nullable + private ReadableDataManager configSnapshot; + + private boolean closed = false; + + /** + * @param configData config data tree manager. Null if config reads are not to be supported + * @param operationalData operational data tree manager. Null if operational reads are not to be supported + */ + private ReadOnlyTransaction(@Nullable final ReadableDataManager configData, + @Nullable final ReadableDataManager operationalData) { + this.configSnapshot = configData; + this.operationalData = operationalData; + } + + @Override + public synchronized void close() { + closed = true; + configSnapshot = null; + operationalData = null; + } + + @Override + public synchronized CheckedFuture>, ReadFailedException> read( + final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + LOG.debug("ReadOnlyTransaction.read(), store={}, path={}", store, path); + checkState(!closed, "Transaction has been closed"); + + if (store == LogicalDatastoreType.OPERATIONAL) { + checkArgument(operationalData != null, "{} reads not supported", store); + return operationalData.read(path); + } else { + checkArgument(configSnapshot != null, "{} reads not supported", store); + return configSnapshot.read(path); + } + } + + @Override + public CheckedFuture exists(final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + LOG.debug("ReadOnlyTransaction.exists() store={}, path={}", store, path); + + ListenableFuture listenableFuture = Futures.transform(read(store, path), IS_NODE_PRESENT); + return Futures.makeChecked(listenableFuture, ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER); + } + + @Nonnull + @Override + public Object getIdentifier() { + return this; + } + + @Nonnull + static ReadOnlyTransaction createOperationalOnly(@Nonnull final ReadableDataManager operationalData) { + return new ReadOnlyTransaction(null, requireNonNull(operationalData)); + } + + @Nonnull + static ReadOnlyTransaction createConfigOnly(@Nonnull final ReadableDataManager configData) { + return new ReadOnlyTransaction(requireNonNull(configData), null); + } + + @Nonnull + static ReadOnlyTransaction create(@Nonnull final ReadableDataManager configData, + @Nonnull final ReadableDataManager operationalData) { + return new ReadOnlyTransaction(requireNonNull(configData), requireNonNull(operationalData)); + } + + private static final Function>, ? extends Boolean> IS_NODE_PRESENT = + (Function>, Boolean>) input -> input == null ? Boolean.FALSE : input.isPresent(); + + private static final Function ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER = + (Function) e -> new ReadFailedException("Exists failed", e); +} \ No newline at end of file diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadWriteTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadWriteTransaction.java new file mode 100644 index 000000000..30035d99e --- /dev/null +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadWriteTransaction.java @@ -0,0 +1,101 @@ +/* + * 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.data.impl; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.ListenableFuture; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Composite DOM transaction that delegates reads to a {@link DOMDataReadTransaction} delegate and writes to a {@link + * DOMDataWriteTransaction} delegate. + */ +final class ReadWriteTransaction implements DOMDataReadWriteTransaction { + + private final DOMDataReadOnlyTransaction delegateReadTx; + private final DOMDataWriteTransaction delegateWriteTx; + + ReadWriteTransaction(@Nonnull final DOMDataReadOnlyTransaction delegateReadTx, + @Nonnull final DOMDataWriteTransaction delegateWriteTx) { + this.delegateReadTx = Preconditions.checkNotNull(delegateReadTx, "delegateReadTx should not be null"); + this.delegateWriteTx = Preconditions.checkNotNull(delegateWriteTx, "delegateWriteTx should not be null"); + } + + @Override + public boolean cancel() { + delegateReadTx.close(); + return delegateWriteTx.cancel(); + } + + @Override + public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, + final NormalizedNode data) { + delegateWriteTx.put(store, path, data); + } + + @Override + public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, + final NormalizedNode data) { + delegateWriteTx.merge(store, path, data); + } + + @Override + public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) { + delegateWriteTx.delete(store, path); + } + + @Override + public CheckedFuture submit() { + return delegateWriteTx.submit(); + } + + @Override + public ListenableFuture> commit() { + return delegateWriteTx.commit(); + } + + @Override + public CheckedFuture>, ReadFailedException> read(final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + return delegateReadTx.read(store, path); + } + + @Override + public CheckedFuture exists(final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + return delegateReadTx.exists(store, path); + } + + @Override + public Object getIdentifier() { + return this; + } +} + diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadableDataTreeDelegator.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadableDataTreeDelegator.java new file mode 100644 index 000000000..775f6326c --- /dev/null +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadableDataTreeDelegator.java @@ -0,0 +1,241 @@ +/* + * 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.data.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.getOnlyElement; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.Collections2; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import io.fd.honeycomb.data.ReadableDataManager; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import io.fd.honeycomb.translate.util.TransactionMappingContext; +import java.util.Collection; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +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.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ReadableDataTree implementation for operational data. + */ +public final class ReadableDataTreeDelegator implements ReadableDataManager { + private static final Logger LOG = LoggerFactory.getLogger(ReadableDataTreeDelegator.class); + + private final BindingNormalizedNodeSerializer serializer; + private final ReaderRegistry readerRegistry; + private final SchemaContext globalContext; + private final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker; + + /** + * Creates operational data tree instance. + * @param serializer service for serialization between Java Binding Data representation and NormalizedNode + * representation. + * @param globalContext service for obtaining top level context data from all yang modules. + * @param readerRegistry service responsible for translation between DataObjects and data provider. + * @param contextBroker BA broker for context data + */ + public ReadableDataTreeDelegator(@Nonnull BindingNormalizedNodeSerializer serializer, + @Nonnull final SchemaContext globalContext, + @Nonnull final ReaderRegistry readerRegistry, + @Nonnull final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker) { + this.contextBroker = checkNotNull(contextBroker, "contextBroker should not be null"); + this.globalContext = checkNotNull(globalContext, "globalContext should not be null"); + this.serializer = checkNotNull(serializer, "serializer should not be null"); + this.readerRegistry = checkNotNull(readerRegistry, "reader should not be null"); + } + + @Override + public CheckedFuture>, + org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> read( + @Nonnull final YangInstanceIdentifier yangInstanceIdentifier) { + + try(TransactionMappingContext mappingContext = new TransactionMappingContext(contextBroker.newReadWriteTransaction()); + ReadContext ctx = new ReadContextImpl(mappingContext)) { + + final Optional> value; + if (checkNotNull(yangInstanceIdentifier).equals(YangInstanceIdentifier.EMPTY)) { + value = readRoot(ctx); + } else { + value = readNode(yangInstanceIdentifier, ctx); + } + + // Submit context mapping updates + final CheckedFuture contextUpdateResult = + ((TransactionMappingContext) ctx.getMappingContext()).submit(); + // Blocking on context data update + contextUpdateResult.checkedGet(); + + return Futures.immediateCheckedFuture(value); + + } catch (ReadFailedException e) { + return Futures.immediateFailedCheckedFuture( + new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException("Failed to read data", e)); + } catch (TransactionCommitFailedException e) { + // FIXME revert should probably occur when context is not written successfully + final String msg = "Error while updating mapping context data"; + LOG.error(msg, e); + return Futures.immediateFailedCheckedFuture( + new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException(msg, e) + ); + } + } + + private Optional> readNode(final YangInstanceIdentifier yangInstanceIdentifier, + final ReadContext ctx) throws ReadFailedException { + LOG.debug("OperationalDataTree.readNode(), yangInstanceIdentifier={}", yangInstanceIdentifier); + final InstanceIdentifier path = serializer.fromYangInstanceIdentifier(yangInstanceIdentifier); + checkNotNull(path, "Invalid instance identifier %s. Cannot create BA equivalent.", yangInstanceIdentifier); + LOG.debug("OperationalDataTree.readNode(), path={}", path); + + final Optional dataObject; + + dataObject = readerRegistry.read(path, ctx); + if (dataObject.isPresent()) { + final NormalizedNode value = toNormalizedNodeFunction(path).apply(dataObject.get()); + return Optional.>fromNullable(value); + } else { + return Optional.absent(); + } + } + + private Optional> readRoot(final ReadContext ctx) throws ReadFailedException { + LOG.debug("OperationalDataTree.readRoot()"); + + final DataContainerNodeAttrBuilder dataNodeBuilder = + Builders.containerBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(SchemaContext.NAME)); + + final Multimap, ? extends DataObject> dataObjects = + readerRegistry.readAll(ctx); + + for (final InstanceIdentifier instanceIdentifier : dataObjects.keySet()) { + final YangInstanceIdentifier rootElementId = serializer.toYangInstanceIdentifier(instanceIdentifier); + final NormalizedNode node = + wrapDataObjects(rootElementId, instanceIdentifier, dataObjects.get(instanceIdentifier)); + dataNodeBuilder.withChild((DataContainerChild) node); + } + return Optional.>of(dataNodeBuilder.build()); + } + + private NormalizedNode wrapDataObjects(final YangInstanceIdentifier yangInstanceIdentifier, + final InstanceIdentifier instanceIdentifier, + final Collection dataObjects) { + final Collection> normalizedRootElements = Collections2 + .transform(dataObjects, toNormalizedNodeFunction(instanceIdentifier)); + + final DataSchemaNode schemaNode = + globalContext.getDataChildByName(yangInstanceIdentifier.getLastPathArgument().getNodeType()); + if (schemaNode instanceof ListSchemaNode) { + // In case of a list, wrap all the values in a Mixin parent node + final ListSchemaNode listSchema = (ListSchemaNode) schemaNode; + return wrapListIntoMixinNode(normalizedRootElements, listSchema); + } else { + Preconditions.checkState(dataObjects.size() == 1, "Singleton list was expected"); + return getOnlyElement(normalizedRootElements); + } + } + + private static DataContainerChild wrapListIntoMixinNode( + final Collection> normalizedRootElements, final ListSchemaNode listSchema) { + if (listSchema.getKeyDefinition().isEmpty()) { + final CollectionNodeBuilder listBuilder = + Builders.unkeyedListBuilder(); + for (NormalizedNode normalizedRootElement : normalizedRootElements) { + listBuilder.withChild((UnkeyedListEntryNode) normalizedRootElement); + } + return listBuilder.build(); + } else { + final CollectionNodeBuilder listBuilder = + listSchema.isUserOrdered() + ? Builders.orderedMapBuilder() + : Builders.mapBuilder(); + + for (NormalizedNode normalizedRootElement : normalizedRootElements) { + listBuilder.withChild((MapEntryNode) normalizedRootElement); + } + return listBuilder.build(); + } + } + + @SuppressWarnings("unchecked") + private Function> toNormalizedNodeFunction(final InstanceIdentifier path) { + return dataObject -> { + LOG.trace("OperationalDataTree.toNormalizedNode(), path={}, dataObject={}", path, dataObject); + final Map.Entry> entry = + serializer.toNormalizedNode(path, dataObject); + + LOG.trace("OperationalDataTree.toNormalizedNode(), normalizedNodeEntry={}", entry); + return entry.getValue(); + }; + } + + private static final class ReadContextImpl implements ReadContext { + + private final ModificationCache ctx = new ModificationCache(); + private final MappingContext mappingContext; + + private ReadContextImpl(final MappingContext mappingContext) { + this.mappingContext = mappingContext; + } + + @Nonnull + @Override + public ModificationCache getModificationCache() { + return ctx; + } + + @Nonnull + @Override + public MappingContext getMappingContext() { + return mappingContext; + } + + @Override + public void close() { + // Make sure to clear the storage in case some customizer stored a reference to it to prevent memory leaks + ctx.close(); + } + } +} diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/WriteTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/WriteTransaction.java new file mode 100644 index 000000000..6bc6b1b4b --- /dev/null +++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/WriteTransaction.java @@ -0,0 +1,177 @@ +/* + * 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.data.impl; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.CANCELED; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.COMMITED; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.FAILED; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.SUBMITED; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import io.fd.honeycomb.data.DataModification; +import io.fd.honeycomb.translate.TranslationException; +import java.util.function.Consumer; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.concurrent.NotThreadSafe; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +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.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.common.RpcResult; +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.DataValidationFailedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@NotThreadSafe +final class WriteTransaction implements DOMDataWriteTransaction { + + private static final Logger LOG = LoggerFactory.getLogger(WriteTransaction.class); + + @Nullable + private DataModification operationalModification; + @Nullable + private DataModification configModification; + private TransactionStatus status = NEW; + + private WriteTransaction(@Nullable final DataModification configModification, + @Nullable final DataModification operationalModification) { + this.operationalModification = operationalModification; + this.configModification = configModification; + } + + private void checkIsNew() { + Preconditions.checkState(status == NEW, "Transaction was submitted or canceled"); + } + + @Override + public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, + final NormalizedNode data) { + LOG.debug("WriteTransaction.put() store={}, path={}, data={}", store, path, data); + checkIsNew(); + handleOperation(store, (modification) -> modification.write(path, data)); + } + + private void handleOperation(final LogicalDatastoreType store, + final Consumer r) { + switch (store) { + case CONFIGURATION: + checkArgument(configModification != null, "Modification of %s is not supported", store); + r.accept(configModification); + break; + case OPERATIONAL: + checkArgument(operationalModification != null, "Modification of %s is not supported", store); + r.accept(operationalModification); + break; + } + } + + @Override + public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, + final NormalizedNode data) { + LOG.debug("WriteTransaction.merge() store={}, path={}, data={}", store, path, data); + checkIsNew(); + handleOperation(store, (modification) -> modification.merge(path, data)); + } + + @Override + public boolean cancel() { + if (status != NEW) { + // only NEW transactions can be cancelled + return false; + } else { + status = CANCELED; + return true; + } + } + + @Override + public void delete(LogicalDatastoreType store, final YangInstanceIdentifier path) { + LOG.debug("WriteTransaction.delete() store={}, path={}", store, path); + checkIsNew(); + handleOperation(store, (modification) -> modification.delete(path)); + } + + @Override + public CheckedFuture submit() { + LOG.trace("WriteTransaction.submit()"); + checkIsNew(); + + try { + status = SUBMITED; + + // Validate first to catch any issues before attempting commit + if (configModification != null) { + configModification.validate(); + } + if (operationalModification != null) { + operationalModification.validate(); + } + + if(configModification != null) { + configModification.commit(); + } + if(operationalModification != null) { + operationalModification.commit(); + } + + status = COMMITED; + } catch (DataValidationFailedException | TranslationException e) { + status = FAILED; + LOG.error("Failed modify data tree", e); + return Futures.immediateFailedCheckedFuture( + new TransactionCommitFailedException("Failed to validate DataTreeModification", e)); + } + return Futures.immediateCheckedFuture(null); + } + + @Override + @Deprecated + public ListenableFuture> commit() { + throw new UnsupportedOperationException("deprecated"); + } + + @Override + public Object getIdentifier() { + return this; + } + + + @Nonnull + static WriteTransaction createOperationalOnly(@Nonnull final DataModification operationalData) { + return new WriteTransaction(null, requireNonNull(operationalData)); + } + + @Nonnull + static WriteTransaction createConfigOnly(@Nonnull final DataModification configData) { + return new WriteTransaction(requireNonNull(configData), null); + } + + @Nonnull + static WriteTransaction create(@Nonnull final DataModification configData, + @Nonnull final DataModification operationalData) { + return new WriteTransaction(requireNonNull(configData), requireNonNull(operationalData)); + } +} diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java deleted file mode 100644 index c418ed332..000000000 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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.data.impl; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.fd.honeycomb.v3po.data.DataModification; -import io.fd.honeycomb.v3po.data.ModifiableDataManager; -import io.fd.honeycomb.v3po.data.ReadableDataManager; -import java.io.Closeable; -import java.io.IOException; -import java.util.Collections; -import java.util.Map; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; -import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Data Broker which provides data transaction functionality for YANG capable data provider using {@link NormalizedNode} - * data format. - */ -public class DataBroker implements DOMDataBroker, Closeable { - - private static final Logger LOG = LoggerFactory.getLogger(DataBroker.class); - private final TransactionFactory transactionFactory; - - /** - * Creates DataBroker instance. - * - * @param transactionFactory transaction producing factory - */ - public DataBroker(final TransactionFactory transactionFactory) { - this.transactionFactory = transactionFactory; - } - - @Override - public DOMDataReadOnlyTransaction newReadOnlyTransaction() { - LOG.trace("DataBroker({}).newReadOnlyTransaction()", this); - return transactionFactory.newReadOnlyTransaction(); - } - - @Override - public DOMDataReadWriteTransaction newReadWriteTransaction() { - LOG.trace("DataBroker({}).newReadWriteTransaction()", this); - return transactionFactory.newReadWriteTransaction(); - } - - @Override - public DOMDataWriteTransaction newWriteOnlyTransaction() { - LOG.trace("DataBroker({}).newWriteOnlyTransaction()", this); - return transactionFactory.newWriteOnlyTransaction(); - } - - @Override - public ListenerRegistration registerDataChangeListener(final LogicalDatastoreType store, - final YangInstanceIdentifier path, - final DOMDataChangeListener listener, - final DataChangeScope triggeringScope) { - throw new UnsupportedOperationException("Not supported"); - } - - @Override - public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) { - throw new UnsupportedOperationException("Not supported"); - } - - @Nonnull - @Override - public Map, DOMDataBrokerExtension> getSupportedExtensions() { - return Collections.emptyMap(); - } - - /** - * Create DataBroker for a modifiable config DT, but only readable Operational - */ - @Nonnull - public static DataBroker create(@Nonnull final ModifiableDataManager configDataTree, - @Nonnull final ReadableDataManager operationalDataTree) { - checkNotNull(operationalDataTree, "operationalDataTree should not be null"); - checkNotNull(configDataTree, "configDataTree should not be null"); - return new DataBroker(new MainPipelineTxFactory(configDataTree, operationalDataTree)); - } - - /** - * Create DataBroker for modifiable operational DT, but no support for config - */ - @Nonnull - public static DataBroker create(@Nonnull final ModifiableDataManager operationalDataTree) { - checkNotNull(operationalDataTree, "operationalDataTree should not be null"); - return new DataBroker(new ContextPipelineTxFactory(operationalDataTree)); - } - - @Override - public void close() throws IOException { - // NOOP - } - - /** - * Transaction provider factory to be used by {@link DataBroker} - */ - public interface TransactionFactory { - - DOMDataReadOnlyTransaction newReadOnlyTransaction(); - - DOMDataReadWriteTransaction newReadWriteTransaction(); - - DOMDataWriteTransaction newWriteOnlyTransaction(); - } - - /** - * Transaction factory specific for Honeycomb's main pipeline (config: read+write, operational: read-only) - */ - private static class MainPipelineTxFactory implements TransactionFactory { - private final ReadableDataManager operationalDataTree; - private final ModifiableDataManager configDataTree; - - MainPipelineTxFactory(@Nonnull final ModifiableDataManager configDataTree, - @Nonnull final ReadableDataManager operationalDataTree) { - this.operationalDataTree = operationalDataTree; - this.configDataTree = configDataTree; - } - - @Override - public DOMDataReadOnlyTransaction newReadOnlyTransaction() { - return ReadOnlyTransaction.create(configDataTree.newModification(), operationalDataTree); - } - - @Override - public DOMDataReadWriteTransaction newReadWriteTransaction() { - final DataModification configModification = configDataTree.newModification(); - return new ReadWriteTransaction( - ReadOnlyTransaction.create(configModification, operationalDataTree), - WriteTransaction.createConfigOnly(configModification)); - } - - @Override - public DOMDataWriteTransaction newWriteOnlyTransaction() { - return WriteTransaction.createConfigOnly(configDataTree.newModification()); - } - } - - /** - * Transaction factory specific for Honeycomb's context pipeline (config: none, operational: read+write) - */ - private static class ContextPipelineTxFactory implements TransactionFactory { - private final ModifiableDataManager operationalDataTree; - - ContextPipelineTxFactory(@Nonnull final ModifiableDataManager operationalDataTree) { - this.operationalDataTree = operationalDataTree; - } - - @Override - public DOMDataReadOnlyTransaction newReadOnlyTransaction() { - return ReadOnlyTransaction.createOperationalOnly(operationalDataTree); - } - - @Override - public DOMDataReadWriteTransaction newReadWriteTransaction() { - final DataModification dataModification = operationalDataTree.newModification(); - return new ReadWriteTransaction( - ReadOnlyTransaction.createOperationalOnly(dataModification), - WriteTransaction.createOperationalOnly(dataModification)); - } - - @Override - public DOMDataWriteTransaction newWriteOnlyTransaction() { - return WriteTransaction.createOperationalOnly(operationalDataTree.newModification()); - } - } -} - - diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java deleted file mode 100644 index 2c2581ec0..000000000 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * 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.data.impl; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.util.concurrent.Futures.immediateCheckedFuture; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.data.DataModification; -import io.fd.honeycomb.v3po.data.ReadableDataManager; -import io.fd.honeycomb.v3po.translate.TranslationException; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.util.TransactionMappingContext; -import io.fd.honeycomb.v3po.translate.util.write.TransactionWriteContext; -import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -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.DataTreeCandidateNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Extension of {@link ModifiableDataTreeManager} that propagates data changes to underlying writer layer before they - * are fully committed in the backing data tree. Data changes are propagated in BA format. - */ -public final class ModifiableDataTreeDelegator extends ModifiableDataTreeManager { - - private static final Logger LOG = LoggerFactory.getLogger(ModifiableDataTreeDelegator.class); - private static final ReadableDataManager EMPTY_OPERATIONAL = p -> immediateCheckedFuture(Optional.absent()); - - private final WriterRegistry writerRegistry; - private final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker; - // TODO what to use instead of deprecated BindingNormalizedNodeSerializer ? - private final BindingNormalizedNodeSerializer serializer; - - /** - * Creates configuration data tree instance. - * @param serializer service for serialization between Java Binding Data representation and NormalizedNode - * representation. - * @param dataTree data tree for configuration data representation - * @param writerRegistry service for translation between Java Binding Data and data provider, capable of performing - * @param contextBroker BA broker providing full access to mapping context data - */ - public ModifiableDataTreeDelegator(@Nonnull final BindingNormalizedNodeSerializer serializer, - @Nonnull final DataTree dataTree, - @Nonnull final WriterRegistry writerRegistry, - @Nonnull final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker) { - super(dataTree); - this.contextBroker = checkNotNull(contextBroker, "contextBroker should not be null"); - this.serializer = checkNotNull(serializer, "serializer should not be null"); - this.writerRegistry = checkNotNull(writerRegistry, "writerRegistry should not be null"); - } - - @Override - public DataModification newModification() { - return new ConfigSnapshot(super.newModification()); - } - - private final class ConfigSnapshot extends ModifiableDataTreeManager.ConfigSnapshot { - - private final DataModification untouchedModification; - - /** - * @param untouchedModification DataModification captured while this modification/snapshot was created. - * To be used later while invoking writers to provide them with before state - * (state without current modifications). - * It must be captured as close as possible to when current modification started. - */ - ConfigSnapshot(final DataModification untouchedModification) { - this.untouchedModification = untouchedModification; - } - - /** - * Pass the changes to underlying writer layer. - * Transform from BI to BA. - * Revert(Write data before to subtrees that have been successfully modified before failure) in case of failure. - */ - @Override - protected void processCandidate(final DataTreeCandidate candidate) - throws TranslationException { - - final DataTreeCandidateNode rootNode = candidate.getRootNode(); - final YangInstanceIdentifier rootPath = candidate.getRootPath(); - LOG.trace("ConfigDataTree.modify() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}", - rootPath, rootNode, rootNode.getDataBefore(), rootNode.getDataAfter()); - - final ModificationDiff modificationDiff = - ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, rootNode); - LOG.debug("ConfigDataTree.modify() diff: {}", modificationDiff); - - // Distinguish between updates (create + update) and deletes - final WriterRegistry.DataObjectUpdates baUpdates = toBindingAware(modificationDiff.getUpdates()); - LOG.debug("ConfigDataTree.modify() extracted updates={}", baUpdates); - - try (final WriteContext ctx = getTransactionWriteContext()) { - writerRegistry.update(baUpdates, ctx); - - final CheckedFuture contextUpdateResult = - ((TransactionMappingContext) ctx.getMappingContext()).submit(); - // Blocking on context data update - contextUpdateResult.checkedGet(); - - } catch (WriterRegistry.BulkUpdateException e) { - LOG.warn("Failed to apply all changes", e); - LOG.info("Trying to revert successful changes for current transaction"); - - try { - e.revertChanges(); - LOG.info("Changes successfully reverted"); - } catch (WriterRegistry.Reverter.RevertFailedException revertFailedException) { - // fail with failed revert - LOG.error("Failed to revert successful changes", revertFailedException); - throw revertFailedException; - } - - throw e; // fail with success revert - } catch (TransactionCommitFailedException e) { - // FIXME revert should probably occur when context is not written successfully - final String msg = "Error while updating mapping context data"; - LOG.error(msg, e); - throw new TranslationException(msg, e); - } catch (TranslationException e) { - LOG.error("Error while processing data change (updates={})", baUpdates, e); - throw e; - } - } - - private TransactionWriteContext getTransactionWriteContext() { - // Before Tx must use modification - final DOMDataReadOnlyTransaction beforeTx = ReadOnlyTransaction.create(untouchedModification, EMPTY_OPERATIONAL); - // After Tx must use current modification - final DOMDataReadOnlyTransaction afterTx = ReadOnlyTransaction.create(this, EMPTY_OPERATIONAL); - final TransactionMappingContext mappingContext = new TransactionMappingContext( - contextBroker.newReadWriteTransaction()); - return new TransactionWriteContext(serializer, beforeTx, afterTx, mappingContext); - } - - private WriterRegistry.DataObjectUpdates toBindingAware( - final Map biNodes) { - return ModifiableDataTreeDelegator.toBindingAware(biNodes, serializer); - } - } - - @VisibleForTesting - static WriterRegistry.DataObjectUpdates toBindingAware( - final Map biNodes, - final BindingNormalizedNodeSerializer serializer) { - - final Multimap, DataObjectUpdate> dataObjectUpdates = HashMultimap.create(); - final Multimap, DataObjectUpdate.DataObjectDelete> dataObjectDeletes = - HashMultimap.create(); - - for (Map.Entry biEntry : biNodes.entrySet()) { - final InstanceIdentifier unkeyedIid = - RWUtils.makeIidWildcarded(serializer.fromYangInstanceIdentifier(biEntry.getKey())); - - ModificationDiff.NormalizedNodeUpdate normalizedNodeUpdate = biEntry.getValue(); - final DataObjectUpdate dataObjectUpdate = toDataObjectUpdate(normalizedNodeUpdate, serializer); - if (dataObjectUpdate != null) { - if (dataObjectUpdate instanceof DataObjectUpdate.DataObjectDelete) { - dataObjectDeletes.put(unkeyedIid, ((DataObjectUpdate.DataObjectDelete) dataObjectUpdate)); - } else { - dataObjectUpdates.put(unkeyedIid, dataObjectUpdate); - } - } - } - return new WriterRegistry.DataObjectUpdates(dataObjectUpdates, dataObjectDeletes); - } - - @Nullable - private static DataObjectUpdate toDataObjectUpdate( - final ModificationDiff.NormalizedNodeUpdate normalizedNodeUpdate, - final BindingNormalizedNodeSerializer serializer) { - - InstanceIdentifier baId = serializer.fromYangInstanceIdentifier(normalizedNodeUpdate.getId()); - checkNotNull(baId, "Unable to transform instance identifier: %s into BA", normalizedNodeUpdate.getId()); - - DataObject dataObjectBefore = getDataObject(serializer, - normalizedNodeUpdate.getDataBefore(), normalizedNodeUpdate.getId()); - DataObject dataObjectAfter = - getDataObject(serializer, normalizedNodeUpdate.getDataAfter(), normalizedNodeUpdate.getId()); - - return dataObjectBefore == null && dataObjectAfter == null - ? null - : DataObjectUpdate.create(baId, dataObjectBefore, dataObjectAfter); - } - - @Nullable - private static DataObject getDataObject(@Nonnull final BindingNormalizedNodeSerializer serializer, - @Nullable final NormalizedNode data, - @Nonnull final YangInstanceIdentifier id) { - DataObject dataObject = null; - if (data != null) { - final Map.Entry, DataObject> dataObjectEntry = - serializer.fromNormalizedNode(id, data); - if (dataObjectEntry != null) { - dataObject = dataObjectEntry.getValue(); - } - } - return dataObject; - } - -} - - - diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java deleted file mode 100644 index 1082c479b..000000000 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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.data.impl; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.util.concurrent.Futures.immediateCheckedFuture; - -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.data.DataModification; -import io.fd.honeycomb.v3po.data.ModifiableDataManager; -import io.fd.honeycomb.v3po.translate.TranslationException; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -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.DataTreeModification; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * DataTree backed implementation for modifiable data manager. - */ -public class ModifiableDataTreeManager implements ModifiableDataManager { - - private static final Logger LOG = LoggerFactory.getLogger(ModifiableDataTreeManager.class); - - private final DataTree dataTree; - - public ModifiableDataTreeManager(@Nonnull final DataTree dataTree) { - this.dataTree = checkNotNull(dataTree, "dataTree should not be null"); - } - - @Override - public DataModification newModification() { - return new ConfigSnapshot(); - } - - @Override - public final CheckedFuture>, ReadFailedException> read(@Nonnull final YangInstanceIdentifier path) { - return newModification().read(path); - } - - protected class ConfigSnapshot implements DataModification { - private final DataTreeModification modification; - private boolean validated = false; - - ConfigSnapshot() { - this(dataTree.takeSnapshot().newModification()); - } - - protected ConfigSnapshot(final DataTreeModification modification) { - this.modification = modification; - } - - @Override - public CheckedFuture>, ReadFailedException> read( - @Nonnull final YangInstanceIdentifier path) { - final Optional> node = modification.readNode(path); - if (LOG.isTraceEnabled() && node.isPresent()) { - LOG.trace("ConfigSnapshot.read: {}", node.get()); - } - return immediateCheckedFuture(node); - } - - @Override - public final void delete(final YangInstanceIdentifier path) { - modification.delete(path); - } - - @Override - public final void merge(final YangInstanceIdentifier path, final NormalizedNode data) { - modification.merge(path, data); - } - - @Override - public final void write(final YangInstanceIdentifier path, final NormalizedNode data) { - modification.write(path, data); - } - - @Override - public final void commit() throws DataValidationFailedException, TranslationException { - if(!validated) { - validate(); - } - final DataTreeCandidate candidate = dataTree.prepare(modification); - processCandidate(candidate); - dataTree.commit(candidate); - } - - protected void processCandidate(final DataTreeCandidate candidate) throws TranslationException { - // NOOP - } - - @Override - public final void validate() throws DataValidationFailedException { - modification.ready(); - dataTree.validate(modification); - validated = true; - } - } -} - - - diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModificationDiff.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModificationDiff.java deleted file mode 100644 index abc0062de..000000000 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModificationDiff.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * 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.data.impl; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.collect.ImmutableMap; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; -import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; -import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; -import org.opendaylight.yangtools.yang.data.api.schema.MixinNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType; - -/** - * Recursively collects and provides all unique and non-null modifications (modified normalized nodes). - */ -final class ModificationDiff { - - private static final ModificationDiff EMPTY_DIFF = new ModificationDiff(Collections.emptyMap()); - private static final EnumSet LEAF_MODIFICATIONS = EnumSet.of(ModificationType.WRITE, ModificationType.DELETE); - - private final Map updates; - - private ModificationDiff(@Nonnull Map updates) { - this.updates = updates; - } - - /** - * Get processed modifications. - * - * @return mapped modifications, where key is keyed {@link YangInstanceIdentifier}. - */ - Map getUpdates() { - return updates; - } - - private ModificationDiff merge(final ModificationDiff other) { - if (this == EMPTY_DIFF) { - return other; - } - - if (other == EMPTY_DIFF) { - return this; - } - - return new ModificationDiff(join(updates, other.updates)); - } - - private static Map join(Map first, - Map second) { - final Map merged = new HashMap<>(); - merged.putAll(first); - merged.putAll(second); - return merged; - } - - private static ModificationDiff create(YangInstanceIdentifier id, DataTreeCandidateNode candidate) { - return new ModificationDiff(ImmutableMap.of(id, NormalizedNodeUpdate.create(id, candidate))); - } - - /** - * Produce an aggregated diff from a candidate node recursively. MixinNodes are ignored as modifications and so - * are complex nodes which direct leaves were not modified. - */ - @Nonnull - static ModificationDiff recursivelyFromCandidate(@Nonnull final YangInstanceIdentifier yangIid, - @Nonnull final DataTreeCandidateNode currentCandidate) { - // recursively process child nodes for exact modifications - return recursivelyChildrenFromCandidate(yangIid, currentCandidate) - // also add modification on current level, if elligible - .merge(isModification(currentCandidate) - ? ModificationDiff.create(yangIid, currentCandidate) - : EMPTY_DIFF); - } - - /** - * Check whether current node was modified. {@link MixinNode}s are ignored - * and only nodes which direct leaves(or choices) are modified are considered a modification. - */ - private static Boolean isModification(@Nonnull final DataTreeCandidateNode currentCandidate) { - // Mixin nodes are not considered modifications - if (isMixin(currentCandidate) && !isAugment(currentCandidate)) { - return false; - } else { - return isCurrentModified(currentCandidate); - } - } - - private static Boolean isCurrentModified(final @Nonnull DataTreeCandidateNode currentCandidate) { - // Check if there are any modified leaves and if so, consider current node as modified - final Boolean directLeavesModified = currentCandidate.getChildNodes().stream() - .filter(ModificationDiff::isLeaf) - // For some reason, we get modifications on unmodified list keys TODO debug and report ODL bug - // and that messes up our modifications collection here, so we need to skip - .filter(ModificationDiff::isBeforeAndAfterDifferent) - .filter(child -> LEAF_MODIFICATIONS.contains(child.getModificationType())) - .findFirst() - .isPresent(); - - return directLeavesModified - // Also check choices (choices do not exist in BA world and if anything within a choice was modified, - // consider its parent as being modified) - || currentCandidate.getChildNodes().stream() - .filter(ModificationDiff::isChoice) - // Recursively check each choice if there was any change to it - .filter(ModificationDiff::isCurrentModified) - .findFirst() - .isPresent(); - } - - /** - * Process all non-leaf child nodes recursively, creating aggregated {@link ModificationDiff}. - */ - private static ModificationDiff recursivelyChildrenFromCandidate(final @Nonnull YangInstanceIdentifier yangIid, - final @Nonnull DataTreeCandidateNode currentCandidate) { - // recursively process child nodes for specific modifications - return currentCandidate.getChildNodes().stream() - // not interested in modifications to leaves - .filter(child -> !isLeaf(child)) - .map(candidate -> recursivelyFromCandidate(yangIid.node(candidate.getIdentifier()), candidate)) - .reduce(ModificationDiff::merge) - .orElse(EMPTY_DIFF); - } - - /** - * Check whether candidate.before and candidate.after is different. If not return false. - */ - private static boolean isBeforeAndAfterDifferent(@Nonnull final DataTreeCandidateNode candidateNode) { - if (candidateNode.getDataBefore().isPresent()) { - return !candidateNode.getDataBefore().get().equals(candidateNode.getDataAfter().orNull()); - } - - // considering not a modification if data after is also null - return candidateNode.getDataAfter().isPresent(); - } - - /** - * Check whether candidate node is for a leaf type node. - */ - private static boolean isLeaf(final DataTreeCandidateNode candidateNode) { - // orNull intentional, some candidate nodes have both data after and data before null - return candidateNode.getDataAfter().orNull() instanceof LeafNode - || candidateNode.getDataBefore().orNull() instanceof LeafNode; - } - - /** - * Check whether candidate node is for a Mixin type node. - */ - private static boolean isMixin(final DataTreeCandidateNode candidateNode) { - // orNull intentional, some candidate nodes have both data after and data before null - return candidateNode.getDataAfter().orNull() instanceof MixinNode - || candidateNode.getDataBefore().orNull() instanceof MixinNode; - } - - /** - * Check whether candidate node is for an Augmentation type node. - */ - private static boolean isAugment(final DataTreeCandidateNode candidateNode) { - // orNull intentional, some candidate nodes have both data after and data before null - return candidateNode.getDataAfter().orNull() instanceof AugmentationNode - || candidateNode.getDataBefore().orNull() instanceof AugmentationNode; - } - - /** - * Check whether candidate node is for a Choice type node. - */ - private static boolean isChoice(final DataTreeCandidateNode candidateNode) { - // orNull intentional, some candidate nodes have both data after and data before null - return candidateNode.getDataAfter().orNull() instanceof ChoiceNode - || candidateNode.getDataBefore().orNull() instanceof ChoiceNode; - } - - @Override - public String toString() { - return "ModificationDiff{updates=" + updates + '}'; - } - - /** - * Update to a normalized node identifiable by its {@link YangInstanceIdentifier}. - */ - static final class NormalizedNodeUpdate { - - @Nonnull - private final YangInstanceIdentifier id; - @Nullable - private final NormalizedNode dataBefore; - @Nullable - private final NormalizedNode dataAfter; - - private NormalizedNodeUpdate(@Nonnull final YangInstanceIdentifier id, - @Nullable final NormalizedNode dataBefore, - @Nullable final NormalizedNode dataAfter) { - this.id = checkNotNull(id); - this.dataAfter = dataAfter; - this.dataBefore = dataBefore; - } - - @Nullable - public NormalizedNode getDataBefore() { - return dataBefore; - } - - @Nullable - public NormalizedNode getDataAfter() { - return dataAfter; - } - - @Nonnull - public YangInstanceIdentifier getId() { - return id; - } - - static NormalizedNodeUpdate create(@Nonnull final YangInstanceIdentifier id, - @Nonnull final DataTreeCandidateNode candidate) { - return create(id, candidate.getDataBefore().orNull(), candidate.getDataAfter().orNull()); - } - - static NormalizedNodeUpdate create(@Nonnull final YangInstanceIdentifier id, - @Nullable final NormalizedNode dataBefore, - @Nullable final NormalizedNode dataAfter) { - checkArgument(!(dataBefore == null && dataAfter == null), "Both before and after data are null"); - return new NormalizedNodeUpdate(id, dataBefore, dataAfter); - } - - @Override - public boolean equals(final Object other) { - if (this == other) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - - final NormalizedNodeUpdate that = (NormalizedNodeUpdate) other; - - return id.equals(that.id); - - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public String toString() { - return "NormalizedNodeUpdate{" + "id=" + id - + ", dataBefore=" + dataBefore - + ", dataAfter=" + dataAfter - + '}'; - } - } - -} diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java deleted file mode 100644 index 9b71dfd62..000000000 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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.data.impl; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.Optional; -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.sal.core.api.model.SchemaService; -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.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.model.api.SchemaContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Adapter for a DataTree that stores current state of data in backing DataTree on each successful commit. - * Uses JSON format. - */ -public class PersistingDataTreeAdapter implements DataTree, AutoCloseable { - - private static final Logger LOG = LoggerFactory.getLogger(PersistingDataTreeAdapter.class); - - private final DataTree delegateDependency; - private final SchemaService schemaServiceDependency; - private final Path path; - - /** - * Create new Persisting DataTree adapter - * - * @param delegate backing data tree that actually handles all the operations - * @param persistPath path to a file (existing or not) to be used as storage for persistence. Full control over - * a file at peristPath is expected - * @param schemaService schemaContext provier - */ - public PersistingDataTreeAdapter(@Nonnull final DataTree delegate, - @Nonnull final SchemaService schemaService, - @Nonnull final Path persistPath) { - this.path = testPersistPath(checkNotNull(persistPath, "persistPath is null")); - this.delegateDependency = checkNotNull(delegate, "delegate is null"); - this.schemaServiceDependency = checkNotNull(schemaService, "schemaService is null"); - } - - /** - * Test whether file at persistPath exists and is readable or create it along with its parent structure - */ - 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 "); - } - - return persistPath; - } - - @Override - public DataTreeSnapshot takeSnapshot() { - return delegateDependency.takeSnapshot(); - } - - @Override - public void setSchemaContext(final SchemaContext schemaContext) { - delegateDependency.setSchemaContext(schemaContext); - } - - @Override - public void commit(final DataTreeCandidate dataTreeCandidate) { - LOG.trace("Commit detected"); - delegateDependency.commit(dataTreeCandidate); - LOG.debug("Delegate commit successful. Persisting data"); - - // FIXME doing full read and full write might not be the fastest way of persisting data here - final DataTreeSnapshot dataTreeSnapshot = delegateDependency.takeSnapshot(); - - // TODO this can be handled in background by a dedicated thread + a limited blocking queue - // TODO enable configurable granularity for persists. Maybe doing write on every modification is too much - // and we could do bulk persist - persistCurrentData(dataTreeSnapshot.readNode(YangInstanceIdentifier.EMPTY)); - } - - private void persistCurrentData(final Optional> currentRoot) { - if(currentRoot.isPresent()) { - try { - LOG.trace("Persisting current data: {} into: {}", currentRoot.get(), path); - JsonUtils.writeJsonRoot(currentRoot.get(), schemaServiceDependency.getGlobalContext(), - Files.newOutputStream(path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)); - LOG.trace("Data persisted successfully in {}", path); - } catch (IOException e) { - throw new IllegalStateException("Unable to persist current data", e); - } - } else { - LOG.debug("Skipping persistence, since there's no data to persist"); - } - } - - @Override - public YangInstanceIdentifier getRootPath() { - return delegateDependency.getRootPath(); - } - - @Override - public void validate(final DataTreeModification dataTreeModification) throws DataValidationFailedException { - delegateDependency.validate(dataTreeModification); - } - - @Override - public DataTreeCandidate prepare( - final DataTreeModification dataTreeModification) { - return delegateDependency.prepare(dataTreeModification); - } - - @Override - public void close() throws Exception { - LOG.trace("Closing {} for {}", getClass().getSimpleName(), path); - // NOOP - } -} diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java deleted file mode 100644 index 2850a0d9a..000000000 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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.data.impl; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; -import static java.util.Objects.requireNonNull; - -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import io.fd.honeycomb.v3po.data.ReadableDataManager; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class ReadOnlyTransaction implements DOMDataReadOnlyTransaction { - - private static final Logger LOG = LoggerFactory.getLogger(ReadOnlyTransaction.class); - - @Nullable - private ReadableDataManager operationalData; - @Nullable - private ReadableDataManager configSnapshot; - - private boolean closed = false; - - /** - * @param configData config data tree manager. Null if config reads are not to be supported - * @param operationalData operational data tree manager. Null if operational reads are not to be supported - */ - private ReadOnlyTransaction(@Nullable final ReadableDataManager configData, - @Nullable final ReadableDataManager operationalData) { - this.configSnapshot = configData; - this.operationalData = operationalData; - } - - @Override - public synchronized void close() { - closed = true; - configSnapshot = null; - operationalData = null; - } - - @Override - public synchronized CheckedFuture>, ReadFailedException> read( - final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - LOG.debug("ReadOnlyTransaction.read(), store={}, path={}", store, path); - checkState(!closed, "Transaction has been closed"); - - if (store == LogicalDatastoreType.OPERATIONAL) { - checkArgument(operationalData != null, "{} reads not supported", store); - return operationalData.read(path); - } else { - checkArgument(configSnapshot != null, "{} reads not supported", store); - return configSnapshot.read(path); - } - } - - @Override - public CheckedFuture exists(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - LOG.debug("ReadOnlyTransaction.exists() store={}, path={}", store, path); - - ListenableFuture listenableFuture = Futures.transform(read(store, path), IS_NODE_PRESENT); - return Futures.makeChecked(listenableFuture, ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER); - } - - @Nonnull - @Override - public Object getIdentifier() { - return this; - } - - @Nonnull - static ReadOnlyTransaction createOperationalOnly(@Nonnull final ReadableDataManager operationalData) { - return new ReadOnlyTransaction(null, requireNonNull(operationalData)); - } - - @Nonnull - static ReadOnlyTransaction createConfigOnly(@Nonnull final ReadableDataManager configData) { - return new ReadOnlyTransaction(requireNonNull(configData), null); - } - - @Nonnull - static ReadOnlyTransaction create(@Nonnull final ReadableDataManager configData, - @Nonnull final ReadableDataManager operationalData) { - return new ReadOnlyTransaction(requireNonNull(configData), requireNonNull(operationalData)); - } - - private static final Function>, ? extends Boolean> IS_NODE_PRESENT = - (Function>, Boolean>) input -> input == null ? Boolean.FALSE : input.isPresent(); - - private static final Function ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER = - (Function) e -> new ReadFailedException("Exists failed", e); -} \ No newline at end of file diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java deleted file mode 100644 index 88b46437e..000000000 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.data.impl; - -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.ListenableFuture; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -/** - * Composite DOM transaction that delegates reads to a {@link DOMDataReadTransaction} delegate and writes to a {@link - * DOMDataWriteTransaction} delegate. - */ -final class ReadWriteTransaction implements DOMDataReadWriteTransaction { - - private final DOMDataReadOnlyTransaction delegateReadTx; - private final DOMDataWriteTransaction delegateWriteTx; - - ReadWriteTransaction(@Nonnull final DOMDataReadOnlyTransaction delegateReadTx, - @Nonnull final DOMDataWriteTransaction delegateWriteTx) { - this.delegateReadTx = Preconditions.checkNotNull(delegateReadTx, "delegateReadTx should not be null"); - this.delegateWriteTx = Preconditions.checkNotNull(delegateWriteTx, "delegateWriteTx should not be null"); - } - - @Override - public boolean cancel() { - delegateReadTx.close(); - return delegateWriteTx.cancel(); - } - - @Override - public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode data) { - delegateWriteTx.put(store, path, data); - } - - @Override - public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode data) { - delegateWriteTx.merge(store, path, data); - } - - @Override - public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) { - delegateWriteTx.delete(store, path); - } - - @Override - public CheckedFuture submit() { - return delegateWriteTx.submit(); - } - - @Override - public ListenableFuture> commit() { - return delegateWriteTx.commit(); - } - - @Override - public CheckedFuture>, ReadFailedException> read(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - return delegateReadTx.read(store, path); - } - - @Override - public CheckedFuture exists(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - return delegateReadTx.exists(store, path); - } - - @Override - public Object getIdentifier() { - return this; - } -} - diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java deleted file mode 100644 index aff023ebc..000000000 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * 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.data.impl; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Iterables.getOnlyElement; - -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.collect.Collections2; -import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; -import io.fd.honeycomb.v3po.data.ReadableDataManager; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry; -import io.fd.honeycomb.v3po.translate.util.TransactionMappingContext; -import java.util.Collection; -import java.util.Map; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -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.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * ReadableDataTree implementation for operational data. - */ -public final class ReadableDataTreeDelegator implements ReadableDataManager { - private static final Logger LOG = LoggerFactory.getLogger(ReadableDataTreeDelegator.class); - - private final BindingNormalizedNodeSerializer serializer; - private final ReaderRegistry readerRegistry; - private final SchemaContext globalContext; - private final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker; - - /** - * Creates operational data tree instance. - * @param serializer service for serialization between Java Binding Data representation and NormalizedNode - * representation. - * @param globalContext service for obtaining top level context data from all yang modules. - * @param readerRegistry service responsible for translation between DataObjects and data provider. - * @param contextBroker BA broker for context data - */ - public ReadableDataTreeDelegator(@Nonnull BindingNormalizedNodeSerializer serializer, - @Nonnull final SchemaContext globalContext, - @Nonnull final ReaderRegistry readerRegistry, - @Nonnull final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker) { - this.contextBroker = checkNotNull(contextBroker, "contextBroker should not be null"); - this.globalContext = checkNotNull(globalContext, "globalContext should not be null"); - this.serializer = checkNotNull(serializer, "serializer should not be null"); - this.readerRegistry = checkNotNull(readerRegistry, "reader should not be null"); - } - - @Override - public CheckedFuture>, - org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> read( - @Nonnull final YangInstanceIdentifier yangInstanceIdentifier) { - - try(TransactionMappingContext mappingContext = new TransactionMappingContext(contextBroker.newReadWriteTransaction()); - ReadContext ctx = new ReadContextImpl(mappingContext)) { - - final Optional> value; - if (checkNotNull(yangInstanceIdentifier).equals(YangInstanceIdentifier.EMPTY)) { - value = readRoot(ctx); - } else { - value = readNode(yangInstanceIdentifier, ctx); - } - - // Submit context mapping updates - final CheckedFuture contextUpdateResult = - ((TransactionMappingContext) ctx.getMappingContext()).submit(); - // Blocking on context data update - contextUpdateResult.checkedGet(); - - return Futures.immediateCheckedFuture(value); - - } catch (ReadFailedException e) { - return Futures.immediateFailedCheckedFuture( - new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException( - "Failed to read VPP data", e)); - } catch (TransactionCommitFailedException e) { - // FIXME revert should probably occur when context is not written successfully - final String msg = "Error while updating mapping context data"; - LOG.error(msg, e); - return Futures.immediateFailedCheckedFuture( - new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException(msg, e) - ); - } - } - - private Optional> readNode(final YangInstanceIdentifier yangInstanceIdentifier, - final ReadContext ctx) throws ReadFailedException { - LOG.debug("OperationalDataTree.readNode(), yangInstanceIdentifier={}", yangInstanceIdentifier); - final InstanceIdentifier path = serializer.fromYangInstanceIdentifier(yangInstanceIdentifier); - checkNotNull(path, "Invalid instance identifier %s. Cannot create BA equivalent.", yangInstanceIdentifier); - LOG.debug("OperationalDataTree.readNode(), path={}", path); - - final Optional dataObject; - - dataObject = readerRegistry.read(path, ctx); - if (dataObject.isPresent()) { - final NormalizedNode value = toNormalizedNodeFunction(path).apply(dataObject.get()); - return Optional.>fromNullable(value); - } else { - return Optional.absent(); - } - } - - private Optional> readRoot(final ReadContext ctx) throws ReadFailedException { - LOG.debug("OperationalDataTree.readRoot()"); - - final DataContainerNodeAttrBuilder dataNodeBuilder = - Builders.containerBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(SchemaContext.NAME)); - - final Multimap, ? extends DataObject> dataObjects = - readerRegistry.readAll(ctx); - - for (final InstanceIdentifier instanceIdentifier : dataObjects.keySet()) { - final YangInstanceIdentifier rootElementId = serializer.toYangInstanceIdentifier(instanceIdentifier); - final NormalizedNode node = - wrapDataObjects(rootElementId, instanceIdentifier, dataObjects.get(instanceIdentifier)); - dataNodeBuilder.withChild((DataContainerChild) node); - } - return Optional.>of(dataNodeBuilder.build()); - } - - private NormalizedNode wrapDataObjects(final YangInstanceIdentifier yangInstanceIdentifier, - final InstanceIdentifier instanceIdentifier, - final Collection dataObjects) { - final Collection> normalizedRootElements = Collections2 - .transform(dataObjects, toNormalizedNodeFunction(instanceIdentifier)); - - final DataSchemaNode schemaNode = - globalContext.getDataChildByName(yangInstanceIdentifier.getLastPathArgument().getNodeType()); - if (schemaNode instanceof ListSchemaNode) { - // In case of a list, wrap all the values in a Mixin parent node - final ListSchemaNode listSchema = (ListSchemaNode) schemaNode; - return wrapListIntoMixinNode(normalizedRootElements, listSchema); - } else { - Preconditions.checkState(dataObjects.size() == 1, "Singleton list was expected"); - return getOnlyElement(normalizedRootElements); - } - } - - private static DataContainerChild wrapListIntoMixinNode( - final Collection> normalizedRootElements, final ListSchemaNode listSchema) { - if (listSchema.getKeyDefinition().isEmpty()) { - final CollectionNodeBuilder listBuilder = - Builders.unkeyedListBuilder(); - for (NormalizedNode normalizedRootElement : normalizedRootElements) { - listBuilder.withChild((UnkeyedListEntryNode) normalizedRootElement); - } - return listBuilder.build(); - } else { - final CollectionNodeBuilder listBuilder = - listSchema.isUserOrdered() - ? Builders.orderedMapBuilder() - : Builders.mapBuilder(); - - for (NormalizedNode normalizedRootElement : normalizedRootElements) { - listBuilder.withChild((MapEntryNode) normalizedRootElement); - } - return listBuilder.build(); - } - } - - @SuppressWarnings("unchecked") - private Function> toNormalizedNodeFunction(final InstanceIdentifier path) { - return dataObject -> { - LOG.trace("OperationalDataTree.toNormalizedNode(), path={}, dataObject={}", path, dataObject); - final Map.Entry> entry = - serializer.toNormalizedNode(path, dataObject); - - LOG.trace("OperationalDataTree.toNormalizedNode(), normalizedNodeEntry={}", entry); - return entry.getValue(); - }; - } - - private static final class ReadContextImpl implements ReadContext { - - private final ModificationCache ctx = new ModificationCache(); - private final MappingContext mappingContext; - - private ReadContextImpl(final MappingContext mappingContext) { - this.mappingContext = mappingContext; - } - - @Nonnull - @Override - public ModificationCache getModificationCache() { - return ctx; - } - - @Nonnull - @Override - public MappingContext getMappingContext() { - return mappingContext; - } - - @Override - public void close() { - // Make sure to clear the storage in case some customizer stored a reference to it to prevent memory leaks - ctx.close(); - } - } -} diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java deleted file mode 100644 index c8f9bd3db..000000000 --- a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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.data.impl; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Objects.requireNonNull; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.CANCELED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.COMMITED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.FAILED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.SUBMITED; - -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import io.fd.honeycomb.v3po.data.DataModification; -import io.fd.honeycomb.v3po.translate.TranslationException; -import java.util.function.Consumer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.annotation.concurrent.NotThreadSafe; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -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.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.common.RpcResult; -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.DataValidationFailedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@NotThreadSafe -final class WriteTransaction implements DOMDataWriteTransaction { - - private static final Logger LOG = LoggerFactory.getLogger(WriteTransaction.class); - - @Nullable - private DataModification operationalModification; - @Nullable - private DataModification configModification; - private TransactionStatus status = NEW; - - private WriteTransaction(@Nullable final DataModification configModification, - @Nullable final DataModification operationalModification) { - this.operationalModification = operationalModification; - this.configModification = configModification; - } - - private void checkIsNew() { - Preconditions.checkState(status == NEW, "Transaction was submitted or canceled"); - } - - @Override - public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode data) { - LOG.debug("WriteTransaction.put() store={}, path={}, data={}", store, path, data); - checkIsNew(); - handleOperation(store, (modification) -> modification.write(path, data)); - } - - private void handleOperation(final LogicalDatastoreType store, - final Consumer r) { - switch (store) { - case CONFIGURATION: - checkArgument(configModification != null, "Modification of %s is not supported", store); - r.accept(configModification); - break; - case OPERATIONAL: - checkArgument(operationalModification != null, "Modification of %s is not supported", store); - r.accept(operationalModification); - break; - } - } - - @Override - public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode data) { - LOG.debug("WriteTransaction.merge() store={}, path={}, data={}", store, path, data); - checkIsNew(); - handleOperation(store, (modification) -> modification.merge(path, data)); - } - - @Override - public boolean cancel() { - if (status != NEW) { - // only NEW transactions can be cancelled - return false; - } else { - status = CANCELED; - return true; - } - } - - @Override - public void delete(LogicalDatastoreType store, final YangInstanceIdentifier path) { - LOG.debug("WriteTransaction.delete() store={}, path={}", store, path); - checkIsNew(); - handleOperation(store, (modification) -> modification.delete(path)); - } - - @Override - public CheckedFuture submit() { - LOG.trace("WriteTransaction.submit()"); - checkIsNew(); - - try { - status = SUBMITED; - - // Validate first to catch any issues before attempting commit - if (configModification != null) { - configModification.validate(); - } - if (operationalModification != null) { - operationalModification.validate(); - } - - if(configModification != null) { - configModification.commit(); - } - if(operationalModification != null) { - operationalModification.commit(); - } - - status = COMMITED; - } catch (DataValidationFailedException | TranslationException e) { - status = FAILED; - LOG.error("Failed modify data tree", e); - return Futures.immediateFailedCheckedFuture( - new TransactionCommitFailedException("Failed to validate DataTreeModification", e)); - } - return Futures.immediateCheckedFuture(null); - } - - @Override - @Deprecated - public ListenableFuture> commit() { - throw new UnsupportedOperationException("deprecated"); - } - - @Override - public Object getIdentifier() { - return this; - } - - - @Nonnull - static WriteTransaction createOperationalOnly(@Nonnull final DataModification operationalData) { - return new WriteTransaction(null, requireNonNull(operationalData)); - } - - @Nonnull - static WriteTransaction createConfigOnly(@Nonnull final DataModification configData) { - return new WriteTransaction(requireNonNull(configData), null); - } - - @Nonnull - static WriteTransaction create(@Nonnull final DataModification configData, - @Nonnull final DataModification operationalData) { - return new WriteTransaction(requireNonNull(configData), requireNonNull(operationalData)); - } -} diff --git a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java index eabcdcbc8..8db0d5404 100644 --- a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java +++ b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java @@ -2,9 +2,9 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl. import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.data.DataModification; -import io.fd.honeycomb.v3po.data.ModifiableDataManager; -import io.fd.honeycomb.v3po.data.impl.ModifiableDataTreeDelegator; +import io.fd.honeycomb.data.DataModification; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.impl.ModifiableDataTreeDelegator; import javax.annotation.Nonnull; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; diff --git a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java index 1526fddca..dcb0053ca 100644 --- a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java +++ b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java @@ -2,8 +2,8 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl. import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.data.ReadableDataManager; -import io.fd.honeycomb.v3po.data.impl.ReadableDataTreeDelegator; +import io.fd.honeycomb.data.ReadableDataManager; +import io.fd.honeycomb.data.impl.ReadableDataTreeDelegator; import javax.annotation.Nonnull; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; diff --git a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java index 145fc4345..c15feace9 100644 --- a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java +++ b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java @@ -29,7 +29,7 @@ public class PersistingDataTreeAdapterModule extends @Override public java.lang.AutoCloseable createInstance() { - return new io.fd.honeycomb.v3po.data.impl.PersistingDataTreeAdapter( + return new io.fd.honeycomb.data.impl.PersistingDataTreeAdapter( getDelegateDependency(), getSchemaServiceDependency(), Paths.get(getPersistFilePath())); diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/DataBrokerTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/DataBrokerTest.java new file mode 100644 index 000000000..08cb3320f --- /dev/null +++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/DataBrokerTest.java @@ -0,0 +1,111 @@ +/* + * 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.data.impl; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.honeycomb.data.ReadableDataManager; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.DataModification; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +public class DataBrokerTest { + + @Mock + private ReadableDataManager operationalData; + @Mock + private ModifiableDataManager confiDataTree; + @Mock + private DataModification configSnapshot; + private DataBroker broker; + + @Before + public void setUp() { + initMocks(this); + when(confiDataTree.newModification()).thenReturn(configSnapshot); + broker = DataBroker.create(confiDataTree, operationalData); + } + + @Test + public void testNewReadWriteTransaction() { + final DOMDataReadWriteTransaction readWriteTx = broker.newReadWriteTransaction(); + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + readWriteTx.read(LogicalDatastoreType.CONFIGURATION, path); + + // verify that read and write transactions use the same config snapshot + verify(configSnapshot).read(path); + verify(confiDataTree).newModification(); + } + + @Test + public void testNewWriteOnlyTransaction() { + final DOMDataWriteTransaction writeTx = broker.newWriteOnlyTransaction(); + + // verify that write transactions use config snapshot + verify(confiDataTree).newModification(); + } + + @Test + public void testNewReadOnlyTransaction() { + final DOMDataReadOnlyTransaction readTx = broker.newReadOnlyTransaction(); + + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + readTx.read(LogicalDatastoreType.CONFIGURATION, path); + + // verify that read transactions use config snapshot + verify(configSnapshot).read(path); + } + + @Test(expected = UnsupportedOperationException.class) + public void testRegisterDataChangeListener() { + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + final DOMDataChangeListener listener = mock(DOMDataChangeListener.class); + broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, path, listener, + AsyncDataBroker.DataChangeScope.BASE); + } + + @Test(expected = UnsupportedOperationException.class) + public void testCreateTransactionChain() { + final TransactionChainListener listener = mock(TransactionChainListener.class); + broker.createTransactionChain(listener); + } + + @Test + public void testGetSupportedExtensions() { + final Map, DOMDataBrokerExtension> supportedExtensions = + broker.getSupportedExtensions(); + assertTrue(supportedExtensions.isEmpty()); + } + + +} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegatorTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegatorTest.java new file mode 100644 index 000000000..dc962662d --- /dev/null +++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegatorTest.java @@ -0,0 +1,269 @@ +/* + * 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.data.impl; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import io.fd.honeycomb.data.DataModification; +import io.fd.honeycomb.translate.TranslationException; +import io.fd.honeycomb.translate.write.DataObjectUpdate; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import java.util.AbstractMap; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +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.MapNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; + +public class ModifiableDataTreeDelegatorTest { + + @Mock + private WriterRegistry writer; + @Mock + private BindingNormalizedNodeSerializer serializer; + private DataTree dataTree; + @Mock + private org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification modification; + @Mock + private DataBroker contextBroker; + @Mock + private org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction tx; + + private ModifiableDataTreeManager configDataTree; + + static final InstanceIdentifier DEFAULT_ID = InstanceIdentifier.create(DataObject.class); + static DataObject DEFAULT_DATA_OBJECT = mockDataObject("serialized", DataObject.class); + + @Before + public void setUp() throws Exception { + initMocks(this); + dataTree = ModificationDiffTest.getDataTree(); + when(contextBroker.newReadWriteTransaction()).thenReturn(tx); + when(tx.submit()).thenReturn(Futures.immediateCheckedFuture(null)); + + when(serializer.fromYangInstanceIdentifier(any(YangInstanceIdentifier.class))).thenReturn(((InstanceIdentifier) DEFAULT_ID)); + final Map.Entry, DataObject> parsed = new AbstractMap.SimpleEntry<>(DEFAULT_ID, DEFAULT_DATA_OBJECT); + when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), any(NormalizedNode.class))).thenReturn(parsed); + + configDataTree = new ModifiableDataTreeDelegator(serializer, dataTree, writer, contextBroker); + } + + @Test + public void testRead() throws Exception { + final ContainerNode topContainer = ModificationDiffTest.getTopContainer("topContainer"); + ModificationDiffTest.addNodeToTree(dataTree, topContainer, ModificationDiffTest.TOP_CONTAINER_ID); + final CheckedFuture>, ReadFailedException> read = + configDataTree.read(ModificationDiffTest.TOP_CONTAINER_ID); + final CheckedFuture>, ReadFailedException> read2 = + configDataTree.newModification().read(ModificationDiffTest.TOP_CONTAINER_ID); + final Optional> normalizedNodeOptional = read.get(); + final Optional> normalizedNodeOptional2 = read2.get(); + + assertEquals(normalizedNodeOptional, normalizedNodeOptional2); + assertTrue(normalizedNodeOptional.isPresent()); + assertEquals(topContainer, normalizedNodeOptional.get()); + assertEquals(dataTree.takeSnapshot().readNode(ModificationDiffTest.TOP_CONTAINER_ID), normalizedNodeOptional); + } + + @Test + public void testCommitSuccessful() throws Exception { + final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue"); + + final DataModification dataModification = configDataTree.newModification(); + dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList); + dataModification.validate(); + dataModification.commit(); + + final Multimap, DataObjectUpdate> map = HashMultimap.create(); + map.put(DEFAULT_ID, DataObjectUpdate.create(DEFAULT_ID, DEFAULT_DATA_OBJECT, DEFAULT_DATA_OBJECT)); + verify(writer).update(eq(new WriterRegistry.DataObjectUpdates(map, ImmutableMultimap.of())), any(WriteContext.class)); + assertEquals(nestedList, dataTree.takeSnapshot().readNode(ModificationDiffTest.NESTED_LIST_ID).get()); + } + + private static DataObject mockDataObject(final String name, final Class classToMock) { + final DataObject dataBefore = mock(classToMock, name); + doReturn(classToMock).when(dataBefore).getImplementedInterface(); + return dataBefore; + } + + @Test + public void testCommitUndoSuccessful() throws Exception { + final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue"); + + // Fail on update: + final WriterRegistry.Reverter reverter = mock(WriterRegistry.Reverter.class); + final TranslationException failedOnUpdateException = new TranslationException("update failed"); + doThrow(new WriterRegistry.BulkUpdateException(Collections.singleton(DEFAULT_ID), reverter, failedOnUpdateException)) + .when(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class)); + + try { + // Run the test + final DataModification dataModification = configDataTree.newModification(); + dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList); + dataModification.validate(); + dataModification.commit(); + fail("WriterRegistry.BulkUpdateException was expected"); + } catch (WriterRegistry.BulkUpdateException e) { + verify(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class)); + assertThat(e.getFailedIds(), hasItem(DEFAULT_ID)); + verify(reverter).revert(); + assertEquals(failedOnUpdateException, e.getCause()); + } + } + + @Test + public void testCommitUndoFailed() throws Exception { + final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue"); + + // Fail on update: + final WriterRegistry.Reverter reverter = mock(WriterRegistry.Reverter.class); + final TranslationException failedOnUpdateException = new TranslationException("update failed"); + doThrow(new WriterRegistry.BulkUpdateException(Collections.singleton(DEFAULT_ID), reverter, failedOnUpdateException)) + .when(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class)); + + // Fail on revert: + final TranslationException failedOnRevertException = new TranslationException("revert failed"); + doThrow(new WriterRegistry.Reverter.RevertFailedException(Collections.emptySet(), failedOnRevertException)) + .when(reverter).revert(); + + try { + // Run the test + final DataModification dataModification = configDataTree.newModification(); + dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList); + dataModification.validate(); + dataModification.commit(); + fail("WriterRegistry.Reverter.RevertFailedException was expected"); + } catch (WriterRegistry.Reverter.RevertFailedException e) { + verify(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class)); + verify(reverter).revert(); + assertEquals(failedOnRevertException, e.getCause()); + } + } + + private abstract static class DataObject1 implements DataObject {} + private abstract static class DataObject2 implements DataObject {} + private abstract static class DataObject3 implements DataObject {} + + @Test + public void testToBindingAware() throws Exception { + when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), eq(null))).thenReturn(null); + + final Map biNodes = new HashMap<>(); + // delete + final QName nn1 = QName.create("namespace", "nn1"); + final YangInstanceIdentifier yid1 = mockYid(nn1); + final InstanceIdentifier iid1 = mockIid(yid1, DataObject1.class); + final NormalizedNode nn1B = mockNormalizedNode(nn1); + final DataObject1 do1B = mockDataObject(yid1, iid1, nn1B, DataObject1.class); + biNodes.put(yid1, ModificationDiff.NormalizedNodeUpdate.create(yid1, nn1B, null)); + + // create + final QName nn2 = QName.create("namespace", "nn1"); + final YangInstanceIdentifier yid2 = mockYid(nn2); + final InstanceIdentifier iid2 = mockIid(yid2, DataObject2.class);; + final NormalizedNode nn2A = mockNormalizedNode(nn2); + final DataObject2 do2A = mockDataObject(yid2, iid2, nn2A, DataObject2.class); + biNodes.put(yid2, ModificationDiff.NormalizedNodeUpdate.create(yid2, null, nn2A)); + + // update + final QName nn3 = QName.create("namespace", "nn1"); + final YangInstanceIdentifier yid3 = mockYid(nn3); + final InstanceIdentifier iid3 = mockIid(yid3, DataObject3.class); + final NormalizedNode nn3B = mockNormalizedNode(nn3); + final DataObject3 do3B = mockDataObject(yid3, iid3, nn3B, DataObject3.class); + final NormalizedNode nn3A = mockNormalizedNode(nn3); + final DataObject3 do3A = mockDataObject(yid3, iid3, nn3A, DataObject3.class);; + biNodes.put(yid3, ModificationDiff.NormalizedNodeUpdate.create(yid3, nn3B, nn3A)); + + final WriterRegistry.DataObjectUpdates dataObjectUpdates = + ModifiableDataTreeDelegator.toBindingAware(biNodes, serializer); + + assertThat(dataObjectUpdates.getDeletes().size(), is(1)); + assertThat(dataObjectUpdates.getDeletes().keySet(), hasItem(((InstanceIdentifier) iid1))); + assertThat(dataObjectUpdates.getDeletes().values(), hasItem( + ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid1, do1B, null)))); + + assertThat(dataObjectUpdates.getUpdates().size(), is(2)); + assertThat(dataObjectUpdates.getUpdates().keySet(), hasItems((InstanceIdentifier) iid2, (InstanceIdentifier) iid3)); + assertThat(dataObjectUpdates.getUpdates().values(), hasItems( + DataObjectUpdate.create(iid2, null, do2A), + DataObjectUpdate.create(iid3, do3B, do3A))); + + assertThat(dataObjectUpdates.getTypeIntersection().size(), is(3)); + } + + private D mockDataObject(final YangInstanceIdentifier yid1, + final InstanceIdentifier iid1, + final NormalizedNode nn1B, + final Class type) { + final D do1B = mock(type); + when(serializer.fromNormalizedNode(yid1, nn1B)).thenReturn(new AbstractMap.SimpleEntry<>(iid1, do1B)); + return do1B; + } + + private NormalizedNode mockNormalizedNode(final QName nn1) { + final NormalizedNode nn1B = mock(NormalizedNode.class); + when(nn1B.getNodeType()).thenReturn(nn1); + return nn1B; + } + + private InstanceIdentifier mockIid(final YangInstanceIdentifier yid1, + final Class type) { + final InstanceIdentifier iid1 = InstanceIdentifier.create(type); + when(serializer.fromYangInstanceIdentifier(yid1)).thenReturn(iid1); + return iid1; + } + + private YangInstanceIdentifier mockYid(final QName nn1) { + final YangInstanceIdentifier yid1 = mock(YangInstanceIdentifier.class); + when(yid1.getLastPathArgument()).thenReturn(new YangInstanceIdentifier.NodeIdentifier(nn1)); + return yid1; + } +} diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java new file mode 100644 index 000000000..2fa82043b --- /dev/null +++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java @@ -0,0 +1,427 @@ +package io.fd.honeycomb.data.impl; + +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Map; +import org.junit.Test; +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.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +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.DataTreeCandidateTip; +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.api.schema.tree.TipProducingDataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; +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; + +public class ModificationDiffTest { + + static final QName TOP_CONTAINER_QNAME = + QName.create("urn:opendaylight:params:xml:ns:yang:test:diff", "2015-01-05", "top-container"); + static final QName STRING_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "string"); + static final QName NAME_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "name"); + static final QName TEXT_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "text"); + static final QName NESTED_LIST_QNAME = QName.create(TOP_CONTAINER_QNAME, "nested-list"); + static final QName DEEP_LIST_QNAME = QName.create(TOP_CONTAINER_QNAME, "deep-list"); + + static final QName WITH_CHOICE_CONTAINER_QNAME = + QName.create("urn:opendaylight:params:xml:ns:yang:test:diff", "2015-01-05", "with-choice"); + static final QName CHOICE_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "choice"); + static final QName IN_CASE1_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case1"); + static final QName IN_CASE2_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case2"); + + static final YangInstanceIdentifier TOP_CONTAINER_ID = YangInstanceIdentifier.of(TOP_CONTAINER_QNAME); + static final YangInstanceIdentifier NESTED_LIST_ID = TOP_CONTAINER_ID.node(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)); + + + @Test + public void testInitialWrite() throws Exception { + final TipProducingDataTree dataTree = getDataTree(); + final DataTreeModification dataTreeModification = getModification(dataTree); + final NormalizedNode topContainer = getTopContainer("string1"); + final YangInstanceIdentifier TOP_CONTAINER_ID = YangInstanceIdentifier.of(TOP_CONTAINER_QNAME); + dataTreeModification.write(TOP_CONTAINER_ID, topContainer); + final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); + + final ModificationDiff modificationDiff = getModificationDiff(prepare); + + assertThat(modificationDiff.getUpdates().size(), is(1)); + assertThat(modificationDiff.getUpdates().values().size(), is(1)); + assertUpdate(modificationDiff.getUpdates().values().iterator().next(), TOP_CONTAINER_ID, null, topContainer); + } + + @Test + public void testInitialWriteForContainerWithChoice() throws Exception { + final TipProducingDataTree dataTree = getDataTree(); + final DataTreeModification dataTreeModification = getModification(dataTree); + final ContainerNode containerWithChoice = Builders.containerBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(WITH_CHOICE_CONTAINER_QNAME)) + .withChild(Builders.choiceBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CHOICE_QNAME)) + .withChild(ImmutableNodes.leafNode(IN_CASE1_LEAF_QNAME, "withinCase1")) + .build()) + .build(); + final YangInstanceIdentifier WITH_CHOICE_CONTAINER_ID = YangInstanceIdentifier.of(WITH_CHOICE_CONTAINER_QNAME); + dataTreeModification.write(WITH_CHOICE_CONTAINER_ID, containerWithChoice); + final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); + + final Map updates = getModificationDiff(prepare).getUpdates(); + + assertThat(updates.size(), is(1)); + assertUpdate(getNormalizedNodeUpdateForAfterType(updates, ContainerNode.class), + WITH_CHOICE_CONTAINER_ID, null, containerWithChoice); + } + + private DataTreeModification getModification(final TipProducingDataTree dataTree) { + final DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); + return dataTreeSnapshot.newModification(); + } + + @Test + public void testWriteNonPresenceEmptyContainer() throws Exception { + final TipProducingDataTree dataTree = getDataTree(); + final DataTreeModification dataTreeModification = getModification(dataTree); + final NormalizedNode topContainer = ImmutableNodes.containerNode(TOP_CONTAINER_QNAME); + dataTreeModification.write(TOP_CONTAINER_ID, topContainer); + final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); + + final ModificationDiff modificationDiff = getModificationDiff(prepare); + + assertThat(modificationDiff.getUpdates().size(), is(0)); + } + + private DataTreeCandidateTip prepareModification(final TipProducingDataTree dataTree, + final DataTreeModification dataTreeModification) + throws DataValidationFailedException { + dataTreeModification.ready(); + dataTree.validate(dataTreeModification); + return dataTree.prepare(dataTreeModification); + } + + @Test + public void testUpdateWrite() throws Exception { + final TipProducingDataTree dataTree = getDataTree(); + final ContainerNode topContainer = getTopContainer("string1"); + addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID); + + final DataTreeModification dataTreeModification = getModification(dataTree); + final NormalizedNode topContainerAfter = getTopContainer("string2"); + dataTreeModification.write(TOP_CONTAINER_ID, topContainerAfter); + final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); + + final Map updates = getModificationDiff(prepare).getUpdates(); + + assertThat(updates.size(), is(1)); + assertThat(updates.values().size(), is(1)); + assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, topContainerAfter); + } + + private ModificationDiff getModificationDiff(final DataTreeCandidateTip prepare) { + return ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, prepare.getRootNode()); + } + + @Test + public void testUpdateMerge() throws Exception { + final TipProducingDataTree dataTree = getDataTree(); + final ContainerNode topContainer = getTopContainer("string1"); + addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID); + + final DataTreeModification dataTreeModification = getModification(dataTree); + final NormalizedNode topContainerAfter = getTopContainer("string2"); + dataTreeModification.merge(TOP_CONTAINER_ID, topContainerAfter); + final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); + + final Map updates = getModificationDiff(prepare).getUpdates(); + assertThat(updates.size(), is(1)); + assertThat(updates.values().size(), is(1)); + assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, topContainerAfter); + } + + @Test + public void testUpdateDelete() throws Exception { + final TipProducingDataTree dataTree = getDataTree(); + final ContainerNode topContainer = getTopContainer("string1"); + addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID); + + final DataTreeModification dataTreeModification = getModification(dataTree); + dataTreeModification.delete(TOP_CONTAINER_ID); + final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); + + final Map updates = getModificationDiff(prepare).getUpdates(); + assertThat(updates.size(), is(1)); + assertThat(updates.values().size(), is(1)); + assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, null); + } + + @Test + public void testWriteAndUpdateInnerList() throws Exception { + final TipProducingDataTree dataTree = getDataTree(); + + DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); + DataTreeModification dataTreeModification = dataTreeSnapshot.newModification(); + final YangInstanceIdentifier listId = + YangInstanceIdentifier.create( + new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME), + new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)); + + final MapNode mapNode = getNestedList("name1", "text"); + final YangInstanceIdentifier listEntryId = listId.node(mapNode.getValue().iterator().next().getIdentifier()); + dataTreeModification.write(listId, mapNode); + dataTreeModification.ready(); + dataTree.validate(dataTreeModification); + DataTreeCandidateTip prepare = dataTree.prepare(dataTreeModification); + + Map updates = getModificationDiff(prepare).getUpdates(); + + assertThat(updates.size(), is(1)); + assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class), + listEntryId, null, mapNode.getValue().iterator().next()); + + // Commit so that update can be tested next + dataTree.commit(prepare); + + YangInstanceIdentifier listItemId = listId.node( + new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME, NAME_LEAF_QNAME, "name1")); + MapEntryNode mapEntryNode = + getNestedList("name1", "text-update").getValue().iterator().next(); + + dataTreeSnapshot = dataTree.takeSnapshot(); + dataTreeModification = dataTreeSnapshot.newModification(); + dataTreeModification.write(listItemId, mapEntryNode); + dataTreeModification.ready(); + dataTree.validate(dataTreeModification); + prepare = dataTree.prepare(dataTreeModification); + + updates = getModificationDiff(prepare).getUpdates(); + assertThat(updates.size(), is(1 /*Actual list entry*/)); + } +// + private void assertUpdate(final ModificationDiff.NormalizedNodeUpdate update, + final YangInstanceIdentifier idExpected, + final NormalizedNode beforeExpected, + final NormalizedNode afterExpected) { + assertThat(update.getId(), is(idExpected)); + assertThat(update.getDataBefore(), is(beforeExpected)); + assertThat(update.getDataAfter(), is(afterExpected)); + } + + @Test + public void testWriteTopContainerAndInnerList() throws Exception { + final TipProducingDataTree dataTree = getDataTree(); + + DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); + DataTreeModification dataTreeModification = dataTreeSnapshot.newModification(); + + final ContainerNode topContainer = getTopContainer("string1"); + dataTreeModification.write(TOP_CONTAINER_ID, topContainer); + + final YangInstanceIdentifier listId = + YangInstanceIdentifier.create( + new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME), + new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)); + + final MapNode mapNode = getNestedList("name1", "text"); + final YangInstanceIdentifier listEntryId = listId.node(mapNode.getValue().iterator().next().getIdentifier()); + + dataTreeModification.write(listId, mapNode); + + final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); + + final Map updates = getModificationDiff(prepare).getUpdates(); + + assertThat(updates.size(), is(2)); + assertThat(updates.values().size(), is(2)); + assertUpdate(getNormalizedNodeUpdateForAfterType(updates, ContainerNode.class), TOP_CONTAINER_ID, null, + Builders.containerBuilder(topContainer).withChild(mapNode).build()); + assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class), listEntryId, null, mapNode.getValue().iterator().next()); + // Assert that keys of the updates map are not wildcarded YID + assertThat(updates.keySet(), hasItems( + TOP_CONTAINER_ID, + listEntryId)); + } + + private ModificationDiff.NormalizedNodeUpdate getNormalizedNodeUpdateForAfterType( + final Map updates, + final Class> containerNodeClass) { + return updates.values().stream() + .filter(update -> containerNodeClass.isAssignableFrom(update.getDataAfter().getClass())) + .findFirst().get(); + } + + private ModificationDiff.NormalizedNodeUpdate getNormalizedNodeUpdateForBeforeType( + final Map updates, + final Class> containerNodeClass) { + return updates.values().stream() + .filter(update -> containerNodeClass.isAssignableFrom(update.getDataBefore().getClass())) + .findFirst().get(); + } + + @Test + public void testWriteDeepList() throws Exception { + final TipProducingDataTree dataTree = getDataTree(); + + DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); + DataTreeModification dataTreeModification = dataTreeSnapshot.newModification(); + + YangInstanceIdentifier listId = + YangInstanceIdentifier.create( + new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME), + new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)); + + MapNode mapNode = getNestedList("name1", "text"); + dataTreeModification.write(listId, mapNode); + + dataTreeModification.ready(); + dataTree.validate(dataTreeModification); + DataTreeCandidateTip prepare = dataTree.prepare(dataTreeModification); + dataTree.commit(prepare); + + dataTreeSnapshot = dataTree.takeSnapshot(); + dataTreeModification = dataTreeSnapshot.newModification(); + + final YangInstanceIdentifier.NodeIdentifierWithPredicates nestedListNodeId = + new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME, NAME_LEAF_QNAME, "name1"); + listId = YangInstanceIdentifier.create( + new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME), + new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME), + nestedListNodeId); + final YangInstanceIdentifier deepListId = + listId.node(new YangInstanceIdentifier.NodeIdentifier(DEEP_LIST_QNAME)); + final YangInstanceIdentifier deepListEntryId = deepListId.node( + new YangInstanceIdentifier.NodeIdentifierWithPredicates(DEEP_LIST_QNAME, NAME_LEAF_QNAME, "name1")); + + final MapEntryNode deepListEntry = getDeepList("name1").getValue().iterator().next(); + // Merge parent list, just to see no modifications on it + dataTreeModification.merge( + listId, + Builders.mapEntryBuilder().withNodeIdentifier(nestedListNodeId) + .withChild(ImmutableNodes.leafNode(NAME_LEAF_QNAME, "name1")).build()); + dataTreeModification.merge( + deepListId, + Builders.mapBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DEEP_LIST_QNAME)) + .build()); + dataTreeModification.merge( + deepListEntryId, + deepListEntry); + + dataTreeModification.ready(); + dataTree.validate(dataTreeModification); + prepare = dataTree.prepare(dataTreeModification); + dataTree.commit(prepare); + + final Map updates = getModificationDiff(prepare).getUpdates(); + assertThat(updates.size(), is(1)); + assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class), deepListEntryId, null, deepListEntry); + } + + @Test + public void testDeleteInnerListItem() throws Exception { + final TipProducingDataTree dataTree = getDataTree(); + + DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); + DataTreeModification dataTreeModification = dataTreeSnapshot.newModification(); + final YangInstanceIdentifier listId = + YangInstanceIdentifier.create( + new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME), + new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)); + + final MapNode mapNode = getNestedList("name1", "text"); + dataTreeModification.write(listId, mapNode); + dataTreeModification.ready(); + dataTree.validate(dataTreeModification); + DataTreeCandidateTip prepare = dataTree.prepare(dataTreeModification); + + // Commit so that update can be tested next + dataTree.commit(prepare); + + YangInstanceIdentifier listItemId = listId.node( + new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME, NAME_LEAF_QNAME, "name1")); + + dataTreeSnapshot = dataTree.takeSnapshot(); + dataTreeModification = dataTreeSnapshot.newModification(); + dataTreeModification.delete(listItemId); + dataTreeModification.ready(); + dataTree.validate(dataTreeModification); + prepare = dataTree.prepare(dataTreeModification); + + final Map updates = getModificationDiff(prepare).getUpdates(); + assertThat(updates.size(), is(1)); + assertUpdate(getNormalizedNodeUpdateForBeforeType(updates, MapEntryNode.class), listItemId, mapNode.getValue().iterator().next(), null); + } + + static void addNodeToTree(final DataTree dataTree, final NormalizedNode node, + final YangInstanceIdentifier id) + throws DataValidationFailedException { + DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); + DataTreeModification dataTreeModification = dataTreeSnapshot.newModification(); + dataTreeModification.write(id, node); + dataTreeModification.ready(); + dataTree.validate(dataTreeModification); + DataTreeCandidate prepare = dataTree.prepare(dataTreeModification); + dataTree.commit(prepare); + } + + static TipProducingDataTree getDataTree() throws ReactorException { + final TipProducingDataTree dataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); + dataTree.setSchemaContext(getSchemaCtx()); + return dataTree; + } + + static ContainerNode getTopContainer(final String stringValue) { + return Builders.containerBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME)) + .withChild(ImmutableNodes.leafNode(STRING_LEAF_QNAME, stringValue)) + .build(); + } + + static MapNode getNestedList(final String listItemName, final String text) { + return Builders.mapBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)) + .withChild( + Builders.mapEntryBuilder() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME, + NAME_LEAF_QNAME, listItemName)) + .withChild(ImmutableNodes.leafNode(NAME_LEAF_QNAME, listItemName)) + .withChild(ImmutableNodes.leafNode(TEXT_LEAF_QNAME, text)) + .build() + ) + .build(); + } + + private MapNode getDeepList(final String listItemName) { + return Builders.mapBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DEEP_LIST_QNAME)) + .withChild( + Builders.mapEntryBuilder() + .withNodeIdentifier( + new YangInstanceIdentifier.NodeIdentifierWithPredicates(DEEP_LIST_QNAME, + NAME_LEAF_QNAME, listItemName)) + .withChild(ImmutableNodes.leafNode(NAME_LEAF_QNAME, listItemName)) + .build() + ) + .build(); + } + + private static SchemaContext getSchemaCtx() throws ReactorException { + final CrossSourceStatementReactor.BuildAction buildAction = YangInferencePipeline.RFC6020_REACTOR.newBuild(); + buildAction.addSource(new YangStatementSourceImpl(ModificationDiffTest.class.getResourceAsStream("/test-diff.yang"))); + return buildAction.buildEffective(); + } +} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/PersistingDataTreeAdapterTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/PersistingDataTreeAdapterTest.java new file mode 100644 index 000000000..305166421 --- /dev/null +++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/PersistingDataTreeAdapterTest.java @@ -0,0 +1,69 @@ +/* + * 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.data.impl; + +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.Before; +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.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; + +public class PersistingDataTreeAdapterTest { + + @Mock + private DataTree delegatingDataTree; + @Mock + private SchemaService schemaService; + @Mock + private DataTreeSnapshot snapshot; + + private Path tmpPersistFile; + + private PersistingDataTreeAdapter persistingDataTreeAdapter; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + tmpPersistFile = Files.createTempFile("testing-hc-persistence", "json"); + persistingDataTreeAdapter = new PersistingDataTreeAdapter(delegatingDataTree, schemaService, tmpPersistFile); + } + + @Test + public void testNoPersistOnFailure() throws Exception { + doThrow(new IllegalStateException("testing errors")).when(delegatingDataTree).commit(any(DataTreeCandidate.class)); + + try { + persistingDataTreeAdapter.commit(null); + fail("Exception expected"); + } catch (IllegalStateException e) { + verify(delegatingDataTree, times(0)).takeSnapshot(); + verify(delegatingDataTree).commit(any(DataTreeCandidate.class)); + } + } + +} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadOnlyTransactionTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadOnlyTransactionTest.java new file mode 100644 index 000000000..77470d17c --- /dev/null +++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadOnlyTransactionTest.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.data.impl; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.data.ReadableDataManager; +import io.fd.honeycomb.data.DataModification; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public class ReadOnlyTransactionTest { + + @Mock + private ReadableDataManager operationalData; + @Mock + private DataModification configSnapshot; + + private ReadOnlyTransaction readOnlyTx; + + @Before + public void setUp() { + initMocks(this); + readOnlyTx = ReadOnlyTransaction.create(configSnapshot, operationalData); + } + + @Test + public void testExists() { + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + final CheckedFuture>, ReadFailedException> + future = mock(CheckedFuture.class); + when(operationalData.read(path)).thenReturn(future); + + readOnlyTx.exists(LogicalDatastoreType.OPERATIONAL, path); + + verify(operationalData).read(path); + } + + @Test + public void testGetIdentifier() { + assertNotNull(readOnlyTx.getIdentifier()); + } +} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadWriteTransactionTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadWriteTransactionTest.java new file mode 100644 index 000000000..820d499be --- /dev/null +++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadWriteTransactionTest.java @@ -0,0 +1,111 @@ +/* + * 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.data.impl; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public class ReadWriteTransactionTest { + + @Mock + private DOMDataReadOnlyTransaction readTx; + + @Mock + private DOMDataWriteTransaction writeTx; + + private LogicalDatastoreType store; + + @Mock + private YangInstanceIdentifier path; + + @Mock + private NormalizedNode data; + + private ReadWriteTransaction readWriteTx; + + @Before + public void setUp() { + initMocks(this); + store = LogicalDatastoreType.CONFIGURATION; + readWriteTx = new ReadWriteTransaction(readTx, writeTx); + } + + @Test + public void testCancel() { + readWriteTx.cancel(); + verify(writeTx).cancel(); + } + + @Test + public void testPut() { + readWriteTx.put(store, path, data); + verify(writeTx).put(store, path, data); + } + + @Test + public void testMerge() { + readWriteTx.merge(store, path, data); + verify(writeTx).merge(store, path, data); + } + + @Test + public void testDelete() { + readWriteTx.delete(store, path); + verify(writeTx).delete(store, path); + } + + @Test + public void testSubmit() throws Exception { + readWriteTx.submit(); + verify(writeTx).submit(); + } + + + @SuppressWarnings("deprecation") + @Test + public void testCommit() throws Exception { + readWriteTx.commit(); + verify(writeTx).commit(); + } + + @Test + public void testRead() { + readWriteTx.read(store, path); + verify(readTx).read(store, path); + } + + @Test + public void testExists() { + readWriteTx.exists(store, path); + verify(readTx).exists(store, path); + } + + @Test + public void testGetIdentifier() throws Exception { + assertNotNull(readWriteTx.getIdentifier()); + } +} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadableDataTreeDelegatorTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadableDataTreeDelegatorTest.java new file mode 100644 index 000000000..2b4cc2a06 --- /dev/null +++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadableDataTreeDelegatorTest.java @@ -0,0 +1,192 @@ +/* + * 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.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.Matchers.same; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import com.google.common.collect.Iterables; +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import java.util.Collections; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +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.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +public class ReadableDataTreeDelegatorTest { + + @Mock + private BindingNormalizedNodeSerializer serializer; + @Mock + private ReaderRegistry reader; + + private ReadableDataTreeDelegator operationalData; + + @Mock + private InstanceIdentifier id; + @Mock + private Map.Entry> entry; + @Mock + private SchemaContext globalContext; + @Mock + private DataSchemaNode schemaNode; + @Mock + private ReadContext readCtx; + @Mock + private DOMDataBroker netconfMonitoringBroker; + @Mock + private DOMDataReadOnlyTransaction domDataReadOnlyTransaction; + @Mock + private DataBroker contextBroker; + + @Before + public void setUp() { + initMocks(this); + operationalData = new ReadableDataTreeDelegator(serializer, globalContext, reader, contextBroker); + doReturn(schemaNode).when(globalContext).getDataChildByName(any(QName.class)); + + doReturn(domDataReadOnlyTransaction).when(netconfMonitoringBroker).newReadOnlyTransaction(); + doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(domDataReadOnlyTransaction) + .read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class)); + + final org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction ctxTransaction = mock( + org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction.class); + doReturn(ctxTransaction).when(contextBroker).newReadWriteTransaction(); + doReturn(Futures.immediateCheckedFuture(null)).when(ctxTransaction).submit(); + } + + @Test + public void testReadNode() throws Exception { + final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); + final YangInstanceIdentifier.PathArgument pArg = mock(YangInstanceIdentifier.PathArgument.class); + doReturn(pArg).when(yangId).getLastPathArgument(); + doReturn(Collections.singletonList(pArg)).when(yangId).getPathArguments(); + + doReturn(QName.create("namespace", "2012-12-12", "local")).when(pArg).getNodeType(); + doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); + + final DataObject dataObject = mock(DataObject.class); + doReturn(Optional.of(dataObject)).when(reader).read(same(id), any(ReadContext.class)); + + when(serializer.toNormalizedNode(id, dataObject)).thenReturn(entry); + final DataContainerChild expectedValue = mock(DataContainerChild.class); + doReturn(expectedValue).when(entry).getValue(); + + final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); + + verify(serializer).fromYangInstanceIdentifier(yangId); + verify(reader).read(same(id), any(ReadContext.class)); + final Optional> result = future.get(); + assertTrue(result.isPresent()); + assertEquals(expectedValue, result.get()); + } + + @Test + public void testReadNonExistingNode() throws Exception { + final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); + doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); + doReturn(Optional.absent()).when(reader).read(same(id), any(ReadContext.class)); + + final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); + + verify(serializer).fromYangInstanceIdentifier(yangId); + verify(reader).read(same(id), any(ReadContext.class)); + final Optional> result = future.get(); + assertFalse(result.isPresent()); + } + + @Test + public void testReadFailed() throws Exception { + doThrow(io.fd.honeycomb.translate.read.ReadFailedException.class).when(reader).readAll(any(ReadContext.class)); + + final CheckedFuture>, ReadFailedException> future = + operationalData.read( YangInstanceIdentifier.EMPTY); + + try { + future.checkedGet(); + } catch (ReadFailedException e) { + assertTrue(e.getCause() instanceof io.fd.honeycomb.translate.read.ReadFailedException); + return; + } + fail("ReadFailedException was expected"); + } + + @Test + public void testReadRootWithOneNonListElement() throws Exception { + // Prepare data + final InstanceIdentifier vppStateII = InstanceIdentifier.create(DataObject.class); + final DataObject vppState = mock(DataObject.class); + Multimap, DataObject> dataObjects = LinkedListMultimap.create(); + dataObjects.put(vppStateII, vppState); + doReturn(dataObjects).when(reader).readAll(any(ReadContext.class)); + + // Init serializer + final YangInstanceIdentifier vppYangId = YangInstanceIdentifier.builder().node(QName.create("n", "d")).build(); + when(serializer.toYangInstanceIdentifier(vppStateII)).thenReturn(vppYangId); + when(serializer.toNormalizedNode(vppStateII, vppState)).thenReturn(entry); + final DataContainerChild vppStateContainer = mock(DataContainerChild.class); + doReturn(vppStateContainer).when(entry).getValue(); + doReturn(vppYangId.getLastPathArgument()).when(vppStateContainer).getIdentifier(); + + // Read root + final CheckedFuture>, ReadFailedException> future = + operationalData.read(YangInstanceIdentifier.EMPTY); + + verify(reader).readAll(any(ReadContext.class)); + verify(serializer).toYangInstanceIdentifier(vppStateII); + verify(serializer).toNormalizedNode(vppStateII, vppState); + + // Check the result is an ContainerNode with only one child + final Optional> result = future.get(); + assertTrue(result.isPresent()); + + final ContainerNode rootNode = (ContainerNode) result.get(); + assertEquals(SchemaContext.NAME, rootNode.getIdentifier().getNodeType()); + assertEquals(vppStateContainer, Iterables.getOnlyElement(rootNode.getValue())); + } +} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/WriteTransactionTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/WriteTransactionTest.java new file mode 100644 index 000000000..1dab5524d --- /dev/null +++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/WriteTransactionTest.java @@ -0,0 +1,128 @@ +/* + * 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.data.impl; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.data.DataModification; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +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.DataValidationFailedException; + +public class WriteTransactionTest { + + @Mock + private DataModification configSnapshot; + @Mock + private YangInstanceIdentifier path; + @Mock + private NormalizedNode data; + + private WriteTransaction writeTx; + + @Before + public void setUp() { + initMocks(this); + writeTx = WriteTransaction.createConfigOnly(configSnapshot); + } + + @Test + public void testPut() { + writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); + verify(configSnapshot).write(path, data); + } + + @Test(expected = IllegalArgumentException.class) + public void testPutOperational() { + writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data); + verify(configSnapshot).write(path, data); + } + + @Test(expected = IllegalStateException.class) + public void testOnFinishedTx() { + writeTx.submit(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); + verify(configSnapshot).write(path, data); + } + + @Test + public void testMerge() { + writeTx.merge(LogicalDatastoreType.CONFIGURATION, path, data); + verify(configSnapshot).merge(path, data); + } + + @Test + public void testCancel() { + assertTrue(writeTx.cancel()); + } + + @Test + public void testCancelFinished() { + writeTx.submit(); + assertFalse(writeTx.cancel()); + } + + @Test + public void testDelete() { + writeTx.delete(LogicalDatastoreType.CONFIGURATION, path); + verify(configSnapshot).delete(path); + } + + @Test + public void testSubmit() throws Exception { + writeTx.submit(); + verify(configSnapshot).validate(); + verify(configSnapshot).commit(); + } + + @Test + public void testSubmitFailed() throws Exception { + doThrow(mock(DataValidationFailedException.class)).when(configSnapshot).commit(); + final CheckedFuture future = writeTx.submit(); + try { + future.get(); + } catch (Exception e) { + assertTrue(e.getCause() instanceof TransactionCommitFailedException); + return; + } + fail("Expected exception to be thrown"); + + } + + @Test(expected = UnsupportedOperationException.class) + public void testCommit() { + writeTx.commit(); + } + + @Test + public void testGetIdentifier() { + assertNotNull(writeTx.getIdentifier()); + } +} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java deleted file mode 100644 index 55b92b50b..000000000 --- a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.data.impl; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import io.fd.honeycomb.v3po.data.ReadableDataManager; -import io.fd.honeycomb.v3po.data.ModifiableDataManager; -import io.fd.honeycomb.v3po.data.DataModification; -import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; -import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; - -public class DataBrokerTest { - - @Mock - private ReadableDataManager operationalData; - @Mock - private ModifiableDataManager confiDataTree; - @Mock - private DataModification configSnapshot; - private DataBroker broker; - - @Before - public void setUp() { - initMocks(this); - when(confiDataTree.newModification()).thenReturn(configSnapshot); - broker = DataBroker.create(confiDataTree, operationalData); - } - - @Test - public void testNewReadWriteTransaction() { - final DOMDataReadWriteTransaction readWriteTx = broker.newReadWriteTransaction(); - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - readWriteTx.read(LogicalDatastoreType.CONFIGURATION, path); - - // verify that read and write transactions use the same config snapshot - verify(configSnapshot).read(path); - verify(confiDataTree).newModification(); - } - - @Test - public void testNewWriteOnlyTransaction() { - final DOMDataWriteTransaction writeTx = broker.newWriteOnlyTransaction(); - - // verify that write transactions use config snapshot - verify(confiDataTree).newModification(); - } - - @Test - public void testNewReadOnlyTransaction() { - final DOMDataReadOnlyTransaction readTx = broker.newReadOnlyTransaction(); - - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - readTx.read(LogicalDatastoreType.CONFIGURATION, path); - - // verify that read transactions use config snapshot - verify(configSnapshot).read(path); - } - - @Test(expected = UnsupportedOperationException.class) - public void testRegisterDataChangeListener() { - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - final DOMDataChangeListener listener = mock(DOMDataChangeListener.class); - broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, path, listener, - AsyncDataBroker.DataChangeScope.BASE); - } - - @Test(expected = UnsupportedOperationException.class) - public void testCreateTransactionChain() { - final TransactionChainListener listener = mock(TransactionChainListener.class); - broker.createTransactionChain(listener); - } - - @Test - public void testGetSupportedExtensions() { - final Map, DOMDataBrokerExtension> supportedExtensions = - broker.getSupportedExtensions(); - assertTrue(supportedExtensions.isEmpty()); - } - - -} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java deleted file mode 100644 index 915d738e9..000000000 --- a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * 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.data.impl; - -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.hasItems; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; -import io.fd.honeycomb.v3po.data.DataModification; -import io.fd.honeycomb.v3po.translate.TranslationException; -import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry; -import java.util.AbstractMap; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -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.MapNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; - -public class ModifiableDataTreeDelegatorTest { - - @Mock - private WriterRegistry writer; - @Mock - private BindingNormalizedNodeSerializer serializer; - private DataTree dataTree; - @Mock - private org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification modification; - @Mock - private DataBroker contextBroker; - @Mock - private org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction tx; - - private ModifiableDataTreeManager configDataTree; - - static final InstanceIdentifier DEFAULT_ID = InstanceIdentifier.create(DataObject.class); - static DataObject DEFAULT_DATA_OBJECT = mockDataObject("serialized", DataObject.class); - - @Before - public void setUp() throws Exception { - initMocks(this); - dataTree = ModificationDiffTest.getDataTree(); - when(contextBroker.newReadWriteTransaction()).thenReturn(tx); - when(tx.submit()).thenReturn(Futures.immediateCheckedFuture(null)); - - when(serializer.fromYangInstanceIdentifier(any(YangInstanceIdentifier.class))).thenReturn(((InstanceIdentifier) DEFAULT_ID)); - final Map.Entry, DataObject> parsed = new AbstractMap.SimpleEntry<>(DEFAULT_ID, DEFAULT_DATA_OBJECT); - when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), any(NormalizedNode.class))).thenReturn(parsed); - - configDataTree = new ModifiableDataTreeDelegator(serializer, dataTree, writer, contextBroker); - } - - @Test - public void testRead() throws Exception { - final ContainerNode topContainer = ModificationDiffTest.getTopContainer("topContainer"); - ModificationDiffTest.addNodeToTree(dataTree, topContainer, ModificationDiffTest.TOP_CONTAINER_ID); - final CheckedFuture>, ReadFailedException> read = - configDataTree.read(ModificationDiffTest.TOP_CONTAINER_ID); - final CheckedFuture>, ReadFailedException> read2 = - configDataTree.newModification().read(ModificationDiffTest.TOP_CONTAINER_ID); - final Optional> normalizedNodeOptional = read.get(); - final Optional> normalizedNodeOptional2 = read2.get(); - - assertEquals(normalizedNodeOptional, normalizedNodeOptional2); - assertTrue(normalizedNodeOptional.isPresent()); - assertEquals(topContainer, normalizedNodeOptional.get()); - assertEquals(dataTree.takeSnapshot().readNode(ModificationDiffTest.TOP_CONTAINER_ID), normalizedNodeOptional); - } - - @Test - public void testCommitSuccessful() throws Exception { - final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue"); - - final DataModification dataModification = configDataTree.newModification(); - dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList); - dataModification.validate(); - dataModification.commit(); - - final Multimap, DataObjectUpdate> map = HashMultimap.create(); - map.put(DEFAULT_ID, DataObjectUpdate.create(DEFAULT_ID, DEFAULT_DATA_OBJECT, DEFAULT_DATA_OBJECT)); - verify(writer).update(eq(new WriterRegistry.DataObjectUpdates(map, ImmutableMultimap.of())), any(WriteContext.class)); - assertEquals(nestedList, dataTree.takeSnapshot().readNode(ModificationDiffTest.NESTED_LIST_ID).get()); - } - - private static DataObject mockDataObject(final String name, final Class classToMock) { - final DataObject dataBefore = mock(classToMock, name); - doReturn(classToMock).when(dataBefore).getImplementedInterface(); - return dataBefore; - } - - @Test - public void testCommitUndoSuccessful() throws Exception { - final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue"); - - // Fail on update: - final WriterRegistry.Reverter reverter = mock(WriterRegistry.Reverter.class); - final TranslationException failedOnUpdateException = new TranslationException("update failed"); - doThrow(new WriterRegistry.BulkUpdateException(Collections.singleton(DEFAULT_ID), reverter, failedOnUpdateException)) - .when(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class)); - - try { - // Run the test - final DataModification dataModification = configDataTree.newModification(); - dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList); - dataModification.validate(); - dataModification.commit(); - fail("WriterRegistry.BulkUpdateException was expected"); - } catch (WriterRegistry.BulkUpdateException e) { - verify(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class)); - assertThat(e.getFailedIds(), hasItem(DEFAULT_ID)); - verify(reverter).revert(); - assertEquals(failedOnUpdateException, e.getCause()); - } - } - - @Test - public void testCommitUndoFailed() throws Exception { - final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue"); - - // Fail on update: - final WriterRegistry.Reverter reverter = mock(WriterRegistry.Reverter.class); - final TranslationException failedOnUpdateException = new TranslationException("update failed"); - doThrow(new WriterRegistry.BulkUpdateException(Collections.singleton(DEFAULT_ID), reverter, failedOnUpdateException)) - .when(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class)); - - // Fail on revert: - final TranslationException failedOnRevertException = new TranslationException("revert failed"); - doThrow(new WriterRegistry.Reverter.RevertFailedException(Collections.emptySet(), failedOnRevertException)) - .when(reverter).revert(); - - try { - // Run the test - final DataModification dataModification = configDataTree.newModification(); - dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList); - dataModification.validate(); - dataModification.commit(); - fail("WriterRegistry.Reverter.RevertFailedException was expected"); - } catch (WriterRegistry.Reverter.RevertFailedException e) { - verify(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class)); - verify(reverter).revert(); - assertEquals(failedOnRevertException, e.getCause()); - } - } - - private abstract static class DataObject1 implements DataObject {} - private abstract static class DataObject2 implements DataObject {} - private abstract static class DataObject3 implements DataObject {} - - @Test - public void testToBindingAware() throws Exception { - when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), eq(null))).thenReturn(null); - - final Map biNodes = new HashMap<>(); - // delete - final QName nn1 = QName.create("namespace", "nn1"); - final YangInstanceIdentifier yid1 = mockYid(nn1); - final InstanceIdentifier iid1 = mockIid(yid1, DataObject1.class); - final NormalizedNode nn1B = mockNormalizedNode(nn1); - final DataObject1 do1B = mockDataObject(yid1, iid1, nn1B, DataObject1.class); - biNodes.put(yid1, ModificationDiff.NormalizedNodeUpdate.create(yid1, nn1B, null)); - - // create - final QName nn2 = QName.create("namespace", "nn1"); - final YangInstanceIdentifier yid2 = mockYid(nn2); - final InstanceIdentifier iid2 = mockIid(yid2, DataObject2.class);; - final NormalizedNode nn2A = mockNormalizedNode(nn2); - final DataObject2 do2A = mockDataObject(yid2, iid2, nn2A, DataObject2.class); - biNodes.put(yid2, ModificationDiff.NormalizedNodeUpdate.create(yid2, null, nn2A)); - - // update - final QName nn3 = QName.create("namespace", "nn1"); - final YangInstanceIdentifier yid3 = mockYid(nn3); - final InstanceIdentifier iid3 = mockIid(yid3, DataObject3.class); - final NormalizedNode nn3B = mockNormalizedNode(nn3); - final DataObject3 do3B = mockDataObject(yid3, iid3, nn3B, DataObject3.class); - final NormalizedNode nn3A = mockNormalizedNode(nn3); - final DataObject3 do3A = mockDataObject(yid3, iid3, nn3A, DataObject3.class);; - biNodes.put(yid3, ModificationDiff.NormalizedNodeUpdate.create(yid3, nn3B, nn3A)); - - final WriterRegistry.DataObjectUpdates dataObjectUpdates = - ModifiableDataTreeDelegator.toBindingAware(biNodes, serializer); - - assertThat(dataObjectUpdates.getDeletes().size(), is(1)); - assertThat(dataObjectUpdates.getDeletes().keySet(), hasItem(((InstanceIdentifier) iid1))); - assertThat(dataObjectUpdates.getDeletes().values(), hasItem( - ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid1, do1B, null)))); - - assertThat(dataObjectUpdates.getUpdates().size(), is(2)); - assertThat(dataObjectUpdates.getUpdates().keySet(), hasItems((InstanceIdentifier) iid2, (InstanceIdentifier) iid3)); - assertThat(dataObjectUpdates.getUpdates().values(), hasItems( - DataObjectUpdate.create(iid2, null, do2A), - DataObjectUpdate.create(iid3, do3B, do3A))); - - assertThat(dataObjectUpdates.getTypeIntersection().size(), is(3)); - } - - private D mockDataObject(final YangInstanceIdentifier yid1, - final InstanceIdentifier iid1, - final NormalizedNode nn1B, - final Class type) { - final D do1B = mock(type); - when(serializer.fromNormalizedNode(yid1, nn1B)).thenReturn(new AbstractMap.SimpleEntry<>(iid1, do1B)); - return do1B; - } - - private NormalizedNode mockNormalizedNode(final QName nn1) { - final NormalizedNode nn1B = mock(NormalizedNode.class); - when(nn1B.getNodeType()).thenReturn(nn1); - return nn1B; - } - - private InstanceIdentifier mockIid(final YangInstanceIdentifier yid1, - final Class type) { - final InstanceIdentifier iid1 = InstanceIdentifier.create(type); - when(serializer.fromYangInstanceIdentifier(yid1)).thenReturn(iid1); - return iid1; - } - - private YangInstanceIdentifier mockYid(final QName nn1) { - final YangInstanceIdentifier yid1 = mock(YangInstanceIdentifier.class); - when(yid1.getLastPathArgument()).thenReturn(new YangInstanceIdentifier.NodeIdentifier(nn1)); - return yid1; - } -} diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java deleted file mode 100644 index bc7582e93..000000000 --- a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java +++ /dev/null @@ -1,427 +0,0 @@ -package io.fd.honeycomb.v3po.data.impl; - -import static org.hamcrest.CoreMatchers.hasItems; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - -import java.util.Map; -import org.junit.Test; -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.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; -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.DataTreeCandidateTip; -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.api.schema.tree.TipProducingDataTree; -import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; -import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; -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; - -public class ModificationDiffTest { - - static final QName TOP_CONTAINER_QNAME = - QName.create("urn:opendaylight:params:xml:ns:yang:test:diff", "2015-01-05", "top-container"); - static final QName STRING_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "string"); - static final QName NAME_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "name"); - static final QName TEXT_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "text"); - static final QName NESTED_LIST_QNAME = QName.create(TOP_CONTAINER_QNAME, "nested-list"); - static final QName DEEP_LIST_QNAME = QName.create(TOP_CONTAINER_QNAME, "deep-list"); - - static final QName WITH_CHOICE_CONTAINER_QNAME = - QName.create("urn:opendaylight:params:xml:ns:yang:test:diff", "2015-01-05", "with-choice"); - static final QName CHOICE_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "choice"); - static final QName IN_CASE1_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case1"); - static final QName IN_CASE2_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case2"); - - static final YangInstanceIdentifier TOP_CONTAINER_ID = YangInstanceIdentifier.of(TOP_CONTAINER_QNAME); - static final YangInstanceIdentifier NESTED_LIST_ID = TOP_CONTAINER_ID.node(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)); - - - @Test - public void testInitialWrite() throws Exception { - final TipProducingDataTree dataTree = getDataTree(); - final DataTreeModification dataTreeModification = getModification(dataTree); - final NormalizedNode topContainer = getTopContainer("string1"); - final YangInstanceIdentifier TOP_CONTAINER_ID = YangInstanceIdentifier.of(TOP_CONTAINER_QNAME); - dataTreeModification.write(TOP_CONTAINER_ID, topContainer); - final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); - - final ModificationDiff modificationDiff = getModificationDiff(prepare); - - assertThat(modificationDiff.getUpdates().size(), is(1)); - assertThat(modificationDiff.getUpdates().values().size(), is(1)); - assertUpdate(modificationDiff.getUpdates().values().iterator().next(), TOP_CONTAINER_ID, null, topContainer); - } - - @Test - public void testInitialWriteForContainerWithChoice() throws Exception { - final TipProducingDataTree dataTree = getDataTree(); - final DataTreeModification dataTreeModification = getModification(dataTree); - final ContainerNode containerWithChoice = Builders.containerBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(WITH_CHOICE_CONTAINER_QNAME)) - .withChild(Builders.choiceBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CHOICE_QNAME)) - .withChild(ImmutableNodes.leafNode(IN_CASE1_LEAF_QNAME, "withinCase1")) - .build()) - .build(); - final YangInstanceIdentifier WITH_CHOICE_CONTAINER_ID = YangInstanceIdentifier.of(WITH_CHOICE_CONTAINER_QNAME); - dataTreeModification.write(WITH_CHOICE_CONTAINER_ID, containerWithChoice); - final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); - - final Map updates = getModificationDiff(prepare).getUpdates(); - - assertThat(updates.size(), is(1)); - assertUpdate(getNormalizedNodeUpdateForAfterType(updates, ContainerNode.class), - WITH_CHOICE_CONTAINER_ID, null, containerWithChoice); - } - - private DataTreeModification getModification(final TipProducingDataTree dataTree) { - final DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); - return dataTreeSnapshot.newModification(); - } - - @Test - public void testWriteNonPresenceEmptyContainer() throws Exception { - final TipProducingDataTree dataTree = getDataTree(); - final DataTreeModification dataTreeModification = getModification(dataTree); - final NormalizedNode topContainer = ImmutableNodes.containerNode(TOP_CONTAINER_QNAME); - dataTreeModification.write(TOP_CONTAINER_ID, topContainer); - final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); - - final ModificationDiff modificationDiff = getModificationDiff(prepare); - - assertThat(modificationDiff.getUpdates().size(), is(0)); - } - - private DataTreeCandidateTip prepareModification(final TipProducingDataTree dataTree, - final DataTreeModification dataTreeModification) - throws DataValidationFailedException { - dataTreeModification.ready(); - dataTree.validate(dataTreeModification); - return dataTree.prepare(dataTreeModification); - } - - @Test - public void testUpdateWrite() throws Exception { - final TipProducingDataTree dataTree = getDataTree(); - final ContainerNode topContainer = getTopContainer("string1"); - addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID); - - final DataTreeModification dataTreeModification = getModification(dataTree); - final NormalizedNode topContainerAfter = getTopContainer("string2"); - dataTreeModification.write(TOP_CONTAINER_ID, topContainerAfter); - final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); - - final Map updates = getModificationDiff(prepare).getUpdates(); - - assertThat(updates.size(), is(1)); - assertThat(updates.values().size(), is(1)); - assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, topContainerAfter); - } - - private ModificationDiff getModificationDiff(final DataTreeCandidateTip prepare) { - return ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, prepare.getRootNode()); - } - - @Test - public void testUpdateMerge() throws Exception { - final TipProducingDataTree dataTree = getDataTree(); - final ContainerNode topContainer = getTopContainer("string1"); - addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID); - - final DataTreeModification dataTreeModification = getModification(dataTree); - final NormalizedNode topContainerAfter = getTopContainer("string2"); - dataTreeModification.merge(TOP_CONTAINER_ID, topContainerAfter); - final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); - - final Map updates = getModificationDiff(prepare).getUpdates(); - assertThat(updates.size(), is(1)); - assertThat(updates.values().size(), is(1)); - assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, topContainerAfter); - } - - @Test - public void testUpdateDelete() throws Exception { - final TipProducingDataTree dataTree = getDataTree(); - final ContainerNode topContainer = getTopContainer("string1"); - addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID); - - final DataTreeModification dataTreeModification = getModification(dataTree); - dataTreeModification.delete(TOP_CONTAINER_ID); - final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); - - final Map updates = getModificationDiff(prepare).getUpdates(); - assertThat(updates.size(), is(1)); - assertThat(updates.values().size(), is(1)); - assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, null); - } - - @Test - public void testWriteAndUpdateInnerList() throws Exception { - final TipProducingDataTree dataTree = getDataTree(); - - DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); - DataTreeModification dataTreeModification = dataTreeSnapshot.newModification(); - final YangInstanceIdentifier listId = - YangInstanceIdentifier.create( - new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME), - new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)); - - final MapNode mapNode = getNestedList("name1", "text"); - final YangInstanceIdentifier listEntryId = listId.node(mapNode.getValue().iterator().next().getIdentifier()); - dataTreeModification.write(listId, mapNode); - dataTreeModification.ready(); - dataTree.validate(dataTreeModification); - DataTreeCandidateTip prepare = dataTree.prepare(dataTreeModification); - - Map updates = getModificationDiff(prepare).getUpdates(); - - assertThat(updates.size(), is(1)); - assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class), - listEntryId, null, mapNode.getValue().iterator().next()); - - // Commit so that update can be tested next - dataTree.commit(prepare); - - YangInstanceIdentifier listItemId = listId.node( - new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME, NAME_LEAF_QNAME, "name1")); - MapEntryNode mapEntryNode = - getNestedList("name1", "text-update").getValue().iterator().next(); - - dataTreeSnapshot = dataTree.takeSnapshot(); - dataTreeModification = dataTreeSnapshot.newModification(); - dataTreeModification.write(listItemId, mapEntryNode); - dataTreeModification.ready(); - dataTree.validate(dataTreeModification); - prepare = dataTree.prepare(dataTreeModification); - - updates = getModificationDiff(prepare).getUpdates(); - assertThat(updates.size(), is(1 /*Actual list entry*/)); - } -// - private void assertUpdate(final ModificationDiff.NormalizedNodeUpdate update, - final YangInstanceIdentifier idExpected, - final NormalizedNode beforeExpected, - final NormalizedNode afterExpected) { - assertThat(update.getId(), is(idExpected)); - assertThat(update.getDataBefore(), is(beforeExpected)); - assertThat(update.getDataAfter(), is(afterExpected)); - } - - @Test - public void testWriteTopContainerAndInnerList() throws Exception { - final TipProducingDataTree dataTree = getDataTree(); - - DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); - DataTreeModification dataTreeModification = dataTreeSnapshot.newModification(); - - final ContainerNode topContainer = getTopContainer("string1"); - dataTreeModification.write(TOP_CONTAINER_ID, topContainer); - - final YangInstanceIdentifier listId = - YangInstanceIdentifier.create( - new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME), - new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)); - - final MapNode mapNode = getNestedList("name1", "text"); - final YangInstanceIdentifier listEntryId = listId.node(mapNode.getValue().iterator().next().getIdentifier()); - - dataTreeModification.write(listId, mapNode); - - final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification); - - final Map updates = getModificationDiff(prepare).getUpdates(); - - assertThat(updates.size(), is(2)); - assertThat(updates.values().size(), is(2)); - assertUpdate(getNormalizedNodeUpdateForAfterType(updates, ContainerNode.class), TOP_CONTAINER_ID, null, - Builders.containerBuilder(topContainer).withChild(mapNode).build()); - assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class), listEntryId, null, mapNode.getValue().iterator().next()); - // Assert that keys of the updates map are not wildcarded YID - assertThat(updates.keySet(), hasItems( - TOP_CONTAINER_ID, - listEntryId)); - } - - private ModificationDiff.NormalizedNodeUpdate getNormalizedNodeUpdateForAfterType( - final Map updates, - final Class> containerNodeClass) { - return updates.values().stream() - .filter(update -> containerNodeClass.isAssignableFrom(update.getDataAfter().getClass())) - .findFirst().get(); - } - - private ModificationDiff.NormalizedNodeUpdate getNormalizedNodeUpdateForBeforeType( - final Map updates, - final Class> containerNodeClass) { - return updates.values().stream() - .filter(update -> containerNodeClass.isAssignableFrom(update.getDataBefore().getClass())) - .findFirst().get(); - } - - @Test - public void testWriteDeepList() throws Exception { - final TipProducingDataTree dataTree = getDataTree(); - - DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); - DataTreeModification dataTreeModification = dataTreeSnapshot.newModification(); - - YangInstanceIdentifier listId = - YangInstanceIdentifier.create( - new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME), - new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)); - - MapNode mapNode = getNestedList("name1", "text"); - dataTreeModification.write(listId, mapNode); - - dataTreeModification.ready(); - dataTree.validate(dataTreeModification); - DataTreeCandidateTip prepare = dataTree.prepare(dataTreeModification); - dataTree.commit(prepare); - - dataTreeSnapshot = dataTree.takeSnapshot(); - dataTreeModification = dataTreeSnapshot.newModification(); - - final YangInstanceIdentifier.NodeIdentifierWithPredicates nestedListNodeId = - new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME, NAME_LEAF_QNAME, "name1"); - listId = YangInstanceIdentifier.create( - new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME), - new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME), - nestedListNodeId); - final YangInstanceIdentifier deepListId = - listId.node(new YangInstanceIdentifier.NodeIdentifier(DEEP_LIST_QNAME)); - final YangInstanceIdentifier deepListEntryId = deepListId.node( - new YangInstanceIdentifier.NodeIdentifierWithPredicates(DEEP_LIST_QNAME, NAME_LEAF_QNAME, "name1")); - - final MapEntryNode deepListEntry = getDeepList("name1").getValue().iterator().next(); - // Merge parent list, just to see no modifications on it - dataTreeModification.merge( - listId, - Builders.mapEntryBuilder().withNodeIdentifier(nestedListNodeId) - .withChild(ImmutableNodes.leafNode(NAME_LEAF_QNAME, "name1")).build()); - dataTreeModification.merge( - deepListId, - Builders.mapBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DEEP_LIST_QNAME)) - .build()); - dataTreeModification.merge( - deepListEntryId, - deepListEntry); - - dataTreeModification.ready(); - dataTree.validate(dataTreeModification); - prepare = dataTree.prepare(dataTreeModification); - dataTree.commit(prepare); - - final Map updates = getModificationDiff(prepare).getUpdates(); - assertThat(updates.size(), is(1)); - assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class), deepListEntryId, null, deepListEntry); - } - - @Test - public void testDeleteInnerListItem() throws Exception { - final TipProducingDataTree dataTree = getDataTree(); - - DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); - DataTreeModification dataTreeModification = dataTreeSnapshot.newModification(); - final YangInstanceIdentifier listId = - YangInstanceIdentifier.create( - new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME), - new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)); - - final MapNode mapNode = getNestedList("name1", "text"); - dataTreeModification.write(listId, mapNode); - dataTreeModification.ready(); - dataTree.validate(dataTreeModification); - DataTreeCandidateTip prepare = dataTree.prepare(dataTreeModification); - - // Commit so that update can be tested next - dataTree.commit(prepare); - - YangInstanceIdentifier listItemId = listId.node( - new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME, NAME_LEAF_QNAME, "name1")); - - dataTreeSnapshot = dataTree.takeSnapshot(); - dataTreeModification = dataTreeSnapshot.newModification(); - dataTreeModification.delete(listItemId); - dataTreeModification.ready(); - dataTree.validate(dataTreeModification); - prepare = dataTree.prepare(dataTreeModification); - - final Map updates = getModificationDiff(prepare).getUpdates(); - assertThat(updates.size(), is(1)); - assertUpdate(getNormalizedNodeUpdateForBeforeType(updates, MapEntryNode.class), listItemId, mapNode.getValue().iterator().next(), null); - } - - static void addNodeToTree(final DataTree dataTree, final NormalizedNode node, - final YangInstanceIdentifier id) - throws DataValidationFailedException { - DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot(); - DataTreeModification dataTreeModification = dataTreeSnapshot.newModification(); - dataTreeModification.write(id, node); - dataTreeModification.ready(); - dataTree.validate(dataTreeModification); - DataTreeCandidate prepare = dataTree.prepare(dataTreeModification); - dataTree.commit(prepare); - } - - static TipProducingDataTree getDataTree() throws ReactorException { - final TipProducingDataTree dataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); - dataTree.setSchemaContext(getSchemaCtx()); - return dataTree; - } - - static ContainerNode getTopContainer(final String stringValue) { - return Builders.containerBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME)) - .withChild(ImmutableNodes.leafNode(STRING_LEAF_QNAME, stringValue)) - .build(); - } - - static MapNode getNestedList(final String listItemName, final String text) { - return Builders.mapBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME)) - .withChild( - Builders.mapEntryBuilder() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME, - NAME_LEAF_QNAME, listItemName)) - .withChild(ImmutableNodes.leafNode(NAME_LEAF_QNAME, listItemName)) - .withChild(ImmutableNodes.leafNode(TEXT_LEAF_QNAME, text)) - .build() - ) - .build(); - } - - private MapNode getDeepList(final String listItemName) { - return Builders.mapBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DEEP_LIST_QNAME)) - .withChild( - Builders.mapEntryBuilder() - .withNodeIdentifier( - new YangInstanceIdentifier.NodeIdentifierWithPredicates(DEEP_LIST_QNAME, - NAME_LEAF_QNAME, listItemName)) - .withChild(ImmutableNodes.leafNode(NAME_LEAF_QNAME, listItemName)) - .build() - ) - .build(); - } - - private static SchemaContext getSchemaCtx() throws ReactorException { - final CrossSourceStatementReactor.BuildAction buildAction = YangInferencePipeline.RFC6020_REACTOR.newBuild(); - buildAction.addSource(new YangStatementSourceImpl(ModificationDiffTest.class.getResourceAsStream("/test-diff.yang"))); - return buildAction.buildEffective(); - } -} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java deleted file mode 100644 index 523d9dd70..000000000 --- a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.data.impl; - -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.nio.file.Files; -import java.nio.file.Path; -import org.junit.Before; -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.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; - -public class PersistingDataTreeAdapterTest { - - @Mock - private DataTree delegatingDataTree; - @Mock - private SchemaService schemaService; - @Mock - private DataTreeSnapshot snapshot; - - private Path tmpPersistFile; - - private PersistingDataTreeAdapter persistingDataTreeAdapter; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - tmpPersistFile = Files.createTempFile("testing-hc-persistence", "json"); - persistingDataTreeAdapter = new PersistingDataTreeAdapter(delegatingDataTree, schemaService, tmpPersistFile); - } - - @Test - public void testNoPersistOnFailure() throws Exception { - doThrow(new IllegalStateException("testing errors")).when(delegatingDataTree).commit(any(DataTreeCandidate.class)); - - try { - persistingDataTreeAdapter.commit(null); - fail("Exception expected"); - } catch (IllegalStateException e) { - verify(delegatingDataTree, times(0)).takeSnapshot(); - verify(delegatingDataTree).commit(any(DataTreeCandidate.class)); - } - } - -} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java deleted file mode 100644 index a13621725..000000000 --- a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.data.impl; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.data.ReadableDataManager; -import io.fd.honeycomb.v3po.data.DataModification; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -public class ReadOnlyTransactionTest { - - @Mock - private ReadableDataManager operationalData; - @Mock - private DataModification configSnapshot; - - private ReadOnlyTransaction readOnlyTx; - - @Before - public void setUp() { - initMocks(this); - readOnlyTx = ReadOnlyTransaction.create(configSnapshot, operationalData); - } - - @Test - public void testExists() { - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - final CheckedFuture>, ReadFailedException> - future = mock(CheckedFuture.class); - when(operationalData.read(path)).thenReturn(future); - - readOnlyTx.exists(LogicalDatastoreType.OPERATIONAL, path); - - verify(operationalData).read(path); - } - - @Test - public void testGetIdentifier() { - assertNotNull(readOnlyTx.getIdentifier()); - } -} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java deleted file mode 100644 index 1b67cd967..000000000 --- a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.data.impl; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -public class ReadWriteTransactionTest { - - @Mock - private DOMDataReadOnlyTransaction readTx; - - @Mock - private DOMDataWriteTransaction writeTx; - - private LogicalDatastoreType store; - - @Mock - private YangInstanceIdentifier path; - - @Mock - private NormalizedNode data; - - private ReadWriteTransaction readWriteTx; - - @Before - public void setUp() { - initMocks(this); - store = LogicalDatastoreType.CONFIGURATION; - readWriteTx = new ReadWriteTransaction(readTx, writeTx); - } - - @Test - public void testCancel() { - readWriteTx.cancel(); - verify(writeTx).cancel(); - } - - @Test - public void testPut() { - readWriteTx.put(store, path, data); - verify(writeTx).put(store, path, data); - } - - @Test - public void testMerge() { - readWriteTx.merge(store, path, data); - verify(writeTx).merge(store, path, data); - } - - @Test - public void testDelete() { - readWriteTx.delete(store, path); - verify(writeTx).delete(store, path); - } - - @Test - public void testSubmit() throws Exception { - readWriteTx.submit(); - verify(writeTx).submit(); - } - - - @SuppressWarnings("deprecation") - @Test - public void testCommit() throws Exception { - readWriteTx.commit(); - verify(writeTx).commit(); - } - - @Test - public void testRead() { - readWriteTx.read(store, path); - verify(readTx).read(store, path); - } - - @Test - public void testExists() { - readWriteTx.exists(store, path); - verify(readTx).exists(store, path); - } - - @Test - public void testGetIdentifier() throws Exception { - assertNotNull(readWriteTx.getIdentifier()); - } -} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java deleted file mode 100644 index 455050ab0..000000000 --- a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * 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.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.Matchers.same; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import com.google.common.collect.Iterables; -import com.google.common.collect.LinkedListMultimap; -import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry; -import java.util.Collections; -import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -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.DataContainerChild; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; - -public class ReadableDataTreeDelegatorTest { - - @Mock - private BindingNormalizedNodeSerializer serializer; - @Mock - private ReaderRegistry reader; - - private ReadableDataTreeDelegator operationalData; - - @Mock - private InstanceIdentifier id; - @Mock - private Map.Entry> entry; - @Mock - private SchemaContext globalContext; - @Mock - private DataSchemaNode schemaNode; - @Mock - private ReadContext readCtx; - @Mock - private DOMDataBroker netconfMonitoringBroker; - @Mock - private DOMDataReadOnlyTransaction domDataReadOnlyTransaction; - @Mock - private DataBroker contextBroker; - - @Before - public void setUp() { - initMocks(this); - operationalData = new ReadableDataTreeDelegator(serializer, globalContext, reader, contextBroker); - doReturn(schemaNode).when(globalContext).getDataChildByName(any(QName.class)); - - doReturn(domDataReadOnlyTransaction).when(netconfMonitoringBroker).newReadOnlyTransaction(); - doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(domDataReadOnlyTransaction) - .read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class)); - - final org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction ctxTransaction = mock( - org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction.class); - doReturn(ctxTransaction).when(contextBroker).newReadWriteTransaction(); - doReturn(Futures.immediateCheckedFuture(null)).when(ctxTransaction).submit(); - } - - @Test - public void testReadNode() throws Exception { - final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); - final YangInstanceIdentifier.PathArgument pArg = mock(YangInstanceIdentifier.PathArgument.class); - doReturn(pArg).when(yangId).getLastPathArgument(); - doReturn(Collections.singletonList(pArg)).when(yangId).getPathArguments(); - - doReturn(QName.create("namespace", "2012-12-12", "local")).when(pArg).getNodeType(); - doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); - - final DataObject dataObject = mock(DataObject.class); - doReturn(Optional.of(dataObject)).when(reader).read(same(id), any(ReadContext.class)); - - when(serializer.toNormalizedNode(id, dataObject)).thenReturn(entry); - final DataContainerChild expectedValue = mock(DataContainerChild.class); - doReturn(expectedValue).when(entry).getValue(); - - final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); - - verify(serializer).fromYangInstanceIdentifier(yangId); - verify(reader).read(same(id), any(ReadContext.class)); - final Optional> result = future.get(); - assertTrue(result.isPresent()); - assertEquals(expectedValue, result.get()); - } - - @Test - public void testReadNonExistingNode() throws Exception { - final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); - doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); - doReturn(Optional.absent()).when(reader).read(same(id), any(ReadContext.class)); - - final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); - - verify(serializer).fromYangInstanceIdentifier(yangId); - verify(reader).read(same(id), any(ReadContext.class)); - final Optional> result = future.get(); - assertFalse(result.isPresent()); - } - - @Test - public void testReadFailed() throws Exception { - doThrow(io.fd.honeycomb.v3po.translate.read.ReadFailedException.class).when(reader).readAll(any(ReadContext.class)); - - final CheckedFuture>, ReadFailedException> future = - operationalData.read( YangInstanceIdentifier.EMPTY); - - try { - future.checkedGet(); - } catch (ReadFailedException e) { - assertTrue(e.getCause() instanceof io.fd.honeycomb.v3po.translate.read.ReadFailedException); - return; - } - fail("ReadFailedException was expected"); - } - - @Test - public void testReadRootWithOneNonListElement() throws Exception { - // Prepare data - final InstanceIdentifier vppStateII = InstanceIdentifier.create(DataObject.class); - final DataObject vppState = mock(DataObject.class); - Multimap, DataObject> dataObjects = LinkedListMultimap.create(); - dataObjects.put(vppStateII, vppState); - doReturn(dataObjects).when(reader).readAll(any(ReadContext.class)); - - // Init serializer - final YangInstanceIdentifier vppYangId = YangInstanceIdentifier.builder().node(QName.create("n", "d")).build(); - when(serializer.toYangInstanceIdentifier(vppStateII)).thenReturn(vppYangId); - when(serializer.toNormalizedNode(vppStateII, vppState)).thenReturn(entry); - final DataContainerChild vppStateContainer = mock(DataContainerChild.class); - doReturn(vppStateContainer).when(entry).getValue(); - doReturn(vppYangId.getLastPathArgument()).when(vppStateContainer).getIdentifier(); - - // Read root - final CheckedFuture>, ReadFailedException> future = - operationalData.read(YangInstanceIdentifier.EMPTY); - - verify(reader).readAll(any(ReadContext.class)); - verify(serializer).toYangInstanceIdentifier(vppStateII); - verify(serializer).toNormalizedNode(vppStateII, vppState); - - // Check the result is an ContainerNode with only one child - final Optional> result = future.get(); - assertTrue(result.isPresent()); - - final ContainerNode rootNode = (ContainerNode) result.get(); - assertEquals(SchemaContext.NAME, rootNode.getIdentifier().getNodeType()); - assertEquals(vppStateContainer, Iterables.getOnlyElement(rootNode.getValue())); - } -} \ No newline at end of file diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java deleted file mode 100644 index 9cde27d2b..000000000 --- a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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.data.impl; - -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.data.DataModification; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -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.DataValidationFailedException; - -public class WriteTransactionTest { - - @Mock - private DataModification configSnapshot; - @Mock - private YangInstanceIdentifier path; - @Mock - private NormalizedNode data; - - private WriteTransaction writeTx; - - @Before - public void setUp() { - initMocks(this); - writeTx = WriteTransaction.createConfigOnly(configSnapshot); - } - - @Test - public void testPut() { - writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); - verify(configSnapshot).write(path, data); - } - - @Test(expected = IllegalArgumentException.class) - public void testPutOperational() { - writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data); - verify(configSnapshot).write(path, data); - } - - @Test(expected = IllegalStateException.class) - public void testOnFinishedTx() { - writeTx.submit(); - writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); - verify(configSnapshot).write(path, data); - } - - @Test - public void testMerge() { - writeTx.merge(LogicalDatastoreType.CONFIGURATION, path, data); - verify(configSnapshot).merge(path, data); - } - - @Test - public void testCancel() { - assertTrue(writeTx.cancel()); - } - - @Test - public void testCancelFinished() { - writeTx.submit(); - assertFalse(writeTx.cancel()); - } - - @Test - public void testDelete() { - writeTx.delete(LogicalDatastoreType.CONFIGURATION, path); - verify(configSnapshot).delete(path); - } - - @Test - public void testSubmit() throws Exception { - writeTx.submit(); - verify(configSnapshot).validate(); - verify(configSnapshot).commit(); - } - - @Test - public void testSubmitFailed() throws Exception { - doThrow(mock(DataValidationFailedException.class)).when(configSnapshot).commit(); - final CheckedFuture future = writeTx.submit(); - try { - future.get(); - } catch (Exception e) { - assertTrue(e.getCause() instanceof TransactionCommitFailedException); - return; - } - fail("Expected exception to be thrown"); - - } - - @Test(expected = UnsupportedOperationException.class) - public void testCommit() { - writeTx.commit(); - } - - @Test - public void testGetIdentifier() { - assertNotNull(writeTx.getIdentifier()); - } -} \ No newline at end of file diff --git a/infra/impl/src/main/config/context-datatree-config.xml b/infra/impl/src/main/config/context-datatree-config.xml index 313f0ebe6..4d43a40cf 100644 --- a/infra/impl/src/main/config/context-datatree-config.xml +++ b/infra/impl/src/main/config/context-datatree-config.xml @@ -19,9 +19,9 @@ - urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&revision=2014-12-10 + urn:opendaylight:params:xml:ns:yang:honeycomb:impl?module=honeycomb-impl&revision=2014-12-10 urn:honeycomb:params:xml:ns:yang:translate:utils?module=translate-utils&revision=2016-04-06 - urn:honeycomb:params:xml:ns:yang:vpp:data:init?module=vpp-cfg-init&revision=2016-04-07 + urn:honeycomb:params:xml:ns:yang:data:init?module=cfg-init&revision=2016-04-07 urn:honeycomb:params:xml:ns:yang:data:api?module=data-api&revision=2016-04-11 urn:honeycomb:params:xml:ns:yang:data:impl?module=data-impl&revision=2016-04-11 urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 @@ -60,7 +60,7 @@ - prefix:honeycomb-context-dom-data-broker + prefix:honeycomb-context-dom-data-broker honeycomb-context-data-broker diff --git a/infra/impl/src/main/config/default-config.xml b/infra/impl/src/main/config/default-config.xml index c817a5db3..9e63917cd 100644 --- a/infra/impl/src/main/config/default-config.xml +++ b/infra/impl/src/main/config/default-config.xml @@ -16,7 +16,7 @@ --> - urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&revision=2014-12-10 + urn:opendaylight:params:xml:ns:yang:honeycomb:impl?module=honeycomb-impl&revision=2014-12-10 urn:honeycomb:params:xml:ns:yang:translate:utils?module=translate-utils&revision=2016-04-06 urn:honeycomb:params:xml:ns:yang:data:api?module=data-api&revision=2016-04-11 urn:honeycomb:params:xml:ns:yang:data:impl?module=data-impl&revision=2016-04-11 @@ -116,7 +116,7 @@ - prefix:honeycomb-dom-data-broker + prefix:honeycomb-dom-data-broker honeycomb-dom-data-broker prefix:honeycomb-modifiable-data-tree @@ -150,8 +150,8 @@ - prefix:v3po - v3po-default + prefix:honeycomb + honeycomb-default prefix:dom-broker-osgi-registry dom-broker @@ -242,8 +242,8 @@ dom:dom-broker-osgi-registry - vpp-dom-broker - /modules/module[type='v3po'][name='v3po-default'] + honeycomb-dom-broker + /modules/module[type='honeycomb'][name='honeycomb-default'] diff --git a/infra/impl/src/main/config/initializer-config.xml b/infra/impl/src/main/config/initializer-config.xml index f46069340..0b87e42dc 100644 --- a/infra/impl/src/main/config/initializer-config.xml +++ b/infra/impl/src/main/config/initializer-config.xml @@ -19,9 +19,9 @@ - urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&revision=2014-12-10 + urn:opendaylight:params:xml:ns:yang:honeycomb:impl?module=honeycomb-impl&revision=2014-12-10 urn:honeycomb:params:xml:ns:yang:translate:utils?module=translate-utils&revision=2016-04-06 - urn:honeycomb:params:xml:ns:yang:vpp:data:init?module=vpp-cfg-init&revision=2016-04-07 + urn:honeycomb:params:xml:ns:yang:data:init?module=cfg-init&revision=2016-04-07 urn:honeycomb:params:xml:ns:yang:data:api?module=data-api&revision=2016-04-11 urn:honeycomb:params:xml:ns:yang:data:impl?module=data-impl&revision=2016-04-11 urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 @@ -60,7 +60,7 @@ - prefix:honeycomb-dom-data-broker + prefix:honeycomb-dom-data-broker cfg-init-dom-data-broker prefix:honeycomb-modifiable-data-tree @@ -92,7 +92,7 @@ - prefix:persisted-file-initializer + prefix:persisted-file-initializer persisted-context-initializer dom:dom-async-data-broker @@ -107,7 +107,7 @@ oper - prefix:persisted-file-initializer + prefix:persisted-file-initializer persisted-config-initializer prefix:dom-async-data-broker @@ -123,14 +123,14 @@ - prefix:cfg-initializer-registry + prefix:cfg-initializer-registry initializer-registry - prefix:cfg-initializer + prefix:cfg-initializer persisted-context-initializer - prefix:cfg-initializer + prefix:cfg-initializer persisted-config-initializer @@ -170,7 +170,7 @@ - prefix:cfg-initializer + prefix:cfg-initializer persisted-context-initializer /modules/module[type='persisted-file-initializer'][name='persisted-context-initializer'] diff --git a/infra/impl/src/main/config/netconf-north-config.xml b/infra/impl/src/main/config/netconf-north-config.xml index 35bd5ff04..8e6f17019 100644 --- a/infra/impl/src/main/config/netconf-north-config.xml +++ b/infra/impl/src/main/config/netconf-north-config.xml @@ -83,7 +83,7 @@ - prefix:binding-broker-netconf + prefix:binding-broker-netconf binding-broker-netconf binding:binding-async-data-broker @@ -96,7 +96,7 @@ prefix:netconf-mdsal-mapper - netconf-vpp-mapper + netconf-honeycomb-mapper dom:schema-service @@ -112,13 +112,13 @@ dom:dom-broker-osgi-registry - vpp-dom-broker + honeycomb-dom-broker prefix:netconf-mapper-registry - vpp-mapper-aggregator-registry + honeycomb-mapper-aggregator-registry @@ -126,19 +126,19 @@ prefix:netconf-server-dispatcher-impl - netconf-vpp-server-dispatcher + netconf-honeycomb-server-dispatcher dom:netconf-northbound-mapper - vpp-mapper-aggregator + honeycomb-mapper-aggregator prefix:netconf-server-monitoring - vpp-server-monitor + honeycomb-server-monitor @@ -165,12 +165,12 @@ prefix:netconf-mdsal-monitoring-mapper - netconf-vpp-monitoring-mapper + netconf-honeycomb-monitoring-mapper prefix:netconf-server-monitoring - vpp-server-monitor + honeycomb-server-monitor @@ -183,7 +183,7 @@ prefix:netconf-mapper-registry - vpp-mapper-aggregator-registry + honeycomb-mapper-aggregator-registry @@ -191,19 +191,19 @@ prefix:netconf-mapper-aggregator - vpp-mapper-aggregator + honeycomb-mapper-aggregator prefix:netconf-server-monitoring-impl - vpp-server-monitor + honeycomb-server-monitor dom:netconf-northbound-mapper - vpp-mapper-aggregator + honeycomb-mapper-aggregator @@ -218,7 +218,7 @@ prefix:netconf-northbound-ssh - netconf-vpp-ssh-server + netconf-honeycomb-ssh-server 2830 @@ -243,7 +243,7 @@ prefix:netconf-server-dispatcher - netconf-vpp-server-dispatcher + netconf-honeycomb-server-dispatcher @@ -257,14 +257,14 @@ prefix:netconf-notification-manager - vpp-netconf-notification-manager + honeycomb-netconf-notification-manager prefix:netconf-mdsal-notification-mapper - netconf-vpp-notification-mapper + netconf-honeycomb-notification-mapper @@ -284,20 +284,20 @@ prefix:netconf-mapper-registry - vpp-mapper-aggregator-registry + honeycomb-mapper-aggregator-registry prefix:netconf-notification-registry - vpp-netconf-notification-manager + honeycomb-netconf-notification-manager prefix:netconf-notification-collector - vpp-netconf-notification-manager + honeycomb-netconf-notification-manager @@ -307,12 +307,12 @@ prefix:netconf-northbound-tcp - netconf-vpp-tcp-server + netconf-honeycomb-tcp-server prefix:netconf-server-dispatcher - netconf-vpp-server-dispatcher + netconf-honeycomb-server-dispatcher 7777 @@ -321,7 +321,7 @@ However netconf is wired to our reader registry, so we need to delegate the reads of netconf-monitoring through our readers to the dedicated DS--> - prefix:netconf-monitoring-reader + prefix:netconf-monitoring-reader netconf-monitoring-reader binding:binding-async-data-broker @@ -394,8 +394,8 @@ prefix:netconf-server-monitoring - vpp-server-monitor - /modules/module[type='netconf-server-monitoring-impl'][name='vpp-server-monitor'] + honeycomb-server-monitor + /modules/module[type='netconf-server-monitoring-impl'][name='honeycomb-server-monitor'] @@ -404,8 +404,8 @@ prefix:netconf-northbound-mapper - netconf-vpp-mapper - /modules/module[type='netconf-mdsal-mapper'][name='netconf-vpp-mapper'] + netconf-honeycomb-mapper + /modules/module[type='netconf-mdsal-mapper'][name='netconf-honeycomb-mapper'] @@ -413,8 +413,8 @@ prefix:netconf-northbound-mapper - vpp-mapper-aggregator - /modules/module[type='netconf-mapper-aggregator'][name='vpp-mapper-aggregator'] + honeycomb-mapper-aggregator + /modules/module[type='netconf-mapper-aggregator'][name='honeycomb-mapper-aggregator'] @@ -422,8 +422,8 @@ prefix:netconf-mapper-registry - vpp-mapper-aggregator-registry - /modules/module[type='netconf-mapper-aggregator'][name='vpp-mapper-aggregator'] + honeycomb-mapper-aggregator-registry + /modules/module[type='netconf-mapper-aggregator'][name='honeycomb-mapper-aggregator'] @@ -431,9 +431,9 @@ prefix:netconf-server-dispatcher - netconf-vpp-server-dispatcher + netconf-honeycomb-server-dispatcher - /modules/module[type='netconf-server-dispatcher-impl'][name='netconf-vpp-server-dispatcher'] + /modules/module[type='netconf-server-dispatcher-impl'][name='netconf-honeycomb-server-dispatcher'] @@ -442,9 +442,9 @@ prefix:netconf-northbound-mapper - netconf-vpp-notification-mapper + netconf-honeycomb-notification-mapper - /modules/module[type='netconf-mdsal-notification-mapper'][name='netconf-vpp-notification-mapper'] + /modules/module[type='netconf-mdsal-notification-mapper'][name='netconf-honeycomb-notification-mapper'] @@ -453,9 +453,9 @@ prefix:netconf-notification-collector - vpp-netconf-notification-manager + honeycomb-netconf-notification-manager - /modules/module[type='netconf-notification-manager'][name='vpp-netconf-notification-manager'] + /modules/module[type='netconf-notification-manager'][name='honeycomb-netconf-notification-manager'] @@ -464,9 +464,9 @@ prefix:netconf-notification-registry - vpp-netconf-notification-manager + honeycomb-netconf-notification-manager - /modules/module[type='netconf-notification-manager'][name='vpp-netconf-notification-manager'] + /modules/module[type='netconf-notification-manager'][name='honeycomb-netconf-notification-manager'] @@ -475,7 +475,7 @@ - urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&revision=2014-12-10 + urn:opendaylight:params:xml:ns:yang:honeycomb:impl?module=honeycomb-impl&revision=2014-12-10 urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper?module=netconf-mdsal-mapper&revision=2015-01-14 diff --git a/infra/impl/src/main/config/restconf-north-config.xml b/infra/impl/src/main/config/restconf-north-config.xml index ff2cdac18..00599b62c 100644 --- a/infra/impl/src/main/config/restconf-north-config.xml +++ b/infra/impl/src/main/config/restconf-north-config.xml @@ -24,7 +24,7 @@ dom:dom-broker-osgi-registry - vpp-dom-broker + honeycomb-dom-broker diff --git a/infra/impl/src/main/java/io/fd/honeycomb/impl/NorthboundFacadeHoneycombDOMBroker.java b/infra/impl/src/main/java/io/fd/honeycomb/impl/NorthboundFacadeHoneycombDOMBroker.java new file mode 100644 index 000000000..7e5dfd873 --- /dev/null +++ b/infra/impl/src/main/java/io/fd/honeycomb/impl/NorthboundFacadeHoneycombDOMBroker.java @@ -0,0 +1,206 @@ +/* + * 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. + */ + +package io.fd.honeycomb.impl; + +import com.google.common.base.Optional; +import com.google.common.collect.Maps; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.concurrent.NotThreadSafe; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; +import org.opendaylight.controller.md.sal.dom.api.DOMNotificationPublishService; +import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcException; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.BrokerService; +import org.opendaylight.controller.sal.core.api.Consumer; +import org.opendaylight.controller.sal.core.api.Provider; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.osgi.framework.BundleContext; + +/** + * Implementation of dom broker to facade VPP pipeline for northbound APIs + */ +public class NorthboundFacadeHoneycombDOMBroker implements AutoCloseable, Broker { + + private static final BrokerService EMPTY_DOM_RPC_SERVICE = new EmptyDomRpcService(); + private static final BrokerService EMPTY_DOM_MOUNT_SERVICE = new EmptyDomMountService(); + + private Map, BrokerService> services; + + public NorthboundFacadeHoneycombDOMBroker(@Nonnull final DOMDataBroker domDataBrokerDependency, + @Nonnull final SchemaService schemaBiService, + @Nonnull final DOMNotificationService domNotificatioNService) { + services = Maps.newHashMap(); + services.put(DOMDataBroker.class, domDataBrokerDependency); + // All services below are required to be present by Restconf northbound + services.put(SchemaService.class, schemaBiService); + services.put(DOMRpcService.class, EMPTY_DOM_RPC_SERVICE); + services.put(DOMMountPointService.class, EMPTY_DOM_MOUNT_SERVICE); + services.put(DOMNotificationService.class, domNotificatioNService); + // TODO do both notification service types have to be registered ? + services.put(DOMNotificationPublishService.class, domNotificatioNService); + } + + @Override + public void close() throws Exception { + // NOOP + } + + @Override + public ConsumerSession registerConsumer(final Consumer consumer) { + final SimpleConsumerSession session = new SimpleConsumerSession(services); + consumer.onSessionInitiated(session); + return session; + } + + @Deprecated + @Override + public ConsumerSession registerConsumer(final Consumer consumer, final BundleContext bundleContext) { + throw new UnsupportedOperationException(); + } + + @Override + public ProviderSession registerProvider(final Provider provider) { + final SimpleProviderSession session = new SimpleProviderSession(services); + provider.onSessionInitiated(session); + return session; + } + + @Override + public ProviderSession registerProvider(final Provider provider, final BundleContext bundleContext) { + throw new UnsupportedOperationException(); + } + + @NotThreadSafe + private static class SimpleConsumerSession implements ConsumerSession { + private boolean closed; + private final Map, BrokerService> services; + + private SimpleConsumerSession(final Map, BrokerService> services) { + this.services = services; + } + + @Override + public boolean isClosed() { + return closed; + } + + @Override + public T getService(final Class aClass) { + return (T)services.get(aClass); + } + + @Override + public void close() { + closed = true; + } + } + + @NotThreadSafe + private static class SimpleProviderSession implements ProviderSession { + private boolean closed; + private final Map, BrokerService> services; + + private SimpleProviderSession(final Map, BrokerService> services) { + this.services = services; + } + + @Override + public boolean isClosed() { + return closed; + } + + @Override + public T getService(final Class aClass) { + return (T)services.get(aClass); + } + + @Override + public void close() { + closed = true; + } + } + + private static class EmptyDomRpcService implements DOMRpcService { + @Nonnull + @Override + public CheckedFuture invokeRpc(@Nonnull final SchemaPath schemaPath, + @Nullable final NormalizedNode normalizedNode) { + return Futures.immediateFailedCheckedFuture( + new DOMRpcImplementationNotAvailableException("RPCs not supported")); + } + + @Nonnull + @Override + public ListenerRegistration registerRpcListener(@Nonnull final T t) { + return new ListenerRegistration() { + @Override + public void close() { + // Noop + } + + @Override + public T getInstance() { + return t; + } + }; + } + } + + private static class EmptyDomMountService implements DOMMountPointService { + @Override + public Optional getMountPoint(final YangInstanceIdentifier yangInstanceIdentifier) { + return Optional.absent(); + } + + @Override + public DOMMountPointBuilder createMountPoint(final YangInstanceIdentifier yangInstanceIdentifier) { + throw new UnsupportedOperationException("No mountpoint support"); + } + + @Override + public ListenerRegistration registerProvisionListener( + final MountProvisionListener mountProvisionListener) { + return new ListenerRegistration() { + @Override + public void close() { + // Noop + } + + @Override + public MountProvisionListener getInstance() { + return mountProvisionListener; + } + }; + } + } +} diff --git a/infra/impl/src/main/java/io/fd/honeycomb/v3po/impl/NorthboundFacadeHoneycombDOMBroker.java b/infra/impl/src/main/java/io/fd/honeycomb/v3po/impl/NorthboundFacadeHoneycombDOMBroker.java deleted file mode 100644 index c2d70c38c..000000000 --- a/infra/impl/src/main/java/io/fd/honeycomb/v3po/impl/NorthboundFacadeHoneycombDOMBroker.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * 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. - */ - -package io.fd.honeycomb.v3po.impl; - -import com.google.common.base.Optional; -import com.google.common.collect.Maps; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.annotation.concurrent.NotThreadSafe; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; -import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; -import org.opendaylight.controller.md.sal.dom.api.DOMNotificationPublishService; -import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService; -import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener; -import org.opendaylight.controller.md.sal.dom.api.DOMRpcException; -import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException; -import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult; -import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; -import org.opendaylight.controller.sal.core.api.Broker; -import org.opendaylight.controller.sal.core.api.BrokerService; -import org.opendaylight.controller.sal.core.api.Consumer; -import org.opendaylight.controller.sal.core.api.Provider; -import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; -import org.osgi.framework.BundleContext; - -/** - * Implementation of dom broker to facade VPP pipeline for northbound APIs - */ -public class NorthboundFacadeHoneycombDOMBroker implements AutoCloseable, Broker { - - private static final BrokerService EMPTY_DOM_RPC_SERVICE = new EmptyDomRpcService(); - private static final BrokerService EMPTY_DOM_MOUNT_SERVICE = new EmptyDomMountService(); - - private Map, BrokerService> services; - - public NorthboundFacadeHoneycombDOMBroker(@Nonnull final DOMDataBroker domDataBrokerDependency, - @Nonnull final SchemaService schemaBiService, - @Nonnull final DOMNotificationService domNotificatioNService) { - services = Maps.newHashMap(); - services.put(DOMDataBroker.class, domDataBrokerDependency); - // All services below are required to be present by Restconf northbound - services.put(SchemaService.class, schemaBiService); - services.put(DOMRpcService.class, EMPTY_DOM_RPC_SERVICE); - services.put(DOMMountPointService.class, EMPTY_DOM_MOUNT_SERVICE); - services.put(DOMNotificationService.class, domNotificatioNService); - // TODO do both notification service types have to be registered ? - services.put(DOMNotificationPublishService.class, domNotificatioNService); - } - - @Override - public void close() throws Exception { - // NOOP - } - - @Override - public ConsumerSession registerConsumer(final Consumer consumer) { - final SimpleConsumerSession session = new SimpleConsumerSession(services); - consumer.onSessionInitiated(session); - return session; - } - - @Deprecated - @Override - public ConsumerSession registerConsumer(final Consumer consumer, final BundleContext bundleContext) { - throw new UnsupportedOperationException(); - } - - @Override - public ProviderSession registerProvider(final Provider provider) { - final SimpleProviderSession session = new SimpleProviderSession(services); - provider.onSessionInitiated(session); - return session; - } - - @Override - public ProviderSession registerProvider(final Provider provider, final BundleContext bundleContext) { - throw new UnsupportedOperationException(); - } - - @NotThreadSafe - private static class SimpleConsumerSession implements ConsumerSession { - private boolean closed; - private final Map, BrokerService> services; - - private SimpleConsumerSession(final Map, BrokerService> services) { - this.services = services; - } - - @Override - public boolean isClosed() { - return closed; - } - - @Override - public T getService(final Class aClass) { - return (T)services.get(aClass); - } - - @Override - public void close() { - closed = true; - } - } - - @NotThreadSafe - private static class SimpleProviderSession implements ProviderSession { - private boolean closed; - private final Map, BrokerService> services; - - private SimpleProviderSession(final Map, BrokerService> services) { - this.services = services; - } - - @Override - public boolean isClosed() { - return closed; - } - - @Override - public T getService(final Class aClass) { - return (T)services.get(aClass); - } - - @Override - public void close() { - closed = true; - } - } - - private static class EmptyDomRpcService implements DOMRpcService { - @Nonnull - @Override - public CheckedFuture invokeRpc(@Nonnull final SchemaPath schemaPath, - @Nullable final NormalizedNode normalizedNode) { - return Futures.immediateFailedCheckedFuture( - new DOMRpcImplementationNotAvailableException("RPCs not supported")); - } - - @Nonnull - @Override - public ListenerRegistration registerRpcListener(@Nonnull final T t) { - return new ListenerRegistration() { - @Override - public void close() { - // Noop - } - - @Override - public T getInstance() { - return t; - } - }; - } - } - - private static class EmptyDomMountService implements DOMMountPointService { - @Override - public Optional getMountPoint(final YangInstanceIdentifier yangInstanceIdentifier) { - return Optional.absent(); - } - - @Override - public DOMMountPointBuilder createMountPoint(final YangInstanceIdentifier yangInstanceIdentifier) { - throw new UnsupportedOperationException("No mountpoint support"); - } - - @Override - public ListenerRegistration registerProvisionListener( - final MountProvisionListener mountProvisionListener) { - return new ListenerRegistration() { - @Override - public void close() { - // Noop - } - - @Override - public MountProvisionListener getInstance() { - return mountProvisionListener; - } - }; - } - } -} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/ContextDataBrokerModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/ContextDataBrokerModule.java new file mode 100644 index 000000000..c2f7d688a --- /dev/null +++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/ContextDataBrokerModule.java @@ -0,0 +1,26 @@ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.honeycomb.impl.rev141210; + +import io.fd.honeycomb.data.impl.DataBroker; +import io.fd.honeycomb.data.impl.ModifiableDataTreeManager; + +public class ContextDataBrokerModule extends AbstractContextDataBrokerModule { + + public ContextDataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public ContextDataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, ContextDataBrokerModule 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 DataBroker.create(new ModifiableDataTreeManager(getContextDataTreeDependency())); + } + +} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/ContextDataBrokerModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/ContextDataBrokerModuleFactory.java new file mode 100644 index 000000000..e07214b2e --- /dev/null +++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/ContextDataBrokerModuleFactory.java @@ -0,0 +1,13 @@ +/* +* Generated file +* +* Generated from: yang module name: v3po-impl yang module local name: honeycomb-context-dom-data-broker +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Mon May 16 15:27:12 CEST 2016 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.honeycomb.impl.rev141210; +public class ContextDataBrokerModuleFactory extends AbstractContextDataBrokerModuleFactory { + +} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/DataBrokerModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/DataBrokerModule.java new file mode 100644 index 000000000..d97573e12 --- /dev/null +++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/DataBrokerModule.java @@ -0,0 +1,34 @@ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.honeycomb.impl.rev141210; + +import io.fd.honeycomb.data.impl.DataBroker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DataBrokerModule extends + AbstractDataBrokerModule { + + private static final Logger LOG = LoggerFactory.getLogger(DataBrokerModule.class); + + public DataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public DataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + DataBrokerModule 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.debug("DataBrokerModule.createInstance()"); + return DataBroker.create(getConfigDataTreeDependency(), getOperationalDataTreeDependency()); + } +} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/DataBrokerModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/DataBrokerModuleFactory.java new file mode 100644 index 000000000..388f26c67 --- /dev/null +++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/DataBrokerModuleFactory.java @@ -0,0 +1,13 @@ +/* +* Generated file +* +* Generated from: yang module name: v3po-impl yang module local name: honeycomb-dom-data-broker +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Mon Apr 11 07:53:38 CEST 2016 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.honeycomb.impl.rev141210; +public class DataBrokerModuleFactory extends AbstractDataBrokerModuleFactory { + +} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/HoneycombModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/HoneycombModule.java new file mode 100644 index 000000000..333219518 --- /dev/null +++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/HoneycombModule.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.honeycomb.impl.rev141210; + +import io.fd.honeycomb.impl.NorthboundFacadeHoneycombDOMBroker; +import org.opendaylight.controller.sal.core.api.AbstractProvider; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.model.SchemaService; + +public class HoneycombModule extends AbstractHoneycombModule { + + public HoneycombModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public HoneycombModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, + org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + HoneycombModule 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() { + + final Broker.ProviderSession providerSession = + getDomBrokerDependency().registerProvider(new AbstractProvider() { + @Override + public void onSessionInitiated(final Broker.ProviderSession providerSession) { + // NOOP + } + }); + final SchemaService schemaBiService = providerSession.getService(SchemaService.class); + + return new NorthboundFacadeHoneycombDOMBroker(getHoneycombDomDataBrokerDependency(), schemaBiService, + getHoneycombDomNotificationServiceDependency()); + } + +} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/HoneycombModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/HoneycombModuleFactory.java new file mode 100644 index 000000000..2e7b0956f --- /dev/null +++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/HoneycombModuleFactory.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +/* +* Generated file +* +* Generated from: yang module name: v3po yang module local name: v3po +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Fri Jan 02 13:49:24 CST 2015 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.honeycomb.impl.rev141210; +public class HoneycombModuleFactory extends AbstractHoneycombModuleFactory { + +} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfBindingBrokerModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfBindingBrokerModule.java new file mode 100644 index 000000000..12fdcfe35 --- /dev/null +++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfBindingBrokerModule.java @@ -0,0 +1,117 @@ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.honeycomb.impl.rev141210; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; +import org.opendaylight.controller.sal.binding.api.BindingAwareService; +import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.osgi.framework.BundleContext; + +public class NetconfBindingBrokerModule extends AbstractNetconfBindingBrokerModule { + public NetconfBindingBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public NetconfBindingBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, NetconfBindingBrokerModule 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 FakeBindingAwareBroker(getNetconfBindingBrokerDependency()); + } + + private static class FakeBindingAwareBroker implements BindingAwareBroker, AutoCloseable { + + private DataBroker netconfBindingBrokerDependency; + + public FakeBindingAwareBroker(final DataBroker netconfBindingBrokerDependency) { + + this.netconfBindingBrokerDependency = netconfBindingBrokerDependency; + } + + @Deprecated + @Override + public ConsumerContext registerConsumer(final BindingAwareConsumer bindingAwareConsumer, + final BundleContext bundleContext) { + throw new UnsupportedOperationException("Unsupported"); + } + + @Override + public ConsumerContext registerConsumer(final BindingAwareConsumer bindingAwareConsumer) { + final ConsumerContext consumerContext = new ConsumerContext() { + @Override + public T getSALService(final Class aClass) { + return aClass.equals(DataBroker.class) + ? (T) netconfBindingBrokerDependency + : null; + } + + @Override + public T getRpcService(final Class aClass) { + return null; + } + }; + bindingAwareConsumer.onSessionInitialized(consumerContext); + return consumerContext; + } + + @Override + public ProviderContext registerProvider(final BindingAwareProvider bindingAwareProvider, + final BundleContext bundleContext) { + throw new UnsupportedOperationException("Unsupported"); + } + + @Override + public ProviderContext registerProvider(final BindingAwareProvider bindingAwareProvider) { + final ProviderContext context = new ProviderContext() { + @Override + public >> ListenerRegistration registerRouteChangeListener( + final L l) { + throw new UnsupportedOperationException("Unsupported"); + } + + @Override + public T getRpcService(final Class aClass) { + throw new UnsupportedOperationException("Unsupported"); + } + + @Override + public RpcRegistration addRpcImplementation(final Class aClass, final T t) + throws IllegalStateException { + throw new UnsupportedOperationException("Unsupported"); + } + + @Override + public RoutedRpcRegistration addRoutedRpcImplementation( + final Class aClass, final T t) throws IllegalStateException { + throw new UnsupportedOperationException("Unsupported"); + } + + @Override + public T getSALService(final Class aClass) { + return aClass.equals(DataBroker.class) + ? (T) netconfBindingBrokerDependency + : null; } + }; + bindingAwareProvider.onSessionInitiated(context); + return context; + } + + @Override + public void close() throws Exception { + netconfBindingBrokerDependency = null; + } + } +} + diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfBindingBrokerModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfBindingBrokerModuleFactory.java new file mode 100644 index 000000000..fe9bdcf48 --- /dev/null +++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfBindingBrokerModuleFactory.java @@ -0,0 +1,13 @@ +/* +* Generated file +* +* Generated from: yang module name: v3po-impl yang module local name: binding-broker-netconf +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Wed Mar 23 10:45:48 CET 2016 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.honeycomb.impl.rev141210; +public class NetconfBindingBrokerModuleFactory extends AbstractNetconfBindingBrokerModuleFactory { + +} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfMonitoringReaderModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfMonitoringReaderModule.java new file mode 100644 index 000000000..5b9a8b819 --- /dev/null +++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfMonitoringReaderModule.java @@ -0,0 +1,46 @@ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.honeycomb.impl.rev141210; + +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.honeycomb.translate.util.read.BindingBrokerReader; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfStateBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class NetconfMonitoringReaderModule extends AbstractNetconfMonitoringReaderModule { + public NetconfMonitoringReaderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public NetconfMonitoringReaderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, NetconfMonitoringReaderModule 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 ReaderFactory(getNetconfMonitoringBindingBrokerDependency()); + } + + + private static final class ReaderFactory implements AutoCloseable, io.fd.honeycomb.translate.read.ReaderFactory { + + private final DataBroker netconfMonitoringBindingBrokerDependency; + + public ReaderFactory(final DataBroker netconfMonitoringBindingBrokerDependency) { + this.netconfMonitoringBindingBrokerDependency = netconfMonitoringBindingBrokerDependency; + } + + @Override + public void init(final ModifiableReaderRegistryBuilder registry) { + registry.add(new BindingBrokerReader<>(InstanceIdentifier.create(NetconfState.class), + netconfMonitoringBindingBrokerDependency, + LogicalDatastoreType.OPERATIONAL, NetconfStateBuilder.class)); + } + } +} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfMonitoringReaderModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfMonitoringReaderModuleFactory.java new file mode 100644 index 000000000..d5130fd53 --- /dev/null +++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/honeycomb/impl/rev141210/NetconfMonitoringReaderModuleFactory.java @@ -0,0 +1,13 @@ +/* +* Generated file +* +* Generated from: yang module name: v3po-impl yang module local name: netconf-monitoring-reader +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Tue Apr 12 13:03:40 CEST 2016 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.honeycomb.impl.rev141210; +public class NetconfMonitoringReaderModuleFactory extends AbstractNetconfMonitoringReaderModuleFactory { + +} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModule.java deleted file mode 100644 index 1d1fa5323..000000000 --- a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModule.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; - -import io.fd.honeycomb.v3po.data.impl.DataBroker; -import io.fd.honeycomb.v3po.data.impl.ModifiableDataTreeManager; - -public class ContextDataBrokerModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractContextDataBrokerModule { - - public ContextDataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { - super(identifier, dependencyResolver); - } - - public ContextDataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.ContextDataBrokerModule 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 DataBroker.create(new ModifiableDataTreeManager(getContextDataTreeDependency())); - } - -} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModuleFactory.java deleted file mode 100644 index 360f5f472..000000000 --- a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModuleFactory.java +++ /dev/null @@ -1,13 +0,0 @@ -/* -* Generated file -* -* Generated from: yang module name: v3po-impl yang module local name: honeycomb-context-dom-data-broker -* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator -* Generated at: Mon May 16 15:27:12 CEST 2016 -* -* Do not modify this file unless it is present under src/main directory -*/ -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; -public class ContextDataBrokerModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractContextDataBrokerModuleFactory { - -} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModule.java deleted file mode 100644 index 8aa3d64d9..000000000 --- a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModule.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; - -import io.fd.honeycomb.v3po.data.impl.DataBroker; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DataBrokerModule extends - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractDataBrokerModule { - - private static final Logger LOG = LoggerFactory.getLogger(DataBrokerModule.class); - - public DataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, - org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { - super(identifier, dependencyResolver); - } - - public DataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, - org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.DataBrokerModule 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.debug("DataBrokerModule.createInstance()"); - return DataBroker.create(getConfigDataTreeDependency(), getOperationalDataTreeDependency()); - } -} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModuleFactory.java deleted file mode 100644 index cc30beacf..000000000 --- a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModuleFactory.java +++ /dev/null @@ -1,13 +0,0 @@ -/* -* Generated file -* -* Generated from: yang module name: v3po-impl yang module local name: honeycomb-dom-data-broker -* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator -* Generated at: Mon Apr 11 07:53:38 CEST 2016 -* -* Do not modify this file unless it is present under src/main directory -*/ -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; -public class DataBrokerModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractDataBrokerModuleFactory { - -} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModule.java deleted file mode 100644 index 48d227d01..000000000 --- a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModule.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; - -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; -import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; -import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; -import org.opendaylight.controller.sal.binding.api.BindingAwareService; -import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.RpcService; -import org.osgi.framework.BundleContext; - -public class NetconfBindingBrokerModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractNetconfBindingBrokerModule { - public NetconfBindingBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { - super(identifier, dependencyResolver); - } - - public NetconfBindingBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.NetconfBindingBrokerModule 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 FakeBindingAwareBroker(getNetconfBindingBrokerDependency()); - } - - private static class FakeBindingAwareBroker implements BindingAwareBroker, AutoCloseable { - - private DataBroker netconfBindingBrokerDependency; - - public FakeBindingAwareBroker(final DataBroker netconfBindingBrokerDependency) { - - this.netconfBindingBrokerDependency = netconfBindingBrokerDependency; - } - - @Deprecated - @Override - public ConsumerContext registerConsumer(final BindingAwareConsumer bindingAwareConsumer, - final BundleContext bundleContext) { - throw new UnsupportedOperationException("Unsupported"); - } - - @Override - public ConsumerContext registerConsumer(final BindingAwareConsumer bindingAwareConsumer) { - final ConsumerContext consumerContext = new ConsumerContext() { - @Override - public T getSALService(final Class aClass) { - return aClass.equals(DataBroker.class) - ? (T) netconfBindingBrokerDependency - : null; - } - - @Override - public T getRpcService(final Class aClass) { - return null; - } - }; - bindingAwareConsumer.onSessionInitialized(consumerContext); - return consumerContext; - } - - @Override - public ProviderContext registerProvider(final BindingAwareProvider bindingAwareProvider, - final BundleContext bundleContext) { - throw new UnsupportedOperationException("Unsupported"); - } - - @Override - public ProviderContext registerProvider(final BindingAwareProvider bindingAwareProvider) { - final ProviderContext context = new ProviderContext() { - @Override - public >> ListenerRegistration registerRouteChangeListener( - final L l) { - throw new UnsupportedOperationException("Unsupported"); - } - - @Override - public T getRpcService(final Class aClass) { - throw new UnsupportedOperationException("Unsupported"); - } - - @Override - public RpcRegistration addRpcImplementation(final Class aClass, final T t) - throws IllegalStateException { - throw new UnsupportedOperationException("Unsupported"); - } - - @Override - public RoutedRpcRegistration addRoutedRpcImplementation( - final Class aClass, final T t) throws IllegalStateException { - throw new UnsupportedOperationException("Unsupported"); - } - - @Override - public T getSALService(final Class aClass) { - return aClass.equals(DataBroker.class) - ? (T) netconfBindingBrokerDependency - : null; } - }; - bindingAwareProvider.onSessionInitiated(context); - return context; - } - - @Override - public void close() throws Exception { - netconfBindingBrokerDependency = null; - } - } -} - diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModuleFactory.java deleted file mode 100644 index b64b0b1e1..000000000 --- a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModuleFactory.java +++ /dev/null @@ -1,13 +0,0 @@ -/* -* Generated file -* -* Generated from: yang module name: v3po-impl yang module local name: binding-broker-netconf -* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator -* Generated at: Wed Mar 23 10:45:48 CET 2016 -* -* Do not modify this file unless it is present under src/main directory -*/ -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; -public class NetconfBindingBrokerModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractNetconfBindingBrokerModuleFactory { - -} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModule.java deleted file mode 100644 index 8502fcbd2..000000000 --- a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModule.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; - -import io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder; -import io.fd.honeycomb.v3po.translate.util.read.BindingBrokerReader; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfStateBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class NetconfMonitoringReaderModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractNetconfMonitoringReaderModule { - public NetconfMonitoringReaderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { - super(identifier, dependencyResolver); - } - - public NetconfMonitoringReaderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.NetconfMonitoringReaderModule 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 ReaderFactory(getNetconfMonitoringBindingBrokerDependency()); - } - - - private static final class ReaderFactory implements AutoCloseable, io.fd.honeycomb.v3po.translate.read.ReaderFactory { - - private final DataBroker netconfMonitoringBindingBrokerDependency; - - public ReaderFactory(final DataBroker netconfMonitoringBindingBrokerDependency) { - this.netconfMonitoringBindingBrokerDependency = netconfMonitoringBindingBrokerDependency; - } - - @Override - public void init(final ModifiableReaderRegistryBuilder registry) { - registry.add(new BindingBrokerReader<>(InstanceIdentifier.create(NetconfState.class), - netconfMonitoringBindingBrokerDependency, - LogicalDatastoreType.OPERATIONAL, NetconfStateBuilder.class)); - } - } -} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModuleFactory.java deleted file mode 100644 index b8b7bec63..000000000 --- a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModuleFactory.java +++ /dev/null @@ -1,13 +0,0 @@ -/* -* Generated file -* -* Generated from: yang module name: v3po-impl yang module local name: netconf-monitoring-reader -* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator -* Generated at: Tue Apr 12 13:03:40 CEST 2016 -* -* Do not modify this file unless it is present under src/main directory -*/ -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; -public class NetconfMonitoringReaderModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractNetconfMonitoringReaderModuleFactory { - -} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java deleted file mode 100644 index caa792da4..000000000 --- a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - */ - -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; - -import io.fd.honeycomb.v3po.impl.NorthboundFacadeHoneycombDOMBroker; -import org.opendaylight.controller.sal.core.api.AbstractProvider; -import org.opendaylight.controller.sal.core.api.Broker; -import org.opendaylight.controller.sal.core.api.model.SchemaService; - -public class V3poModule extends - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractV3poModule { - - public V3poModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, - org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { - super(identifier, dependencyResolver); - } - - public V3poModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, - org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.V3poModule 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() { - - final Broker.ProviderSession providerSession = - getDomBrokerDependency().registerProvider(new AbstractProvider() { - @Override - public void onSessionInitiated(final Broker.ProviderSession providerSession) { - // NOOP - } - }); - final SchemaService schemaBiService = providerSession.getService(SchemaService.class); - - return new NorthboundFacadeHoneycombDOMBroker(getHoneycombDomDataBrokerDependency(), schemaBiService, - getHoneycombDomNotificationServiceDependency()); - } - -} diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java deleted file mode 100644 index 5c942861d..000000000 --- a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - */ -/* -* Generated file -* -* Generated from: yang module name: v3po yang module local name: v3po -* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator -* Generated at: Fri Jan 02 13:49:24 CST 2015 -* -* Do not modify this file unless it is present under src/main directory -*/ -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; -public class V3poModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractV3poModuleFactory { - -} diff --git a/infra/impl/src/main/yang/honeycomb-impl.yang b/infra/impl/src/main/yang/honeycomb-impl.yang new file mode 100644 index 000000000..46f1af862 --- /dev/null +++ b/infra/impl/src/main/yang/honeycomb-impl.yang @@ -0,0 +1,155 @@ +module honeycomb-impl { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:honeycomb:impl"; + prefix "hc-impl"; + + 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; } + import notification-api { prefix hc-notif-a; revision-date 2016-06-01; } + + description + "Service definition for honeycomb project"; + + revision "2014-12-10" { + description + "Initial revision"; + } + + identity honeycomb { + base config:module-type; + config:provided-service dom:dom-broker-osgi-registry; + config:java-name-prefix Honeycomb; + } + + augment "/config:modules/config:module/config:configuration" { + case honeycomb { + when "/config:modules/config:module/config:type = 'honeycomb'"; + container dom-broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dom:dom-broker-osgi-registry; + } + } + } + + container honeycomb-dom-data-broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dom:dom-async-data-broker; + } + } + } + + container honeycomb-dom-notification-service { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity hc-notif-a:dom-notification-service; + } + } + } + + } + } + + identity binding-broker-netconf { + base config:module-type; + config:provided-service md-sal-binding:binding-broker-osgi-registry; + config:java-name-prefix NetconfBindingBroker; + } + + augment "/config:modules/config:module/config:configuration" { + case binding-broker-netconf { + when "/config:modules/config:module/config:type = 'binding-broker-netconf'"; + + container netconf-binding-broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity md-sal-binding:binding-async-data-broker; + } + } + } + + } + } + + identity honeycomb-dom-data-broker { + base config:module-type; + config:provided-service dom:dom-async-data-broker; + config:java-name-prefix DataBroker; + } + + augment "/config:modules/config:module/config:configuration" { + case honeycomb-dom-data-broker { + when "/config:modules/config:module/config:type = 'honeycomb-dom-data-broker'"; + + container config-data-tree { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dapi:honeycomb-modifiable-data-tree; + } + } + } + + container operational-data-tree { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dapi:honeycomb-readable-data-tree; + } + } + } + + } + } + + identity honeycomb-context-dom-data-broker { + base config:module-type; + config:provided-service dom:dom-async-data-broker; + config:java-name-prefix ContextDataBroker; + description "DomBroker on top of context data-tree"; + } + + augment "/config:modules/config:module/config:configuration" { + case honeycomb-context-dom-data-broker { + when "/config:modules/config:module/config:type = 'honeycomb-context-dom-data-broker'"; + + container context-data-tree { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dapi:data-tree; + } + } + } + } + } + + identity netconf-monitoring-reader { + base config:module-type; + config:provided-service tapi:honeycomb-reader-factory; + } + + augment "/config:modules/config:module/config:configuration" { + case netconf-monitoring-reader { + when "/config:modules/config:module/config:type = 'netconf-monitoring-reader'"; + + container netconf-monitoring-binding-broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity md-sal-binding:binding-async-data-broker; + } + } + } + + } + } +} diff --git a/infra/impl/src/main/yang/v3po-impl.yang b/infra/impl/src/main/yang/v3po-impl.yang deleted file mode 100644 index fa9670678..000000000 --- a/infra/impl/src/main/yang/v3po-impl.yang +++ /dev/null @@ -1,155 +0,0 @@ -module v3po-impl { - yang-version 1; - namespace "urn:opendaylight:params:xml:ns:yang:v3po:impl"; - prefix "v3po-impl"; - - 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; } - import notification-api { prefix hc-notif-a; revision-date 2016-06-01; } - - description - "Service definition for v3po project"; - - revision "2014-12-10" { - description - "Initial revision"; - } - - identity v3po { - base config:module-type; - config:provided-service dom:dom-broker-osgi-registry; - config:java-name-prefix V3po; - } - - augment "/config:modules/config:module/config:configuration" { - case v3po { - when "/config:modules/config:module/config:type = 'v3po'"; - container dom-broker { - uses config:service-ref { - refine type { - mandatory true; - config:required-identity dom:dom-broker-osgi-registry; - } - } - } - - container honeycomb-dom-data-broker { - uses config:service-ref { - refine type { - mandatory true; - config:required-identity dom:dom-async-data-broker; - } - } - } - - container honeycomb-dom-notification-service { - uses config:service-ref { - refine type { - mandatory true; - config:required-identity hc-notif-a:dom-notification-service; - } - } - } - - } - } - - identity binding-broker-netconf { - base config:module-type; - config:provided-service md-sal-binding:binding-broker-osgi-registry; - config:java-name-prefix NetconfBindingBroker; - } - - augment "/config:modules/config:module/config:configuration" { - case binding-broker-netconf { - when "/config:modules/config:module/config:type = 'binding-broker-netconf'"; - - container netconf-binding-broker { - uses config:service-ref { - refine type { - mandatory true; - config:required-identity md-sal-binding:binding-async-data-broker; - } - } - } - - } - } - - identity honeycomb-dom-data-broker { - base config:module-type; - config:provided-service dom:dom-async-data-broker; - config:java-name-prefix DataBroker; - } - - augment "/config:modules/config:module/config:configuration" { - case honeycomb-dom-data-broker { - when "/config:modules/config:module/config:type = 'honeycomb-dom-data-broker'"; - - container config-data-tree { - uses config:service-ref { - refine type { - mandatory true; - config:required-identity dapi:honeycomb-modifiable-data-tree; - } - } - } - - container operational-data-tree { - uses config:service-ref { - refine type { - mandatory true; - config:required-identity dapi:honeycomb-readable-data-tree; - } - } - } - - } - } - - identity honeycomb-context-dom-data-broker { - base config:module-type; - config:provided-service dom:dom-async-data-broker; - config:java-name-prefix ContextDataBroker; - description "DomBroker on top of context data-tree"; - } - - augment "/config:modules/config:module/config:configuration" { - case honeycomb-context-dom-data-broker { - when "/config:modules/config:module/config:type = 'honeycomb-context-dom-data-broker'"; - - container context-data-tree { - uses config:service-ref { - refine type { - mandatory true; - config:required-identity dapi:data-tree; - } - } - } - } - } - - identity netconf-monitoring-reader { - base config:module-type; - config:provided-service tapi:honeycomb-reader-factory; - } - - augment "/config:modules/config:module/config:configuration" { - case netconf-monitoring-reader { - when "/config:modules/config:module/config:type = 'netconf-monitoring-reader'"; - - container netconf-monitoring-binding-broker { - uses config:service-ref { - refine type { - mandatory true; - config:required-identity md-sal-binding:binding-async-data-broker; - } - } - } - - } - } -} diff --git a/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java b/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java deleted file mode 100644 index 5b9a67458..000000000 --- a/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; - -import org.junit.Test; - -public class V3poModuleFactoryTest { - @Test - public void testFactoryConstructor() { - // ensure no exceptions on construction - new V3poModuleFactory(); - } -} diff --git a/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java b/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java deleted file mode 100644 index 3d8e79641..000000000 --- a/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - */ -package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import javax.management.ObjectName; -import org.junit.Test; -import org.opendaylight.controller.config.api.DependencyResolver; -import org.opendaylight.controller.config.api.JmxAttribute; -import org.opendaylight.controller.config.api.ModuleIdentifier; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; -import org.opendaylight.controller.sal.core.api.Broker; -import org.opendaylight.controller.sal.core.api.Provider; -import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; - -public class V3poModuleTest { - @Test - public void testCustomValidation() { - V3poModule module = new V3poModule(mock(ModuleIdentifier.class), mock(DependencyResolver.class)); - - // ensure no exceptions on validation - // currently this method is empty - module.customValidation(); - } - - @Test - public void testCreateInstance() throws Exception { - // configure mocks - DependencyResolver dependencyResolver = mock(DependencyResolver.class); - BindingAwareBroker broker = mock(BindingAwareBroker.class); - when(dependencyResolver.resolveInstance(eq(BindingAwareBroker.class), any(ObjectName.class), any(JmxAttribute.class))) - .thenReturn(broker); - final org.opendaylight.controller.sal.core.api.Broker domBroker = mock(org.opendaylight.controller.sal.core.api.Broker.class); - when(dependencyResolver.resolveInstance(eq(org.opendaylight.controller.sal.core.api.Broker.class), any(ObjectName.class), any(JmxAttribute.class))) - .thenReturn(domBroker); - doReturn(mock(Broker.ProviderSession.class)).when(domBroker).registerProvider(any(Provider.class)); - when(dependencyResolver.resolveInstance(eq(BindingNormalizedNodeSerializer.class), any(ObjectName.class), any(JmxAttribute.class))) - .thenReturn(mock(BindingNormalizedNodeSerializer.class)); - when(dependencyResolver.resolveInstance(eq(DOMDataBroker.class), any(ObjectName.class), any(JmxAttribute.class))) - .thenReturn(mock(DOMDataBroker.class)); - - // create instance of module with injected mocks - V3poModule module = new V3poModule(mock(ModuleIdentifier.class), dependencyResolver); - - // getInstance calls resolveInstance to get the broker dependency and then calls createInstance - AutoCloseable closeable = module.getInstance(); - - // ensure no exceptions on close - closeable.close(); - } -} diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/AbstractInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/AbstractInfraTest.java new file mode 100644 index 000000000..3c996f6a6 --- /dev/null +++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/AbstractInfraTest.java @@ -0,0 +1,106 @@ +/* + * 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.data.impl; + +import static org.mockito.Mockito.when; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.Futures; +import java.util.Collections; +import java.util.Map; +import javassist.ClassPool; +import org.junit.Before; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.$YangModuleInfoImpl; +import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext; +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +/** + * Base IT test infrastructure. + */ +abstract class AbstractInfraTest { + + protected BindingNormalizedNodeSerializer serializer; + protected SchemaContext schemaContext; + + @Mock + protected org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker; + @Mock + private org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction ctxTx; + + static BindingToNormalizedNodeCodec getSerializer(final ModuleInfoBackedContext moduleInfoBackedContext, + final SchemaContext schemaContext) { + final DataObjectSerializerGenerator serializerGenerator = new StreamWriterGenerator(JavassistUtils.forClassPool( + ClassPool.getDefault())); + final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(serializerGenerator); + final BindingRuntimeContext ctx = + BindingRuntimeContext.create(moduleInfoBackedContext, schemaContext); + codecRegistry.onBindingRuntimeContextUpdated(ctx); + return new BindingToNormalizedNodeCodec(moduleInfoBackedContext, codecRegistry); + } + + static ModuleInfoBackedContext getSchemaContext() { + final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create(); + moduleInfoBackedContext.addModuleInfos(Collections.singleton($YangModuleInfoImpl.getInstance())); + return moduleInfoBackedContext; + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(contextBroker.newReadWriteTransaction()).thenReturn(ctxTx); + when(ctxTx.submit()).thenReturn(Futures.immediateCheckedFuture(null)); + + initSerializer(); + postSetup(); + } + + abstract void postSetup(); + + private void initSerializer() { + final ModuleInfoBackedContext moduleInfoBackedContext = getSchemaContext(); + schemaContext = moduleInfoBackedContext.tryToCreateSchemaContext().get(); + serializer = getSerializer(moduleInfoBackedContext, schemaContext); + } + + protected Multimap, ? extends DataObject> toBinding( + final NormalizedNode read) { + Multimap, DataObject> baNodes = HashMultimap.create(); + + for (DataContainerChild o : ((DataContainerNode) read).getValue()) { + final YangInstanceIdentifier yid = YangInstanceIdentifier.of(o.getNodeType()); + final Map.Entry, DataObject> baEntry = serializer.fromNormalizedNode(yid, o); + baNodes.put(baEntry.getKey(), baEntry.getValue()); + } + return baNodes; + } +} diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombReadInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombReadInfraTest.java new file mode 100644 index 000000000..5ec2b55ba --- /dev/null +++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombReadInfraTest.java @@ -0,0 +1,460 @@ +/* + * 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.data.impl; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyListOf; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.read.ListReader; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.util.read.ReflexiveListReaderCustomizer; +import io.fd.honeycomb.translate.util.read.ReflexiveReader; +import io.fd.honeycomb.translate.util.read.registry.CompositeReaderRegistryBuilder; +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.exceptions.misusing.MockitoConfigurationException; +import org.mockito.invocation.InvocationOnMock; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainerBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainerBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public class HoneycombReadInfraTest extends AbstractInfraTest { + + @Mock + private ReadContext ctx; + private ReaderRegistry registry; + + // 1 + private Reader simpleContainerReader = + mockReader(Ids.SIMPLE_CONTAINER_ID, this::readSimpleContainer, SimpleContainerBuilder.class); + // 1.1 + private Reader simpleAugmentReader = + mockReader(Ids.SIMPLE_AUGMENT_ID, this::readSimpleAugment, SimpleAugmentBuilder.class); + // 1.2 + // Noop reader(no real attributes) + private Reader complexAugmentReader = + mockReader(Ids.COMPLEX_AUGMENT_ID, HoneycombReadInfraTest::noopRead, ComplexAugmentBuilder.class); + // 1.2.1 + private Reader complexAugmentContainerReader = + mockReader(Ids.COMPLEX_AUGMENT_CONTAINER_ID, this::readComplexAugmentContainer, ComplexAugmentContainerBuilder.class); + // 2 + // Noop reader(no real attributes) + private Reader containerWithListReader = + mockReader(Ids.CONTAINER_WITH_LIST_ID, HoneycombReadInfraTest::noopRead, ContainerWithListBuilder.class); + // 2.1 + private ListReader listInContainerReader = + mockListReader(Ids.LIST_IN_CONTAINER_ID, this::readListInContainer, this::getListInContainerIds, + ListInContainerBuilder.class); + // 2.1.1 + private Reader containerInListReader = + mockReader(Ids.CONTAINER_IN_LIST_ID, this::readContainerInList, ContainerInListBuilder.class); + // 2.1.1.1 + private ListReader nestedListReader = + mockListReader(Ids.NESTED_LIST_ID, this::readNestedList, this::getNestedListIds, + NestedListBuilder.class); + + @Override + void postSetup() { + initReaderRegistry(); + } + + private void initReaderRegistry() { + registry = new CompositeReaderRegistryBuilder() + .add(containerWithListReader) // 2 + .addBefore(simpleContainerReader, Ids.CONTAINER_WITH_LIST_ID) // 1 + .add(simpleAugmentReader) // 1.1 + .addAfter(complexAugmentReader, Ids.SIMPLE_AUGMENT_ID) // 1.2 + .add(complexAugmentContainerReader) // 1.2.1 + .add(listInContainerReader) // 2.1 + .add(containerInListReader) // 2.1.1 + .addBefore(nestedListReader, Ids.SIMPLE_AUGMENT_ID) // 2.1.1.1 - Before relationship should be ignored + .build(); + } + + private Reader[] getOrderedReaders() { + return new Reader[]{simpleContainerReader, // 1 + simpleAugmentReader, // 1.1 + complexAugmentReader, // 1.2 + complexAugmentContainerReader, // 1.2.1 + containerWithListReader, // 2 + listInContainerReader, // 2.1 + containerInListReader, // 2.1.1 + nestedListReader}; // 2.1.1.1 + } + + @Test + public void testReadAll() throws Exception { + final ReadableDataTreeDelegator readableDataTreeDelegator = + new ReadableDataTreeDelegator(serializer, schemaContext, registry, contextBroker); + final CheckedFuture>, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> + read = readableDataTreeDelegator.read(YangInstanceIdentifier.EMPTY); + + final Multimap, ? extends DataObject> readAll = + toBinding(read.checkedGet().get()); + assertThat(readAll.size(), is(2)); + assertTrue(readAll.containsKey(Ids.CONTAINER_WITH_LIST_ID)); + assertEquals(readContainerWithList(), readAll.get(Ids.CONTAINER_WITH_LIST_ID).stream().findFirst().get()); + assertTrue(readAll.containsKey(Ids.SIMPLE_CONTAINER_ID)); + assertEquals(readSimpleContainer(), readAll.get(Ids.SIMPLE_CONTAINER_ID).stream().findFirst().get()); + + final Reader[] ordered = getOrderedReaders(); + final InOrder inOrder = inOrder(ordered); + + final List listInContainerKeys = getListInContainerIds(Ids.LIST_IN_CONTAINER_ID, ctx); + + verifyRootReader(inOrder, simpleContainerReader, Ids.SIMPLE_CONTAINER_ID, SimpleContainerBuilder.class); + verifyLeafChildReader(inOrder, simpleAugmentReader, Ids.SIMPLE_AUGMENT_ID); + verifyCompositeChildReader(inOrder, complexAugmentReader, ComplexAugmentBuilder.class, Ids.COMPLEX_AUGMENT_ID); + verifyLeafChildReader(inOrder, complexAugmentContainerReader, Ids.COMPLEX_AUGMENT_CONTAINER_ID); + verifyRootReader(inOrder, containerWithListReader, Ids.CONTAINER_WITH_LIST_ID, ContainerWithListBuilder.class); + verifyCompositeListReader(inOrder, listInContainerReader, Ids.LIST_IN_CONTAINER_ID, + listInContainerKeys, ListInContainerBuilder.class); + + for (ListInContainerKey k : listInContainerKeys) { + final InstanceIdentifier id = + Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, k).child(ContainerInList.class); + verifyCompositeChildReader(inOrder, containerInListReader, ContainerInListBuilder.class, id); + final InstanceIdentifier nestedId = id.child(NestedList.class); + verifyLeafListReader(inOrder, nestedListReader, nestedId); + } + + for (Reader reader : ordered) { + verifyNoMoreReadInteractions(reader); + } + } + + private > void verifyNoMoreReadInteractions(final Reader reader) { + verify(reader, atLeastOnce()).getManagedDataObjectType(); + verifyNoMoreInteractions(reader); + } + + private > void verifyCompositeChildReader(final InOrder inOrder, + final Reader reader, + final Class builderCls, + final InstanceIdentifier id) + throws ReadFailedException { + verifyRootReader(inOrder, reader, id, builderCls); + verify(reader, atLeastOnce()).merge(any(Builder.class), any(id.getTargetType())); + } + + private , K extends Identifier, B extends Builder> void verifyCompositeListReader( + final InOrder inOrder, + final ListReader reader, + final InstanceIdentifier id, + final List keys, + final Class builderCls) + throws ReadFailedException { + + // Id has to be wildcarded, since it was created using InstanceIdentifier.child() method + inOrder.verify(reader).getAllIds(eq(RWUtils.makeIidLastWildcarded(id)), any(ReadContext.class)); + keys.stream() + .map(k -> RWUtils.replaceLastInId(id, RWUtils.getCurrentIdItem(id, k))) + .forEach(keyedId -> { + try { + verify(reader).getBuilder(keyedId); + verify(reader).readCurrentAttributes(eq(keyedId), any(builderCls), any(ReadContext.class)); + } catch (ReadFailedException e) { throw new RuntimeException(e); } + }); + verify(reader, atLeastOnce()).merge(any(Builder.class), anyListOf(id.getTargetType())); + } + + private , K extends Identifier, B extends Builder> void verifyLeafListReader( + final InOrder inOrder, + final ListReader reader, + final InstanceIdentifier id) + throws ReadFailedException { + + // Id has to be wildcarded, since it was created using InstanceIdentifier.child() method + inOrder.verify(reader).readList(eq(RWUtils.makeIidLastWildcarded(id)), any(ReadContext.class)); + verify(reader, atLeastOnce()).merge(any(Builder.class), anyListOf(id.getTargetType())); + } + + private > void verifyRootReader(final InOrder inOrder, + final Reader reader, + final InstanceIdentifier id, + final Class builderCls) + throws ReadFailedException { + inOrder.verify(reader).readCurrentAttributes(eq(id), any(builderCls), any(ReadContext.class)); + verify(reader).getBuilder(id); + } + + + private > void verifyLeafChildReader(final InOrder inOrder, + final Reader reader, + final InstanceIdentifier... id) + throws ReadFailedException { + for (InstanceIdentifier singleId : id) { + inOrder.verify(reader).read(eq(singleId), any(ReadContext.class)); + verify(reader, atLeastOnce()).merge(any(Builder.class), any(singleId.getTargetType())); + } + } + + static > Reader mockReader(InstanceIdentifier id, + CurrentAttributesReader currentAttributesReader, + Class builderClass) { + final ReflexiveReader reflex = new ReflexiveReader(id, builderClass) { + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final B builder, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + currentAttributesReader.readCurrentAttributes(id, builder, ctx); + } + }; + + // Simple spy on top of this reflexive reader cannot be used, spy also checks protected methods for invocation + // but those cannot be verified by mockito + final Reader mock = mock(Reader.class); + try { + doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).read(any(InstanceIdentifier.class), any(ReadContext.class)); + doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock) + .readCurrentAttributes(any(InstanceIdentifier.class), any(builderClass), any(ReadContext.class)); + doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), any(id.getTargetType())); + doReturn(id).when(mock).getManagedDataObjectType(); + doReturn(builderClass.newInstance()).when(mock).getBuilder(any(InstanceIdentifier.class)); + } catch (Exception e) { + throw new RuntimeException(e); + } + + return mock; + } + + static , K extends Identifier, B extends Builder> ListReader mockListReader( + InstanceIdentifier id, + CurrentAttributesReader currentAttributesReader, + ListKeysReader listKeysReader, + Class builderClass) { + + ListReader reflex = new GenericListReader<>(id, + new ReflexiveListReaderCustomizer(id.getTargetType(), builderClass) { + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext context) + throws ReadFailedException { + return listKeysReader.getAllIds(id, context); + } + + @Override + public void readCurrentAttributes(final InstanceIdentifier id, final B builder, + final ReadContext context) + throws ReadFailedException { + currentAttributesReader.readCurrentAttributes(id, builder, context); + } + }); + + final ListReader mock = mock(ListReader.class /*, withSettings().verboseLogging()*/); + try { + // not using eq(id) instead using any(InstanceIdentifier.class) due to InstanceIdentifier.equals weird behavior + // with wildcarded instance identifiers for lists + doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).read(any(InstanceIdentifier.class), any(ReadContext.class)); + doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock) + .readCurrentAttributes(any(InstanceIdentifier.class), any(builderClass), any(ReadContext.class)); + doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), any(id.getTargetType())); + doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), anyListOf(id.getTargetType())); + doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).getAllIds(any(InstanceIdentifier.class), any(ReadContext.class)); + doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).readList(any(InstanceIdentifier.class), any(ReadContext.class)); + doReturn(id).when(mock).getManagedDataObjectType(); + doReturn(builderClass.newInstance()).when(mock).getBuilder(any(InstanceIdentifier.class)); + } catch (Exception e) { + throw new RuntimeException(e); + } + + return mock; + } + + private static > Object reflexiveAnswer(final Reader instance, + final InvocationOnMock i) { + try { + return i.getMethod().invoke(instance, i.getArguments()); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new MockitoConfigurationException("Unable to invoke stubbed method invocation: " + i + " on " + instance); + } + } + + @FunctionalInterface + interface CurrentAttributesReader> { + void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final B builder, + @Nonnull final ReadContext ctx); + } + + @FunctionalInterface + interface ListKeysReader, K extends Identifier> { + List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx); + } + + + private void readSimpleContainer(final InstanceIdentifier id, + final SimpleContainerBuilder b, + final ReadContext readContext) { + b.setSimpleContainerName("simple"); + } + + private SimpleContainer readSimpleContainer() { + final SimpleContainerBuilder b = new SimpleContainerBuilder(); + readSimpleContainer(Ids.SIMPLE_CONTAINER_ID, b, ctx); + b.addAugmentation(SimpleAugment.class, readSimpleAugment()); + b.addAugmentation(ComplexAugment.class, + new ComplexAugmentBuilder().setComplexAugmentContainer(readComplexAugmentContainer()).build()); + return b.build(); + } + + private void readSimpleAugment(final InstanceIdentifier id, + final SimpleAugmentBuilder b, + final ReadContext readContext) { + b.setSimpleAugmentLeaf("simple augment"); + } + + private SimpleAugment readSimpleAugment() { + final SimpleAugmentBuilder b = new SimpleAugmentBuilder(); + readSimpleAugment(Ids.SIMPLE_AUGMENT_ID, b, ctx); + return b.build(); + } + + private void readComplexAugmentContainer(final InstanceIdentifier id, + final ComplexAugmentContainerBuilder b, + final ReadContext readContext) { + b.setSomeLeaf("nested container in augment"); + } + + private ComplexAugmentContainer readComplexAugmentContainer() { + final ComplexAugmentContainerBuilder b = new ComplexAugmentContainerBuilder(); + readComplexAugmentContainer(Ids.COMPLEX_AUGMENT_CONTAINER_ID, b, ctx); + return b.build(); + } + + private ContainerWithList readContainerWithList() { + final ContainerWithListBuilder b = new ContainerWithListBuilder(); + b.setListInContainer(readListInContainer()); + return b.build(); + } + + private List getListInContainerIds(final InstanceIdentifier id, + final ReadContext readContext) { + return Lists.newArrayList(1L, 2L) + .stream() + .map(ListInContainerKey::new) + .collect(Collectors.toList()); + } + + private List getNestedListIds(final InstanceIdentifier id, + final ReadContext readContext) { + return Lists.newArrayList("one", "two") + .stream() + .map(NestedListKey::new) + .collect(Collectors.toList()); + } + + private void readListInContainer(final InstanceIdentifier id, + final ListInContainerBuilder b, + final ReadContext readContext) { + final ListInContainerKey key = id.firstKeyOf(ListInContainer.class); + b.setId(key.getId()); + final ContainerInListBuilder cilBuilder = new ContainerInListBuilder(); + readContainerInList(id.child(ContainerInList.class), cilBuilder, readContext); + b.setContainerInList(cilBuilder.build()); + } + + private void readNestedList(final InstanceIdentifier id, + final NestedListBuilder b, + final ReadContext readContext) { + final NestedListKey key = id.firstKeyOf(NestedList.class); + b.setNestedId(key.getNestedId()); + b.setNestedName(key.getNestedId() + "name"); + } + + private void readContainerInList(final InstanceIdentifier id, + final ContainerInListBuilder b, + final ReadContext readContext) { + b.setName(id.firstKeyOf(ListInContainer.class).getId().toString()); + b.setNestedList(getNestedListIds(Ids.NESTED_LIST_ID, ctx).stream() + .map(key -> id.child(NestedList.class, key)) + .map(nestedId -> { + final NestedListBuilder nestedB = new NestedListBuilder(); + readNestedList(nestedId, nestedB, readContext); + return nestedB.build(); + }) + .collect(Collectors.toList())); + } + + private List readListInContainer() { + return getListInContainerIds(Ids.LIST_IN_CONTAINER_ID, ctx).stream() + .map(key -> Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, key)) + .map(id -> { + final ListInContainerBuilder b = new ListInContainerBuilder(); + readListInContainer(id, b, ctx); + return b.build(); + }).collect(Collectors.toList()); + } + + static > void noopRead(final InstanceIdentifier id, final B b, + final ReadContext readContext) { + // NOOP + } + +} diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombSubtreeReadInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombSubtreeReadInfraTest.java new file mode 100644 index 000000000..a43f70a84 --- /dev/null +++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombSubtreeReadInfraTest.java @@ -0,0 +1,150 @@ +/* + * 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.data.impl; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.read.ListReader; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import io.fd.honeycomb.translate.util.read.ReflexiveListReaderCustomizer; +import io.fd.honeycomb.translate.util.read.registry.CompositeReaderRegistryBuilder; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public class HoneycombSubtreeReadInfraTest extends AbstractInfraTest { + + @Mock + private ReadContext ctx; + private ReaderRegistry registry; + + private Reader containerWithListReader = + HoneycombReadInfraTest.mockReader(Ids.CONTAINER_WITH_LIST_ID, this::readSubtree, ContainerWithListBuilder.class); + + private ListReader listInContainerReader = + new GenericListReader<>(Ids.LIST_IN_CONTAINER_ID, + new ReflexiveListReaderCustomizer(Ids.LIST_IN_CONTAINER_ID.getTargetType(), ListInContainerBuilder.class) { + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext context) + throws ReadFailedException { + // FIXME this is the only way of extending subtree reader via its list child + // Reflexive list reader has to be used in place of the list(managed by subtree reader perent) + // to enable further children readers. However, it will not work out of the box, because + // reflexive list reader has no way to tell what are the IDs to correctly invoke its children. + // Only way is to override the getAllIds method in reflexive reader and return the same list + // as parent used (this can be done using cache or repeated dump call) + return Lists.newArrayList(new ListInContainerKey(1L), new ListInContainerKey(2L)); + } + + @Override + public void readCurrentAttributes(final InstanceIdentifier id, + final ListInContainerBuilder builder, + final ReadContext context) throws ReadFailedException { + super.readCurrentAttributes(id, builder, context); + builder.setKey(id.firstKeyOf(ListInContainer.class)); + } + }); + + private Reader containerInListReader = + HoneycombReadInfraTest.mockReader(Ids.CONTAINER_IN_LIST_ID, this::readContainerInList, ContainerInListBuilder.class); + + // TODO Test subtree readers especially composite structure where readers are under subtree reader + + @Override + void postSetup() { + initReaderRegistry(); + } + + private void initReaderRegistry() { + registry = new CompositeReaderRegistryBuilder() + // Subtree reader handling its child list + .subtreeAdd(Sets.newHashSet(Ids.LIST_IN_CONTAINER_ID), containerWithListReader) + // Reflexive + .add(listInContainerReader) + .add(containerInListReader) + .build(); + } + + @Test + public void testReadAll() throws Exception { + final ReadableDataTreeDelegator readableDataTreeDelegator = + new ReadableDataTreeDelegator(serializer, schemaContext, registry, contextBroker); + final CheckedFuture>, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> + read = readableDataTreeDelegator.read(YangInstanceIdentifier.EMPTY); + + final Multimap, ? extends DataObject> readAll = + toBinding(read.checkedGet().get()); + assertThat(readAll.size(), is(1)); + assertEquals(readEntireSubtree(), readAll.get(Ids.CONTAINER_WITH_LIST_ID).stream().findFirst().get()); + } + + private void readSubtree(final InstanceIdentifier id, + final ContainerWithListBuilder b, + final ReadContext readContext) { + b.setListInContainer(Lists.newArrayList(1L, 2L).stream() + .map(l -> new ListInContainerBuilder().setId(l).build()) + .collect(Collectors.toList())); + } + + private ContainerWithList readEntireSubtree() { + final ContainerWithListBuilder b = new ContainerWithListBuilder(); + b.setListInContainer(Lists.newArrayList(1L, 2L).stream() + .map(l -> { + final ContainerInListBuilder containerInListBuilder = new ContainerInListBuilder(); + readContainerInList( + Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey(l)).child(ContainerInList.class), + containerInListBuilder, + ctx); + return new ListInContainerBuilder().setId(l).setContainerInList(containerInListBuilder.build()).build(); + }) + .collect(Collectors.toList())); + return b.build(); + } + + private void readContainerInList(final InstanceIdentifier id, + final ContainerInListBuilder b, + final ReadContext readContext) { + b.setName(id.firstKeyOf(ListInContainer.class).getId().toString()); + } +} diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java new file mode 100644 index 000000000..90a18dd7a --- /dev/null +++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java @@ -0,0 +1,522 @@ +/* + * 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.data.impl; + +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import io.fd.honeycomb.data.DataModification; +import io.fd.honeycomb.translate.util.write.registry.FlatWriterRegistryBuilder; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.Writer; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.mockito.InOrder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoice; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoiceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugmentBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainerBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.Choice; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainerBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGrouping; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGroupingBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +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.TipProducingDataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; +import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; + +/** + * Testing honeycomb writes from data tree up to mocked writers. + */ +public class HoneycombWriteInfraTest extends AbstractInfraTest { + + private TipProducingDataTree dataTree; + private WriterRegistry writerRegistry; + + Writer simpleContainerWriter = mockWriter(Ids.SIMPLE_CONTAINER_ID); + Writer complexAugmentWriter = mockWriter(Ids.COMPLEX_AUGMENT_ID); + Writer complexAugmentContainerWriter = mockWriter(Ids.COMPLEX_AUGMENT_CONTAINER_ID); + Writer simpleAugmentWriter = mockWriter(Ids.SIMPLE_AUGMENT_ID); + + Writer containerWithListWriter = mockWriter(Ids.CONTAINER_WITH_LIST_ID); + Writer listInContainerWriter = mockWriter(Ids.LIST_IN_CONTAINER_ID); + Writer containerInListWriter = mockWriter(Ids.CONTAINER_IN_LIST_ID); + Writer nestedListWriter = mockWriter(Ids.NESTED_LIST_ID); + + Writer containerWithChoiceWriter = mockWriter(Ids.CONTAINER_WITH_CHOICE_ID); + Writer containerFromGroupingWriter = mockWriter(Ids.CONTAINER_FROM_GROUPING_ID); + Writer c3Writer = mockWriter(Ids.C3_ID); + + + private static Writer mockWriter(final InstanceIdentifier id) { + final Writer mock = (Writer) mock(Writer.class); + when(mock.getManagedDataObjectType()).thenReturn(id); + return mock; + } + + @Override + void postSetup() { + initDataTree(); + initWriterRegistry(); + } + + private void initDataTree() { + dataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); + dataTree.setSchemaContext(schemaContext); + } + + private void initWriterRegistry() { + writerRegistry = new FlatWriterRegistryBuilder() + .add(complexAugmentWriter) // unordered + .add(nestedListWriter) // 6 + .addAfter(listInContainerWriter, Ids.NESTED_LIST_ID) // 7 + .addAfter(containerInListWriter, Ids.LIST_IN_CONTAINER_ID) // 8 + .addAfter(containerWithListWriter, Ids.CONTAINER_IN_LIST_ID) // 9 + .addBefore(containerFromGroupingWriter, Ids.NESTED_LIST_ID) // 5 + .addBefore(containerWithChoiceWriter, Ids.CONTAINER_FROM_GROUPING_ID) // 4 + .addBefore(simpleContainerWriter, Ids.CONTAINER_WITH_CHOICE_ID) // 3 + .addBefore(c3Writer, Ids.SIMPLE_CONTAINER_ID) // 2 + .addBefore(simpleAugmentWriter, Ids.SIMPLE_CONTAINER_ID) // 2 + .addBefore(complexAugmentContainerWriter, Sets.newHashSet(Ids.C3_ID, Ids.SIMPLE_AUGMENT_ID)) // 1 + .build(); + } + + @Test + public void testWriteEmptyNonPresenceContainer() throws Exception { + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker); + + final DataModification dataModification = modifiableDataTreeDelegator.newModification(); + final SimpleContainer data = new SimpleContainerBuilder() + .build(); + + final Map.Entry> normalizedNode = + serializer.toNormalizedNode(Ids.SIMPLE_CONTAINER_ID, data); + dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); + + dataModification.commit(); + + verify(simpleContainerWriter).getManagedDataObjectType(); + verifyNoMoreInteractions(simpleContainerWriter); + } + + @Test + public void testWriteEverything() throws Exception { + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker); + + final DataModification dataModification = modifiableDataTreeDelegator.newModification(); + // Now write everything we can + writeSimpleContainer(dataModification); + writeContainerWithChoice(dataModification); + writeContainerWithList(dataModification); + dataModification.commit(); + + final Writer[] orderedWriters = getOrderedWriters(); + final InOrder inOrder = inOrder(orderedWriters); + verifyOrderedWrites(orderedWriters, inOrder); + } + + private void verifyOrderedWrites(final Writer[] orderedWriters, final InOrder inOrder) + throws WriteFailedException { + // TODO Modifications are not produced for nodes that do not contain any actual leaves (except when choice is a child) do we need those triggers ? + // Unordered + // verify(complexAugmentWriter).update(eq(COMPLEX_AUGMENT_ID), eq(null), eq(getComplexAugment()), any(WriteContext.class)); + // 1 + inOrder.verify(complexAugmentContainerWriter) + .update(eq(Ids.COMPLEX_AUGMENT_CONTAINER_ID), eq(null), eq(getComplexAugmentContainer()), any(WriteContext.class)); + // 2 + inOrder.verify(c3Writer) + .update(eq(Ids.C3_ID), eq(null), eq(getC3()), any(WriteContext.class)); + // 2 + verify(simpleAugmentWriter) + .update(eq(Ids.SIMPLE_AUGMENT_ID), eq(null), eq(getSimpleAugment()), any(WriteContext.class)); + // 3 + inOrder.verify(simpleContainerWriter) + .update(eq(Ids.SIMPLE_CONTAINER_ID), eq(null), eq(getSimpleContainer()), any(WriteContext.class)); + // 4 + inOrder.verify(containerWithChoiceWriter) + .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(null), eq(getContainerWithChoiceWithComplexCase()), any(WriteContext.class)); + // 5 + inOrder.verify(containerFromGroupingWriter) + .update(eq(Ids.CONTAINER_FROM_GROUPING_ID), eq(null), eq(getContainerFromGrouping()), any(WriteContext.class)); + + final KeyedInstanceIdentifier keyedListInContainer1 = + Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 1)); + final KeyedInstanceIdentifier keyedNestedList1 = + keyedListInContainer1.child(ContainerInList.class).child(NestedList.class, new NestedListKey("1")); + final KeyedInstanceIdentifier keyedListInContainer2 = + Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 2)); + final KeyedInstanceIdentifier keyedNestedList2 = + keyedListInContainer2.child(ContainerInList.class).child(NestedList.class, new NestedListKey("2")); + + // 6 - two items + inOrder.verify(nestedListWriter) + .update(eq(keyedNestedList1), eq(null), eq(getSingleNestedList("1")), any(WriteContext.class)); + verify(nestedListWriter) + .update(eq(keyedNestedList2), eq(null), eq(getSingleNestedList("2")), any(WriteContext.class)); + + // 7 - two items + inOrder.verify(listInContainerWriter) + .update(eq(keyedListInContainer1), eq(null), eq(getSingleListInContainer((long)1)), any(WriteContext.class)); + verify(listInContainerWriter) + .update(eq(keyedListInContainer2), eq(null), eq(getSingleListInContainer((long)2)), any(WriteContext.class)); + + // 8 + inOrder.verify(containerInListWriter) + .update(eq(keyedListInContainer1.child(ContainerInList.class)), eq(null), eq(getContainerInList("1")), any(WriteContext.class)); + verify(containerInListWriter) + .update(eq(keyedListInContainer2.child(ContainerInList.class)), eq(null), eq(getContainerInList("2")), any(WriteContext.class)); + + // 9 - Ignored because the container has no leaves, only complex child nodes + // inOrder.verify(containerWithListWriter) + // .update(eq(CONTAINER_WITH_LIST_ID), eq(null), eq(getContainerWithList()), any(WriteContext.class)); + + for (Writer orderedWriter : orderedWriters) { + verify(orderedWriter).getManagedDataObjectType(); + verifyNoMoreInteractions(orderedWriter); + } + } + + private Writer[] getOrderedWriters() { + return new Writer[]{complexAugmentWriter, // Unordered + complexAugmentContainerWriter, // 1 + c3Writer, // 2 + simpleAugmentWriter, // 2 + simpleContainerWriter, // 3 + containerWithChoiceWriter, // 4 + containerFromGroupingWriter, // 5 + nestedListWriter, // 6 + listInContainerWriter, // 7 + containerInListWriter, // 8 + containerWithListWriter}; + } + + @Test + public void testDeletes() throws Exception { + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker); + + DataModification dataModification = modifiableDataTreeDelegator.newModification(); + // Now write everything we can + writeSimpleContainer(dataModification); + writeContainerWithChoice(dataModification); + writeContainerWithList(dataModification); + dataModification.commit(); + // Verify writes to be able to verifyNoMore interactions at the end + verifyOrderedWrites(getOrderedWriters(), inOrder(getOrderedWriters())); + + dataModification = modifiableDataTreeDelegator.newModification(); + deleteSimpleContainer(dataModification); + deleteContainerWithChoice(dataModification); + deleteContainerWithList(dataModification); + dataModification.commit(); + + final Writer[] orderedWriters = getOrderedWriters(); + Collections.reverse(Arrays.asList(orderedWriters)); + final InOrder inOrder = inOrder(orderedWriters); + + final KeyedInstanceIdentifier keyedListInContainer1 = + Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 1)); + final KeyedInstanceIdentifier keyedNestedList1 = + keyedListInContainer1.child(ContainerInList.class).child(NestedList.class, new NestedListKey("1")); + final KeyedInstanceIdentifier keyedListInContainer2 = + Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 2)); + final KeyedInstanceIdentifier keyedNestedList2 = + keyedListInContainer2.child(ContainerInList.class).child(NestedList.class, new NestedListKey("2")); + + // Deletes are handled in reverse order + // 1 + inOrder.verify(containerInListWriter) + .update(eq(keyedListInContainer1.child(ContainerInList.class)), eq(getContainerInList("1")), eq(null), any(WriteContext.class)); + verify(containerInListWriter) + .update(eq(keyedListInContainer2.child(ContainerInList.class)), eq(getContainerInList("2")), eq(null), any(WriteContext.class)); + + // 2 + inOrder.verify(listInContainerWriter) + .update(eq(keyedListInContainer1), eq(getSingleListInContainer((long)1)), eq(null), any(WriteContext.class)); + verify(listInContainerWriter) + .update(eq(keyedListInContainer2), eq(getSingleListInContainer((long)2)), eq(null), any(WriteContext.class)); + + // 3 + inOrder.verify(nestedListWriter) + .update(eq(keyedNestedList1), eq(getSingleNestedList("1")), eq(null), any(WriteContext.class)); + verify(nestedListWriter) + .update(eq(keyedNestedList2), eq(getSingleNestedList("2")), eq(null), any(WriteContext.class)); + // 4 + inOrder.verify(containerFromGroupingWriter) + .update(eq(Ids.CONTAINER_FROM_GROUPING_ID), eq(getContainerFromGrouping()), eq(null), any(WriteContext.class)); + // 5 + inOrder.verify(containerWithChoiceWriter) + .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(getContainerWithChoiceWithComplexCase()), eq(null), any(WriteContext.class)); + // 6 + inOrder.verify(simpleContainerWriter) + .update(eq(Ids.SIMPLE_CONTAINER_ID), eq(getSimpleContainer()), eq(null), any(WriteContext.class)); + // 7 + verify(simpleAugmentWriter) + .update(eq(Ids.SIMPLE_AUGMENT_ID), eq(getSimpleAugment()), eq(null), any(WriteContext.class)); + // 8 + inOrder.verify(c3Writer) + .update(eq(Ids.C3_ID), eq(getC3()), eq(null), any(WriteContext.class)); + // 9 + inOrder.verify(complexAugmentContainerWriter) + .update(eq(Ids.COMPLEX_AUGMENT_CONTAINER_ID), eq(getComplexAugmentContainer()), eq(null), any(WriteContext.class)); + + for (Writer orderedWriter : orderedWriters) { + verify(orderedWriter).getManagedDataObjectType(); + verifyNoMoreInteractions(orderedWriter); + } + } + + private void writeContainerWithList(final DataModification dataModification) { + final Map.Entry> normalizedNode = + serializer.toNormalizedNode(Ids.CONTAINER_WITH_LIST_ID, getContainerWithList()); + dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); + } + + private void deleteContainerWithList(final DataModification dataModification) { + dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_WITH_LIST_ID)); + } + + private ContainerWithList getContainerWithList() { + return new ContainerWithListBuilder() + .setListInContainer(getListInContainer((long)1, (long)2)) + .build(); + } + + private List getListInContainer(final Long... keys) { + final ArrayList objects = Lists.newArrayList(); + for (Long key : keys) { + objects.add(getSingleListInContainer(key)); + } + return objects; + } + + private ListInContainer getSingleListInContainer(final Long key) { + return new ListInContainerBuilder() + .setId(key) + .setContainerInList(getContainerInList(Long.toString(key))) + .build(); + } + + private ContainerInList getContainerInList(String... nestedKeys) { + return new ContainerInListBuilder() + .setName("inlist") + .setNestedList(getNestedList(nestedKeys)) + .build(); + } + + private List getNestedList(String... keys) { + final ArrayList nestedList = new ArrayList<>(); + for (String key : keys) { + nestedList.add(getSingleNestedList(key)); + } + return nestedList; + } + + private NestedList getSingleNestedList(final String key) { + return new NestedListBuilder() + .setNestedId(key) + .setNestedName(key) + .build(); + } + + private void writeContainerWithChoice(final DataModification dataModification) { + writeContainerWithChoice(dataModification, getContainerWithChoiceWithComplexCase()); + } + + + private void deleteContainerWithChoice(final DataModification dataModification) { + dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_WITH_CHOICE_ID)); + } + + private void writeContainerWithChoice(final DataModification dataModification, + final ContainerWithChoice containerWithChoice) { + final Map.Entry> normalizedNode = + serializer.toNormalizedNode(Ids.CONTAINER_WITH_CHOICE_ID, containerWithChoice); + dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); + } + + private ContainerWithChoice getContainerWithChoiceWithComplexCase() { + return new ContainerWithChoiceBuilder() + .setLeafFromGrouping("fromG") + .setName("name") + .setContainerFromGrouping(getContainerFromGrouping()) + .setChoice(getComplexCase()) + .build(); + } + + private Choice getComplexCase() { + return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.C3Builder() + .setC3(getC3()) + .build(); + } + + private C3 getC3() { + return new C3Builder() + .setName("c3") + .build(); + } + + private void writeContainerFromGrouping(final DataModification dataModification) { + final Map.Entry> normalizedNode = + serializer.toNormalizedNode(Ids.CONTAINER_FROM_GROUPING_ID, getContainerFromGrouping()); + dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); + } + + private ContainerFromGrouping getContainerFromGrouping() { + return new ContainerFromGroupingBuilder() + .setLeafInContainerFromGrouping(111) + .build(); + } + + + private void writeSimpleContainer(final DataModification dataModification) { + final Map.Entry> normalizedNode = + serializer.toNormalizedNode(Ids.SIMPLE_CONTAINER_ID, getSimpleContainer()); + dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); + } + + private void deleteSimpleContainer(final DataModification dataModification) { + final YangInstanceIdentifier yangId = + serializer.toYangInstanceIdentifier(Ids.SIMPLE_CONTAINER_ID); + dataModification.delete(yangId); + } + + private SimpleContainer getSimpleContainer() { + return new SimpleContainerBuilder() + .setSimpleContainerName("n") + .addAugmentation(SimpleAugment.class, getSimpleAugment()) + .addAugmentation(ComplexAugment.class, getComplexAugment()) + .build(); + } + + private ComplexAugment getComplexAugment() { + return new ComplexAugmentBuilder() + .setComplexAugmentContainer(getComplexAugmentContainer()) + .build(); + } + + private ComplexAugmentContainer getComplexAugmentContainer() { + return new ComplexAugmentContainerBuilder().setSomeLeaf("s").build(); + } + + private SimpleAugment getSimpleAugment() { + return new SimpleAugmentBuilder().setSimpleAugmentLeaf("a").build(); + } + + @Test + public void testWriteAndDeleteInTx() throws Exception { + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker); + + final DataModification dataModification = modifiableDataTreeDelegator.newModification(); + // Now write everything we can + writeSimpleContainer(dataModification); + deleteSimpleContainer(dataModification); + dataModification.commit(); + + verify(simpleContainerWriter).getManagedDataObjectType(); + // No modification + verifyNoMoreInteractions(simpleContainerWriter); + } + + @Test + public void testSubtreeWriter() throws Exception { + writerRegistry = new FlatWriterRegistryBuilder() + // Handles also container from grouping + .subtreeAdd(Sets.newHashSet(Ids.CONTAINER_FROM_GROUPING_ID), containerWithChoiceWriter) + .build(); + + final ModifiableDataTreeDelegator modifiableDataTreeDelegator = + new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker); + + final ContainerWithChoice containerWithChoice = + new ContainerWithChoiceBuilder().setContainerFromGrouping(getContainerFromGrouping()).build(); + + // Test write subtree node + DataModification dataModification = modifiableDataTreeDelegator.newModification(); + writeContainerFromGrouping(dataModification); + dataModification.commit(); + + verify(containerWithChoiceWriter, atLeastOnce()).getManagedDataObjectType(); + verify(containerWithChoiceWriter) + .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(null), eq(containerWithChoice), any(WriteContext.class)); + verifyNoMoreInteractions(containerWithChoiceWriter); + + // Test delete sub-node + dataModification = modifiableDataTreeDelegator.newModification(); + final ContainerWithChoice containerWithChoiceEmpty = new ContainerWithChoiceBuilder().build(); + deleteContainerFromGrouping(dataModification); + dataModification.commit(); + + verify(containerWithChoiceWriter, atLeastOnce()).getManagedDataObjectType(); + verify(containerWithChoiceWriter) + .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(containerWithChoice), eq(containerWithChoiceEmpty), any(WriteContext.class)); + verifyNoMoreInteractions(containerWithChoiceWriter); + + // Test write with subtree node that's not handled by subtree writer + dataModification = modifiableDataTreeDelegator.newModification(); + writeContainerWithChoice(dataModification); + try { + dataModification.commit(); + fail("Missing writer for C3 should occur"); + } catch (IllegalArgumentException e) { + return; + } + } + + private void deleteContainerFromGrouping(final DataModification dataModification) { + dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_FROM_GROUPING_ID)); + } +} \ No newline at end of file diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/Ids.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/Ids.java new file mode 100644 index 000000000..1ef83a0ed --- /dev/null +++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/Ids.java @@ -0,0 +1,62 @@ +/* + * 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.data.impl; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoice; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGrouping; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Instance identifiers referencing all complex nodes within IT test-model. + */ +interface Ids { + + // Simple container + // ORDER = 3 + InstanceIdentifier SIMPLE_CONTAINER_ID = InstanceIdentifier.create(SimpleContainer.class); + // 2 + InstanceIdentifier SIMPLE_AUGMENT_ID = SIMPLE_CONTAINER_ID.augmentation(SimpleAugment.class); + // UNORDERED + InstanceIdentifier COMPLEX_AUGMENT_ID = SIMPLE_CONTAINER_ID.augmentation(ComplexAugment.class); + // 1 + InstanceIdentifier COMPLEX_AUGMENT_CONTAINER_ID = COMPLEX_AUGMENT_ID.child(ComplexAugmentContainer.class); + // Container with list + // 9 + InstanceIdentifier CONTAINER_WITH_LIST_ID = InstanceIdentifier.create(ContainerWithList.class); + // 7 + InstanceIdentifier LIST_IN_CONTAINER_ID = CONTAINER_WITH_LIST_ID.child(ListInContainer.class); + // 8 + InstanceIdentifier CONTAINER_IN_LIST_ID = LIST_IN_CONTAINER_ID.child(ContainerInList.class); + // 6 + InstanceIdentifier NESTED_LIST_ID = CONTAINER_IN_LIST_ID.child(NestedList.class); + // Container with choice + // 4 + InstanceIdentifier CONTAINER_WITH_CHOICE_ID = InstanceIdentifier.create(ContainerWithChoice.class); + // 2 + InstanceIdentifier C3_ID = CONTAINER_WITH_CHOICE_ID.child(C3.class); + // 5 + InstanceIdentifier CONTAINER_FROM_GROUPING_ID = CONTAINER_WITH_CHOICE_ID.child(ContainerFromGrouping.class); +} diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/AbstractInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/AbstractInfraTest.java deleted file mode 100644 index 47644cc70..000000000 --- a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/AbstractInfraTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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.data.impl; - -import static org.mockito.Mockito.when; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.Futures; -import java.util.Collections; -import java.util.Map; -import javassist.ClassPool; -import org.junit.Before; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.$YangModuleInfoImpl; -import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; -import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; -import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; -import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext; -import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; - -/** - * Base IT test infrastructure. - */ -abstract class AbstractInfraTest { - - protected BindingNormalizedNodeSerializer serializer; - protected SchemaContext schemaContext; - - @Mock - protected org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker; - @Mock - private org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction ctxTx; - - static BindingToNormalizedNodeCodec getSerializer(final ModuleInfoBackedContext moduleInfoBackedContext, - final SchemaContext schemaContext) { - final DataObjectSerializerGenerator serializerGenerator = new StreamWriterGenerator(JavassistUtils.forClassPool( - ClassPool.getDefault())); - final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(serializerGenerator); - final BindingRuntimeContext ctx = - BindingRuntimeContext.create(moduleInfoBackedContext, schemaContext); - codecRegistry.onBindingRuntimeContextUpdated(ctx); - return new BindingToNormalizedNodeCodec(moduleInfoBackedContext, codecRegistry); - } - - static ModuleInfoBackedContext getSchemaContext() { - final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create(); - moduleInfoBackedContext.addModuleInfos(Collections.singleton($YangModuleInfoImpl.getInstance())); - return moduleInfoBackedContext; - } - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - when(contextBroker.newReadWriteTransaction()).thenReturn(ctxTx); - when(ctxTx.submit()).thenReturn(Futures.immediateCheckedFuture(null)); - - initSerializer(); - postSetup(); - } - - abstract void postSetup(); - - private void initSerializer() { - final ModuleInfoBackedContext moduleInfoBackedContext = getSchemaContext(); - schemaContext = moduleInfoBackedContext.tryToCreateSchemaContext().get(); - serializer = getSerializer(moduleInfoBackedContext, schemaContext); - } - - protected Multimap, ? extends DataObject> toBinding( - final NormalizedNode read) { - Multimap, DataObject> baNodes = HashMultimap.create(); - - for (DataContainerChild o : ((DataContainerNode) read).getValue()) { - final YangInstanceIdentifier yid = YangInstanceIdentifier.of(o.getNodeType()); - final Map.Entry, DataObject> baEntry = serializer.fromNormalizedNode(yid, o); - baNodes.put(baEntry.getKey(), baEntry.getValue()); - } - return baNodes; - } -} diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombReadInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombReadInfraTest.java deleted file mode 100644 index b1f3a196a..000000000 --- a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombReadInfraTest.java +++ /dev/null @@ -1,460 +0,0 @@ -/* - * 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.data.impl; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyListOf; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader; -import io.fd.honeycomb.v3po.translate.read.ListReader; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.util.read.ReflexiveListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.util.read.ReflexiveReader; -import io.fd.honeycomb.v3po.translate.util.read.registry.CompositeReaderRegistryBuilder; -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.exceptions.misusing.MockitoConfigurationException; -import org.mockito.invocation.InvocationOnMock; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugmentBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugmentBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainerBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainerBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -public class HoneycombReadInfraTest extends AbstractInfraTest { - - @Mock - private ReadContext ctx; - private ReaderRegistry registry; - - // 1 - private Reader simpleContainerReader = - mockReader(Ids.SIMPLE_CONTAINER_ID, this::readSimpleContainer, SimpleContainerBuilder.class); - // 1.1 - private Reader simpleAugmentReader = - mockReader(Ids.SIMPLE_AUGMENT_ID, this::readSimpleAugment, SimpleAugmentBuilder.class); - // 1.2 - // Noop reader(no real attributes) - private Reader complexAugmentReader = - mockReader(Ids.COMPLEX_AUGMENT_ID, HoneycombReadInfraTest::noopRead, ComplexAugmentBuilder.class); - // 1.2.1 - private Reader complexAugmentContainerReader = - mockReader(Ids.COMPLEX_AUGMENT_CONTAINER_ID, this::readComplexAugmentContainer, ComplexAugmentContainerBuilder.class); - // 2 - // Noop reader(no real attributes) - private Reader containerWithListReader = - mockReader(Ids.CONTAINER_WITH_LIST_ID, HoneycombReadInfraTest::noopRead, ContainerWithListBuilder.class); - // 2.1 - private ListReader listInContainerReader = - mockListReader(Ids.LIST_IN_CONTAINER_ID, this::readListInContainer, this::getListInContainerIds, - ListInContainerBuilder.class); - // 2.1.1 - private Reader containerInListReader = - mockReader(Ids.CONTAINER_IN_LIST_ID, this::readContainerInList, ContainerInListBuilder.class); - // 2.1.1.1 - private ListReader nestedListReader = - mockListReader(Ids.NESTED_LIST_ID, this::readNestedList, this::getNestedListIds, - NestedListBuilder.class); - - @Override - void postSetup() { - initReaderRegistry(); - } - - private void initReaderRegistry() { - registry = new CompositeReaderRegistryBuilder() - .add(containerWithListReader) // 2 - .addBefore(simpleContainerReader, Ids.CONTAINER_WITH_LIST_ID) // 1 - .add(simpleAugmentReader) // 1.1 - .addAfter(complexAugmentReader, Ids.SIMPLE_AUGMENT_ID) // 1.2 - .add(complexAugmentContainerReader) // 1.2.1 - .add(listInContainerReader) // 2.1 - .add(containerInListReader) // 2.1.1 - .addBefore(nestedListReader, Ids.SIMPLE_AUGMENT_ID) // 2.1.1.1 - Before relationship should be ignored - .build(); - } - - private Reader[] getOrderedReaders() { - return new Reader[]{simpleContainerReader, // 1 - simpleAugmentReader, // 1.1 - complexAugmentReader, // 1.2 - complexAugmentContainerReader, // 1.2.1 - containerWithListReader, // 2 - listInContainerReader, // 2.1 - containerInListReader, // 2.1.1 - nestedListReader}; // 2.1.1.1 - } - - @Test - public void testReadAll() throws Exception { - final ReadableDataTreeDelegator readableDataTreeDelegator = - new ReadableDataTreeDelegator(serializer, schemaContext, registry, contextBroker); - final CheckedFuture>, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> - read = readableDataTreeDelegator.read(YangInstanceIdentifier.EMPTY); - - final Multimap, ? extends DataObject> readAll = - toBinding(read.checkedGet().get()); - assertThat(readAll.size(), is(2)); - assertTrue(readAll.containsKey(Ids.CONTAINER_WITH_LIST_ID)); - assertEquals(readContainerWithList(), readAll.get(Ids.CONTAINER_WITH_LIST_ID).stream().findFirst().get()); - assertTrue(readAll.containsKey(Ids.SIMPLE_CONTAINER_ID)); - assertEquals(readSimpleContainer(), readAll.get(Ids.SIMPLE_CONTAINER_ID).stream().findFirst().get()); - - final Reader[] ordered = getOrderedReaders(); - final InOrder inOrder = inOrder(ordered); - - final List listInContainerKeys = getListInContainerIds(Ids.LIST_IN_CONTAINER_ID, ctx); - - verifyRootReader(inOrder, simpleContainerReader, Ids.SIMPLE_CONTAINER_ID, SimpleContainerBuilder.class); - verifyLeafChildReader(inOrder, simpleAugmentReader, Ids.SIMPLE_AUGMENT_ID); - verifyCompositeChildReader(inOrder, complexAugmentReader, ComplexAugmentBuilder.class, Ids.COMPLEX_AUGMENT_ID); - verifyLeafChildReader(inOrder, complexAugmentContainerReader, Ids.COMPLEX_AUGMENT_CONTAINER_ID); - verifyRootReader(inOrder, containerWithListReader, Ids.CONTAINER_WITH_LIST_ID, ContainerWithListBuilder.class); - verifyCompositeListReader(inOrder, listInContainerReader, Ids.LIST_IN_CONTAINER_ID, - listInContainerKeys, ListInContainerBuilder.class); - - for (ListInContainerKey k : listInContainerKeys) { - final InstanceIdentifier id = - Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, k).child(ContainerInList.class); - verifyCompositeChildReader(inOrder, containerInListReader, ContainerInListBuilder.class, id); - final InstanceIdentifier nestedId = id.child(NestedList.class); - verifyLeafListReader(inOrder, nestedListReader, nestedId); - } - - for (Reader reader : ordered) { - verifyNoMoreReadInteractions(reader); - } - } - - private > void verifyNoMoreReadInteractions(final Reader reader) { - verify(reader, atLeastOnce()).getManagedDataObjectType(); - verifyNoMoreInteractions(reader); - } - - private > void verifyCompositeChildReader(final InOrder inOrder, - final Reader reader, - final Class builderCls, - final InstanceIdentifier id) - throws ReadFailedException { - verifyRootReader(inOrder, reader, id, builderCls); - verify(reader, atLeastOnce()).merge(any(Builder.class), any(id.getTargetType())); - } - - private , K extends Identifier, B extends Builder> void verifyCompositeListReader( - final InOrder inOrder, - final ListReader reader, - final InstanceIdentifier id, - final List keys, - final Class builderCls) - throws ReadFailedException { - - // Id has to be wildcarded, since it was created using InstanceIdentifier.child() method - inOrder.verify(reader).getAllIds(eq(RWUtils.makeIidLastWildcarded(id)), any(ReadContext.class)); - keys.stream() - .map(k -> RWUtils.replaceLastInId(id, RWUtils.getCurrentIdItem(id, k))) - .forEach(keyedId -> { - try { - verify(reader).getBuilder(keyedId); - verify(reader).readCurrentAttributes(eq(keyedId), any(builderCls), any(ReadContext.class)); - } catch (ReadFailedException e) { throw new RuntimeException(e); } - }); - verify(reader, atLeastOnce()).merge(any(Builder.class), anyListOf(id.getTargetType())); - } - - private , K extends Identifier, B extends Builder> void verifyLeafListReader( - final InOrder inOrder, - final ListReader reader, - final InstanceIdentifier id) - throws ReadFailedException { - - // Id has to be wildcarded, since it was created using InstanceIdentifier.child() method - inOrder.verify(reader).readList(eq(RWUtils.makeIidLastWildcarded(id)), any(ReadContext.class)); - verify(reader, atLeastOnce()).merge(any(Builder.class), anyListOf(id.getTargetType())); - } - - private > void verifyRootReader(final InOrder inOrder, - final Reader reader, - final InstanceIdentifier id, - final Class builderCls) - throws ReadFailedException { - inOrder.verify(reader).readCurrentAttributes(eq(id), any(builderCls), any(ReadContext.class)); - verify(reader).getBuilder(id); - } - - - private > void verifyLeafChildReader(final InOrder inOrder, - final Reader reader, - final InstanceIdentifier... id) - throws ReadFailedException { - for (InstanceIdentifier singleId : id) { - inOrder.verify(reader).read(eq(singleId), any(ReadContext.class)); - verify(reader, atLeastOnce()).merge(any(Builder.class), any(singleId.getTargetType())); - } - } - - static > Reader mockReader(InstanceIdentifier id, - CurrentAttributesReader currentAttributesReader, - Class builderClass) { - final ReflexiveReader reflex = new ReflexiveReader(id, builderClass) { - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final B builder, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - currentAttributesReader.readCurrentAttributes(id, builder, ctx); - } - }; - - // Simple spy on top of this reflexive reader cannot be used, spy also checks protected methods for invocation - // but those cannot be verified by mockito - final Reader mock = mock(Reader.class); - try { - doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).read(any(InstanceIdentifier.class), any(ReadContext.class)); - doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock) - .readCurrentAttributes(any(InstanceIdentifier.class), any(builderClass), any(ReadContext.class)); - doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), any(id.getTargetType())); - doReturn(id).when(mock).getManagedDataObjectType(); - doReturn(builderClass.newInstance()).when(mock).getBuilder(any(InstanceIdentifier.class)); - } catch (Exception e) { - throw new RuntimeException(e); - } - - return mock; - } - - static , K extends Identifier, B extends Builder> ListReader mockListReader( - InstanceIdentifier id, - CurrentAttributesReader currentAttributesReader, - ListKeysReader listKeysReader, - Class builderClass) { - - ListReader reflex = new GenericListReader<>(id, - new ReflexiveListReaderCustomizer(id.getTargetType(), builderClass) { - - @Nonnull - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext context) - throws ReadFailedException { - return listKeysReader.getAllIds(id, context); - } - - @Override - public void readCurrentAttributes(final InstanceIdentifier id, final B builder, - final ReadContext context) - throws ReadFailedException { - currentAttributesReader.readCurrentAttributes(id, builder, context); - } - }); - - final ListReader mock = mock(ListReader.class /*, withSettings().verboseLogging()*/); - try { - // not using eq(id) instead using any(InstanceIdentifier.class) due to InstanceIdentifier.equals weird behavior - // with wildcarded instance identifiers for lists - doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).read(any(InstanceIdentifier.class), any(ReadContext.class)); - doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock) - .readCurrentAttributes(any(InstanceIdentifier.class), any(builderClass), any(ReadContext.class)); - doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), any(id.getTargetType())); - doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), anyListOf(id.getTargetType())); - doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).getAllIds(any(InstanceIdentifier.class), any(ReadContext.class)); - doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).readList(any(InstanceIdentifier.class), any(ReadContext.class)); - doReturn(id).when(mock).getManagedDataObjectType(); - doReturn(builderClass.newInstance()).when(mock).getBuilder(any(InstanceIdentifier.class)); - } catch (Exception e) { - throw new RuntimeException(e); - } - - return mock; - } - - private static > Object reflexiveAnswer(final Reader instance, - final InvocationOnMock i) { - try { - return i.getMethod().invoke(instance, i.getArguments()); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new MockitoConfigurationException("Unable to invoke stubbed method invocation: " + i + " on " + instance); - } - } - - @FunctionalInterface - interface CurrentAttributesReader> { - void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final B builder, - @Nonnull final ReadContext ctx); - } - - @FunctionalInterface - interface ListKeysReader, K extends Identifier> { - List getAllIds(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx); - } - - - private void readSimpleContainer(final InstanceIdentifier id, - final SimpleContainerBuilder b, - final ReadContext readContext) { - b.setSimpleContainerName("simple"); - } - - private SimpleContainer readSimpleContainer() { - final SimpleContainerBuilder b = new SimpleContainerBuilder(); - readSimpleContainer(Ids.SIMPLE_CONTAINER_ID, b, ctx); - b.addAugmentation(SimpleAugment.class, readSimpleAugment()); - b.addAugmentation(ComplexAugment.class, - new ComplexAugmentBuilder().setComplexAugmentContainer(readComplexAugmentContainer()).build()); - return b.build(); - } - - private void readSimpleAugment(final InstanceIdentifier id, - final SimpleAugmentBuilder b, - final ReadContext readContext) { - b.setSimpleAugmentLeaf("simple augment"); - } - - private SimpleAugment readSimpleAugment() { - final SimpleAugmentBuilder b = new SimpleAugmentBuilder(); - readSimpleAugment(Ids.SIMPLE_AUGMENT_ID, b, ctx); - return b.build(); - } - - private void readComplexAugmentContainer(final InstanceIdentifier id, - final ComplexAugmentContainerBuilder b, - final ReadContext readContext) { - b.setSomeLeaf("nested container in augment"); - } - - private ComplexAugmentContainer readComplexAugmentContainer() { - final ComplexAugmentContainerBuilder b = new ComplexAugmentContainerBuilder(); - readComplexAugmentContainer(Ids.COMPLEX_AUGMENT_CONTAINER_ID, b, ctx); - return b.build(); - } - - private ContainerWithList readContainerWithList() { - final ContainerWithListBuilder b = new ContainerWithListBuilder(); - b.setListInContainer(readListInContainer()); - return b.build(); - } - - private List getListInContainerIds(final InstanceIdentifier id, - final ReadContext readContext) { - return Lists.newArrayList(1L, 2L) - .stream() - .map(ListInContainerKey::new) - .collect(Collectors.toList()); - } - - private List getNestedListIds(final InstanceIdentifier id, - final ReadContext readContext) { - return Lists.newArrayList("one", "two") - .stream() - .map(NestedListKey::new) - .collect(Collectors.toList()); - } - - private void readListInContainer(final InstanceIdentifier id, - final ListInContainerBuilder b, - final ReadContext readContext) { - final ListInContainerKey key = id.firstKeyOf(ListInContainer.class); - b.setId(key.getId()); - final ContainerInListBuilder cilBuilder = new ContainerInListBuilder(); - readContainerInList(id.child(ContainerInList.class), cilBuilder, readContext); - b.setContainerInList(cilBuilder.build()); - } - - private void readNestedList(final InstanceIdentifier id, - final NestedListBuilder b, - final ReadContext readContext) { - final NestedListKey key = id.firstKeyOf(NestedList.class); - b.setNestedId(key.getNestedId()); - b.setNestedName(key.getNestedId() + "name"); - } - - private void readContainerInList(final InstanceIdentifier id, - final ContainerInListBuilder b, - final ReadContext readContext) { - b.setName(id.firstKeyOf(ListInContainer.class).getId().toString()); - b.setNestedList(getNestedListIds(Ids.NESTED_LIST_ID, ctx).stream() - .map(key -> id.child(NestedList.class, key)) - .map(nestedId -> { - final NestedListBuilder nestedB = new NestedListBuilder(); - readNestedList(nestedId, nestedB, readContext); - return nestedB.build(); - }) - .collect(Collectors.toList())); - } - - private List readListInContainer() { - return getListInContainerIds(Ids.LIST_IN_CONTAINER_ID, ctx).stream() - .map(key -> Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, key)) - .map(id -> { - final ListInContainerBuilder b = new ListInContainerBuilder(); - readListInContainer(id, b, ctx); - return b.build(); - }).collect(Collectors.toList()); - } - - static > void noopRead(final InstanceIdentifier id, final B b, - final ReadContext readContext) { - // NOOP - } - -} diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombSubtreeReadInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombSubtreeReadInfraTest.java deleted file mode 100644 index 8faeb84b6..000000000 --- a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombSubtreeReadInfraTest.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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.data.impl; - -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader; -import io.fd.honeycomb.v3po.translate.read.ListReader; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry; -import io.fd.honeycomb.v3po.translate.util.read.ReflexiveListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.util.read.registry.CompositeReaderRegistryBuilder; -import java.util.List; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -public class HoneycombSubtreeReadInfraTest extends AbstractInfraTest { - - @Mock - private ReadContext ctx; - private ReaderRegistry registry; - - private Reader containerWithListReader = - HoneycombReadInfraTest.mockReader(Ids.CONTAINER_WITH_LIST_ID, this::readSubtree, ContainerWithListBuilder.class); - - private ListReader listInContainerReader = - new GenericListReader<>(Ids.LIST_IN_CONTAINER_ID, - new ReflexiveListReaderCustomizer(Ids.LIST_IN_CONTAINER_ID.getTargetType(), ListInContainerBuilder.class) { - - @Nonnull - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext context) - throws ReadFailedException { - // FIXME this is the only way of extending subtree reader via its list child - // Reflexive list reader has to be used in place of the list(managed by subtree reader perent) - // to enable further children readers. However, it will not work out of the box, because - // reflexive list reader has no way to tell what are the IDs to correctly invoke its children. - // Only way is to override the getAllIds method in reflexive reader and return the same list - // as parent used (this can be done using cache or repeated dump call) - return Lists.newArrayList(new ListInContainerKey(1L), new ListInContainerKey(2L)); - } - - @Override - public void readCurrentAttributes(final InstanceIdentifier id, - final ListInContainerBuilder builder, - final ReadContext context) throws ReadFailedException { - super.readCurrentAttributes(id, builder, context); - builder.setKey(id.firstKeyOf(ListInContainer.class)); - } - }); - - private Reader containerInListReader = - HoneycombReadInfraTest.mockReader(Ids.CONTAINER_IN_LIST_ID, this::readContainerInList, ContainerInListBuilder.class); - - // TODO Test subtree readers especially composite structure where readers are under subtree reader - - @Override - void postSetup() { - initReaderRegistry(); - } - - private void initReaderRegistry() { - registry = new CompositeReaderRegistryBuilder() - // Subtree reader handling its child list - .subtreeAdd(Sets.newHashSet(Ids.LIST_IN_CONTAINER_ID), containerWithListReader) - // Reflexive - .add(listInContainerReader) - .add(containerInListReader) - .build(); - } - - @Test - public void testReadAll() throws Exception { - final ReadableDataTreeDelegator readableDataTreeDelegator = - new ReadableDataTreeDelegator(serializer, schemaContext, registry, contextBroker); - final CheckedFuture>, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> - read = readableDataTreeDelegator.read(YangInstanceIdentifier.EMPTY); - - final Multimap, ? extends DataObject> readAll = - toBinding(read.checkedGet().get()); - assertThat(readAll.size(), is(1)); - assertEquals(readEntireSubtree(), readAll.get(Ids.CONTAINER_WITH_LIST_ID).stream().findFirst().get()); - } - - private void readSubtree(final InstanceIdentifier id, - final ContainerWithListBuilder b, - final ReadContext readContext) { - b.setListInContainer(Lists.newArrayList(1L, 2L).stream() - .map(l -> new ListInContainerBuilder().setId(l).build()) - .collect(Collectors.toList())); - } - - private ContainerWithList readEntireSubtree() { - final ContainerWithListBuilder b = new ContainerWithListBuilder(); - b.setListInContainer(Lists.newArrayList(1L, 2L).stream() - .map(l -> { - final ContainerInListBuilder containerInListBuilder = new ContainerInListBuilder(); - readContainerInList( - Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey(l)).child(ContainerInList.class), - containerInListBuilder, - ctx); - return new ListInContainerBuilder().setId(l).setContainerInList(containerInListBuilder.build()).build(); - }) - .collect(Collectors.toList())); - return b.build(); - } - - private void readContainerInList(final InstanceIdentifier id, - final ContainerInListBuilder b, - final ReadContext readContext) { - b.setName(id.firstKeyOf(ListInContainer.class).getId().toString()); - } -} diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombWriteInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombWriteInfraTest.java deleted file mode 100644 index b3a06ec46..000000000 --- a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombWriteInfraTest.java +++ /dev/null @@ -1,521 +0,0 @@ -/* - * 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.data.impl; - -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.data.DataModification; -import io.fd.honeycomb.v3po.translate.util.write.registry.FlatWriterRegistryBuilder; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.Writer; -import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import org.junit.Test; -import org.mockito.InOrder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugmentBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoice; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoiceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugmentBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainerBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.Choice; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3Builder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainerBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGrouping; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGroupingBuilder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -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.TipProducingDataTree; -import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; -import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; - -/** - * Testing honeycomb writes from data tree up to mocked writers. - */ -public class HoneycombWriteInfraTest extends AbstractInfraTest { - - private TipProducingDataTree dataTree; - private WriterRegistry writerRegistry; - - Writer simpleContainerWriter = mockWriter(Ids.SIMPLE_CONTAINER_ID); - Writer complexAugmentWriter = mockWriter(Ids.COMPLEX_AUGMENT_ID); - Writer complexAugmentContainerWriter = mockWriter(Ids.COMPLEX_AUGMENT_CONTAINER_ID); - Writer simpleAugmentWriter = mockWriter(Ids.SIMPLE_AUGMENT_ID); - - Writer containerWithListWriter = mockWriter(Ids.CONTAINER_WITH_LIST_ID); - Writer listInContainerWriter = mockWriter(Ids.LIST_IN_CONTAINER_ID); - Writer containerInListWriter = mockWriter(Ids.CONTAINER_IN_LIST_ID); - Writer nestedListWriter = mockWriter(Ids.NESTED_LIST_ID); - - Writer containerWithChoiceWriter = mockWriter(Ids.CONTAINER_WITH_CHOICE_ID); - Writer containerFromGroupingWriter = mockWriter(Ids.CONTAINER_FROM_GROUPING_ID); - Writer c3Writer = mockWriter(Ids.C3_ID); - - - private static Writer mockWriter(final InstanceIdentifier id) { - final Writer mock = (Writer) mock(Writer.class); - when(mock.getManagedDataObjectType()).thenReturn(id); - return mock; - } - - @Override - void postSetup() { - initDataTree(); - initWriterRegistry(); - } - - private void initDataTree() { - dataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); - dataTree.setSchemaContext(schemaContext); - } - - private void initWriterRegistry() { - writerRegistry = new FlatWriterRegistryBuilder() - .add(complexAugmentWriter) // unordered - .add(nestedListWriter) // 6 - .addAfter(listInContainerWriter, Ids.NESTED_LIST_ID) // 7 - .addAfter(containerInListWriter, Ids.LIST_IN_CONTAINER_ID) // 8 - .addAfter(containerWithListWriter, Ids.CONTAINER_IN_LIST_ID) // 9 - .addBefore(containerFromGroupingWriter, Ids.NESTED_LIST_ID) // 5 - .addBefore(containerWithChoiceWriter, Ids.CONTAINER_FROM_GROUPING_ID) // 4 - .addBefore(simpleContainerWriter, Ids.CONTAINER_WITH_CHOICE_ID) // 3 - .addBefore(c3Writer, Ids.SIMPLE_CONTAINER_ID) // 2 - .addBefore(simpleAugmentWriter, Ids.SIMPLE_CONTAINER_ID) // 2 - .addBefore(complexAugmentContainerWriter, Sets.newHashSet(Ids.C3_ID, Ids.SIMPLE_AUGMENT_ID)) // 1 - .build(); - } - - @Test - public void testWriteEmptyNonPresenceContainer() throws Exception { - final ModifiableDataTreeDelegator modifiableDataTreeDelegator = - new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker); - - final DataModification dataModification = modifiableDataTreeDelegator.newModification(); - final SimpleContainer data = new SimpleContainerBuilder() - .build(); - - final Map.Entry> normalizedNode = - serializer.toNormalizedNode(Ids.SIMPLE_CONTAINER_ID, data); - dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); - - dataModification.commit(); - - verify(simpleContainerWriter).getManagedDataObjectType(); - verifyNoMoreInteractions(simpleContainerWriter); - } - - @Test - public void testWriteEverything() throws Exception { - final ModifiableDataTreeDelegator modifiableDataTreeDelegator = - new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker); - - final DataModification dataModification = modifiableDataTreeDelegator.newModification(); - // Now write everything we can - writeSimpleContainer(dataModification); - writeContainerWithChoice(dataModification); - writeContainerWithList(dataModification); - dataModification.commit(); - - final Writer[] orderedWriters = getOrderedWriters(); - final InOrder inOrder = inOrder(orderedWriters); - verifyOrderedWrites(orderedWriters, inOrder); - } - - private void verifyOrderedWrites(final Writer[] orderedWriters, final InOrder inOrder) - throws io.fd.honeycomb.v3po.translate.write.WriteFailedException { - // TODO Modifications are not produced for nodes that do not contain any actual leaves (except when choice is a child) do we need those triggers ? - // Unordered - // verify(complexAugmentWriter).update(eq(COMPLEX_AUGMENT_ID), eq(null), eq(getComplexAugment()), any(WriteContext.class)); - // 1 - inOrder.verify(complexAugmentContainerWriter) - .update(eq(Ids.COMPLEX_AUGMENT_CONTAINER_ID), eq(null), eq(getComplexAugmentContainer()), any(WriteContext.class)); - // 2 - inOrder.verify(c3Writer) - .update(eq(Ids.C3_ID), eq(null), eq(getC3()), any(WriteContext.class)); - // 2 - verify(simpleAugmentWriter) - .update(eq(Ids.SIMPLE_AUGMENT_ID), eq(null), eq(getSimpleAugment()), any(WriteContext.class)); - // 3 - inOrder.verify(simpleContainerWriter) - .update(eq(Ids.SIMPLE_CONTAINER_ID), eq(null), eq(getSimpleContainer()), any(WriteContext.class)); - // 4 - inOrder.verify(containerWithChoiceWriter) - .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(null), eq(getContainerWithChoiceWithComplexCase()), any(WriteContext.class)); - // 5 - inOrder.verify(containerFromGroupingWriter) - .update(eq(Ids.CONTAINER_FROM_GROUPING_ID), eq(null), eq(getContainerFromGrouping()), any(WriteContext.class)); - - final KeyedInstanceIdentifier keyedListInContainer1 = - Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 1)); - final KeyedInstanceIdentifier keyedNestedList1 = - keyedListInContainer1.child(ContainerInList.class).child(NestedList.class, new NestedListKey("1")); - final KeyedInstanceIdentifier keyedListInContainer2 = - Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 2)); - final KeyedInstanceIdentifier keyedNestedList2 = - keyedListInContainer2.child(ContainerInList.class).child(NestedList.class, new NestedListKey("2")); - - // 6 - two items - inOrder.verify(nestedListWriter) - .update(eq(keyedNestedList1), eq(null), eq(getSingleNestedList("1")), any(WriteContext.class)); - verify(nestedListWriter) - .update(eq(keyedNestedList2), eq(null), eq(getSingleNestedList("2")), any(WriteContext.class)); - - // 7 - two items - inOrder.verify(listInContainerWriter) - .update(eq(keyedListInContainer1), eq(null), eq(getSingleListInContainer((long)1)), any(WriteContext.class)); - verify(listInContainerWriter) - .update(eq(keyedListInContainer2), eq(null), eq(getSingleListInContainer((long)2)), any(WriteContext.class)); - - // 8 - inOrder.verify(containerInListWriter) - .update(eq(keyedListInContainer1.child(ContainerInList.class)), eq(null), eq(getContainerInList("1")), any(WriteContext.class)); - verify(containerInListWriter) - .update(eq(keyedListInContainer2.child(ContainerInList.class)), eq(null), eq(getContainerInList("2")), any(WriteContext.class)); - - // 9 - Ignored because the container has no leaves, only complex child nodes - // inOrder.verify(containerWithListWriter) - // .update(eq(CONTAINER_WITH_LIST_ID), eq(null), eq(getContainerWithList()), any(WriteContext.class)); - - for (Writer orderedWriter : orderedWriters) { - verify(orderedWriter).getManagedDataObjectType(); - verifyNoMoreInteractions(orderedWriter); - } - } - - private Writer[] getOrderedWriters() { - return new Writer[]{complexAugmentWriter, // Unordered - complexAugmentContainerWriter, // 1 - c3Writer, // 2 - simpleAugmentWriter, // 2 - simpleContainerWriter, // 3 - containerWithChoiceWriter, // 4 - containerFromGroupingWriter, // 5 - nestedListWriter, // 6 - listInContainerWriter, // 7 - containerInListWriter, // 8 - containerWithListWriter}; - } - - @Test - public void testDeletes() throws Exception { - final ModifiableDataTreeDelegator modifiableDataTreeDelegator = - new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker); - - DataModification dataModification = modifiableDataTreeDelegator.newModification(); - // Now write everything we can - writeSimpleContainer(dataModification); - writeContainerWithChoice(dataModification); - writeContainerWithList(dataModification); - dataModification.commit(); - // Verify writes to be able to verifyNoMore interactions at the end - verifyOrderedWrites(getOrderedWriters(), inOrder(getOrderedWriters())); - - dataModification = modifiableDataTreeDelegator.newModification(); - deleteSimpleContainer(dataModification); - deleteContainerWithChoice(dataModification); - deleteContainerWithList(dataModification); - dataModification.commit(); - - final Writer[] orderedWriters = getOrderedWriters(); - Collections.reverse(Arrays.asList(orderedWriters)); - final InOrder inOrder = inOrder(orderedWriters); - - final KeyedInstanceIdentifier keyedListInContainer1 = - Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 1)); - final KeyedInstanceIdentifier keyedNestedList1 = - keyedListInContainer1.child(ContainerInList.class).child(NestedList.class, new NestedListKey("1")); - final KeyedInstanceIdentifier keyedListInContainer2 = - Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 2)); - final KeyedInstanceIdentifier keyedNestedList2 = - keyedListInContainer2.child(ContainerInList.class).child(NestedList.class, new NestedListKey("2")); - - // Deletes are handled in reverse order - // 1 - inOrder.verify(containerInListWriter) - .update(eq(keyedListInContainer1.child(ContainerInList.class)), eq(getContainerInList("1")), eq(null), any(WriteContext.class)); - verify(containerInListWriter) - .update(eq(keyedListInContainer2.child(ContainerInList.class)), eq(getContainerInList("2")), eq(null), any(WriteContext.class)); - - // 2 - inOrder.verify(listInContainerWriter) - .update(eq(keyedListInContainer1), eq(getSingleListInContainer((long)1)), eq(null), any(WriteContext.class)); - verify(listInContainerWriter) - .update(eq(keyedListInContainer2), eq(getSingleListInContainer((long)2)), eq(null), any(WriteContext.class)); - - // 3 - inOrder.verify(nestedListWriter) - .update(eq(keyedNestedList1), eq(getSingleNestedList("1")), eq(null), any(WriteContext.class)); - verify(nestedListWriter) - .update(eq(keyedNestedList2), eq(getSingleNestedList("2")), eq(null), any(WriteContext.class)); - // 4 - inOrder.verify(containerFromGroupingWriter) - .update(eq(Ids.CONTAINER_FROM_GROUPING_ID), eq(getContainerFromGrouping()), eq(null), any(WriteContext.class)); - // 5 - inOrder.verify(containerWithChoiceWriter) - .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(getContainerWithChoiceWithComplexCase()), eq(null), any(WriteContext.class)); - // 6 - inOrder.verify(simpleContainerWriter) - .update(eq(Ids.SIMPLE_CONTAINER_ID), eq(getSimpleContainer()), eq(null), any(WriteContext.class)); - // 7 - verify(simpleAugmentWriter) - .update(eq(Ids.SIMPLE_AUGMENT_ID), eq(getSimpleAugment()), eq(null), any(WriteContext.class)); - // 8 - inOrder.verify(c3Writer) - .update(eq(Ids.C3_ID), eq(getC3()), eq(null), any(WriteContext.class)); - // 9 - inOrder.verify(complexAugmentContainerWriter) - .update(eq(Ids.COMPLEX_AUGMENT_CONTAINER_ID), eq(getComplexAugmentContainer()), eq(null), any(WriteContext.class)); - - for (Writer orderedWriter : orderedWriters) { - verify(orderedWriter).getManagedDataObjectType(); - verifyNoMoreInteractions(orderedWriter); - } - } - - private void writeContainerWithList(final DataModification dataModification) { - final Map.Entry> normalizedNode = - serializer.toNormalizedNode(Ids.CONTAINER_WITH_LIST_ID, getContainerWithList()); - dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); - } - - private void deleteContainerWithList(final DataModification dataModification) { - dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_WITH_LIST_ID)); - } - - private ContainerWithList getContainerWithList() { - return new ContainerWithListBuilder() - .setListInContainer(getListInContainer((long)1, (long)2)) - .build(); - } - - private List getListInContainer(final Long... keys) { - final ArrayList objects = Lists.newArrayList(); - for (Long key : keys) { - objects.add(getSingleListInContainer(key)); - } - return objects; - } - - private ListInContainer getSingleListInContainer(final Long key) { - return new ListInContainerBuilder() - .setId(key) - .setContainerInList(getContainerInList(Long.toString(key))) - .build(); - } - - private ContainerInList getContainerInList(String... nestedKeys) { - return new ContainerInListBuilder() - .setName("inlist") - .setNestedList(getNestedList(nestedKeys)) - .build(); - } - - private List getNestedList(String... keys) { - final ArrayList nestedList = new ArrayList<>(); - for (String key : keys) { - nestedList.add(getSingleNestedList(key)); - } - return nestedList; - } - - private NestedList getSingleNestedList(final String key) { - return new NestedListBuilder() - .setNestedId(key) - .setNestedName(key) - .build(); - } - - private void writeContainerWithChoice(final DataModification dataModification) { - writeContainerWithChoice(dataModification, getContainerWithChoiceWithComplexCase()); - } - - - private void deleteContainerWithChoice(final DataModification dataModification) { - dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_WITH_CHOICE_ID)); - } - - private void writeContainerWithChoice(final DataModification dataModification, - final ContainerWithChoice containerWithChoice) { - final Map.Entry> normalizedNode = - serializer.toNormalizedNode(Ids.CONTAINER_WITH_CHOICE_ID, containerWithChoice); - dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); - } - - private ContainerWithChoice getContainerWithChoiceWithComplexCase() { - return new ContainerWithChoiceBuilder() - .setLeafFromGrouping("fromG") - .setName("name") - .setContainerFromGrouping(getContainerFromGrouping()) - .setChoice(getComplexCase()) - .build(); - } - - private Choice getComplexCase() { - return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.C3Builder() - .setC3(getC3()) - .build(); - } - - private C3 getC3() { - return new C3Builder() - .setName("c3") - .build(); - } - - private void writeContainerFromGrouping(final DataModification dataModification) { - final Map.Entry> normalizedNode = - serializer.toNormalizedNode(Ids.CONTAINER_FROM_GROUPING_ID, getContainerFromGrouping()); - dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); - } - - private ContainerFromGrouping getContainerFromGrouping() { - return new ContainerFromGroupingBuilder() - .setLeafInContainerFromGrouping(111) - .build(); - } - - - private void writeSimpleContainer(final DataModification dataModification) { - final Map.Entry> normalizedNode = - serializer.toNormalizedNode(Ids.SIMPLE_CONTAINER_ID, getSimpleContainer()); - dataModification.write(normalizedNode.getKey(), normalizedNode.getValue()); - } - - private void deleteSimpleContainer(final DataModification dataModification) { - final YangInstanceIdentifier yangId = - serializer.toYangInstanceIdentifier(Ids.SIMPLE_CONTAINER_ID); - dataModification.delete(yangId); - } - - private SimpleContainer getSimpleContainer() { - return new SimpleContainerBuilder() - .setSimpleContainerName("n") - .addAugmentation(SimpleAugment.class, getSimpleAugment()) - .addAugmentation(ComplexAugment.class, getComplexAugment()) - .build(); - } - - private ComplexAugment getComplexAugment() { - return new ComplexAugmentBuilder() - .setComplexAugmentContainer(getComplexAugmentContainer()) - .build(); - } - - private ComplexAugmentContainer getComplexAugmentContainer() { - return new ComplexAugmentContainerBuilder().setSomeLeaf("s").build(); - } - - private SimpleAugment getSimpleAugment() { - return new SimpleAugmentBuilder().setSimpleAugmentLeaf("a").build(); - } - - @Test - public void testWriteAndDeleteInTx() throws Exception { - final ModifiableDataTreeDelegator modifiableDataTreeDelegator = - new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker); - - final DataModification dataModification = modifiableDataTreeDelegator.newModification(); - // Now write everything we can - writeSimpleContainer(dataModification); - deleteSimpleContainer(dataModification); - dataModification.commit(); - - verify(simpleContainerWriter).getManagedDataObjectType(); - // No modification - verifyNoMoreInteractions(simpleContainerWriter); - } - - @Test - public void testSubtreeWriter() throws Exception { - writerRegistry = new FlatWriterRegistryBuilder() - // Handles also container from grouping - .subtreeAdd(Sets.newHashSet(Ids.CONTAINER_FROM_GROUPING_ID), containerWithChoiceWriter) - .build(); - - final ModifiableDataTreeDelegator modifiableDataTreeDelegator = - new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker); - - final ContainerWithChoice containerWithChoice = - new ContainerWithChoiceBuilder().setContainerFromGrouping(getContainerFromGrouping()).build(); - - // Test write subtree node - DataModification dataModification = modifiableDataTreeDelegator.newModification(); - writeContainerFromGrouping(dataModification); - dataModification.commit(); - - verify(containerWithChoiceWriter, atLeastOnce()).getManagedDataObjectType(); - verify(containerWithChoiceWriter) - .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(null), eq(containerWithChoice), any(WriteContext.class)); - verifyNoMoreInteractions(containerWithChoiceWriter); - - // Test delete sub-node - dataModification = modifiableDataTreeDelegator.newModification(); - final ContainerWithChoice containerWithChoiceEmpty = new ContainerWithChoiceBuilder().build(); - deleteContainerFromGrouping(dataModification); - dataModification.commit(); - - verify(containerWithChoiceWriter, atLeastOnce()).getManagedDataObjectType(); - verify(containerWithChoiceWriter) - .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(containerWithChoice), eq(containerWithChoiceEmpty), any(WriteContext.class)); - verifyNoMoreInteractions(containerWithChoiceWriter); - - // Test write with subtree node that's not handled by subtree writer - dataModification = modifiableDataTreeDelegator.newModification(); - writeContainerWithChoice(dataModification); - try { - dataModification.commit(); - fail("Missing writer for C3 should occur"); - } catch (IllegalArgumentException e) { - return; - } - } - - private void deleteContainerFromGrouping(final DataModification dataModification) { - dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_FROM_GROUPING_ID)); - } -} \ No newline at end of file diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/Ids.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/Ids.java deleted file mode 100644 index 200f50c32..000000000 --- a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/Ids.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.data.impl; - -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoice; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGrouping; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Instance identifiers referencing all complex nodes within IT test-model. - */ -interface Ids { - - // Simple container - // ORDER = 3 - InstanceIdentifier SIMPLE_CONTAINER_ID = InstanceIdentifier.create(SimpleContainer.class); - // 2 - InstanceIdentifier SIMPLE_AUGMENT_ID = SIMPLE_CONTAINER_ID.augmentation(SimpleAugment.class); - // UNORDERED - InstanceIdentifier COMPLEX_AUGMENT_ID = SIMPLE_CONTAINER_ID.augmentation(ComplexAugment.class); - // 1 - InstanceIdentifier COMPLEX_AUGMENT_CONTAINER_ID = COMPLEX_AUGMENT_ID.child(ComplexAugmentContainer.class); - // Container with list - // 9 - InstanceIdentifier CONTAINER_WITH_LIST_ID = InstanceIdentifier.create(ContainerWithList.class); - // 7 - InstanceIdentifier LIST_IN_CONTAINER_ID = CONTAINER_WITH_LIST_ID.child(ListInContainer.class); - // 8 - InstanceIdentifier CONTAINER_IN_LIST_ID = LIST_IN_CONTAINER_ID.child(ContainerInList.class); - // 6 - InstanceIdentifier NESTED_LIST_ID = CONTAINER_IN_LIST_ID.child(NestedList.class); - // Container with choice - // 4 - InstanceIdentifier CONTAINER_WITH_CHOICE_ID = InstanceIdentifier.create(ContainerWithChoice.class); - // 2 - InstanceIdentifier C3_ID = CONTAINER_WITH_CHOICE_ID.child(C3.class); - // 5 - InstanceIdentifier CONTAINER_FROM_GROUPING_ID = CONTAINER_WITH_CHOICE_ID.child(ContainerFromGrouping.class); -} diff --git a/infra/notification/api/src/main/java/io/fd/honeycomb/notification/ManagedNotificationProducer.java b/infra/notification/api/src/main/java/io/fd/honeycomb/notification/ManagedNotificationProducer.java new file mode 100644 index 000000000..433512164 --- /dev/null +++ b/infra/notification/api/src/main/java/io/fd/honeycomb/notification/ManagedNotificationProducer.java @@ -0,0 +1,38 @@ +/* + * 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.notification; + +import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; + +/** + * Special notification producer that is capable of starting and stopping the notification stream + */ +@Beta +public interface ManagedNotificationProducer extends NotificationProducer { + + /** + * Start notification stream managed by this producer. + * + * @param collector Notification collector expected to collect produced notifications + */ + void start(@Nonnull NotificationCollector collector); + + /** + * Stop notification stream managed by this producer. + */ + void stop(); +} diff --git a/infra/notification/api/src/main/java/io/fd/honeycomb/notification/NotificationCollector.java b/infra/notification/api/src/main/java/io/fd/honeycomb/notification/NotificationCollector.java new file mode 100644 index 000000000..e40b874d5 --- /dev/null +++ b/infra/notification/api/src/main/java/io/fd/honeycomb/notification/NotificationCollector.java @@ -0,0 +1,35 @@ +/* + * 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.notification; + +import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.Notification; + +/** + * Notification collector. Collects all the notifications, which are further + * propagated to all wired northbound interfaces. + */ +@Beta +public interface NotificationCollector extends AutoCloseable, NotificationProducer { + + /** + * Publish a single notification. + * + * @param notification notification to be published + */ + void onNotification(@Nonnull Notification notification); +} diff --git a/infra/notification/api/src/main/java/io/fd/honeycomb/notification/NotificationProducer.java b/infra/notification/api/src/main/java/io/fd/honeycomb/notification/NotificationProducer.java new file mode 100644 index 000000000..665318d0e --- /dev/null +++ b/infra/notification/api/src/main/java/io/fd/honeycomb/notification/NotificationProducer.java @@ -0,0 +1,37 @@ +/* + * 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.notification; + +import com.google.common.annotations.Beta; +import java.util.Collection; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.Notification; + +/** + * Produces notification of exposed notification types + */ +@Beta +public interface NotificationProducer extends AutoCloseable { + + /** + * Return collection of notification types that will be emitted by this producer. + * Other types of notifications should not be emitted, since they can be rejected. + * + * @return collection of all notification types emitted by this producer + */ + @Nonnull + Collection> getNotificationTypes(); +} diff --git a/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/ManagedNotificationProducer.java b/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/ManagedNotificationProducer.java deleted file mode 100644 index 0f5e28cde..000000000 --- a/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/ManagedNotificationProducer.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.notification; - -import com.google.common.annotations.Beta; -import javax.annotation.Nonnull; - -/** - * Special notification producer that is capable of starting and stopping the notification stream - */ -@Beta -public interface ManagedNotificationProducer extends NotificationProducer { - - /** - * Start notification stream managed by this producer. - * - * @param collector Notification collector expected to collect produced notifications - */ - void start(@Nonnull NotificationCollector collector); - - /** - * Stop notification stream managed by this producer. - */ - void stop(); -} diff --git a/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationCollector.java b/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationCollector.java deleted file mode 100644 index 406ab03d2..000000000 --- a/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationCollector.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.notification; - -import com.google.common.annotations.Beta; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.Notification; - -/** - * Notification collector. Collects all the notifications, which are further - * propagated to all wired northbound interfaces. - */ -@Beta -public interface NotificationCollector extends AutoCloseable, NotificationProducer { - - /** - * Publish a single notification. - * - * @param notification notification to be published - */ - void onNotification(@Nonnull Notification notification); -} diff --git a/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationProducer.java b/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationProducer.java deleted file mode 100644 index dab773c45..000000000 --- a/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationProducer.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.notification; - -import com.google.common.annotations.Beta; -import java.util.Collection; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.Notification; - -/** - * Produces notification of exposed notification types - */ -@Beta -public interface NotificationProducer extends AutoCloseable { - - /** - * Return collection of notification types that will be emitted by this producer. - * Other types of notifications should not be emitted, since they can be rejected. - * - * @return collection of all notification types emitted by this producer - */ - @Nonnull - Collection> getNotificationTypes(); -} diff --git a/infra/notification/api/src/main/yang/notification-api.yang b/infra/notification/api/src/main/yang/notification-api.yang index 4e6eb98ae..f0331bc07 100644 --- a/infra/notification/api/src/main/yang/notification-api.yang +++ b/infra/notification/api/src/main/yang/notification-api.yang @@ -15,7 +15,7 @@ module notification-api { identity honeycomb-notification-collector { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.notification.NotificationCollector; + config:java-class io.fd.honeycomb.notification.NotificationCollector; } identity dom-notification-service { @@ -25,7 +25,7 @@ module notification-api { identity honeycomb-notification-producer { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.notification.ManagedNotificationProducer; + config:java-class io.fd.honeycomb.notification.ManagedNotificationProducer; } } diff --git a/infra/notification/impl/src/main/config/notification-to-netconf-config.xml b/infra/notification/impl/src/main/config/notification-to-netconf-config.xml index d2aac0932..d64de6413 100644 --- a/infra/notification/impl/src/main/config/notification-to-netconf-config.xml +++ b/infra/notification/impl/src/main/config/notification-to-netconf-config.xml @@ -29,13 +29,13 @@ prefix:netconf-notification-registry - vpp-netconf-notification-manager + honeycomb-netconf-notification-manager prefix:netconf-notification-collector - vpp-netconf-notification-manager + honeycomb-netconf-notification-manager dom:schema-service diff --git a/infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/HoneycombNotificationCollector.java b/infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/HoneycombNotificationCollector.java new file mode 100644 index 000000000..c37e6925c --- /dev/null +++ b/infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/HoneycombNotificationCollector.java @@ -0,0 +1,66 @@ +/* + * 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.notification.impl; + +import io.fd.honeycomb.notification.NotificationCollector; +import java.util.Collection; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService; +import org.opendaylight.yangtools.yang.binding.Notification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Notification collector based on MD-SAL's {@link NotificationPublishService}. + */ +public final class HoneycombNotificationCollector implements NotificationCollector, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(HoneycombNotificationCollector.class); + + private final NotificationPublishService bindingDOMNotificationPublishServiceAdapter; + private final NotificationProducerRegistry notificationProducerRegistry; + + public HoneycombNotificationCollector( + @Nonnull final NotificationPublishService bindingDOMNotificationPublishServiceAdapter, + @Nonnull final NotificationProducerRegistry notificationProducerRegistry) { + this.bindingDOMNotificationPublishServiceAdapter = bindingDOMNotificationPublishServiceAdapter; + this.notificationProducerRegistry = notificationProducerRegistry; + } + + @Override + public void close() throws Exception { + LOG.trace("Closing"); + } + + @Override + public void onNotification(@Nonnull final Notification notification) { + LOG.debug("Notification: {} pushed into collector", notification.getClass().getSimpleName()); + LOG.trace("Notification: {} pushed into collector", notification); + try { + bindingDOMNotificationPublishServiceAdapter.putNotification(notification); + } catch (InterruptedException e) { + LOG.warn("Interrupted", e); + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + } + + @Override + @Nonnull + public Collection> getNotificationTypes() { + return notificationProducerRegistry.getNotificationTypes(); + } +} diff --git a/infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/NotificationProducerRegistry.java b/infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/NotificationProducerRegistry.java new file mode 100644 index 000000000..7b46c60b7 --- /dev/null +++ b/infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/NotificationProducerRegistry.java @@ -0,0 +1,112 @@ +/* + * 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.notification.impl; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import io.fd.honeycomb.notification.ManagedNotificationProducer; +import io.fd.honeycomb.notification.NotificationProducer; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.yangtools.yang.binding.Notification; +import org.opendaylight.yangtools.yang.common.QName; + +/** + * Holds the collection of registered notification producers. + * Provides additional information about the types of notifications produced per producer and overall. + */ +@ThreadSafe +public final class NotificationProducerRegistry { + + private final Set> notificationTypes; + private final Map notificationQNameToProducer; + private final Multimap notificationProducerQNames; + + public NotificationProducerRegistry(final List notificationProducersDependency) { + this.notificationTypes = toTypes(notificationProducersDependency); + this.notificationQNameToProducer = toQNameMap(notificationProducersDependency); + this.notificationProducerQNames = toQNameMapReversed(notificationProducersDependency); + } + + private static Multimap toQNameMapReversed(final List notificationProducers) { + final Multimap multimap = HashMultimap.create(); + + for (ManagedNotificationProducer producer : notificationProducers) { + for (Class aClass : producer.getNotificationTypes()) { + multimap.put(producer, getQName(aClass)); + } + } + return multimap; + } + + private static Set> toTypes(final List notificationProducersDependency) { + // Get all notification types registered from HC notification producers + return notificationProducersDependency + .stream() + .flatMap(producer -> producer.getNotificationTypes().stream()) + .collect(Collectors.toSet()); + } + + + private static Map toQNameMap(final List producerDependencies) { + // Only a single notification producer per notification type is allowed + final Map qNamesToProducers = Maps.newHashMap(); + for (ManagedNotificationProducer notificationProducer : producerDependencies) { + for (QName qName : typesToQNames(notificationProducer.getNotificationTypes())) { + final NotificationProducer previousProducer = qNamesToProducers.put(qName, notificationProducer); + checkArgument(previousProducer == null, "2 producers of the same notification type: %s. " + + "Producer 1: {} Producer 2: {}" , qName, previousProducer, notificationProducer); + } + } + return qNamesToProducers; + } + + + private static Set typesToQNames(final Collection> notificationTypes) { + return notificationTypes + .stream() + .map(NotificationProducerRegistry::getQName) + .collect(Collectors.toSet()); + } + + + public static QName getQName(final Class aClass) { + try { + return (QName) aClass.getField("QNAME").get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new IllegalArgumentException("Unable to retrieve QName for notification of type: " + aClass, e); + } + } + + Set> getNotificationTypes() { + return notificationTypes; + } + + Map getNotificationQNameToProducer() { + return notificationQNameToProducer; + } + + Multimap getNotificationProducerQNames() { + return notificationProducerQNames; + } +} diff --git a/infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/NotificationProducerTracker.java b/infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/NotificationProducerTracker.java new file mode 100644 index 000000000..808512c21 --- /dev/null +++ b/infra/notification/impl/src/main/java/io/fd/honeycomb/notification/impl/NotificationProducerTracker.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.notification.impl; + +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.collect.Sets; +import io.fd.honeycomb.notification.ManagedNotificationProducer; +import io.fd.honeycomb.notification.NotificationCollector; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListener; +import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListenerRegistry; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Starts & stops notification producer dependencies on demand. + * Uses {@link DOMNotificationSubscriptionListenerRegistry} to receive subscription change notifications. + */ +@ThreadSafe +public final class NotificationProducerTracker + implements DOMNotificationSubscriptionListener, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(NotificationProducerTracker.class); + + private final ListenerRegistration subscriptionListener; + private final NotificationProducerRegistry registry; + private final NotificationCollector collector; + + private final Set alreadyStartedProducers = new HashSet<>(); + + public NotificationProducerTracker(@Nonnull final NotificationProducerRegistry registry, + @Nonnull final NotificationCollector collector, + @Nonnull final DOMNotificationSubscriptionListenerRegistry notificationRouter) { + this.registry = registry; + this.collector = collector; + this.subscriptionListener = notificationRouter.registerSubscriptionListener(this); + } + + @Override + public synchronized void onSubscriptionChanged(final Set set) { + LOG.debug("Subscriptions changed. Current subscriptions: {}", set); + final Set currentSubscriptions = set.stream().map(SchemaPath::getLastComponent).collect(Collectors.toSet()); + final Set startedQNames = getStartedQNames(alreadyStartedProducers); + final Sets.SetView newSubscriptions = Sets.difference(currentSubscriptions, startedQNames); + LOG.debug("Subscriptions changed. New subscriptions: {}", newSubscriptions); + final Sets.SetView deletedSubscriptions = Sets.difference(startedQNames, currentSubscriptions); + LOG.debug("Subscriptions changed. Deleted subscriptions: {}", deletedSubscriptions); + + newSubscriptions.stream().forEach(newSub -> { + if(!registry.getNotificationQNameToProducer().containsKey(newSub)) { + return; + } + final ManagedNotificationProducer producer = registry.getNotificationQNameToProducer().get(newSub); + if(alreadyStartedProducers.contains(producer)) { + return; + } + LOG.debug("Starting notification producer: {}", producer); + producer.start(collector); + alreadyStartedProducers.add(producer); + }); + + deletedSubscriptions.stream().forEach(newSub -> { + checkState(registry.getNotificationQNameToProducer().containsKey(newSub)); + final ManagedNotificationProducer producer = registry.getNotificationQNameToProducer().get(newSub); + checkState(alreadyStartedProducers.contains(producer)); + LOG.debug("Stopping notification producer: {}", producer); + producer.stop(); + alreadyStartedProducers.remove(producer); + }); + + } + + private Set getStartedQNames(final Set alreadyStartedProducers) { + return alreadyStartedProducers.stream() + .flatMap(p -> registry.getNotificationProducerQNames().get(p).stream()) + .collect(Collectors.toSet()); + } + + @Override + public synchronized void close() throws Exception { + LOG.trace("Closing"); + subscriptionListener.close(); + // Stop all producers + LOG.debug("Stopping all producers: {}", alreadyStartedProducers); + alreadyStartedProducers.forEach(ManagedNotificationProducer::stop); + alreadyStartedProducers.clear(); + } +} diff --git a/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollector.java b/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollector.java deleted file mode 100644 index e7d54e318..000000000 --- a/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollector.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.notification.impl; - -import io.fd.honeycomb.v3po.notification.NotificationCollector; -import java.util.Collection; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService; -import org.opendaylight.yangtools.yang.binding.Notification; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Notification collector based on MD-SAL's {@link NotificationPublishService}. - */ -public final class HoneycombNotificationCollector implements NotificationCollector, AutoCloseable { - - private static final Logger LOG = LoggerFactory.getLogger(HoneycombNotificationCollector.class); - - private final NotificationPublishService bindingDOMNotificationPublishServiceAdapter; - private final NotificationProducerRegistry notificationProducerRegistry; - - public HoneycombNotificationCollector( - @Nonnull final NotificationPublishService bindingDOMNotificationPublishServiceAdapter, - @Nonnull final NotificationProducerRegistry notificationProducerRegistry) { - this.bindingDOMNotificationPublishServiceAdapter = bindingDOMNotificationPublishServiceAdapter; - this.notificationProducerRegistry = notificationProducerRegistry; - } - - @Override - public void close() throws Exception { - LOG.trace("Closing"); - } - - @Override - public void onNotification(@Nonnull final Notification notification) { - LOG.debug("Notification: {} pushed into collector", notification.getClass().getSimpleName()); - LOG.trace("Notification: {} pushed into collector", notification); - try { - bindingDOMNotificationPublishServiceAdapter.putNotification(notification); - } catch (InterruptedException e) { - LOG.warn("Interrupted", e); - Thread.currentThread().interrupt(); - throw new RuntimeException(e); - } - } - - @Override - @Nonnull - public Collection> getNotificationTypes() { - return notificationProducerRegistry.getNotificationTypes(); - } -} diff --git a/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistry.java b/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistry.java deleted file mode 100644 index 8fba700bd..000000000 --- a/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistry.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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.notification.impl; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import io.fd.honeycomb.v3po.notification.ManagedNotificationProducer; -import io.fd.honeycomb.v3po.notification.NotificationProducer; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.yangtools.yang.binding.Notification; -import org.opendaylight.yangtools.yang.common.QName; - -/** - * Holds the collection of registered notification producers. - * Provides additional information about the types of notifications produced per producer and overall. - */ -@ThreadSafe -public final class NotificationProducerRegistry { - - private final Set> notificationTypes; - private final Map notificationQNameToProducer; - private final Multimap notificationProducerQNames; - - public NotificationProducerRegistry(final List notificationProducersDependency) { - this.notificationTypes = toTypes(notificationProducersDependency); - this.notificationQNameToProducer = toQNameMap(notificationProducersDependency); - this.notificationProducerQNames = toQNameMapReversed(notificationProducersDependency); - } - - private static Multimap toQNameMapReversed(final List notificationProducers) { - final Multimap multimap = HashMultimap.create(); - - for (ManagedNotificationProducer producer : notificationProducers) { - for (Class aClass : producer.getNotificationTypes()) { - multimap.put(producer, getQName(aClass)); - } - } - return multimap; - } - - private static Set> toTypes(final List notificationProducersDependency) { - // Get all notification types registered from HC notification producers - return notificationProducersDependency - .stream() - .flatMap(producer -> producer.getNotificationTypes().stream()) - .collect(Collectors.toSet()); - } - - - private static Map toQNameMap(final List producerDependencies) { - // Only a single notification producer per notification type is allowed - final Map qNamesToProducers = Maps.newHashMap(); - for (ManagedNotificationProducer notificationProducer : producerDependencies) { - for (QName qName : typesToQNames(notificationProducer.getNotificationTypes())) { - final NotificationProducer previousProducer = qNamesToProducers.put(qName, notificationProducer); - checkArgument(previousProducer == null, "2 producers of the same notification type: %s. " + - "Producer 1: {} Producer 2: {}" , qName, previousProducer, notificationProducer); - } - } - return qNamesToProducers; - } - - - private static Set typesToQNames(final Collection> notificationTypes) { - return notificationTypes - .stream() - .map(NotificationProducerRegistry::getQName) - .collect(Collectors.toSet()); - } - - - public static QName getQName(final Class aClass) { - try { - return (QName) aClass.getField("QNAME").get(null); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new IllegalArgumentException("Unable to retrieve QName for notification of type: " + aClass, e); - } - } - - Set> getNotificationTypes() { - return notificationTypes; - } - - Map getNotificationQNameToProducer() { - return notificationQNameToProducer; - } - - Multimap getNotificationProducerQNames() { - return notificationProducerQNames; - } -} diff --git a/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTracker.java b/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTracker.java deleted file mode 100644 index cefb50ac9..000000000 --- a/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTracker.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.notification.impl; - -import static com.google.common.base.Preconditions.checkState; - -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.notification.ManagedNotificationProducer; -import io.fd.honeycomb.v3po.notification.NotificationCollector; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListener; -import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListenerRegistry; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Starts & stops notification producer dependencies on demand. - * Uses {@link DOMNotificationSubscriptionListenerRegistry} to receive subscription change notifications. - */ -@ThreadSafe -public final class NotificationProducerTracker - implements DOMNotificationSubscriptionListener, AutoCloseable { - - private static final Logger LOG = LoggerFactory.getLogger(NotificationProducerTracker.class); - - private final ListenerRegistration subscriptionListener; - private final NotificationProducerRegistry registry; - private final NotificationCollector collector; - - private final Set alreadyStartedProducers = new HashSet<>(); - - public NotificationProducerTracker(@Nonnull final NotificationProducerRegistry registry, - @Nonnull final NotificationCollector collector, - @Nonnull final DOMNotificationSubscriptionListenerRegistry notificationRouter) { - this.registry = registry; - this.collector = collector; - this.subscriptionListener = notificationRouter.registerSubscriptionListener(this); - } - - @Override - public synchronized void onSubscriptionChanged(final Set set) { - LOG.debug("Subscriptions changed. Current subscriptions: {}", set); - final Set currentSubscriptions = set.stream().map(SchemaPath::getLastComponent).collect(Collectors.toSet()); - final Set startedQNames = getStartedQNames(alreadyStartedProducers); - final Sets.SetView newSubscriptions = Sets.difference(currentSubscriptions, startedQNames); - LOG.debug("Subscriptions changed. New subscriptions: {}", newSubscriptions); - final Sets.SetView deletedSubscriptions = Sets.difference(startedQNames, currentSubscriptions); - LOG.debug("Subscriptions changed. Deleted subscriptions: {}", deletedSubscriptions); - - newSubscriptions.stream().forEach(newSub -> { - if(!registry.getNotificationQNameToProducer().containsKey(newSub)) { - return; - } - final ManagedNotificationProducer producer = registry.getNotificationQNameToProducer().get(newSub); - if(alreadyStartedProducers.contains(producer)) { - return; - } - LOG.debug("Starting notification producer: {}", producer); - producer.start(collector); - alreadyStartedProducers.add(producer); - }); - - deletedSubscriptions.stream().forEach(newSub -> { - checkState(registry.getNotificationQNameToProducer().containsKey(newSub)); - final ManagedNotificationProducer producer = registry.getNotificationQNameToProducer().get(newSub); - checkState(alreadyStartedProducers.contains(producer)); - LOG.debug("Stopping notification producer: {}", producer); - producer.stop(); - alreadyStartedProducers.remove(producer); - }); - - } - - private Set getStartedQNames(final Set alreadyStartedProducers) { - return alreadyStartedProducers.stream() - .flatMap(p -> registry.getNotificationProducerQNames().get(p).stream()) - .collect(Collectors.toSet()); - } - - @Override - public synchronized void close() throws Exception { - LOG.trace("Closing"); - subscriptionListener.close(); - // Stop all producers - LOG.debug("Stopping all producers: {}", alreadyStartedProducers); - alreadyStartedProducers.forEach(ManagedNotificationProducer::stop); - alreadyStartedProducers.clear(); - } -} diff --git a/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModule.java b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModule.java index 4a9440cbc..056b38798 100644 --- a/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModule.java +++ b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModule.java @@ -1,10 +1,10 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601; -import io.fd.honeycomb.v3po.notification.NotificationCollector; -import io.fd.honeycomb.v3po.notification.NotificationProducer; -import io.fd.honeycomb.v3po.notification.impl.HoneycombNotificationCollector; -import io.fd.honeycomb.v3po.notification.impl.NotificationProducerRegistry; -import io.fd.honeycomb.v3po.notification.impl.NotificationProducerTracker; +import io.fd.honeycomb.notification.NotificationCollector; +import io.fd.honeycomb.notification.NotificationProducer; +import io.fd.honeycomb.notification.impl.HoneycombNotificationCollector; +import io.fd.honeycomb.notification.impl.NotificationProducerRegistry; +import io.fd.honeycomb.notification.impl.NotificationProducerTracker; import java.util.Collection; import org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationPublishServiceAdapter; import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; diff --git a/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModule.java b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModule.java index 4d85d64c5..734d340e8 100644 --- a/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModule.java +++ b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModule.java @@ -1,8 +1,8 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601; import com.google.common.annotations.VisibleForTesting; -import io.fd.honeycomb.v3po.notification.NotificationCollector; -import io.fd.honeycomb.v3po.notification.impl.NotificationProducerRegistry; +import io.fd.honeycomb.notification.NotificationCollector; +import io.fd.honeycomb.notification.impl.NotificationProducerRegistry; import java.io.IOException; import java.util.Set; import java.util.stream.Collectors; diff --git a/infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/HoneycombNotificationCollectorTest.java b/infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/HoneycombNotificationCollectorTest.java new file mode 100644 index 000000000..ef9f548b7 --- /dev/null +++ b/infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/HoneycombNotificationCollectorTest.java @@ -0,0 +1,63 @@ +/* + * 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.notification.impl; + +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.verify; + +import com.google.common.collect.Lists; +import io.fd.honeycomb.notification.ManagedNotificationProducer; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStart; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStartBuilder; + +public class HoneycombNotificationCollectorTest { + + private NotificationProducerRegistry notificationRegistry; + @Mock + private NotificationPublishService notificationService; + @Mock + private ManagedNotificationProducer producer; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + notificationRegistry = new NotificationProducerRegistry(Lists.newArrayList(producer)); + } + + @Test + public void testNotificationTypes() throws Exception { + final HoneycombNotificationCollector honeycombNotificationCollector = + new HoneycombNotificationCollector(notificationService, notificationRegistry); + + honeycombNotificationCollector.getNotificationTypes(); + verify(producer, atLeast(1)).getNotificationTypes(); + } + + @Test + public void testCollect() throws Exception { + final HoneycombNotificationCollector honeycombNotificationCollector = + new HoneycombNotificationCollector(notificationService, notificationRegistry); + + final NetconfSessionStart notif = new NetconfSessionStartBuilder().build(); + honeycombNotificationCollector.onNotification(notif); + verify(notificationService).putNotification(notif); + } +} \ No newline at end of file diff --git a/infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/NotificationProducerRegistryTest.java b/infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/NotificationProducerRegistryTest.java new file mode 100644 index 000000000..a09803f02 --- /dev/null +++ b/infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/NotificationProducerRegistryTest.java @@ -0,0 +1,98 @@ +/* + * 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.notification.impl; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.mockito.Mockito.doReturn; + +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; +import io.fd.honeycomb.notification.ManagedNotificationProducer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionEnd; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStart; +import org.opendaylight.yangtools.yang.binding.Notification; +import org.opendaylight.yangtools.yang.common.QName; + +public class NotificationProducerRegistryTest { + + @Mock + private ManagedNotificationProducer producer; + @Mock + private ManagedNotificationProducer producer2; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn(Collections.singleton(NetconfCapabilityChange.class)) + .when(producer).getNotificationTypes(); + final ArrayList producer2Notifications = Lists.newArrayList(); + producer2Notifications.add(NetconfSessionStart.class); + producer2Notifications.add(NetconfSessionEnd.class); + doReturn(producer2Notifications).when(producer2).getNotificationTypes(); + } + + @Test + public void testNotificationTypes() throws Exception { + final NotificationProducerRegistry notificationRegistry = + new NotificationProducerRegistry(Lists.newArrayList(producer, producer2)); + + final Set> notificationTypes = + notificationRegistry.getNotificationTypes(); + + Assert.assertThat(notificationTypes, hasItem(NetconfSessionEnd.class)); + Assert.assertThat(notificationTypes, hasItem(NetconfSessionStart.class)); + Assert.assertThat(notificationTypes, hasItem(NetconfCapabilityChange.class)); + } + + @Test + public void testNotificationTypesMapped() throws Exception { + final NotificationProducerRegistry notificationRegistry = + new NotificationProducerRegistry(Lists.newArrayList(producer, producer2)); + + final Multimap notificationTypes = + notificationRegistry.getNotificationProducerQNames(); + + Assert.assertThat(notificationTypes.keySet(), hasItem(producer)); + Assert.assertThat(notificationTypes.get(producer), hasItem(NetconfCapabilityChange.QNAME)); + Assert.assertThat(notificationTypes.keySet(), hasItem(producer2)); + Assert.assertThat(notificationTypes.get(producer2), hasItem(NetconfSessionStart.QNAME)); + Assert.assertThat(notificationTypes.get(producer2), hasItem(NetconfSessionEnd.QNAME)); + + final Map notificationQNameToProducer = + notificationRegistry.getNotificationQNameToProducer(); + + Assert.assertThat(notificationQNameToProducer.keySet(), hasItem(NetconfCapabilityChange.QNAME)); + Assert.assertThat(notificationQNameToProducer.get(NetconfCapabilityChange.QNAME), is(producer)); + + Assert.assertThat(notificationQNameToProducer.keySet(), hasItem(NetconfSessionStart.QNAME)); + Assert.assertThat(notificationQNameToProducer.keySet(), hasItem(NetconfSessionEnd.QNAME)); + Assert.assertThat(notificationQNameToProducer.get(NetconfSessionStart.QNAME), is(producer2)); + Assert.assertThat(notificationQNameToProducer.get(NetconfSessionEnd.QNAME), is(producer2)); + + + } +} \ No newline at end of file diff --git a/infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/NotificationProducerTrackerTest.java b/infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/NotificationProducerTrackerTest.java new file mode 100644 index 000000000..4de2e7773 --- /dev/null +++ b/infra/notification/impl/src/test/java/io/fd/honeycomb/notification/impl/NotificationProducerTrackerTest.java @@ -0,0 +1,67 @@ +/* + * 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.notification.impl; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import io.fd.honeycomb.notification.ManagedNotificationProducer; +import io.fd.honeycomb.notification.NotificationCollector; +import java.util.Collections; +import java.util.Set; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListenerRegistry; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStart; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; + +public class NotificationProducerTrackerTest { + + private NotificationProducerRegistry registry; + @Mock + private DOMNotificationSubscriptionListenerRegistry subscriptionRegistry; + @Mock + private NotificationCollector collector; + @Mock + private ManagedNotificationProducer producer; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn(Collections.singleton(NetconfSessionStart.class)).when(producer).getNotificationTypes(); + registry = new NotificationProducerRegistry(Lists.newArrayList(producer)); + } + + @Test + public void name() throws Exception { + final NotificationProducerTracker notificationProducerTracker = + new NotificationProducerTracker(registry, collector, subscriptionRegistry); + verify(subscriptionRegistry).registerSubscriptionListener(notificationProducerTracker); + + final Set subscriptions = Sets.newHashSet(); + subscriptions.add(SchemaPath.create(true, NetconfSessionStart.QNAME)); + notificationProducerTracker.onSubscriptionChanged(subscriptions); + + verify(producer).start(collector); + + notificationProducerTracker.onSubscriptionChanged(Sets.newHashSet()); + verify(producer).stop(); + } +} \ No newline at end of file diff --git a/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollectorTest.java b/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollectorTest.java deleted file mode 100644 index f55d3abdf..000000000 --- a/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollectorTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.notification.impl; - -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.notification.ManagedNotificationProducer; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStart; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStartBuilder; - -public class HoneycombNotificationCollectorTest { - - private NotificationProducerRegistry notificationRegistry; - @Mock - private NotificationPublishService notificationService; - @Mock - private ManagedNotificationProducer producer; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - notificationRegistry = new NotificationProducerRegistry(Lists.newArrayList(producer)); - } - - @Test - public void testNotificationTypes() throws Exception { - final HoneycombNotificationCollector honeycombNotificationCollector = - new HoneycombNotificationCollector(notificationService, notificationRegistry); - - honeycombNotificationCollector.getNotificationTypes(); - verify(producer, atLeast(1)).getNotificationTypes(); - } - - @Test - public void testCollect() throws Exception { - final HoneycombNotificationCollector honeycombNotificationCollector = - new HoneycombNotificationCollector(notificationService, notificationRegistry); - - final NetconfSessionStart notif = new NetconfSessionStartBuilder().build(); - honeycombNotificationCollector.onNotification(notif); - verify(notificationService).putNotification(notif); - } -} \ No newline at end of file diff --git a/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistryTest.java b/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistryTest.java deleted file mode 100644 index 5fdf502b9..000000000 --- a/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistryTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.notification.impl; - -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.is; -import static org.mockito.Mockito.doReturn; - -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; -import io.fd.honeycomb.v3po.notification.ManagedNotificationProducer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionEnd; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStart; -import org.opendaylight.yangtools.yang.binding.Notification; -import org.opendaylight.yangtools.yang.common.QName; - -public class NotificationProducerRegistryTest { - - @Mock - private ManagedNotificationProducer producer; - @Mock - private ManagedNotificationProducer producer2; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - doReturn(Collections.singleton(NetconfCapabilityChange.class)) - .when(producer).getNotificationTypes(); - final ArrayList producer2Notifications = Lists.newArrayList(); - producer2Notifications.add(NetconfSessionStart.class); - producer2Notifications.add(NetconfSessionEnd.class); - doReturn(producer2Notifications).when(producer2).getNotificationTypes(); - } - - @Test - public void testNotificationTypes() throws Exception { - final NotificationProducerRegistry notificationRegistry = - new NotificationProducerRegistry(Lists.newArrayList(producer, producer2)); - - final Set> notificationTypes = - notificationRegistry.getNotificationTypes(); - - Assert.assertThat(notificationTypes, hasItem(NetconfSessionEnd.class)); - Assert.assertThat(notificationTypes, hasItem(NetconfSessionStart.class)); - Assert.assertThat(notificationTypes, hasItem(NetconfCapabilityChange.class)); - } - - @Test - public void testNotificationTypesMapped() throws Exception { - final NotificationProducerRegistry notificationRegistry = - new NotificationProducerRegistry(Lists.newArrayList(producer, producer2)); - - final Multimap notificationTypes = - notificationRegistry.getNotificationProducerQNames(); - - Assert.assertThat(notificationTypes.keySet(), hasItem(producer)); - Assert.assertThat(notificationTypes.get(producer), hasItem(NetconfCapabilityChange.QNAME)); - Assert.assertThat(notificationTypes.keySet(), hasItem(producer2)); - Assert.assertThat(notificationTypes.get(producer2), hasItem(NetconfSessionStart.QNAME)); - Assert.assertThat(notificationTypes.get(producer2), hasItem(NetconfSessionEnd.QNAME)); - - final Map notificationQNameToProducer = - notificationRegistry.getNotificationQNameToProducer(); - - Assert.assertThat(notificationQNameToProducer.keySet(), hasItem(NetconfCapabilityChange.QNAME)); - Assert.assertThat(notificationQNameToProducer.get(NetconfCapabilityChange.QNAME), is(producer)); - - Assert.assertThat(notificationQNameToProducer.keySet(), hasItem(NetconfSessionStart.QNAME)); - Assert.assertThat(notificationQNameToProducer.keySet(), hasItem(NetconfSessionEnd.QNAME)); - Assert.assertThat(notificationQNameToProducer.get(NetconfSessionStart.QNAME), is(producer2)); - Assert.assertThat(notificationQNameToProducer.get(NetconfSessionEnd.QNAME), is(producer2)); - - - } -} \ No newline at end of file diff --git a/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTrackerTest.java b/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTrackerTest.java deleted file mode 100644 index b62bf0709..000000000 --- a/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTrackerTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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.notification.impl; - -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.notification.ManagedNotificationProducer; -import io.fd.honeycomb.v3po.notification.NotificationCollector; -import java.util.Collections; -import java.util.Set; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListenerRegistry; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStart; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; - -public class NotificationProducerTrackerTest { - - private NotificationProducerRegistry registry; - @Mock - private DOMNotificationSubscriptionListenerRegistry subscriptionRegistry; - @Mock - private NotificationCollector collector; - @Mock - private ManagedNotificationProducer producer; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - doReturn(Collections.singleton(NetconfSessionStart.class)).when(producer).getNotificationTypes(); - registry = new NotificationProducerRegistry(Lists.newArrayList(producer)); - } - - @Test - public void name() throws Exception { - final NotificationProducerTracker notificationProducerTracker = - new NotificationProducerTracker(registry, collector, subscriptionRegistry); - verify(subscriptionRegistry).registerSubscriptionListener(notificationProducerTracker); - - final Set subscriptions = Sets.newHashSet(); - subscriptions.add(SchemaPath.create(true, NetconfSessionStart.QNAME)); - notificationProducerTracker.onSubscriptionChanged(subscriptions); - - verify(producer).start(collector); - - notificationProducerTracker.onSubscriptionChanged(Sets.newHashSet()); - verify(producer).stop(); - } -} \ No newline at end of file diff --git a/infra/notification/pom.xml b/infra/notification/pom.xml index 81b8aae40..3deb37797 100644 --- a/infra/notification/pom.xml +++ b/infra/notification/pom.xml @@ -22,6 +22,7 @@ + io.fd.honeycomb notification-aggregator 1.0.0-SNAPSHOT notification diff --git a/infra/postman_rest_collection.json b/infra/postman_rest_collection.json deleted file mode 100644 index 3adf19582..000000000 --- a/infra/postman_rest_collection.json +++ /dev/null @@ -1,1386 +0,0 @@ -{ - "id": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "name": "Honeycomb RESTCONF calls", - "description": "Common mgmt operations on VPP using Honeycomb REST interface", - "order": [ - "286f2d2d-88eb-ad68-7c6f-43caecc6073e", - "d27322b8-59d5-a2dc-a7a2-8f7197057164", - "5dc1d9f4-e7ae-bb21-e558-8a56ac825922", - "2f1d8e0d-4961-4b7f-50ad-0210e52e59aa", - "93022e97-24fa-5784-1e59-94674817215f", - "8b867c90-459f-68f6-4b2e-fa653098c28d", - "e611d23a-c205-192b-e8f9-dd99fa169274", - "3fccc4cd-f14b-0333-83d5-924afe3938e4" - ], - "folders": [ - { - "id": "7a914134-23ea-3154-1557-d29dc8d464e7", - "name": "IP", - "description": "", - "order": [ - "014dcd2b-1024-37a3-bc85-c18b0fdc0e8c", - "eb4852a6-ff3a-f9f4-4332-6677a93fcd2a", - "dc22d351-497a-4f01-52c1-6f01c76cf80b", - "69a05849-026d-f120-5c6a-f3e2b0884d88", - "b10169c2-ae0e-bb1c-3dea-ca06839c6c9c", - "8d49cf41-facc-c4ac-cee7-475d50e2a0be", - "70835949-7252-a3cc-491b-f8aa69286399", - "d5a90cfd-fd7e-63b6-e1f1-16fc0671b0e1", - "3f7ee49b-ae11-b032-915f-a14bf838246f", - "345ba26c-60cf-5fa1-37d0-f5af7a8c33bf" - ], - "owner": "45557" - }, - { - "id": "3d67940d-3c7a-8127-3965-6aee160e6b6f", - "name": "L2 FIB", - "description": "", - "order": [ - "76e9ee89-1594-ff38-ffff-ffc8de5d4054", - "dfbcc9e8-6f3d-b1c2-8bf6-989b1b1b3196", - "e2ff4db0-c013-cf89-d7b5-66de22bc7115", - "a937f1fc-10d5-bc19-ad5f-ac91fc007779", - "cf177689-9dd7-bcfe-d490-e9de6bde4dbb", - "0b63013d-3958-b427-2288-380019800468", - "99674f70-ec54-99f2-9300-545a031d5bab", - "f624bc96-502b-685c-1596-672ad5fcf6a9", - "0a1d6c0d-fe5e-1e1d-2471-96d7a4683e2f", - "d752fed9-127a-9289-71f3-90ba2b459d77", - "5c800144-cf89-7b77-1dd2-f488101ca441" - ], - "owner": "45557", - "collectionId": "e9ba4e80-fb4d-1eae-07e7-97b323164130" - }, - { - "id": "f91a6422-9724-e504-a94c-c5a953315b6f", - "name": "ACL", - "description": "", - "order": [ - "d7cb3d97-fc40-f471-33f3-07aad557777d", - "c067f721-6b1c-f205-799d-720b242f8592", - "5ab03c5f-03c5-8d42-bf65-024239049857", - "4f11c937-9562-3377-d03b-a9829b25f688", - "491ee2b7-88bf-3a71-282d-a16a62996026", - "fa63c194-ea7a-51ad-a6d8-d7485ed67f2e", - "b9931024-fa86-4e04-e2a4-4feeaa9e99e1", - "d39e4c39-90b6-072c-44b8-d909cac53a5b", - "2ce36b98-d7a9-fe37-80f6-f3a4abf25103", - "d0984799-d321-d1e0-a855-cc434519bef0", - "be223323-bf59-9c4f-f896-ff74c03b01a1", - "ee11f1c0-a1fe-51a6-a5e5-fcdcfc2b620a" - ], - "owner": "45557", - "collectionId": "e9ba4e80-fb4d-1eae-07e7-97b323164130" - }, - { - "id": "60596aab-a4f1-bb64-d701-816de9482201", - "name": "TAP", - "description": "", - "order": [ - "3f9588e4-885f-3792-bdf4-d0f10704ae4d", - "27106942-aff5-6ab5-07ae-5315135297a1", - "4db9b360-0d57-6ce6-7e3c-a6acfe17d512", - "5995dcf7-51c0-42ef-448b-a70bb68735d5" - ], - "owner": "45557" - }, - { - "id": "c97b9ad9-64e6-5de3-09b8-851c1189d767", - "name": "VHOST", - "description": "", - "order": [ - "7f312f15-a81e-b513-83b7-a5f7755eae67", - "ac161bec-e046-4bb7-d695-60bdfb0c6cea", - "55102dbd-1fc9-5f91-2082-40a2dc311f4f" - ], - "owner": "45557" - }, - { - "id": "37fd9569-06e3-1f08-fbcc-4b1462107a32", - "name": "VLAN", - "description": "", - "order": [ - "2ca639f4-f4a4-07c7-9419-79fd66061458", - "27eb70b8-a191-dd5c-f106-6693086ce872", - "f2e9a3cb-f3cc-f501-6015-8ebf7d8b2c3e", - "cbb77318-52e0-5647-cd1c-8c679ea7b830", - "8b339568-b60a-715f-d4fd-416bafe981a9", - "bd2897c6-5fc7-bec5-87be-4fd52bb8e471", - "44de3eff-ace5-90a9-dd16-af3f5f13daad", - "b08a0677-6b59-74ea-e5c6-7383194b19dd" - ], - "owner": "45557", - "collectionId": "e9ba4e80-fb4d-1eae-07e7-97b323164130" - }, - { - "id": "288569d0-e425-7877-4fd9-a82e8a340ade", - "name": "VXLAN-GPE-TUNNEL", - "description": "", - "order": [ - "0f223706-ca7f-fb8f-60ed-2b18e769e344", - "203ea32c-e43a-669c-4f28-232926df6928" - ], - "owner": "45557" - }, - { - "id": "3868e66d-0ee5-bd4d-6b35-075c4841b5c1", - "name": "VXLAN-TUNNEL", - "description": "", - "order": [ - "f014ab21-8e40-c344-a68b-0f1b86578bd8", - "4f15d0e9-8530-157e-0fe8-d24034bc31df" - ], - "owner": "45557" - } - ], - "timestamp": 1460119141419, - "owner": "45557", - "remoteLink": "", - "public": false, - "requests": [ - { - "id": "0f223706-ca7f-fb8f-60ed-2b18e769e344", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanGpeTun3", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1464768006369, - "name": "Add vxlan-gpe - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vxlanGpeTun3\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vxlan-gpe-tunnel\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"routing\" : {\r\n \"vrf-id\" : \"0\"\r\n },\r\n \"vxlan-gpe\" : {\r\n \"local\" : \"192.168.50.76\",\r\n \"remote\" : \"192.168.50.71\",\r\n \"vni\" : \"9\",\r\n \"next-protocol\" : \"ethernet\",\r\n \"encap-vrf-id\" : \"0\",\r\n \"decap-vrf-id\" : \"0\"\r\n }\r\n }\r\n ]\r\n \r\n}", - "folder": "288569d0-e425-7877-4fd9-a82e8a340ade" - }, - { - "id": "203ea32c-e43a-669c-4f28-232926df6928", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanGpeTun3", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1464764638498, - "name": "Delete vxlan-gpe - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "", - "folder": "288569d0-e425-7877-4fd9-a82e8a340ade" - }, - { - "id": "27106942-aff5-6ab5-07ae-5315135297a1", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp2", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1462796722186, - "name": "Add complex tap ifc - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"tapp2\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:tap\",\r\n \"tap\" :{\r\n \"tap-name\" : \"tapp2\",\r\n \"mac\" : \"00:ff:ff:ff:ff:ff\",\r\n \"device-instance\" : 55\r\n }\r\n }\r\n ]\r\n \r\n}", - "folder": "60596aab-a4f1-bb64-d701-816de9482201" - }, - { - "id": "27eb70b8-a191-dd5c-f106-6693086ce872", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1464804325716, - "name": "Enable GigabitEthernet0/9/0 interface - cfg", - "description": "Enables GigabitEthernet0/9/0 interface. Equivalent vppctl command:\n\nvppctl set in state GigabitEthernet0/9/0 up\n\nNeeded to enable sub interface.\n\nTo verify invoke:\n\nvppctl show int", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"GigabitEthernet0/9/0\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"v3po:ethernet\": {\r\n \"mtu\": 9216\r\n },\r\n \"enabled\": true,\r\n \"vpp-vlan:sub-interfaces\": {\r\n \"sub-interface\": [\r\n {\r\n \"identifier\": 1,\r\n \"vlan-type\": \"802dot1q\",\r\n \"tags\": {\r\n \"tag\": [\r\n {\r\n \"index\": 1,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": \"any\"\r\n }\r\n },\r\n {\r\n \"index\": 0,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": \"100\"\r\n }\r\n }\r\n ]\r\n },\r\n \"match\": {\r\n \"vlan-tagged\": {\r\n \"match-exact-tags\": true\r\n }\r\n },\r\n \"enabled\": false\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "286f2d2d-88eb-ad68-7c6f-43caecc6073e", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1460539962712, - "name": "List ifcs - cfg", - "description": "List ifcs - cfg", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "014dcd2b-1024-37a3-bc85-c18b0fdc0e8c", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F8%2F0/ipv4/neighbor/172.16.0.2", - "preRequestScript": null, - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": null, - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1466498440466, - "name": "Ip Neighbour Get", - "description": "This call returns data stored in honeycomb,to verify actual data stored by vpp, call vppctl show ip fib|arp", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\n \n \"interface\":{\n \"name\":\"GigabitEthernet0/8/0\",\n \"type\": \"iana-if-type:ethernetCsmacd\",\n \"enabled\":\"true\",\n \"ipv4\":{\n \"neighbor\":{\n \"ip\":\"172.16.0.2\",\n \"link-layer-address\":\"00:01:11:00:02:02\"\n }\n }\n }\n}\n" - }, - { - "id": "dc22d351-497a-4f01-52c1-6f01c76cf80b", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F8%2F0/ipv4/neighbor/172.16.0.2", - "preRequestScript": null, - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": null, - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1466498502212, - "name": "Ip Neighbour Delete", - "description": "Verify this call by invoking vppctl show ip fib|arp", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\n \"neighbor\":{\n \"ip\":\"172.16.0.2\",\n \"link-layer-address\":\"00:01:11:00:02:02\"\n }\n}\n" - }, - { - "id": "eb4852a6-ff3a-f9f4-4332-6677a93fcd2a", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F8%2F0/ipv4/neighbor/172.16.0.2", - "preRequestScript": null, - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": null, - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1466498409820, - "name": "Ip Neighbour Add", - "description": "This call doesnt have respective dump call,because of performance issues(dump for this can contain millions of entries). Data inserted throught this call can be verified by calling vppctl show ip fib|arp", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\n \n \"neighbor\":{\n \"ip\":\"172.16.0.2\",\n \"link-layer-address\":\"00:01:11:00:02:02\"\n }\n \n}\n" - }, - { - "id": "2ca639f4-f4a4-07c7-9419-79fd66061458", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1464804304987, - "name": "Add sub interface - cfg", - "description": "Adds sub interface. Corresponsing vpp cli command:\n\nvppctl create sub GigabitEthernet0/9/0 1 dot1q 100 inner-dot1q any\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", - "rawModeData": "{\r\n \"sub-interface\": [\r\n {\r\n \"identifier\": \"1\",\r\n \"vlan-type\": \"802dot1q\",\r\n \"tags\": {\r\n \"tag\": [\r\n {\r\n \"index\": \"0\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": \"100\"\r\n }\r\n },\r\n {\r\n \"index\": \"1\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": \"any\"\r\n }\r\n }\r\n ]\r\n },\r\n \"match\": {\r\n \"vlan-tagged\": {\r\n \"match-exact-tags\": \"true\"\r\n }\r\n },\r\n \"enabled\": \"false\"\r\n }\r\n ]\r\n}" - }, - { - "id": "2f1d8e0d-4961-4b7f-50ad-0210e52e59aa", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/v3po:vpp", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1460540006597, - "name": "Read vpp - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "76e9ee89-1594-ff38-ffff-ffc8de5d4054", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD", - "pathVariables": {}, - "preRequestScript": "", - "method": "PUT", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "data": [], - "dataMode": "raw", - "name": "Create bridge domain - cfg", - "description": "Creates bridgfe domain. Corresponds to invoking:\n\nvat# bridge_domain_add_del bd_id [bd_id] learn 0 forward 0 uu-flood 0 flood 1 arp-term 0\n\nTo verify run:\n\nvppctl show bridge-domain [bd_id] detail", - "descriptionFormat": "html", - "time": 1465805138795, - "version": 2, - "responses": [], - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "folder": "3d67940d-3c7a-8127-3965-6aee160e6b6f", - "rawModeData": "{\r\n \"bridge-domain\": [\r\n {\r\n \"name\": \"testBD\",\r\n \"flood\": \"true\",\r\n \"forward\": \"false\",\r\n \"learn\": \"false\",\r\n \"unknown-unicast-flood\": \"false\",\r\n \"arp-termination\": \"false\"\r\n }\r\n ]\r\n}" - }, - { - "id": "dfbcc9e8-6f3d-b1c2-8bf6-989b1b1b3196", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465806733493, - "name": "Show bridge domain - cfg", - "description": "Shows testBD bridge domain configuration.", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \"bridge-domain\": [\r\n {\r\n \"name\": \"testBD\",\r\n \"flood\": \"true\",\r\n \"forward\": \"false\",\r\n \"learn\": \"false\",\r\n \"unknown-unicast-flood\": \"false\",\r\n \"arp-termination\": \"false\"\r\n }\r\n ]\r\n}" - }, - { - "id": "e2ff4db0-c013-cf89-d7b5-66de22bc7115", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/operational/v3po:vpp-state/bridge-domains/bridge-domain/testBD", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465806752970, - "name": "Show bridge domain - oper", - "description": "Shows testBD bridge domain operational state.\nCorresponds to invoking:\n\nvppctl show bridge-domain [bd_id] detail", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \"bridge-domain\": [\r\n {\r\n \"name\": \"testBD\",\r\n \"flood\": \"true\",\r\n \"forward\": \"false\",\r\n \"learn\": \"false\",\r\n \"unknown-unicast-flood\": \"false\",\r\n \"arp-termination\": \"false\"\r\n }\r\n ]\r\n}" - }, - { - "id": "a937f1fc-10d5-bc19-ad5f-ac91fc007779", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:l2", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465805545425, - "name": "Add local0 to bridge domain", - "description": "Adds l2 interconnection of bridge-based type to local0 interface.\nCorresponds to the following command:\n\nvppctl set interface l2 bridge local0 [bd_id]\n\nTo verify invoke:\n\nvppctl show bridge-domain [bd_id] detail", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \"l2\": {\r\n \"bridge-domain\": \"testBD\",\r\n \"split-horizon-group\": 1,\r\n \"bridged-virtual-interface\": \"false\"\r\n }\r\n}" - }, - { - "id": "cf177689-9dd7-bcfe-d490-e9de6bde4dbb", - "headers": "", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/", - "preRequestScript": null, - "pathVariables": {}, - "method": "GET", - "data": null, - "dataMode": "params", - "tests": null, - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465805728052, - "name": "Show local0 - cfg", - "description": "Shows local0 interface configuration", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [] - }, - { - "id": "0b63013d-3958-b427-2288-380019800468", - "headers": "", - "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0/", - "pathVariables": {}, - "preRequestScript": null, - "method": "GET", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "data": null, - "dataMode": "params", - "name": "Show local0 - oper", - "description": "Shows local0 interface operational state", - "descriptionFormat": "html", - "time": 1465805719840, - "version": 2, - "responses": [], - "tests": null, - "currentHelper": "normal", - "helperAttributes": {}, - "folder": "3d67940d-3c7a-8127-3965-6aee160e6b6f" - }, - { - "id": "99674f70-ec54-99f2-9300-545a031d5bab", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/aa:bb:cc:dd:ee:ff", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465806456783, - "name": "Add L2 FIB entry (forward)", - "description": "Adds L2 FIB static entry. Corresponds to invoking:\n\nvppctl l2fib add aa:bb:cc:dd:ee:ff [bd_id] local0\n\nTo verify run:\n\nvppctl show l2fib verbose", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\n \"l2-fib-entry\": [\n {\n \"phys-address\": \"aa:bb:cc:dd:ee:ff\",\n \"outgoing-interface\": \"local0\",\n \"action\": \"l2-fib-forward\"\n }\n ]\n}" - }, - { - "id": "f624bc96-502b-685c-1596-672ad5fcf6a9", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/aa:bb:cc:dd:ee:ff", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465806577485, - "name": "Delete L2 FIB entry", - "description": "Removes L2 FIB entry. Corresponds to invoking:\n\nvppctl l2fib del aa:bb:cc:dd:ee:ff [bd_id]\n\nTo verify run:\n\nvppctl show l2fib verbose", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "" - }, - { - "id": "0a1d6c0d-fe5e-1e1d-2471-96d7a4683e2f", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/11:22:33:44:55:66", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465806064247, - "name": "Add L2 FIB entry (static, forward)", - "description": "Adds L2 FIB static entry. Corresponds to invoking:\n\nvppctl l2fib add 11:22:33:44:55:66 [bd_id] local0 static\n\nTo verify run:\n\nvppctl show l2fib verbose", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\n \"l2-fib-entry\": [\n {\n \"phys-address\": \"11:22:33:44:55:66\",\n \"outgoing-interface\": \"local0\",\n \"static-config\": \"true\",\n \"action\": \"l2-fib-forward\"\n }\n ]\n}" - }, - { - "id": "d752fed9-127a-9289-71f3-90ba2b459d77", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/00:01:02:03:04:05", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465814845273, - "name": "Add L2 FIB entry (filter)", - "description": "Adds L2 FIB static entry. Corresponds to invoking:\n\nvppctl l2fib add 00:01:02:03:04:05 [bd_id] filter\n\nTo verify run:\n\nvppctl show l2fib verbose", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\n \"l2-fib-entry\": [\n {\n \"phys-address\": \"00:01:02:03:04:05\",\n \"outgoing-interface\": \"local0\",\n \"static-config\": \"true\",\n \"action\": \"l2-fib-filter\"\n }\n ]\n}" - }, - { - "id": "5c800144-cf89-7b77-1dd2-f488101ca441", - "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:l2", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465984375972, - "name": "Remove local0 from bridge domain", - "description": "Removes l2 interconnection of bridge-based type from local0 interface.\nCorresponds to the following VAT command:\n\nvat# sw_interface_set_l2_bridge sw_if_index 0 bd_id 1 disable\n\nVerification in VAT:\n\nvat# bridge_domain_dump", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "" - }, - { - "id": "d7cb3d97-fc40-f471-33f3-07aad557777d", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1467377260818, - "name": "Get classify tables - cfg", - "description": "Shows classify table configuration.", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "" - }, - { - "id": "c067f721-6b1c-f205-799d-720b242f8592", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/operational/vpp-classifier:vpp-classifier-state/", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1467377066230, - "name": "Get classify tables - oper", - "description": "Shows classify tables configured in the VPP.\n\nCorresponds to:\n\nvppctl sh class table verbose", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "" - }, - { - "id": "5ab03c5f-03c5-8d42-bf65-024239049857", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1468493354688, - "name": "Add classify table0", - "description": "Adds classify table0. Corresponding vpp cli command:\n\nvppctl classify table mask l2 src\n\nTo verify invoke:\n\nvppctl sh class table verbose\n\nor:\n\nvat# classify_table_info table_id 0", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "{\n \"classify-table\": [\n {\n \"name\": \"table0\",\n \"nbuckets\": \"2\",\n \"memory_size\": \"1048576\",\n \"miss_next\": \"permit\",\n \"mask\": \"00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:00:00:00:00\"\n }\n ]\n}" - }, - { - "id": "4f11c937-9562-3377-d03b-a9829b25f688", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/operational/vpp-classifier:vpp-classifier-state/classify-table/table0", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1467378420028, - "name": "Get classify table - oper", - "description": "Shows classify table 0 operational state.\n\nCorresponds to:\n\nvat# classify_table_info table_id 0", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "" - }, - { - "id": "491ee2b7-88bf-3a71-282d-a16a62996026", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table1", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1468493298160, - "name": "Add classify table1", - "description": "Adds classify table1 chained to classify table0.\n\nCorresponding vpp cli command:\n\nvppctl classify table mask l2 dst next-table 0\n\nTo verify invoke:\n\nvppctl sh class table verbose\n\nor:\n\nvat# classify_table_info table_id 1", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "{\n \"classify-table\": [\n {\n \"name\": \"table1\",\n \"next_table\": \"table0\",\n \"nbuckets\": \"2\",\n \"memory_size\": \"1048576\",\n \"miss_next\": \"permit\",\n \"mask\": \"ff:ff:ff:ff:ff:ff:00:00:00:00:00:00:00:00:00:00\"\n }\n ]\n}" - }, - { - "id": "fa63c194-ea7a-51ad-a6d8-d7485ed67f2e", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0/classify-session/00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1468493546163, - "name": "Add classify session", - "description": "Adds classify session to table0. Corresponding vpp cli command:\n\nvppctl classify session acl-hit-next deny opaque-index 0 table-index 0 match l2 src 01:02:03:04:05:06\n\nTo verify invoke:\n\nvppctl sh class table verbose", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "{\n \"classify-session\": [\n {\n \"hit_next\": \"deny\",\n \"match\": \"00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00\"\n }\n ]\n}" - }, - { - "id": "b9931024-fa86-4e04-e2a4-4feeaa9e99e1", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0/classify-session/00:00:00:00:00:00:01:02:03:04:05:07:00:00:00:00", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1468493583927, - "name": "Add another classify session", - "description": "Adds second classify session to table0. Corresponding vpp cli command:\n\nvppctl classify session acl-hit-next deny opaque-index 0 table-index 0 match l2 src 01:02:03:04:05:07\n\nTo verify invoke:\n\nvppctl sh class table verbose", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "{\n \"classify-session\": [\n {\n \"hit_next\": \"deny\",\n \"match\": \"00:00:00:00:00:00:01:02:03:04:05:07:00:00:00:00\"\n }\n ]\n}" - }, - { - "id": "d39e4c39-90b6-072c-44b8-d909cac53a5b", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:acl", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1468495690154, - "name": "Enable L2 and Ipv4 ACL on local0 interface", - "description": "Enables L2 and Ipv4 ACL on local0. Corresponding vpp cli commands:\n\nset int input acl intfc local0 l2-table 0\n\nset int input acl intfc local0 ip4-table 0\n\nTo verify invoke:\n\nvppctl show inacl type l2\n\nthen:\n\nvppctl show inacl type ip4", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "{\n \"v3po:acl\": {\n \"l2-acl\": {\n \"classify-table\": \"table0\"\n },\n \"ip4-acl\": {\n \"classify-table\": \"table0\"\n }\n }\n}" - }, - { - "id": "2ce36b98-d7a9-fe37-80f6-f3a4abf25103", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:acl/", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1467380189765, - "name": "Disable ACL on local0 interface", - "description": "Disables ACL on local0. To verify invoke:\n\nvppctl show inacl type l2\n\nand:\n\nvppctl show inacl type ip4", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "" - }, - { - "id": "d0984799-d321-d1e0-a855-cc434519bef0", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0/classify-session/00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1468493934488, - "name": "Remove classify session", - "description": "Removes classify session. To verify invoke:\n\nvppctl sh class table verbose", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "" - }, - { - "id": "be223323-bf59-9c4f-f896-ff74c03b01a1", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1467377830897, - "name": "Remove classify table0", - "description": "Removes classify table0. Corresponds to the following command:\n\nvppctl classify table del table 0\n\nTo verify invoke:\n\nvppctl sh class table verbose", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "" - }, - { - "id": "ee11f1c0-a1fe-51a6-a5e5-fcdcfc2b620a", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table1", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1467377388428, - "name": "Remove classify table1", - "description": "Removes classify table1. Corresponds to the following command:\n\nvppctl classify table del table 1\n\nTo verify invoke:\n\nvppctl sh class table verbose", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", - "rawModeData": "" - }, - { - "id": "3f9588e4-885f-3792-bdf4-d0f10704ae4d", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1462535811974, - "name": "Add simple tap ifc -cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "60596aab-a4f1-bb64-d701-816de9482201", - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"tapp\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:tap\",\r\n \"tap\" :{\r\n \"tap-name\" : \"tapp\"\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "3fccc4cd-f14b-0333-83d5-924afe3938e4", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1460640004531, - "name": "Set vrf id for local0 - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"local0\",\r\n \"description\": \"for testing purposes only\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"routing\" : {\r\n \"vrf-id\" : \"7\"\r\n },\r\n \"v3po:ethernet\": {\r\n \"mtu\": 64\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "44de3eff-ace5-90a9-dd16-af3f5f13daad", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1464805188780, - "name": "Enable tag-rewrite translate 1-2 - cfg", - "description": "Enables tag-rewrite translate 1-2 operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 translate 1-2 dot1q 111 222\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", - "rawModeData": "{\r\n \"rewrite\": {\r\n \"vlan-type\": \"vpp-vlan:802dot1q\",\r\n \"pop-tags\": \"1\",\r\n \"push-tags\": [\r\n {\r\n \"index\": 0,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": 111\r\n }\r\n },\r\n {\r\n \"index\": 1,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": 222\r\n }\r\n }\r\n ]\r\n }\r\n}" - }, - { - "id": "4db9b360-0d57-6ce6-7e3c-a6acfe17d512", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp2", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1462796801468, - "name": "Modify complex tap ifc - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"tapp2\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:tap\",\r\n \"tap\" :{\r\n \"tap-name\" : \"tapp2\",\r\n \"mac\" : \"00:ff:ff:ff:ff:ae\",\r\n \"device-instance\" : 77\r\n }\r\n }\r\n ]\r\n \r\n}", - "folder": "60596aab-a4f1-bb64-d701-816de9482201" - }, - { - "id": "4f15d0e9-8530-157e-0fe8-d24034bc31df", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanTun1", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": "{}", - "time": 1462892071867, - "name": "Delete virtual ifc - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "3868e66d-0ee5-bd4d-6b35-075c4841b5c1", - "timestamp": null, - "rawModeData": "" - }, - { - "id": "55102dbd-1fc9-5f91-2082-40a2dc311f4f", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vhost1", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": "{}", - "time": 1462891488523, - "name": "Delete vhost user ifc - cfg", - "description": "Deletes vhost user interface.\nCorresponding vpp CLI command:\n\nvppctl delete vhost-user sw_if_index [index]\n\nTo verify invoke:\n\nvppctl show vhost-user\n\nor\n\nvppctl show int", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "c97b9ad9-64e6-5de3-09b8-851c1189d767", - "rawModeData": "", - "descriptionFormat": null - }, - { - "id": "5995dcf7-51c0-42ef-448b-a70bb68735d5", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp2", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1462796994090, - "name": "Delete complex tap ifc - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "", - "folder": "60596aab-a4f1-bb64-d701-816de9482201" - }, - { - "id": "5dc1d9f4-e7ae-bb21-e558-8a56ac825922", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/operational/v3po:vpp-state", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1460539994330, - "name": "Read vpp-state - oper", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "7f312f15-a81e-b513-83b7-a5f7755eae67", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vhost1", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1462891472552, - "name": "Add vhost user ifc - cfg", - "description": "Adds vhost-user interface.\nCorresponsing vpp cli command:\n\ncreate vhost-user socket /tmp/soc1 server\n\nTo verify invoke:\n\nvppctl show vhost-user\n\nor\n\nvppctl show int", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vhost1\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vhost-user\",\r\n \"enabled\": \"true\",\r\n \"vhost-user\" : {\r\n \"socket\": \"/tmp/soc1\",\r\n \"role\": \"server\"\r\n }\r\n }\r\n ]\r\n \r\n}", - "folder": "c97b9ad9-64e6-5de3-09b8-851c1189d767" - }, - { - "id": "8b339568-b60a-715f-d4fd-416bafe981a9", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": "{}", - "time": 1464803940412, - "name": "Enable tag-rewrite push - cfg", - "description": "Enables tag-rewrite push operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 push dot1q 123 456\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", - "timestamp": null, - "rawModeData": "{\r\n \"rewrite\": {\r\n \"vlan-type\": \"vpp-vlan:802dot1q\",\r\n \"push-tags\": [\r\n {\r\n \"index\": 0,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": 123\r\n }\r\n },\r\n {\r\n \"index\": 1,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": 456\r\n }\r\n }\r\n ]\r\n }\r\n}" - }, - { - "id": "8b867c90-459f-68f6-4b2e-fa653098c28d", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1460540047356, - "name": "Enable local0 interface - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"local0\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"v3po:ethernet\": {\r\n \"mtu\": 64\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "93022e97-24fa-5784-1e59-94674817215f", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/operational/naming-context:contexts", - "pathVariables": {}, - "preRequestScript": "", - "method": "GET", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "data": [], - "dataMode": "raw", - "name": "List naming contexts - context", - "description": "List mapping context stored in context datastore", - "descriptionFormat": "html", - "time": 1463556756647, - "version": 2, - "responses": [], - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "69a05849-026d-f120-5c6a-f3e2b0884d88", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465472429324, - "name": "Read local0 - oper", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "b10169c2-ae0e-bb1c-3dea-ca06839c6c9c", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1466496859574, - "name": "Set ipv4 local0 interface - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", - "rawModeData": "{\r\n \"address\": [{\r\n \"ip\" : \"127.0.0.1\",\r\n \"prefix-length\" : \"24\"\r\n }]\r\n}" - }, - { - "id": "8d49cf41-facc-c4ac-cee7-475d50e2a0be", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1466497187475, - "name": "Remove ipv4 from local0 interface - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", - "rawModeData": "" - }, - { - "id": "70835949-7252-a3cc-491b-f8aa69286399", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1466497176571, - "name": "Set ipv4 local0 interface - cfg netmask", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", - "rawModeData": "{\r\n \"address\": [{\r\n \"ip\" : \"127.0.0.1\",\r\n \"netmask\": \"255.255.255.128\"\r\n }]\r\n}" - }, - { - "id": "d5a90cfd-fd7e-63b6-e1f1-16fc0671b0e1", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0/ipv4", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465473594194, - "name": "Read local0/ipv4 - oper", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "3f7ee49b-ae11-b032-915f-a14bf838246f", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1466497212835, - "name": "Read local0/ipv4 - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "345ba26c-60cf-5fa1-37d0-f5af7a8c33bf", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/ipv4/address/1.2.3.4", - "pathVariables": {}, - "preRequestScript": "", - "method": "PUT", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "data": [], - "dataMode": "raw", - "name": "Set ipv4 for sub-interface - cfg", - "description": "Correponds to the following command:\n\nvppctl set interface ip address GigabitEthernet0/9/0.1 1.2.3.4/8\n\nTo verify invoke:\nvppctl show int", - "descriptionFormat": "html", - "time": 1467117222646, - "version": 2, - "responses": [], - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", - "rawModeData": "{\r\n \"address\": [{\r\n \"ip\" : \"1.2.3.4\",\r\n \"prefix-length\" : \"8\"\r\n }]\r\n}" - }, - { - "id": "ac161bec-e046-4bb7-d695-60bdfb0c6cea", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vhost1", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1462891483790, - "name": "Modify vhost user ifc - cfg", - "description": "Modifies vhost-user interface socket.\nTo verify invoke:\n\nvppctl show vhost-user", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vhost1\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vhost-user\",\r\n \"enabled\": \"true\",\r\n \"vhost-user\" : {\r\n \"socket\": \"/tmp/soc2\",\r\n \"role\": \"server\"\r\n }\r\n }\r\n ]\r\n \r\n}", - "folder": "c97b9ad9-64e6-5de3-09b8-851c1189d767" - }, - { - "id": "b08a0677-6b59-74ea-e5c6-7383194b19dd", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite", - "preRequestScript": "", - "pathVariables": {}, - "method": "DELETE", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1464804511683, - "name": "Disable tag-rewrite - cfg", - "description": "Disables tag-rewrite operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 disable\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", - "rawModeData": "" - }, - { - "id": "bd2897c6-5fc7-bec5-87be-4fd52bb8e471", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1464805111410, - "name": "Enable tag-rewrite pop 1 - cfg", - "description": "Enables tag-rewrite pop 1 operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 pop 1\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", - "rawModeData": "{\r\n \"rewrite\": {\r\n \"pop-tags\": \"1\"\r\n }\r\n}" - }, - { - "id": "cbb77318-52e0-5647-cd1c-8c679ea7b830", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1464813539029, - "name": "Add sub interface to bridge-domain", - "description": "Adds sub interface to bridge domain. Corresponsing vpp cli command:\n\nvppctl set interface l2 bridge GigabitEthernet0/9/0.1 1 1\n\nTo verify invoke:\nvppctl show bridge-domain 1 detail", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", - "rawModeData": "{\r\n \"l2\": {\r\n \"bridge-domain\": \"testBD\",\r\n \"split-horizon-group\": 1,\r\n \"bridged-virtual-interface\": \"false\"\r\n }\r\n}" - }, - { - "id": "d27322b8-59d5-a2dc-a7a2-8f7197057164", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1460539972177, - "name": "List ifcs - oper", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { - "id": "e611d23a-c205-192b-e8f9-dd99fa169274", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1460636113690, - "name": "Set interfaces bulk edit - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\n \"interfaces\": {\n \"interface\": [\n {\n \"name\": \"pg/stream-2\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n },\n {\n \"name\": \"pg/stream-3\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n },\n {\n \"name\": \"pg/stream-0\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n },\n {\n \"name\": \"local0\",\n \"description\": \"for testing purposes\",\n \"type\": \"iana-if-type:ethernetCsmacd\",\n \"enabled\": true\n },\n {\n \"name\": \"pg/stream-1\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n }\n ]\n }\n}" - }, - { - "id": "f014ab21-8e40-c344-a68b-0f1b86578bd8", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanTun1", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1464767860505, - "name": "Add virtual ifc - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vxlanTun1\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vxlan-tunnel\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"routing\" : {\r\n \"vrf-id\" : \"0\"\r\n },\r\n \"vxlan\" : {\r\n \"src\" : \"192.168.1.6\",\r\n \"dst\" : \"192.168.1.9\",\r\n \"vni\" : \"88\",\r\n \"encap-vrf-id\" : \"0\"\r\n }\r\n }\r\n ]\r\n \r\n}", - "folder": "3868e66d-0ee5-bd4d-6b35-075c4841b5c1" - }, - { - "id": "f2e9a3cb-f3cc-f501-6015-8ebf7d8b2c3e", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1", - "preRequestScript": "", - "pathVariables": {}, - "method": "PUT", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1464804333865, - "name": "Enable GigabitEthernet0/9/0.1 interface - cfg", - "description": "Enables GigabitEthernet0/9/0.1 sub interface. Equivalent vppctl command:\n\nvppctl set in state GigabitEthernet0/9/0.1 up\n\nTo enable sub interface, super interface should be enabled first.\n\nTo verify invoke:\n\nvppctl show int", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", - "rawModeData": "{\r\n \"sub-interface\": [\r\n {\r\n \"identifier\": \"1\",\r\n \"vlan-type\": \"802dot1q\",\r\n \"tags\": {\r\n \"tag\": [\r\n {\r\n \"index\": \"0\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": \"100\"\r\n }\r\n },\r\n {\r\n \"index\": \"1\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": \"any\"\r\n }\r\n }\r\n ]\r\n },\r\n \"match\": {\r\n \"vlan-tagged\": {\r\n \"match-exact-tags\": \"true\"\r\n }\r\n },\r\n \"enabled\": \"true\"\r\n }\r\n ]\r\n}" - } - ] -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/MappingContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/MappingContext.java new file mode 100644 index 000000000..5a5ba980c --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/MappingContext.java @@ -0,0 +1,66 @@ +/* + * 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.translate; + +import com.google.common.base.Optional; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Mapping context is persisted storage where mapping matadata are stored. + * A snapshot is created for each transaction to provide consistent view over context data. + * After a transaction is successfully finished, objects added to this context are propagated to backing storage. + */ +public interface MappingContext extends AutoCloseable { + + /** + * Read any mapping context data + * + * @param currentId Id of an object to read + * + * @return Relevant mapping context data + */ + Optional read(@Nonnull final InstanceIdentifier currentId); + + /** + * Delete the node at specified path. + * + * @param path Node path + */ + void delete(InstanceIdentifier path); + + /** + * Merge the specified data with the currently-present data + * at specified path. + * + * @param path Node path + * @param data Data to be merged + */ + void merge(InstanceIdentifier path, T data); + + /** + * Replace the data at specified path with supplied data. + * + * @param path Node path + * @param data New node data + */ + void put(InstanceIdentifier path, T data); + + @Override + void close(); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModifiableSubtreeManagerRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModifiableSubtreeManagerRegistryBuilder.java new file mode 100644 index 000000000..4e6b2d805 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModifiableSubtreeManagerRegistryBuilder.java @@ -0,0 +1,77 @@ +/* + * 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.translate; + +import java.util.Collection; +import java.util.Set; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Registry builder where {@link SubtreeManager}s can be added with or without relationships between them. + * The relationships express what the order of execution should be. + */ +public interface ModifiableSubtreeManagerRegistryBuilder> { + + /** + * Add a handler responsible for writing only a single complex node. + */ + ModifiableSubtreeManagerRegistryBuilder add(@Nonnull S handler); + + /** + * Add a handler responsible for writing multiple complex nodes within a subtree its responsible for. Identifiers for + * subtree nodes handled by a single handler have to be relative from {@link DataObject} that represents subtree + * root. + */ + ModifiableSubtreeManagerRegistryBuilder subtreeAdd(@Nonnull Set> handledChildren, + @Nonnull S handler); + + /** + * Add a handler and make sure it will be executed before handler identifier by relatedType is executed. + */ + ModifiableSubtreeManagerRegistryBuilder addBefore(@Nonnull S handler, + @Nonnull InstanceIdentifier relatedType); + + ModifiableSubtreeManagerRegistryBuilder addBefore(@Nonnull S handler, + @Nonnull Collection> relatedTypes); + + ModifiableSubtreeManagerRegistryBuilder subtreeAddBefore(@Nonnull Set> handledChildren, + @Nonnull S handler, + @Nonnull InstanceIdentifier relatedType); + + ModifiableSubtreeManagerRegistryBuilder subtreeAddBefore(@Nonnull Set> handledChildren, + @Nonnull S handler, + @Nonnull Collection> relatedTypes); + + /** + * Add a handler and make sure it will be executed after handler identifier by relatedType is executed. + */ + ModifiableSubtreeManagerRegistryBuilder addAfter(@Nonnull S handler, + @Nonnull InstanceIdentifier relatedType); + + ModifiableSubtreeManagerRegistryBuilder addAfter(@Nonnull S handler, + @Nonnull Collection> relatedTypes); + + ModifiableSubtreeManagerRegistryBuilder subtreeAddAfter(@Nonnull Set> handledChildren, + @Nonnull S handler, + @Nonnull InstanceIdentifier relatedType); + + ModifiableSubtreeManagerRegistryBuilder subtreeAddAfter(@Nonnull Set> handledChildren, + @Nonnull S handler, + @Nonnull Collection> relatedTypes); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModificationCache.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModificationCache.java new file mode 100644 index 000000000..dcf97439b --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModificationCache.java @@ -0,0 +1,49 @@ +/* + * 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.translate; + +import com.google.common.collect.Maps; +import java.util.HashMap; + +/** + * Simple context class that provides transient storage during one or more read/write operations + */ +public class ModificationCache implements AutoCloseable { + + protected final HashMap map; + + public ModificationCache() { + map = Maps.newHashMap(); + } + + public Object get(final Object o) { + return map.get(o); + } + + public boolean containsKey(final Object o) { + return map.containsKey(o); + } + + public Object put(final Object o, final Object o2) { + return map.put(o, o2); + } + + @Override + public void close() { + map.clear(); + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModificationContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModificationContext.java new file mode 100644 index 000000000..049c6c05e --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModificationContext.java @@ -0,0 +1,44 @@ +/* + * 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.translate; + +import javax.annotation.Nonnull; + +/** + * Common context for both writes and reads + */ +public interface ModificationContext extends AutoCloseable { + + /** + * Get key value transient storage for customizers. Is cleared for each new transaction. + * + * @return Context for customizers + */ + @Nonnull + ModificationCache getModificationCache(); + + /** + * Get persistent storage for mapping context. This context survives a modification. + * + * @return Mapping context accessor + */ + @Nonnull + MappingContext getMappingContext(); + + @Override + void close(); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/SubtreeManager.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/SubtreeManager.java new file mode 100644 index 000000000..1e98582df --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/SubtreeManager.java @@ -0,0 +1,39 @@ +/* + * 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.translate; + +import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Base identifiable subtree manager(reader, writer etc.) + * + * @param Specific DataObject derived type, that is managed by this manager + */ +@Beta +public interface SubtreeManager { + + /** + * Gets the type of node managed by this reader. + * + * @return Absolute instance identifier for managed type + */ + @Nonnull + InstanceIdentifier getManagedDataObjectType(); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/SubtreeManagerRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/SubtreeManagerRegistryBuilder.java new file mode 100644 index 000000000..7d4104916 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/SubtreeManagerRegistryBuilder.java @@ -0,0 +1,22 @@ +/* + * 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.translate; + +public interface SubtreeManagerRegistryBuilder { + + R build(); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/TranslationException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/TranslationException.java new file mode 100644 index 000000000..6037391e2 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/TranslationException.java @@ -0,0 +1,38 @@ +/* + * 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.translate; + +import com.google.common.annotations.Beta; + +/** + * Base exception for the translation layer + */ +@Beta +public class TranslationException extends Exception { + + public TranslationException(final String s) { + super(s); + } + + public TranslationException(final String s, final Throwable cause) { + super(s, cause); + } + + public TranslationException(final Throwable cause) { + super(cause); + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ListReader.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ListReader.java new file mode 100644 index 000000000..3791d8e2a --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ListReader.java @@ -0,0 +1,66 @@ +/* + * 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.translate.read; + +import com.google.common.annotations.Beta; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * List reader, allowing read of all the elements. + * + * @param Specific DataObject derived type, that is handled by this reader + */ +@Beta +public interface ListReader + , K extends Identifier, B extends Builder> extends Reader { + + /** + * Read all elements in this list. + * + * @param id Wildcarded identifier of list managed by this reader + * @param ctx Read context + * + * @return List of all entries in this list + * @throws ReadFailedException if read was unsuccessful + */ + @Nonnull + List readList(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext ctx) + throws ReadFailedException; + + /** + * Get IDs for all entries in the list. + */ + List getAllIds(@Nonnull InstanceIdentifier id, @Nonnull ReadContext ctx) + throws ReadFailedException; + + /** + * Merge read data into provided parent builder. + */ + void merge(@Nonnull final Builder builder, @Nonnull final List readData); + + @Override + default void merge(@Nonnull final Builder parentBuilder, @Nonnull final D readValue) { + merge(parentBuilder, Collections.singletonList(readValue)); + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReadContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReadContext.java new file mode 100644 index 000000000..655a5164c --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReadContext.java @@ -0,0 +1,26 @@ +/* + * 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.translate.read; + +import io.fd.honeycomb.translate.ModificationContext; + +/** + * Context providing information about current state of DataTree to readers + */ +public interface ReadContext extends ModificationContext { + +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReadFailedException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReadFailedException.java new file mode 100644 index 000000000..fc429b1d0 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReadFailedException.java @@ -0,0 +1,61 @@ +/* + * 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.translate.read; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.TranslationException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Thrown when a reader or customizer is not able to read data for the given id. + */ +public class ReadFailedException extends TranslationException { + + private final InstanceIdentifier failedId; + + /** + * Constructs an ReadFailedException given data id and exception cause. + * + * @param failedId instance identifier of the data object that could not be read + * @param cause the cause of read failure + */ + public ReadFailedException(@Nonnull final InstanceIdentifier failedId, final Throwable cause) { + super("Failed to read " + failedId, cause); + this.failedId = checkNotNull(failedId, "failedId should not be null"); + } + + /** + * Constructs an ReadFailedException given data id. + * + * @param failedId instance identifier of the data object that could not be read + */ + public ReadFailedException(@Nonnull final InstanceIdentifier failedId) { + this(failedId, null); + } + + /** + * Returns id of the data object that could not be read. + * + * @return data object instance identifier + */ + @Nonnull + public InstanceIdentifier getFailedId() { + return failedId; + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/Reader.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/Reader.java new file mode 100644 index 000000000..177b52415 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/Reader.java @@ -0,0 +1,76 @@ +/* + * 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.translate.read; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.SubtreeManager; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Base reader, responsible for translation between DataObjects and any other side. + * + * @param Specific DataObject derived type, that is handled by this reader + */ +@Beta +public interface Reader> extends SubtreeManager { + + // TODO make async + + /** + * Reads data identified by id + * + * @param id unique identifier of subtree to be read. The subtree must contain managed data object type. For + * identifiers pointing below node managed by this reader, it's reader's responsibility to filter out the + * right node or to delegate the read to a child reader. + * @param ctx Read context + * + * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list + * @throws ReadFailedException if read was unsuccessful + */ + @Nonnull + Optional read(@Nonnull InstanceIdentifier id, + @Nonnull ReadContext ctx) throws ReadFailedException; + + /** + * Fill in current node's attributes + * + * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. + * @param builder Builder object for current node where the read attributes must be placed + * @param ctx Current read context + */ + void readCurrentAttributes(@Nonnull InstanceIdentifier id, + @Nonnull B builder, + @Nonnull ReadContext ctx) throws ReadFailedException; + + /** + * Return new instance of a builder object for current node + * + * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. + * @return Builder object for current node type + */ + @Nonnull + B getBuilder(InstanceIdentifier id); + + /** + * Merge read data into provided parent builder. + */ + void merge(@Nonnull final Builder parentBuilder, @Nonnull final D readValue); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReaderFactory.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReaderFactory.java new file mode 100644 index 000000000..701a26dd5 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/ReaderFactory.java @@ -0,0 +1,38 @@ +/* + * 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.translate.read; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import javax.annotation.Nonnull; + +/** + * Factory producing readers for {@link ModifiableReaderRegistryBuilder}. + */ +@Beta +public interface ReaderFactory extends AutoCloseable { + + /** + * Initialize 1 or more readers and add them to provided registry. + */ + void init(@Nonnull ModifiableReaderRegistryBuilder registry); + + @Override + default void close() { + // NOOP TODO allow unregister + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ModifiableReaderRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ModifiableReaderRegistryBuilder.java new file mode 100644 index 000000000..10dcd9280 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ModifiableReaderRegistryBuilder.java @@ -0,0 +1,41 @@ +/* + * 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.translate.read.registry; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.ModifiableSubtreeManagerRegistryBuilder; +import io.fd.honeycomb.translate.read.Reader; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Mutable registry that allows adding new readers. + */ +@Beta +public interface ModifiableReaderRegistryBuilder + extends ModifiableSubtreeManagerRegistryBuilder>> { + + // TODO we should be able to add structural/reflexive readers automatically in the registry builder, we just need builder class + // We would need generated class loading strategy instance and then load builder classes relying on naming + package conventions of Binding spec + /** + * Add a structural reader that performs no read operation on its own, just fills in the hierarchy. + */ + void addStructuralReader(@Nonnull InstanceIdentifier id, + @Nonnull Class> builderType); +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ReaderRegistry.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ReaderRegistry.java new file mode 100644 index 000000000..9a1c99508 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ReaderRegistry.java @@ -0,0 +1,62 @@ +/* + * 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.translate.read.registry; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import com.google.common.collect.Multimap; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Simple delegating reader suitable as a holder for all other root readers, providing readAll feature. + */ +@Beta +public interface ReaderRegistry { + + /** + * Performs read on all registered root readers and merges the results into a Multimap. Keys represent identifiers + * for root DataObjects from the data tree modeled by YANG. + * + * @param ctx Read context + * + * @return multimap that preserves deterministic iteration order across non-distinct key values + * @throws ReadFailedException if read was unsuccessful + */ + @Nonnull + Multimap, ? extends DataObject> readAll(@Nonnull final ReadContext ctx) + throws ReadFailedException; + + /** + * Reads data identified by id. + * + * @param id unique identifier of subtree to be read. The subtree must contain managed data object type. For + * identifiers pointing below node managed by this reader, it's reader's responsibility to filter out the + * right node or to delegate the read to a child reader. + * @param ctx Read context + * + * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list + * @throws ReadFailedException if read was unsuccessful + */ + @Nonnull + Optional read(@Nonnull InstanceIdentifier id, + @Nonnull ReadContext ctx) + throws ReadFailedException; +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ReaderRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ReaderRegistryBuilder.java new file mode 100644 index 000000000..3f775f274 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/read/registry/ReaderRegistryBuilder.java @@ -0,0 +1,27 @@ +/* + * 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.translate.read.registry; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.SubtreeManagerRegistryBuilder; + +/** + * Builder for reader registries. + */ +@Beta +public interface ReaderRegistryBuilder extends SubtreeManagerRegistryBuilder { +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/DataObjectUpdate.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/DataObjectUpdate.java new file mode 100644 index 000000000..e76d76fcd --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/DataObjectUpdate.java @@ -0,0 +1,114 @@ +/* + * 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.translate.write; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Simple wrapper for BA id + data before and after state. Does not allow both before and after to be null. + */ +public class DataObjectUpdate { + + @Nonnull + private final InstanceIdentifier id; + @Nullable + private final DataObject dataBefore; + @Nullable + private final DataObject dataAfter; + + private DataObjectUpdate(@Nonnull final InstanceIdentifier id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter) { + this.id = checkNotNull(id); + this.dataAfter = dataAfter; + this.dataBefore = dataBefore; + } + + public DataObject getDataBefore() { + return dataBefore; + } + + public DataObject getDataAfter() { + return dataAfter; + } + + public InstanceIdentifier getId() { + return id; + } + + public static DataObjectUpdate create(@Nonnull final InstanceIdentifier id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter) { + checkArgument(!(dataBefore == null && dataAfter == null), "Both before and after data are null"); + if (dataBefore != null) { + checkArgument(id.getTargetType().isAssignableFrom(dataBefore.getClass())); + } + if (dataAfter != null) { + checkArgument(id.getTargetType().isAssignableFrom(dataAfter.getClass())); + } + + return dataAfter == null + ? new DataObjectDelete(id, dataBefore) + : new DataObjectUpdate(id, dataBefore, dataAfter); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final DataObjectUpdate that = (DataObjectUpdate) o; + + return id.equals(that.id); + + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public String toString() { + return "DataObjectUpdate{" + "id=" + id + + ", dataBefore=" + dataBefore + + ", dataAfter=" + dataAfter + + '}'; + } + + public DataObjectUpdate reverse() { + return DataObjectUpdate.create(id, dataAfter, dataBefore); + } + + public static class DataObjectDelete extends DataObjectUpdate { + + private DataObjectDelete(@Nonnull final InstanceIdentifier id, + @Nullable final DataObject dataBefore) { + super(id, dataBefore, null); + } + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/ListWriter.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/ListWriter.java new file mode 100644 index 000000000..ea4ed9c93 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/ListWriter.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.translate.write; + +import com.google.common.annotations.Beta; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; + +/** + * List writer, responsible for translation between a list of DataObjects and any other side. + * Handling all update operations(create, update, delete) + * + * @param Specific DataObject derived type, that is handled by this writer + * @param Identifier/key for D + */ +@Beta +public interface ListWriter, K extends Identifier> extends Writer { +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriteContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriteContext.java new file mode 100644 index 000000000..17aea8d8a --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriteContext.java @@ -0,0 +1,50 @@ +/* + * 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.translate.write; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.ModificationContext; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Context providing information about current state of DataTree to writers + */ +@Beta +public interface WriteContext extends ModificationContext { + + /** + * Read any config data object before current modification was applied + * + * @param currentId Id of an object to read + * + * @return Data before the modification was applied + */ + Optional readBefore(@Nonnull final InstanceIdentifier currentId); + + /** + * Read any config data object from current modification + * + * @param currentId Id of an object to read + * + * @return Data from the modification + */ + Optional readAfter(@Nonnull final InstanceIdentifier currentId); + +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriteFailedException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriteFailedException.java new file mode 100644 index 000000000..8f89d3163 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriteFailedException.java @@ -0,0 +1,166 @@ +/* + * 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.translate.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.TranslationException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Thrown when a writer or customizer is not able to write/update/delete data . + */ +public class WriteFailedException extends TranslationException { + + private final InstanceIdentifier failedId; + + /** + * Constructs an WriteFailedException given data id, exception detail message and exception cause. + * + * @param failedId instance identifier of the data object that could not be read + * @param cause the cause of read failure + * @param message the exception detail message + */ + public WriteFailedException(@Nonnull final InstanceIdentifier failedId, + @Nonnull final String message, + @Nonnull final Throwable cause) { + super(message, cause); + this.failedId = checkNotNull(failedId, "failedId should not be null"); + } + + /** + * Constructs an WriteFailedException given data id. + * + * @param failedId instance identifier of the data object that could not be written + */ + public WriteFailedException(@Nonnull final InstanceIdentifier failedId, + @Nonnull final String message) { + super(message); + this.failedId = checkNotNull(failedId, "failedId should not be null"); + } + + /** + * Constructs an WriteFailedException given data id and exception cause. + * + * @param failedId instance identifier of the data object that could not be read + * @param cause the cause of read failure + */ + public WriteFailedException(@Nonnull final InstanceIdentifier failedId, + @Nonnull final Throwable cause) { + super(cause); + this.failedId = checkNotNull(failedId, "failedId should not be null"); + } + + /** + * Returns id of the data object that could not be written. + * + * @return data object instance identifier + */ + @Nonnull + public InstanceIdentifier getFailedId() { + return failedId; + } + + + /** + * Delete specific write failed exception + */ + public static class DeleteFailedException extends WriteFailedException { + + public DeleteFailedException(@Nonnull final InstanceIdentifier failedId, @Nonnull final Throwable cause) { + super(failedId, getMsg(failedId), cause); + } + + private static String getMsg(@Nonnull final InstanceIdentifier failedId) { + return String.format("Failed to delete data at: %s", failedId); + } + + public DeleteFailedException(@Nonnull final InstanceIdentifier failedId) { + super(failedId, getMsg(failedId)); + } + } + + /** + * Create specific write failed exception + */ + public static class CreateFailedException extends WriteFailedException { + + private final DataObject data; + + public CreateFailedException(@Nonnull final InstanceIdentifier failedId, + @Nonnull final DataObject data, + @Nonnull final Throwable cause) { + super(failedId, getMsg(failedId, data), cause); + this.data = checkNotNull(data, "data"); + } + + private static String getMsg(final @Nonnull InstanceIdentifier failedId, final DataObject data) { + return String.format("Failed to create data: %s at: %s", data, failedId); + } + + public CreateFailedException(@Nonnull final InstanceIdentifier failedId, + @Nonnull final DataObject data) { + super(failedId, getMsg(failedId, data)); + this.data = checkNotNull(data, "data"); + } + + public DataObject getData() { + return data; + } + } + + /** + * Update specific write failed exception + */ + public static class UpdateFailedException extends WriteFailedException { + + private final DataObject dataBefore; + private final DataObject dataAfter; + + public UpdateFailedException(@Nonnull final InstanceIdentifier failedId, + @Nonnull final DataObject dataBefore, + @Nonnull final DataObject dataAfter, + @Nonnull final Throwable cause) { + super(failedId, getMsg(failedId, dataBefore, dataAfter), cause); + this.dataBefore = checkNotNull(dataBefore, "dataBefore"); + this.dataAfter = checkNotNull(dataAfter, "dataAfter"); + } + + private static String getMsg(final @Nonnull InstanceIdentifier failedId, final DataObject dataBefore, + final DataObject dataAfter) { + return String.format("Failed to update data from: %s to: %s, at: %s", dataBefore, dataAfter, failedId); + } + + public UpdateFailedException(@Nonnull final InstanceIdentifier failedId, + @Nonnull final DataObject dataBefore, + @Nonnull final DataObject dataAfter) { + super(failedId, getMsg(failedId, dataBefore, dataAfter)); + this.dataBefore = checkNotNull(dataBefore, "dataBefore"); + this.dataAfter = checkNotNull(dataAfter, "dataAfter"); + } + + public DataObject getDataBefore() { + return dataBefore; + } + + public DataObject getDataAfter() { + return dataAfter; + } + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/Writer.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/Writer.java new file mode 100644 index 000000000..e6538012b --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/Writer.java @@ -0,0 +1,48 @@ +/* + * 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.translate.write; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.SubtreeManager; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Base writer, responsible for translation between DataObjects and any other side. Handling all update operations(create, + * update, delete) + * + * @param Specific DataObject derived type, that is handled by this writer + */ +@Beta +public interface Writer extends SubtreeManager { + + /** + * Handle update operation. U from CRUD. + * + * @param id Identifier of data being written + * @param dataBefore Old data + * @param dataAfter New, updated data + * @param ctx Write context enabling writer to get information about candidate data as well as current data + * @throws WriteFailedException if update failed + */ + void update(@Nonnull final InstanceIdentifier id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter, + @Nonnull final WriteContext ctx) throws WriteFailedException; +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriterFactory.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriterFactory.java new file mode 100644 index 000000000..70328c7f5 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/WriterFactory.java @@ -0,0 +1,38 @@ +/* + * 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.translate.write; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import javax.annotation.Nonnull; + +/** + * Factory producing writers for {@link ModifiableWriterRegistryBuilder}. + */ +@Beta +public interface WriterFactory extends AutoCloseable { + + /** + * Initialize 1 or more writers and add them to provided registry. + */ + void init(@Nonnull ModifiableWriterRegistryBuilder registry); + + @Override + default void close() { + // NOOP TODO allow unregister + } +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/ModifiableWriterRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/ModifiableWriterRegistryBuilder.java new file mode 100644 index 000000000..27761e5b4 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/ModifiableWriterRegistryBuilder.java @@ -0,0 +1,31 @@ +/* + * 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.translate.write.registry; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.ModifiableSubtreeManagerRegistryBuilder; +import io.fd.honeycomb.translate.write.Writer; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * Mutable registry that allows adding new writers. + */ +@Beta +public interface ModifiableWriterRegistryBuilder + extends ModifiableSubtreeManagerRegistryBuilder> { + +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/WriterRegistry.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/WriterRegistry.java new file mode 100644 index 000000000..2467972da --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/WriterRegistry.java @@ -0,0 +1,213 @@ +/* + * 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.translate.write.registry; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; +import io.fd.honeycomb.translate.TranslationException; +import io.fd.honeycomb.translate.write.DataObjectUpdate; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.Writer; +import java.util.Set; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Special {@link Writer} capable of performing bulk updates. + */ +@Beta +public interface WriterRegistry { + + /** + * Performs bulk update. + * + * @throws BulkUpdateException in case bulk update fails + * @throws TranslationException in case some other error occurs while processing update request + */ + void update(@Nonnull DataObjectUpdates updates, + @Nonnull WriteContext ctx) throws TranslationException; + + /** + * Simple DTO containing updates for {@link WriterRegistry}. Currently only deletes and updates (create + update) + * are distinguished. + */ + @Beta + final class DataObjectUpdates { + + private final Multimap, DataObjectUpdate> updates; + private final Multimap, DataObjectUpdate.DataObjectDelete> deletes; + + /** + * Create new instance. + * + * @param updates All updates indexed by their unkeyed {@link InstanceIdentifier} + * @param deletes All deletes indexed by their unkeyed {@link InstanceIdentifier} + */ + public DataObjectUpdates(@Nonnull final Multimap, DataObjectUpdate> updates, + @Nonnull final Multimap, DataObjectUpdate.DataObjectDelete> deletes) { + this.deletes = deletes; + this.updates = updates; + } + + public Multimap, DataObjectUpdate> getUpdates() { + return updates; + } + + public Multimap, DataObjectUpdate.DataObjectDelete> getDeletes() { + return deletes; + } + + public boolean isEmpty() { + return updates.isEmpty() && deletes.isEmpty(); + } + + @Override + public String toString() { + return "DataObjectUpdates{" + "updates=" + updates + ", deletes=" + deletes + '}'; + } + + /** + * Get a {@link Set} containing all update types from both updates as well as deletes. + */ + public Set> getTypeIntersection() { + return Sets.union(deletes.keySet(), updates.keySet()); + } + + /** + * Check whether there is only a single type of data object to be updated. + * + * @return true if there is only a single type of updates (update + delete) + */ + public boolean containsOnlySingleType() { + return getTypeIntersection().size() == 1; + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + + final DataObjectUpdates that = (DataObjectUpdates) other; + + if (!updates.equals(that.updates)) { + return false; + } + return deletes.equals(that.deletes); + + } + + @Override + public int hashCode() { + int result = updates.hashCode(); + result = 31 * result + deletes.hashCode(); + return result; + } + + } + + /** + * Thrown when bulk update failed. + */ + @Beta + class BulkUpdateException extends TranslationException { + + private final Reverter reverter; + private final Set> failedIds; + + /** + * Constructs an BulkUpdateException. + * @param failedIds instance identifiers of the data objects that were not processed during bulk update. + * @param cause the cause of bulk update failure + */ + public BulkUpdateException(@Nonnull final Set> failedIds, + @Nonnull final Reverter reverter, + @Nonnull final Throwable cause) { + super("Bulk update failed at: " + failedIds, cause); + this.failedIds = failedIds; + this.reverter = checkNotNull(reverter, "reverter should not be null"); + } + + /** + * Reverts changes that were successfully applied during bulk update before failure occurred. + * + * @throws Reverter.RevertFailedException if revert fails + */ + public void revertChanges() throws Reverter.RevertFailedException { + reverter.revert(); + } + + public Set> getFailedIds() { + return failedIds; + } + } + + /** + * Abstraction over revert mechanism in case of a bulk update failure. + */ + @Beta + interface Reverter { + + /** + * Reverts changes that were successfully applied during bulk update before failure occurred. Changes are + * reverted in reverse order they were applied. + * + * @throws RevertFailedException if not all of applied changes were successfully reverted + */ + void revert() throws RevertFailedException; + + /** + * Thrown when some of the changes applied during bulk update were not reverted. + */ + @Beta + class RevertFailedException extends TranslationException { + + // TODO change to list of VppDataModifications to make debugging easier + private final Set> notRevertedChanges; + + /** + * Constructs a RevertFailedException with the list of changes that were not reverted. + * + * @param notRevertedChanges list of changes that were not reverted + * @param cause the cause of revert failure + */ + public RevertFailedException(@Nonnull final Set> notRevertedChanges, + final Throwable cause) { + super(cause); + checkNotNull(notRevertedChanges, "notRevertedChanges should not be null"); + this.notRevertedChanges = ImmutableSet.copyOf(notRevertedChanges); + } + + /** + * Returns the list of changes that were not reverted. + * + * @return list of changes that were not reverted + */ + @Nonnull + public Set> getNotRevertedChanges() { + return notRevertedChanges; + } + } + } +} \ No newline at end of file diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/WriterRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/WriterRegistryBuilder.java new file mode 100644 index 000000000..5e3481966 --- /dev/null +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/registry/WriterRegistryBuilder.java @@ -0,0 +1,27 @@ +/* + * 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.translate.write.registry; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.SubtreeManagerRegistryBuilder; + +/** + * Builder for writer registries. + */ +@Beta +public interface WriterRegistryBuilder extends SubtreeManagerRegistryBuilder { +} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java deleted file mode 100644 index cff766e2a..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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; - -import com.google.common.base.Optional; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Mapping context is persisted storage where mapping matadata are stored. - * A snapshot is created for each transaction to provide consistent view over context data. - * After a transaction is successfully finished, objects added to this context are propagated to backing storage. - */ -public interface MappingContext extends AutoCloseable { - - /** - * Read any mapping context data - * - * @param currentId Id of an object to read - * - * @return Relevant mapping context data - */ - Optional read(@Nonnull final InstanceIdentifier currentId); - - /** - * Delete the node at specified path. - * - * @param path Node path - */ - void delete(InstanceIdentifier path); - - /** - * Merge the specified data with the currently-present data - * at specified path. - * - * @param path Node path - * @param data Data to be merged - */ - void merge(InstanceIdentifier path, T data); - - /** - * Replace the data at specified path with supplied data. - * - * @param path Node path - * @param data New node data - */ - void put(InstanceIdentifier path, T data); - - @Override - void close(); -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java deleted file mode 100644 index 591a9e9bb..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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; - -import java.util.Collection; -import java.util.Set; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Registry builder where {@link SubtreeManager}s can be added with or without relationships between them. - * The relationships express what the order of execution should be. - */ -public interface ModifiableSubtreeManagerRegistryBuilder> { - - /** - * Add a handler responsible for writing only a single complex node. - */ - ModifiableSubtreeManagerRegistryBuilder add(@Nonnull S handler); - - /** - * Add a handler responsible for writing multiple complex nodes within a subtree its responsible for. Identifiers for - * subtree nodes handled by a single handler have to be relative from {@link DataObject} that represents subtree - * root. - */ - ModifiableSubtreeManagerRegistryBuilder subtreeAdd(@Nonnull Set> handledChildren, - @Nonnull S handler); - - /** - * Add a handler and make sure it will be executed before handler identifier by relatedType is executed. - */ - ModifiableSubtreeManagerRegistryBuilder addBefore(@Nonnull S handler, - @Nonnull InstanceIdentifier relatedType); - - ModifiableSubtreeManagerRegistryBuilder addBefore(@Nonnull S handler, - @Nonnull Collection> relatedTypes); - - ModifiableSubtreeManagerRegistryBuilder subtreeAddBefore(@Nonnull Set> handledChildren, - @Nonnull S handler, - @Nonnull InstanceIdentifier relatedType); - - ModifiableSubtreeManagerRegistryBuilder subtreeAddBefore(@Nonnull Set> handledChildren, - @Nonnull S handler, - @Nonnull Collection> relatedTypes); - - /** - * Add a handler and make sure it will be executed after handler identifier by relatedType is executed. - */ - ModifiableSubtreeManagerRegistryBuilder addAfter(@Nonnull S handler, - @Nonnull InstanceIdentifier relatedType); - - ModifiableSubtreeManagerRegistryBuilder addAfter(@Nonnull S handler, - @Nonnull Collection> relatedTypes); - - ModifiableSubtreeManagerRegistryBuilder subtreeAddAfter(@Nonnull Set> handledChildren, - @Nonnull S handler, - @Nonnull InstanceIdentifier relatedType); - - ModifiableSubtreeManagerRegistryBuilder subtreeAddAfter(@Nonnull Set> handledChildren, - @Nonnull S handler, - @Nonnull Collection> relatedTypes); -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java deleted file mode 100644 index cb2d4fde0..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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; - -import com.google.common.collect.Maps; -import java.util.HashMap; - -/** - * Simple context class that provides transient storage during one or more read/write operations - */ -public class ModificationCache implements AutoCloseable { - - protected final HashMap map; - - public ModificationCache() { - map = Maps.newHashMap(); - } - - public Object get(final Object o) { - return map.get(o); - } - - public boolean containsKey(final Object o) { - return map.containsKey(o); - } - - public Object put(final Object o, final Object o2) { - return map.put(o, o2); - } - - @Override - public void close() { - map.clear(); - } -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java deleted file mode 100644 index 2c039aba0..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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; - -import javax.annotation.Nonnull; - -/** - * Common context for both writes and reads - */ -public interface ModificationContext extends AutoCloseable { - - /** - * Get key value transient storage for customizers. Is cleared for each new transaction. - * - * @return Context for customizers - */ - @Nonnull - ModificationCache getModificationCache(); - - /** - * Get persistent storage for mapping context. This context survives a modification. - * - * @return Mapping context accessor - */ - @Nonnull - MappingContext getMappingContext(); - - @Override - void close(); -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java deleted file mode 100644 index 40842763d..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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; - -import com.google.common.annotations.Beta; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Base identifiable subtree manager(reader, writer etc.) - * - * @param Specific DataObject derived type, that is managed by this manager - */ -@Beta -public interface SubtreeManager { - - /** - * Gets the type of node managed by this reader. - * - * @return Absolute instance identifier for managed type - */ - @Nonnull - InstanceIdentifier getManagedDataObjectType(); -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java deleted file mode 100644 index 2434deddb..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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; - -public interface SubtreeManagerRegistryBuilder { - - R build(); -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java deleted file mode 100644 index ee0049977..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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; - -import com.google.common.annotations.Beta; - -/** - * Base exception for the translation layer - */ -@Beta -public class TranslationException extends Exception { - - public TranslationException(final String s) { - super(s); - } - - public TranslationException(final String s, final Throwable cause) { - super(s, cause); - } - - public TranslationException(final Throwable cause) { - super(cause); - } -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java deleted file mode 100644 index 13a7a55da..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.read; - -import com.google.common.annotations.Beta; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * List reader, allowing read of all the elements. - * - * @param Specific DataObject derived type, that is handled by this reader - */ -@Beta -public interface ListReader - , K extends Identifier, B extends Builder> extends Reader { - - /** - * Read all elements in this list. - * - * @param id Wildcarded identifier of list managed by this reader - * @param ctx Read context - * - * @return List of all entries in this list - * @throws ReadFailedException if read was unsuccessful - */ - @Nonnull - List readList(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext ctx) - throws ReadFailedException; - - /** - * Get IDs for all entries in the list. - */ - List getAllIds(@Nonnull InstanceIdentifier id, @Nonnull ReadContext ctx) - throws ReadFailedException; - - /** - * Merge read data into provided parent builder. - */ - void merge(@Nonnull final Builder builder, @Nonnull final List readData); - - @Override - default void merge(@Nonnull final Builder parentBuilder, @Nonnull final D readValue) { - merge(parentBuilder, Collections.singletonList(readValue)); - } -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java deleted file mode 100644 index e3ddd420c..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.read; - -import io.fd.honeycomb.v3po.translate.ModificationContext; - -/** - * Context providing information about current state of DataTree to readers - */ -public interface ReadContext extends ModificationContext { - -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java deleted file mode 100644 index 51d4fcb5a..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.read; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.fd.honeycomb.v3po.translate.TranslationException; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Thrown when a reader or customizer is not able to read data for the given id. - */ -public class ReadFailedException extends TranslationException { - - private final InstanceIdentifier failedId; - - /** - * Constructs an ReadFailedException given data id and exception cause. - * - * @param failedId instance identifier of the data object that could not be read - * @param cause the cause of read failure - */ - public ReadFailedException(@Nonnull final InstanceIdentifier failedId, final Throwable cause) { - super("Failed to read " + failedId, cause); - this.failedId = checkNotNull(failedId, "failedId should not be null"); - } - - /** - * Constructs an ReadFailedException given data id. - * - * @param failedId instance identifier of the data object that could not be read - */ - public ReadFailedException(@Nonnull final InstanceIdentifier failedId) { - this(failedId, null); - } - - /** - * Returns id of the data object that could not be read. - * - * @return data object instance identifier - */ - @Nonnull - public InstanceIdentifier getFailedId() { - return failedId; - } -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java deleted file mode 100644 index d0bf0dea1..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.read; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.SubtreeManager; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Base reader, responsible for translation between DataObjects and any other side. - * - * @param Specific DataObject derived type, that is handled by this reader - */ -@Beta -public interface Reader> extends SubtreeManager { - - // TODO make async - - /** - * Reads data identified by id - * - * @param id unique identifier of subtree to be read. The subtree must contain managed data object type. For - * identifiers pointing below node managed by this reader, it's reader's responsibility to filter out the - * right node or to delegate the read to a child reader. - * @param ctx Read context - * - * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list - * @throws ReadFailedException if read was unsuccessful - */ - @Nonnull - Optional read(@Nonnull InstanceIdentifier id, - @Nonnull ReadContext ctx) throws ReadFailedException; - - /** - * Fill in current node's attributes - * - * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. - * @param builder Builder object for current node where the read attributes must be placed - * @param ctx Current read context - */ - void readCurrentAttributes(@Nonnull InstanceIdentifier id, - @Nonnull B builder, - @Nonnull ReadContext ctx) throws ReadFailedException; - - /** - * Return new instance of a builder object for current node - * - * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. - * @return Builder object for current node type - */ - @Nonnull - B getBuilder(InstanceIdentifier id); - - /** - * Merge read data into provided parent builder. - */ - void merge(@Nonnull final Builder parentBuilder, @Nonnull final D readValue); -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java deleted file mode 100644 index 61472f8d2..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.read; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder; -import javax.annotation.Nonnull; - -/** - * Factory producing readers for {@link ModifiableReaderRegistryBuilder}. - */ -@Beta -public interface ReaderFactory extends AutoCloseable { - - /** - * Initialize 1 or more readers and add them to provided registry. - */ - void init(@Nonnull ModifiableReaderRegistryBuilder registry); - - @Override - default void close() { - // NOOP TODO allow unregister - } -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java deleted file mode 100644 index c2eba4f72..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.read.registry; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.ModifiableSubtreeManagerRegistryBuilder; -import io.fd.honeycomb.v3po.translate.read.Reader; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Mutable registry that allows adding new readers. - */ -@Beta -public interface ModifiableReaderRegistryBuilder - extends ModifiableSubtreeManagerRegistryBuilder>> { - - // TODO we should be able to add structural/reflexive readers automatically in the registry builder, we just need builder class - // We would need generated class loading strategy instance and then load builder classes relying on naming + package conventions of Binding spec - /** - * Add a structural reader that performs no read operation on its own, just fills in the hierarchy. - */ - void addStructuralReader(@Nonnull InstanceIdentifier id, - @Nonnull Class> builderType); -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java deleted file mode 100644 index 308ec238d..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.read.registry; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import com.google.common.collect.Multimap; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Simple delegating reader suitable as a holder for all other root readers, providing readAll feature. - */ -@Beta -public interface ReaderRegistry { - - /** - * Performs read on all registered root readers and merges the results into a Multimap. Keys represent identifiers - * for root DataObjects from the data tree modeled by YANG. - * - * @param ctx Read context - * - * @return multimap that preserves deterministic iteration order across non-distinct key values - * @throws ReadFailedException if read was unsuccessful - */ - @Nonnull - Multimap, ? extends DataObject> readAll(@Nonnull final ReadContext ctx) - throws ReadFailedException; - - /** - * Reads data identified by id. - * - * @param id unique identifier of subtree to be read. The subtree must contain managed data object type. For - * identifiers pointing below node managed by this reader, it's reader's responsibility to filter out the - * right node or to delegate the read to a child reader. - * @param ctx Read context - * - * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list - * @throws ReadFailedException if read was unsuccessful - */ - @Nonnull - Optional read(@Nonnull InstanceIdentifier id, - @Nonnull ReadContext ctx) - throws ReadFailedException; -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java deleted file mode 100644 index ff95d6248..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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.read.registry; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.SubtreeManagerRegistryBuilder; - -/** - * Builder for reader registries. - */ -@Beta -public interface ReaderRegistryBuilder extends SubtreeManagerRegistryBuilder { -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java deleted file mode 100644 index 0d891ecba..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.write; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Simple wrapper for BA id + data before and after state. Does not allow both before and after to be null. - */ -public class DataObjectUpdate { - - @Nonnull - private final InstanceIdentifier id; - @Nullable - private final DataObject dataBefore; - @Nullable - private final DataObject dataAfter; - - private DataObjectUpdate(@Nonnull final InstanceIdentifier id, - @Nullable final DataObject dataBefore, - @Nullable final DataObject dataAfter) { - this.id = checkNotNull(id); - this.dataAfter = dataAfter; - this.dataBefore = dataBefore; - } - - public DataObject getDataBefore() { - return dataBefore; - } - - public DataObject getDataAfter() { - return dataAfter; - } - - public InstanceIdentifier getId() { - return id; - } - - public static DataObjectUpdate create(@Nonnull final InstanceIdentifier id, - @Nullable final DataObject dataBefore, - @Nullable final DataObject dataAfter) { - checkArgument(!(dataBefore == null && dataAfter == null), "Both before and after data are null"); - if (dataBefore != null) { - checkArgument(id.getTargetType().isAssignableFrom(dataBefore.getClass())); - } - if (dataAfter != null) { - checkArgument(id.getTargetType().isAssignableFrom(dataAfter.getClass())); - } - - return dataAfter == null - ? new DataObjectDelete(id, dataBefore) - : new DataObjectUpdate(id, dataBefore, dataAfter); - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - final DataObjectUpdate that = (DataObjectUpdate) o; - - return id.equals(that.id); - - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public String toString() { - return "DataObjectUpdate{" + "id=" + id - + ", dataBefore=" + dataBefore - + ", dataAfter=" + dataAfter - + '}'; - } - - public DataObjectUpdate reverse() { - return DataObjectUpdate.create(id, dataAfter, dataBefore); - } - - public static class DataObjectDelete extends DataObjectUpdate { - - private DataObjectDelete(@Nonnull final InstanceIdentifier id, - @Nullable final DataObject dataBefore) { - super(id, dataBefore, null); - } - } -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java deleted file mode 100644 index f29289d2d..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.write; - -import com.google.common.annotations.Beta; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; - -/** - * List writer, responsible for translation between a list of DataObjects and any other side. - * Handling all update operations(create, update, delete) - * - * @param Specific DataObject derived type, that is handled by this writer - * @param Identifier/key for D - */ -@Beta -public interface ListWriter, K extends Identifier> extends Writer { -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java deleted file mode 100644 index 3433b3f34..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.write; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.ModificationContext; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Context providing information about current state of DataTree to writers - */ -@Beta -public interface WriteContext extends ModificationContext { - - /** - * Read any config data object before current modification was applied - * - * @param currentId Id of an object to read - * - * @return Data before the modification was applied - */ - Optional readBefore(@Nonnull final InstanceIdentifier currentId); - - /** - * Read any config data object from current modification - * - * @param currentId Id of an object to read - * - * @return Data from the modification - */ - Optional readAfter(@Nonnull final InstanceIdentifier currentId); - -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java deleted file mode 100644 index 10a664fcf..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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.write; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.fd.honeycomb.v3po.translate.TranslationException; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Thrown when a writer or customizer is not able to write/update/delete data . - */ -public class WriteFailedException extends TranslationException { - - private final InstanceIdentifier failedId; - - /** - * Constructs an WriteFailedException given data id, exception detail message and exception cause. - * - * @param failedId instance identifier of the data object that could not be read - * @param cause the cause of read failure - * @param message the exception detail message - */ - public WriteFailedException(@Nonnull final InstanceIdentifier failedId, - @Nonnull final String message, - @Nonnull final Throwable cause) { - super(message, cause); - this.failedId = checkNotNull(failedId, "failedId should not be null"); - } - - /** - * Constructs an WriteFailedException given data id. - * - * @param failedId instance identifier of the data object that could not be written - */ - public WriteFailedException(@Nonnull final InstanceIdentifier failedId, - @Nonnull final String message) { - super(message); - this.failedId = checkNotNull(failedId, "failedId should not be null"); - } - - /** - * Constructs an WriteFailedException given data id and exception cause. - * - * @param failedId instance identifier of the data object that could not be read - * @param cause the cause of read failure - */ - public WriteFailedException(@Nonnull final InstanceIdentifier failedId, - @Nonnull final Throwable cause) { - super(cause); - this.failedId = checkNotNull(failedId, "failedId should not be null"); - } - - /** - * Returns id of the data object that could not be written. - * - * @return data object instance identifier - */ - @Nonnull - public InstanceIdentifier getFailedId() { - return failedId; - } - - - /** - * Delete specific write failed exception - */ - public static class DeleteFailedException extends WriteFailedException { - - public DeleteFailedException(@Nonnull final InstanceIdentifier failedId, @Nonnull final Throwable cause) { - super(failedId, getMsg(failedId), cause); - } - - private static String getMsg(@Nonnull final InstanceIdentifier failedId) { - return String.format("Failed to delete data at: %s", failedId); - } - - public DeleteFailedException(@Nonnull final InstanceIdentifier failedId) { - super(failedId, getMsg(failedId)); - } - } - - /** - * Create specific write failed exception - */ - public static class CreateFailedException extends WriteFailedException { - - private final DataObject data; - - public CreateFailedException(@Nonnull final InstanceIdentifier failedId, - @Nonnull final DataObject data, - @Nonnull final Throwable cause) { - super(failedId, getMsg(failedId, data), cause); - this.data = checkNotNull(data, "data"); - } - - private static String getMsg(final @Nonnull InstanceIdentifier failedId, final DataObject data) { - return String.format("Failed to create data: %s at: %s", data, failedId); - } - - public CreateFailedException(@Nonnull final InstanceIdentifier failedId, - @Nonnull final DataObject data) { - super(failedId, getMsg(failedId, data)); - this.data = checkNotNull(data, "data"); - } - - public DataObject getData() { - return data; - } - } - - /** - * Update specific write failed exception - */ - public static class UpdateFailedException extends WriteFailedException { - - private final DataObject dataBefore; - private final DataObject dataAfter; - - public UpdateFailedException(@Nonnull final InstanceIdentifier failedId, - @Nonnull final DataObject dataBefore, - @Nonnull final DataObject dataAfter, - @Nonnull final Throwable cause) { - super(failedId, getMsg(failedId, dataBefore, dataAfter), cause); - this.dataBefore = checkNotNull(dataBefore, "dataBefore"); - this.dataAfter = checkNotNull(dataAfter, "dataAfter"); - } - - private static String getMsg(final @Nonnull InstanceIdentifier failedId, final DataObject dataBefore, - final DataObject dataAfter) { - return String.format("Failed to update data from: %s to: %s, at: %s", dataBefore, dataAfter, failedId); - } - - public UpdateFailedException(@Nonnull final InstanceIdentifier failedId, - @Nonnull final DataObject dataBefore, - @Nonnull final DataObject dataAfter) { - super(failedId, getMsg(failedId, dataBefore, dataAfter)); - this.dataBefore = checkNotNull(dataBefore, "dataBefore"); - this.dataAfter = checkNotNull(dataAfter, "dataAfter"); - } - - public DataObject getDataBefore() { - return dataBefore; - } - - public DataObject getDataAfter() { - return dataAfter; - } - } -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java deleted file mode 100644 index 77abe341c..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.write; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.SubtreeManager; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Base writer, responsible for translation between DataObjects and any other side. Handling all update operations(create, - * update, delete) - * - * @param Specific DataObject derived type, that is handled by this writer - */ -@Beta -public interface Writer extends SubtreeManager { - - /** - * Handle update operation. U from CRUD. - * - * @param id Identifier of data being written - * @param dataBefore Old data - * @param dataAfter New, updated data - * @param ctx Write context enabling writer to get information about candidate data as well as current data - * @throws WriteFailedException if update failed - */ - void update(@Nonnull final InstanceIdentifier id, - @Nullable final DataObject dataBefore, - @Nullable final DataObject dataAfter, - @Nonnull final WriteContext ctx) throws WriteFailedException; -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java deleted file mode 100644 index ffc76a0e4..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.write; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.write.registry.ModifiableWriterRegistryBuilder; -import javax.annotation.Nonnull; - -/** - * Factory producing writers for {@link ModifiableWriterRegistryBuilder}. - */ -@Beta -public interface WriterFactory extends AutoCloseable { - - /** - * Initialize 1 or more writers and add them to provided registry. - */ - void init(@Nonnull ModifiableWriterRegistryBuilder registry); - - @Override - default void close() { - // NOOP TODO allow unregister - } -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java deleted file mode 100644 index 8670a5059..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.write.registry; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.ModifiableSubtreeManagerRegistryBuilder; -import io.fd.honeycomb.v3po.translate.write.Writer; -import org.opendaylight.yangtools.yang.binding.DataObject; - -/** - * Mutable registry that allows adding new writers. - */ -@Beta -public interface ModifiableWriterRegistryBuilder - extends ModifiableSubtreeManagerRegistryBuilder> { - -} diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java deleted file mode 100644 index 439a85410..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * 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.write.registry; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.annotations.Beta; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.TranslationException; -import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.Writer; -import java.util.Set; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Special {@link Writer} capable of performing bulk updates. - */ -@Beta -public interface WriterRegistry { - - /** - * Performs bulk update. - * - * @throws BulkUpdateException in case bulk update fails - * @throws TranslationException in case some other error occurs while processing update request - */ - void update(@Nonnull DataObjectUpdates updates, - @Nonnull WriteContext ctx) throws TranslationException; - - /** - * Simple DTO containing updates for {@link WriterRegistry}. Currently only deletes and updates (create + update) - * are distinguished. - */ - @Beta - final class DataObjectUpdates { - - private final Multimap, DataObjectUpdate> updates; - private final Multimap, DataObjectUpdate.DataObjectDelete> deletes; - - /** - * Create new instance. - * - * @param updates All updates indexed by their unkeyed {@link InstanceIdentifier} - * @param deletes All deletes indexed by their unkeyed {@link InstanceIdentifier} - */ - public DataObjectUpdates(@Nonnull final Multimap, DataObjectUpdate> updates, - @Nonnull final Multimap, DataObjectUpdate.DataObjectDelete> deletes) { - this.deletes = deletes; - this.updates = updates; - } - - public Multimap, DataObjectUpdate> getUpdates() { - return updates; - } - - public Multimap, DataObjectUpdate.DataObjectDelete> getDeletes() { - return deletes; - } - - public boolean isEmpty() { - return updates.isEmpty() && deletes.isEmpty(); - } - - @Override - public String toString() { - return "DataObjectUpdates{" + "updates=" + updates + ", deletes=" + deletes + '}'; - } - - /** - * Get a {@link Set} containing all update types from both updates as well as deletes. - */ - public Set> getTypeIntersection() { - return Sets.union(deletes.keySet(), updates.keySet()); - } - - /** - * Check whether there is only a single type of data object to be updated. - * - * @return true if there is only a single type of updates (update + delete) - */ - public boolean containsOnlySingleType() { - return getTypeIntersection().size() == 1; - } - - @Override - public boolean equals(final Object other) { - if (this == other) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - - final DataObjectUpdates that = (DataObjectUpdates) other; - - if (!updates.equals(that.updates)) { - return false; - } - return deletes.equals(that.deletes); - - } - - @Override - public int hashCode() { - int result = updates.hashCode(); - result = 31 * result + deletes.hashCode(); - return result; - } - - } - - /** - * Thrown when bulk update failed. - */ - @Beta - class BulkUpdateException extends TranslationException { - - private final Reverter reverter; - private final Set> failedIds; - - /** - * Constructs an BulkUpdateException. - * @param failedIds instance identifiers of the data objects that were not processed during bulk update. - * @param cause the cause of bulk update failure - */ - public BulkUpdateException(@Nonnull final Set> failedIds, - @Nonnull final Reverter reverter, - @Nonnull final Throwable cause) { - super("Bulk update failed at: " + failedIds, cause); - this.failedIds = failedIds; - this.reverter = checkNotNull(reverter, "reverter should not be null"); - } - - /** - * Reverts changes that were successfully applied during bulk update before failure occurred. - * - * @throws Reverter.RevertFailedException if revert fails - */ - public void revertChanges() throws Reverter.RevertFailedException { - reverter.revert(); - } - - public Set> getFailedIds() { - return failedIds; - } - } - - /** - * Abstraction over revert mechanism in case of a bulk update failure. - */ - @Beta - interface Reverter { - - /** - * Reverts changes that were successfully applied during bulk update before failure occurred. Changes are - * reverted in reverse order they were applied. - * - * @throws RevertFailedException if not all of applied changes were successfully reverted - */ - void revert() throws RevertFailedException; - - /** - * Thrown when some of the changes applied during bulk update were not reverted. - */ - @Beta - class RevertFailedException extends TranslationException { - - // TODO change to list of VppDataModifications to make debugging easier - private final Set> notRevertedChanges; - - /** - * Constructs a RevertFailedException with the list of changes that were not reverted. - * - * @param notRevertedChanges list of changes that were not reverted - * @param cause the cause of revert failure - */ - public RevertFailedException(@Nonnull final Set> notRevertedChanges, - final Throwable cause) { - super(cause); - checkNotNull(notRevertedChanges, "notRevertedChanges should not be null"); - this.notRevertedChanges = ImmutableSet.copyOf(notRevertedChanges); - } - - /** - * Returns the list of changes that were not reverted. - * - * @return list of changes that were not reverted - */ - @Nonnull - public Set> getNotRevertedChanges() { - return notRevertedChanges; - } - } - } -} \ No newline at end of file diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java deleted file mode 100644 index 3f0289ece..000000000 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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.write.registry; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.SubtreeManagerRegistryBuilder; - -/** - * Builder for writer registries. - */ -@Beta -public interface WriterRegistryBuilder extends SubtreeManagerRegistryBuilder { -} diff --git a/infra/translate-api/src/main/yang/translate-api.yang b/infra/translate-api/src/main/yang/translate-api.yang index 796632dd2..133662289 100644 --- a/infra/translate-api/src/main/yang/translate-api.yang +++ b/infra/translate-api/src/main/yang/translate-api.yang @@ -16,37 +16,37 @@ module translate-api { identity honeycomb-reader-factory { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.translate.read.ReaderFactory; + config:java-class io.fd.honeycomb.translate.read.ReaderFactory; } identity honeycomb-reader-registry { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder; + config:java-class io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; } identity honeycomb-reader-registry-builder { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistryBuilder; + config:java-class io.fd.honeycomb.translate.read.registry.ReaderRegistryBuilder; } identity honeycomb-writer-factory { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.translate.write.WriterFactory; + config:java-class io.fd.honeycomb.translate.write.WriterFactory; } identity honeycomb-writer-registry { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.translate.write.registry.ModifiableWriterRegistryBuilder; + config:java-class io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; } identity honeycomb-writer-registry-builder { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.translate.write.registry.WriterRegistryBuilder; + config:java-class io.fd.honeycomb.translate.write.registry.WriterRegistryBuilder; } identity honeycomb-mapping-context { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.translate.MappingContext; + config:java-class io.fd.honeycomb.translate.MappingContext; } } \ No newline at end of file diff --git a/infra/translate-api/src/test/java/io/fd/honeycomb/translate/ReadFailedExceptionTest.java b/infra/translate-api/src/test/java/io/fd/honeycomb/translate/ReadFailedExceptionTest.java new file mode 100644 index 000000000..eb3d746c9 --- /dev/null +++ b/infra/translate-api/src/test/java/io/fd/honeycomb/translate/ReadFailedExceptionTest.java @@ -0,0 +1,50 @@ +/* + * 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.translate; + +import io.fd.honeycomb.translate.read.ReadFailedException; +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class ReadFailedExceptionTest { + + @Test + public void testInstantiation() { + final InstanceIdentifier id = InstanceIdentifier.create(DataObject.class); + ReadFailedException e = new ReadFailedException(id); + Assert.assertEquals(id, e.getFailedId()); + Assert.assertNull(e.getCause()); + Assert.assertTrue(e.getMessage().contains(id.toString())); + } + + @Test + public void testInstantiationWithCause() { + final InstanceIdentifier id = InstanceIdentifier.create(DataObject.class); + final RuntimeException cause = new RuntimeException(); + ReadFailedException e = new ReadFailedException(id, cause); + Assert.assertEquals(id, e.getFailedId()); + Assert.assertEquals(cause, e.getCause()); + Assert.assertTrue(e.getMessage().contains(id.toString())); + } + + @Test(expected = NullPointerException.class) + public void testInstantiationFailed() { + new ReadFailedException(null); + } +} \ No newline at end of file diff --git a/infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java b/infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java deleted file mode 100644 index 71c0afbd3..000000000 --- a/infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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; - -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import org.junit.Assert; -import org.junit.Test; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class ReadFailedExceptionTest { - - @Test - public void testInstantiation() { - final InstanceIdentifier id = InstanceIdentifier.create(DataObject.class); - ReadFailedException e = new ReadFailedException(id); - Assert.assertEquals(id, e.getFailedId()); - Assert.assertNull(e.getCause()); - Assert.assertTrue(e.getMessage().contains(id.toString())); - } - - @Test - public void testInstantiationWithCause() { - final InstanceIdentifier id = InstanceIdentifier.create(DataObject.class); - final RuntimeException cause = new RuntimeException(); - ReadFailedException e = new ReadFailedException(id, cause); - Assert.assertEquals(id, e.getFailedId()); - Assert.assertEquals(cause, e.getCause()); - Assert.assertTrue(e.getMessage().contains(id.toString())); - } - - @Test(expected = NullPointerException.class) - public void testInstantiationFailed() { - new ReadFailedException(null); - } -} \ No newline at end of file diff --git a/infra/translate-impl/pom.xml b/infra/translate-impl/pom.xml index 264f10956..f8906e7a3 100644 --- a/infra/translate-impl/pom.xml +++ b/infra/translate-impl/pom.xml @@ -71,7 +71,7 @@ ${project.groupId}.${project.artifactId} - io.fd.honeycomb.v3po.translate.impl.* + io.fd.honeycomb.translate.impl.* diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/GenericListReader.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/GenericListReader.java new file mode 100644 index 000000000..c6e7f3cb5 --- /dev/null +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/GenericListReader.java @@ -0,0 +1,117 @@ +/* + * 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.translate.impl.read; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.read.ListReader; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.util.read.AbstractGenericReader; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Composite implementation of {@link ListReader} able to place the read result into parent builder object intended + * for list node type. + *

+ * This reader checks if the IDs are wildcarded in which case it performs read of all list entries. In case the ID has a + * key, it reads only the specified value. + */ +@Beta +@ThreadSafe +public final class GenericListReader, K extends Identifier, B extends Builder> + extends AbstractGenericReader implements ListReader { + + private static final Logger LOG = LoggerFactory.getLogger(GenericListReader.class); + + private final ListReaderCustomizer customizer; + + /** + * Create new {@link GenericListReader} + * + * @param managedDataObjectType Class object for managed data type. Must come from a list node type. + * @param customizer Customizer instance to customize this generic reader + */ + public GenericListReader(@Nonnull final InstanceIdentifier managedDataObjectType, + @Nonnull final ListReaderCustomizer customizer) { + super(managedDataObjectType); + this.customizer = customizer; + } + + @Override + @Nonnull + public List readList(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + LOG.trace("{}: Reading all list entries", this); + final List allIds = getAllIds(id, ctx); + LOG.debug("{}: Reading list entries for: {}", this, allIds); + + final ArrayList allEntries = new ArrayList<>(allIds.size()); + for (K key : allIds) { + final InstanceIdentifier.IdentifiableItem currentBdItem = RWUtils.getCurrentIdItem(id, key); + final InstanceIdentifier keyedId = RWUtils.replaceLastInId(id, currentBdItem); + final Optional read = readCurrent(keyedId, ctx); + if (read.isPresent()) { + final DataObject singleItem = read.get(); + checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(singleItem.getClass())); + allEntries.add(getManagedDataObjectType().getTargetType().cast(singleItem)); + } + } + return allEntries; + } + + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext ctx) + throws ReadFailedException { + LOG.trace("{}: Getting all list ids", this); + final List allIds = customizer.getAllIds(id, ctx); + LOG.debug("{}: All list ids: {}", this, allIds); + return allIds; + } + + @Override + public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { + customizer.merge(builder, readData); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + customizer.readCurrentAttributes(id, builder, ctx); + } + + @Override + public B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(id); + } + +} diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/GenericReader.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/GenericReader.java new file mode 100644 index 000000000..1c638317a --- /dev/null +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/GenericReader.java @@ -0,0 +1,70 @@ +/* + * 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.translate.impl.read; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.util.read.AbstractGenericReader; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Composite implementation of {@link Reader}. + */ +@Beta +@ThreadSafe +public final class GenericReader> extends AbstractGenericReader + implements Reader { + + private final ReaderCustomizer customizer; + + /** + * Create a new {@link GenericReader}. + * + * @param id Instance identifier for managed data type + * @param customizer Customizer instance to customize this generic reader + */ + public GenericReader(@Nonnull final InstanceIdentifier id, + @Nonnull final ReaderCustomizer customizer) { + super(id); + this.customizer = customizer; + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final B builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + customizer.readCurrentAttributes(id, builder, ctx); + } + + @Override + public B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(id); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue) { + customizer.merge(parentBuilder, readValue); + } + +} diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/GenericListWriter.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/GenericListWriter.java new file mode 100644 index 000000000..f61812931 --- /dev/null +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/GenericListWriter.java @@ -0,0 +1,106 @@ +/* + * 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.translate.impl.write; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.util.write.AbstractGenericWriter; +import io.fd.honeycomb.translate.write.ListWriter; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Generic list node writer with customizable behavior thanks to injected customizer. + */ +public final class GenericListWriter, K extends Identifier> extends + AbstractGenericWriter implements ListWriter { + + private final WriterCustomizer customizer; + + public GenericListWriter(@Nonnull final InstanceIdentifier type, + @Nonnull final ListWriterCustomizer customizer) { + super(type); + this.customizer = customizer; + } + + @Override + protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D data, + @Nonnull final WriteContext ctx) throws WriteFailedException { + customizer.writeCurrentAttributes(id, data, ctx); + } + + @Override + protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, + @Nonnull final WriteContext ctx) throws WriteFailedException { + customizer.deleteCurrentAttributes(id, dataBefore, ctx); + } + + @Override + protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, + @Nonnull final D dataAfter, @Nonnull final WriteContext ctx) + throws WriteFailedException { + customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx); + } + + @Override + protected void writeCurrent(final InstanceIdentifier id, final D data, final WriteContext ctx) + throws WriteFailedException { + // Make sure the key is present + if (isWildcarded(id)) { + super.writeCurrent(getSpecificId(id, data), data, ctx); + } else { + super.writeCurrent(id, data, ctx); + } + } + + @Override + protected void updateCurrent(final InstanceIdentifier id, final D dataBefore, final D dataAfter, + final WriteContext ctx) throws WriteFailedException { + // Make sure the key is present + if (isWildcarded(id)) { + super.updateCurrent(getSpecificId(id, dataBefore), dataBefore, dataAfter, ctx); + } else { + super.updateCurrent(id, dataBefore, dataAfter, ctx); + } + } + + @Override + protected void deleteCurrent(final InstanceIdentifier id, final D dataBefore, final WriteContext ctx) + throws WriteFailedException { + // Make sure the key is present + if (isWildcarded(id)) { + super.deleteCurrent(getSpecificId(id, dataBefore), dataBefore, ctx); + } else { + super.deleteCurrent(id, dataBefore, ctx); + } + } + + private boolean isWildcarded(final InstanceIdentifier id) { + return id.firstIdentifierOf(getManagedDataObjectType().getTargetType()).isWildcarded(); + } + + private InstanceIdentifier getSpecificId(final InstanceIdentifier currentId, final D current) { + return RWUtils.replaceLastInId(currentId, + new InstanceIdentifier.IdentifiableItem<>(currentId.getTargetType(), current.getKey())); + } +} diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/GenericWriter.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/GenericWriter.java new file mode 100644 index 000000000..486da9b4a --- /dev/null +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/GenericWriter.java @@ -0,0 +1,61 @@ +/* + * 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.translate.impl.write; + +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.util.write.AbstractGenericWriter; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Generic writer with customizable behavior thanks to injected customizer. + */ +public final class GenericWriter extends AbstractGenericWriter { + + private final WriterCustomizer customizer; + + public GenericWriter(@Nonnull final InstanceIdentifier type, + @Nonnull final WriterCustomizer customizer) { + super(type); + this.customizer = customizer; + } + + @Override + protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D data, + @Nonnull final WriteContext ctx) throws WriteFailedException { + // TODO wrap all customizer invocations in try catch, and wrap runtime exceptions in ReadFailed + // TODO same for readers + customizer.writeCurrentAttributes(id, data, ctx); + } + + @Override + protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, + @Nonnull final WriteContext ctx) throws WriteFailedException { + customizer.deleteCurrentAttributes(id, dataBefore, ctx); + } + + @Override + protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataBefore, + @Nonnull final D dataAfter, + @Nonnull final WriteContext ctx) throws WriteFailedException { + customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx); + } +} diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericListReader.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericListReader.java deleted file mode 100644 index defb2e51b..000000000 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericListReader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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.impl.read; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.read.ListReader; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.util.read.AbstractGenericReader; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Composite implementation of {@link ListReader} able to place the read result into parent builder object intended - * for list node type. - *

- * This reader checks if the IDs are wildcarded in which case it performs read of all list entries. In case the ID has a - * key, it reads only the specified value. - */ -@Beta -@ThreadSafe -public final class GenericListReader, K extends Identifier, B extends Builder> - extends AbstractGenericReader implements ListReader { - - private static final Logger LOG = LoggerFactory.getLogger(GenericListReader.class); - - private final ListReaderCustomizer customizer; - - /** - * Create new {@link GenericListReader} - * - * @param managedDataObjectType Class object for managed data type. Must come from a list node type. - * @param customizer Customizer instance to customize this generic reader - */ - public GenericListReader(@Nonnull final InstanceIdentifier managedDataObjectType, - @Nonnull final ListReaderCustomizer customizer) { - super(managedDataObjectType); - this.customizer = customizer; - } - - @Override - @Nonnull - public List readList(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - LOG.trace("{}: Reading all list entries", this); - final List allIds = getAllIds(id, ctx); - LOG.debug("{}: Reading list entries for: {}", this, allIds); - - final ArrayList allEntries = new ArrayList<>(allIds.size()); - for (K key : allIds) { - final InstanceIdentifier.IdentifiableItem currentBdItem = RWUtils.getCurrentIdItem(id, key); - final InstanceIdentifier keyedId = RWUtils.replaceLastInId(id, currentBdItem); - final Optional read = readCurrent(keyedId, ctx); - if (read.isPresent()) { - final DataObject singleItem = read.get(); - checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(singleItem.getClass())); - allEntries.add(getManagedDataObjectType().getTargetType().cast(singleItem)); - } - } - return allEntries; - } - - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext ctx) - throws ReadFailedException { - LOG.trace("{}: Getting all list ids", this); - final List allIds = customizer.getAllIds(id, ctx); - LOG.debug("{}: All list ids: {}", this, allIds); - return allIds; - } - - @Override - public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { - customizer.merge(builder, readData); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - customizer.readCurrentAttributes(id, builder, ctx); - } - - @Override - public B getBuilder(@Nonnull final InstanceIdentifier id) { - return customizer.getBuilder(id); - } - -} diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericReader.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericReader.java deleted file mode 100644 index eace7fa89..000000000 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericReader.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.impl.read; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.util.read.AbstractGenericReader; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Composite implementation of {@link Reader}. - */ -@Beta -@ThreadSafe -public final class GenericReader> extends AbstractGenericReader - implements Reader { - - private final ReaderCustomizer customizer; - - /** - * Create a new {@link GenericReader}. - * - * @param id Instance identifier for managed data type - * @param customizer Customizer instance to customize this generic reader - */ - public GenericReader(@Nonnull final InstanceIdentifier id, - @Nonnull final ReaderCustomizer customizer) { - super(id); - this.customizer = customizer; - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final B builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - customizer.readCurrentAttributes(id, builder, ctx); - } - - @Override - public B getBuilder(@Nonnull final InstanceIdentifier id) { - return customizer.getBuilder(id); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue) { - customizer.merge(parentBuilder, readValue); - } - -} diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriter.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriter.java deleted file mode 100644 index 32daf5975..000000000 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriter.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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.impl.write; - -import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.util.write.AbstractGenericWriter; -import io.fd.honeycomb.v3po.translate.write.ListWriter; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Generic list node writer with customizable behavior thanks to injected customizer. - */ -public final class GenericListWriter, K extends Identifier> extends - AbstractGenericWriter implements ListWriter { - - private final WriterCustomizer customizer; - - public GenericListWriter(@Nonnull final InstanceIdentifier type, - @Nonnull final ListWriterCustomizer customizer) { - super(type); - this.customizer = customizer; - } - - @Override - protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D data, - @Nonnull final WriteContext ctx) throws WriteFailedException { - customizer.writeCurrentAttributes(id, data, ctx); - } - - @Override - protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, - @Nonnull final WriteContext ctx) throws WriteFailedException { - customizer.deleteCurrentAttributes(id, dataBefore, ctx); - } - - @Override - protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, - @Nonnull final D dataAfter, @Nonnull final WriteContext ctx) - throws WriteFailedException { - customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx); - } - - @Override - protected void writeCurrent(final InstanceIdentifier id, final D data, final WriteContext ctx) - throws WriteFailedException { - // Make sure the key is present - if (isWildcarded(id)) { - super.writeCurrent(getSpecificId(id, data), data, ctx); - } else { - super.writeCurrent(id, data, ctx); - } - } - - @Override - protected void updateCurrent(final InstanceIdentifier id, final D dataBefore, final D dataAfter, - final WriteContext ctx) throws WriteFailedException { - // Make sure the key is present - if (isWildcarded(id)) { - super.updateCurrent(getSpecificId(id, dataBefore), dataBefore, dataAfter, ctx); - } else { - super.updateCurrent(id, dataBefore, dataAfter, ctx); - } - } - - @Override - protected void deleteCurrent(final InstanceIdentifier id, final D dataBefore, final WriteContext ctx) - throws WriteFailedException { - // Make sure the key is present - if (isWildcarded(id)) { - super.deleteCurrent(getSpecificId(id, dataBefore), dataBefore, ctx); - } else { - super.deleteCurrent(id, dataBefore, ctx); - } - } - - private boolean isWildcarded(final InstanceIdentifier id) { - return id.firstIdentifierOf(getManagedDataObjectType().getTargetType()).isWildcarded(); - } - - private InstanceIdentifier getSpecificId(final InstanceIdentifier currentId, final D current) { - return RWUtils.replaceLastInId(currentId, - new InstanceIdentifier.IdentifiableItem<>(currentId.getTargetType(), current.getKey())); - } -} diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java deleted file mode 100644 index 65c192ffa..000000000 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.impl.write; - -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.util.write.AbstractGenericWriter; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Generic writer with customizable behavior thanks to injected customizer. - */ -public final class GenericWriter extends AbstractGenericWriter { - - private final WriterCustomizer customizer; - - public GenericWriter(@Nonnull final InstanceIdentifier type, - @Nonnull final WriterCustomizer customizer) { - super(type); - this.customizer = customizer; - } - - @Override - protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D data, - @Nonnull final WriteContext ctx) throws WriteFailedException { - // TODO wrap all customizer invocations in try catch, and wrap runtime exceptions in ReadFailed - // TODO same for readers - customizer.writeCurrentAttributes(id, data, ctx); - } - - @Override - protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, - @Nonnull final WriteContext ctx) throws WriteFailedException { - customizer.deleteCurrentAttributes(id, dataBefore, ctx); - } - - @Override - protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final D dataAfter, - @Nonnull final WriteContext ctx) throws WriteFailedException { - customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx); - } -} diff --git a/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/GenericListWriterTest.java b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/GenericListWriterTest.java new file mode 100644 index 000000000..d8bf96d86 --- /dev/null +++ b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/GenericListWriterTest.java @@ -0,0 +1,83 @@ +/* + * 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.translate.impl.write; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import java.util.Collections; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class GenericListWriterTest { + + private static final InstanceIdentifier + DATA_OBJECT_INSTANCE_IDENTIFIER = InstanceIdentifier.create(IdentifiableDataObject.class); + @Mock + private ListWriterCustomizer customizer; + @Mock + private WriteContext ctx; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testUpdate() throws Exception { + final GenericListWriter writer = + new GenericListWriter<>(DATA_OBJECT_INSTANCE_IDENTIFIER, customizer); + + final IdentifiableDataObject before = mock(IdentifiableDataObject.class); + final DataObjectIdentifier beforeKey = mock(DataObjectIdentifier.class); + when(before.getKey()).thenReturn(beforeKey); + final IdentifiableDataObject after = mock(IdentifiableDataObject.class); + final DataObjectIdentifier keyAfter = mock(DataObjectIdentifier.class); + when(after.getKey()).thenReturn(keyAfter); + + assertEquals(DATA_OBJECT_INSTANCE_IDENTIFIER, writer.getManagedDataObjectType()); + + final InstanceIdentifier keyedIdBefore = + (InstanceIdentifier) InstanceIdentifier.create(Collections + .singleton(new InstanceIdentifier.IdentifiableItem<>(IdentifiableDataObject.class, beforeKey))); + final InstanceIdentifier keyedIdAfter = + (InstanceIdentifier) InstanceIdentifier.create(Collections + .singleton(new InstanceIdentifier.IdentifiableItem<>(IdentifiableDataObject.class, keyAfter))); + + writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, after, ctx); + verify(customizer).updateCurrentAttributes(keyedIdBefore, before, after, ctx); + + writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, null, ctx); + verify(customizer).deleteCurrentAttributes(keyedIdBefore, before, ctx); + + writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, null, after, ctx); + verify(customizer).writeCurrentAttributes(keyedIdAfter, after, ctx); + } + + private abstract static class IdentifiableDataObject implements DataObject, Identifiable {} + private abstract static class DataObjectIdentifier implements Identifier {} +} \ No newline at end of file diff --git a/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/GenericWriterTest.java b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/GenericWriterTest.java new file mode 100644 index 000000000..827481322 --- /dev/null +++ b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/GenericWriterTest.java @@ -0,0 +1,64 @@ +/* + * 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.translate.impl.write; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class GenericWriterTest { + + private static final InstanceIdentifier + DATA_OBJECT_INSTANCE_IDENTIFIER = InstanceIdentifier.create(DataObject.class); + @Mock + private WriterCustomizer customizer; + @Mock + private WriteContext ctx; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testUpdate() throws Exception { + final GenericWriter writer = + new GenericWriter<>(DATA_OBJECT_INSTANCE_IDENTIFIER, customizer); + + final DataObject before = mock(DataObject.class); + final DataObject after = mock(DataObject.class); + + assertEquals(DATA_OBJECT_INSTANCE_IDENTIFIER, writer.getManagedDataObjectType()); + writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, after, ctx); + verify(customizer).updateCurrentAttributes(DATA_OBJECT_INSTANCE_IDENTIFIER, before, after, ctx); + + writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, null, ctx); + verify(customizer).deleteCurrentAttributes(DATA_OBJECT_INSTANCE_IDENTIFIER, before, ctx); + + writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, null, after, ctx); + verify(customizer).writeCurrentAttributes(DATA_OBJECT_INSTANCE_IDENTIFIER, after, ctx); + } +} \ No newline at end of file diff --git a/infra/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriterTest.java b/infra/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriterTest.java deleted file mode 100644 index 54a7466e1..000000000 --- a/infra/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriterTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.impl.write; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import java.util.Collections; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class GenericListWriterTest { - - private static final InstanceIdentifier - DATA_OBJECT_INSTANCE_IDENTIFIER = InstanceIdentifier.create(IdentifiableDataObject.class); - @Mock - private ListWriterCustomizer customizer; - @Mock - private WriteContext ctx; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testUpdate() throws Exception { - final GenericListWriter writer = - new GenericListWriter<>(DATA_OBJECT_INSTANCE_IDENTIFIER, customizer); - - final IdentifiableDataObject before = mock(IdentifiableDataObject.class); - final DataObjectIdentifier beforeKey = mock(DataObjectIdentifier.class); - when(before.getKey()).thenReturn(beforeKey); - final IdentifiableDataObject after = mock(IdentifiableDataObject.class); - final DataObjectIdentifier keyAfter = mock(DataObjectIdentifier.class); - when(after.getKey()).thenReturn(keyAfter); - - assertEquals(DATA_OBJECT_INSTANCE_IDENTIFIER, writer.getManagedDataObjectType()); - - final InstanceIdentifier keyedIdBefore = - (InstanceIdentifier) InstanceIdentifier.create(Collections - .singleton(new InstanceIdentifier.IdentifiableItem<>(IdentifiableDataObject.class, beforeKey))); - final InstanceIdentifier keyedIdAfter = - (InstanceIdentifier) InstanceIdentifier.create(Collections - .singleton(new InstanceIdentifier.IdentifiableItem<>(IdentifiableDataObject.class, keyAfter))); - - writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, after, ctx); - verify(customizer).updateCurrentAttributes(keyedIdBefore, before, after, ctx); - - writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, null, ctx); - verify(customizer).deleteCurrentAttributes(keyedIdBefore, before, ctx); - - writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, null, after, ctx); - verify(customizer).writeCurrentAttributes(keyedIdAfter, after, ctx); - } - - private abstract static class IdentifiableDataObject implements DataObject, Identifiable {} - private abstract static class DataObjectIdentifier implements Identifier {} -} \ No newline at end of file diff --git a/infra/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriterTest.java b/infra/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriterTest.java deleted file mode 100644 index 87f18965b..000000000 --- a/infra/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriterTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.impl.write; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class GenericWriterTest { - - private static final InstanceIdentifier - DATA_OBJECT_INSTANCE_IDENTIFIER = InstanceIdentifier.create(DataObject.class); - @Mock - private WriterCustomizer customizer; - @Mock - private WriteContext ctx; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testUpdate() throws Exception { - final GenericWriter writer = - new GenericWriter<>(DATA_OBJECT_INSTANCE_IDENTIFIER, customizer); - - final DataObject before = mock(DataObject.class); - final DataObject after = mock(DataObject.class); - - assertEquals(DATA_OBJECT_INSTANCE_IDENTIFIER, writer.getManagedDataObjectType()); - writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, after, ctx); - verify(customizer).updateCurrentAttributes(DATA_OBJECT_INSTANCE_IDENTIFIER, before, after, ctx); - - writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, before, null, ctx); - verify(customizer).deleteCurrentAttributes(DATA_OBJECT_INSTANCE_IDENTIFIER, before, ctx); - - writer.update(DATA_OBJECT_INSTANCE_IDENTIFIER, null, after, ctx); - verify(customizer).writeCurrentAttributes(DATA_OBJECT_INSTANCE_IDENTIFIER, after, ctx); - } -} \ No newline at end of file diff --git a/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/read/ListReaderCustomizer.java b/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/read/ListReaderCustomizer.java new file mode 100644 index 000000000..deb0a279d --- /dev/null +++ b/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/read/ListReaderCustomizer.java @@ -0,0 +1,63 @@ +/* + * 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.translate.spi.read; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * CompositeListReader SPI to customize its behavior. + * + * @param Specific DataObject derived type (Identifiable), that is handled by this customizer + * @param Specific Identifier for handled type (C) + * @param Specific Builder for handled type (C) + */ +@Beta +public interface ListReaderCustomizer, K extends Identifier, B extends Builder> + extends ReaderCustomizer { + + /** + * Return list with IDs of all list nodes to be read. + * + * @param id Wildcarded ID pointing to list node managed by enclosing reader + * @param context Read context + * @throws ReadFailedException if the list of IDs could not be read + */ + @Nonnull + List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext context) throws + ReadFailedException; + // TODO does it make sense with vpp APIs ? Should we replace it with a simple readAll ? + + /** + * Merge read data into provided parent builder. + */ + void merge(@Nonnull final Builder builder, @Nonnull final List readData); + + @Override + default void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue) { + merge(parentBuilder, Collections.singletonList(readValue)); + } +} diff --git a/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/read/ReaderCustomizer.java b/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/read/ReaderCustomizer.java new file mode 100644 index 000000000..610fe1514 --- /dev/null +++ b/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/read/ReaderCustomizer.java @@ -0,0 +1,63 @@ +/* + * 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.translate.spi.read; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * CompositeChildReader SPI to customize its behavior. + * + * @param Specific DataObject derived type (Identifiable), that is handled by this customizer + * @param Specific Builder for handled type (C) + */ +@Beta +public interface ReaderCustomizer> { + + /** + * Creates new builder that will be used to build read value. + */ + @Nonnull + B getBuilder(@Nonnull final InstanceIdentifier id); + + /** + * Adds current data (identified by id) to the provided builder. + * + * @param id id of current data object + * @param builder builder for creating read value + * @param ctx + * @throws ReadFailedException if read was unsuccessful + */ + void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final B builder, + @Nonnull final ReadContext ctx) throws ReadFailedException; + + // FIXME need to capture parent builder type, but that's inconvenient at best, is it ok to leave it Builder and + // cast in specific customizers ? ... probably better than adding another type parameter + + /** + * Merge read data into provided parent builder. + */ + void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue); + + +} diff --git a/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/write/ListWriterCustomizer.java b/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/write/ListWriterCustomizer.java new file mode 100644 index 000000000..cb99be6c7 --- /dev/null +++ b/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/write/ListWriterCustomizer.java @@ -0,0 +1,34 @@ +/* + * 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.translate.spi.write; + +import com.google.common.annotations.Beta; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; + +/** + * CompositeListWriter SPI to customize its behavior. + * + * @param Specific DataObject derived type (Identifiable), that is handled by this customizer + * @param Specific Identifier for handled type (C) + */ +@Beta +public interface ListWriterCustomizer, K extends Identifier> extends + WriterCustomizer { + +} \ No newline at end of file diff --git a/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/write/WriterCustomizer.java b/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/write/WriterCustomizer.java new file mode 100644 index 000000000..8148657da --- /dev/null +++ b/infra/translate-spi/src/main/java/io/fd/honeycomb/translate/spi/write/WriterCustomizer.java @@ -0,0 +1,75 @@ +/* + * 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.translate.spi.write; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * CompositeChildWriter SPI to customize its behavior. + * + * @param Specific DataObject derived type (Identifiable), that is handled by this customizer + */ +@Beta +public interface WriterCustomizer { + + /** + * Handle write operation. C from CRUD. + * + * @param id Identifier(from root) of data being written + * @param dataAfter New data to be written + * @param writeContext Write context can be used to store any useful information and then utilized by other customizers + * + * @throws WriteFailedException if write was unsuccessful + */ + void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException; + + /** + * Handle update operation. U from CRUD. + * + * @param id Identifier(from root) of data being written + * @param dataBefore Old data + * @param dataAfter New, updated data + * @param writeContext Write context can be used to store any useful information and then utilized by other customizers + * + * @throws WriteFailedException if update was unsuccessful + */ + void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataBefore, + @Nonnull final D dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException; + + /** + * Handle delete operation. D from CRUD. + * + * @param id Identifier(from root) of data being written + * @param dataBefore Old data being deleted + * @param writeContext Write context can be used to store any useful information and then utilized by other customizers + * + * @throws WriteFailedException if delete was unsuccessful + */ + void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException; + +} diff --git a/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/ListReaderCustomizer.java b/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/ListReaderCustomizer.java deleted file mode 100644 index 59557554f..000000000 --- a/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/ListReaderCustomizer.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.spi.read; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * CompositeListReader SPI to customize its behavior. - * - * @param Specific DataObject derived type (Identifiable), that is handled by this customizer - * @param Specific Identifier for handled type (C) - * @param Specific Builder for handled type (C) - */ -@Beta -public interface ListReaderCustomizer, K extends Identifier, B extends Builder> - extends ReaderCustomizer { - - /** - * Return list with IDs of all list nodes to be read. - * - * @param id Wildcarded ID pointing to list node managed by enclosing reader - * @param context Read context - * @throws ReadFailedException if the list of IDs could not be read - */ - @Nonnull - List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext context) throws - ReadFailedException; - // TODO does it make sense with vpp APIs ? Should we replace it with a simple readAll ? - - /** - * Merge read data into provided parent builder. - */ - void merge(@Nonnull final Builder builder, @Nonnull final List readData); - - @Override - default void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue) { - merge(parentBuilder, Collections.singletonList(readValue)); - } -} diff --git a/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/ReaderCustomizer.java b/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/ReaderCustomizer.java deleted file mode 100644 index 270da8beb..000000000 --- a/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/ReaderCustomizer.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.spi.read; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * CompositeChildReader SPI to customize its behavior. - * - * @param Specific DataObject derived type (Identifiable), that is handled by this customizer - * @param Specific Builder for handled type (C) - */ -@Beta -public interface ReaderCustomizer> { - - /** - * Creates new builder that will be used to build read value. - */ - @Nonnull - B getBuilder(@Nonnull final InstanceIdentifier id); - - /** - * Adds current data (identified by id) to the provided builder. - * - * @param id id of current data object - * @param builder builder for creating read value - * @param ctx - * @throws ReadFailedException if read was unsuccessful - */ - void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final B builder, - @Nonnull final ReadContext ctx) throws ReadFailedException; - - // FIXME need to capture parent builder type, but that's inconvenient at best, is it ok to leave it Builder and - // cast in specific customizers ? ... probably better than adding another type parameter - - /** - * Merge read data into provided parent builder. - */ - void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue); - - -} diff --git a/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/write/ListWriterCustomizer.java b/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/write/ListWriterCustomizer.java deleted file mode 100644 index 41cdb94b6..000000000 --- a/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/write/ListWriterCustomizer.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.spi.write; - -import com.google.common.annotations.Beta; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; - -/** - * CompositeListWriter SPI to customize its behavior. - * - * @param Specific DataObject derived type (Identifiable), that is handled by this customizer - * @param Specific Identifier for handled type (C) - */ -@Beta -public interface ListWriterCustomizer, K extends Identifier> extends - WriterCustomizer { - -} \ No newline at end of file diff --git a/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/write/WriterCustomizer.java b/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/write/WriterCustomizer.java deleted file mode 100644 index 06ce3f814..000000000 --- a/infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/write/WriterCustomizer.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.spi.write; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * CompositeChildWriter SPI to customize its behavior. - * - * @param Specific DataObject derived type (Identifiable), that is handled by this customizer - */ -@Beta -public interface WriterCustomizer { - - /** - * Handle write operation. C from CRUD. - * - * @param id Identifier(from root) of data being written - * @param dataAfter New data to be written - * @param writeContext Write context can be used to store any useful information and then utilized by other customizers - * - * @throws WriteFailedException if write was unsuccessful - */ - void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataAfter, - @Nonnull final WriteContext writeContext) throws WriteFailedException; - - /** - * Handle update operation. U from CRUD. - * - * @param id Identifier(from root) of data being written - * @param dataBefore Old data - * @param dataAfter New, updated data - * @param writeContext Write context can be used to store any useful information and then utilized by other customizers - * - * @throws WriteFailedException if update was unsuccessful - */ - void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final D dataAfter, - @Nonnull final WriteContext writeContext) throws WriteFailedException; - - /** - * Handle delete operation. D from CRUD. - * - * @param id Identifier(from root) of data being written - * @param dataBefore Old data being deleted - * @param writeContext Write context can be used to store any useful information and then utilized by other customizers - * - * @throws WriteFailedException if delete was unsuccessful - */ - void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final WriteContext writeContext) throws WriteFailedException; - -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java new file mode 100644 index 000000000..bf1e89c12 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java @@ -0,0 +1,213 @@ +/* + * 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.translate.util; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; +import io.fd.honeycomb.translate.ModifiableSubtreeManagerRegistryBuilder; +import io.fd.honeycomb.translate.SubtreeManager; +import io.fd.honeycomb.translate.SubtreeManagerRegistryBuilder; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nonnull; +import org.jgrapht.experimental.dag.DirectedAcyclicGraph; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public abstract class AbstractSubtreeManagerRegistryBuilderBuilder, R> + implements ModifiableSubtreeManagerRegistryBuilder, SubtreeManagerRegistryBuilder, AutoCloseable { + + // Using directed acyclic graph to represent the ordering relationships between writers + private final DirectedAcyclicGraph, Order> + handlersRelations = new DirectedAcyclicGraph<>((sourceVertex, targetVertex) -> new Order()); + private final Map, S> handlersMap = new HashMap<>(); + + /** + * Add handler without any special relationship to any other type. + */ + @Override + public AbstractSubtreeManagerRegistryBuilderBuilder add(@Nonnull final S handler) { + // Make IID wildcarded just in case + // + the way InstanceIdentifier.create + equals work for Identifiable items is unexpected, meaning updates would + // not be matched to writers in registry + final InstanceIdentifier targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType()); + checkWriterNotPresentYet(targetType); + handlersRelations.addVertex(targetType); + handlersMap.put(targetType, handler); + return this; + } + + /** + * Add handler without any special relationship to any other type. + */ + @Override + public AbstractSubtreeManagerRegistryBuilderBuilder subtreeAdd(@Nonnull final Set> handledChildren, + @Nonnull final S handler) { + add(getSubtreeHandler(handledChildren, handler)); + return this; + } + + private void checkWriterNotPresentYet(final InstanceIdentifier targetType) { + Preconditions.checkArgument(!handlersMap.containsKey(targetType), + "Writer for type: %s already present: %s", targetType, handlersMap.get(targetType)); + } + + /** + * Add handler with relationship: to be executed before handler handling relatedType. + */ + @Override + public AbstractSubtreeManagerRegistryBuilderBuilder addBefore(@Nonnull final S handler, + @Nonnull final InstanceIdentifier relatedType) { + final InstanceIdentifier targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType()); + final InstanceIdentifier wildcardedRelatedType = RWUtils.makeIidWildcarded(relatedType); + checkWriterNotPresentYet(targetType); + handlersRelations.addVertex(targetType); + handlersRelations.addVertex(wildcardedRelatedType); + addEdge(targetType, wildcardedRelatedType); + handlersMap.put(targetType, handler); + return this; + } + + @Override + public AbstractSubtreeManagerRegistryBuilderBuilder addBefore(@Nonnull final S handler, + @Nonnull final Collection> relatedTypes) { + final InstanceIdentifier targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType()); + checkWriterNotPresentYet(targetType); + handlersRelations.addVertex(targetType); + relatedTypes.stream() + .map(RWUtils::makeIidWildcarded) + .forEach(handlersRelations::addVertex); + relatedTypes.stream() + .map(RWUtils::makeIidWildcarded) + .forEach(type -> addEdge(targetType, type)); + handlersMap.put(targetType, handler); + return this; + } + + @Override + public AbstractSubtreeManagerRegistryBuilderBuilder subtreeAddBefore( + @Nonnull final Set> handledChildren, + @Nonnull final S handler, + @Nonnull final InstanceIdentifier relatedType) { + return addBefore(getSubtreeHandler(handledChildren, handler), relatedType); + } + + @Override + public AbstractSubtreeManagerRegistryBuilderBuilder subtreeAddBefore( + @Nonnull final Set> handledChildren, + @Nonnull final S handler, + @Nonnull final Collection> relatedTypes) { + return addBefore(getSubtreeHandler(handledChildren, handler), relatedTypes); + } + + protected abstract S getSubtreeHandler(@Nonnull final Set> handledChildren, + @Nonnull final S handler); + + /** + * Add handler with relationship: to be executed after handler handling relatedType. + */ + @Override + public AbstractSubtreeManagerRegistryBuilderBuilder addAfter(@Nonnull final S handler, + @Nonnull final InstanceIdentifier relatedType) { + final InstanceIdentifier targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType()); + final InstanceIdentifier wildcardedRelatedType = RWUtils.makeIidWildcarded(relatedType); + checkWriterNotPresentYet(targetType); + handlersRelations.addVertex(targetType); + handlersRelations.addVertex(wildcardedRelatedType); + // set edge to indicate before relationship, just reversed + addEdge(wildcardedRelatedType, targetType); + handlersMap.put(targetType, handler); + return this; + } + + @Override + public AbstractSubtreeManagerRegistryBuilderBuilder addAfter(@Nonnull final S handler, + @Nonnull final Collection> relatedTypes) { + final InstanceIdentifier targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType()); + checkWriterNotPresentYet(targetType); + handlersRelations.addVertex(targetType); + relatedTypes.stream() + .map(RWUtils::makeIidWildcarded) + .forEach(handlersRelations::addVertex); + // set edge to indicate before relationship, just reversed + relatedTypes.stream() + .map(RWUtils::makeIidWildcarded) + .forEach(type -> addEdge(type, targetType)); + handlersMap.put(targetType, handler); + return this; + } + + @Override + public AbstractSubtreeManagerRegistryBuilderBuilder subtreeAddAfter( + @Nonnull final Set> handledChildren, + @Nonnull final S handler, + @Nonnull final InstanceIdentifier relatedType) { + return addAfter(getSubtreeHandler(handledChildren, handler), relatedType); + } + + @Override + public AbstractSubtreeManagerRegistryBuilderBuilder subtreeAddAfter( + @Nonnull final Set> handledChildren, + @Nonnull final S handler, + @Nonnull final Collection> relatedTypes) { + return addAfter(getSubtreeHandler(handledChildren, handler), relatedTypes); + } + + + private void addEdge(final InstanceIdentifier targetType, + final InstanceIdentifier relatedType) { + try { + handlersRelations.addDagEdge(targetType, relatedType); + } catch (DirectedAcyclicGraph.CycleFoundException e) { + throw new IllegalArgumentException(String.format( + "Unable to add writer with relation: %s -> %s. Loop detected", targetType, relatedType), e); + } + } + + protected ImmutableMap, S> getMappedHandlers() { + final ImmutableMap.Builder, S> builder = ImmutableMap.builder(); + // Iterate writer types according to their relationships from graph + handlersRelations.iterator() + .forEachRemaining(writerType -> { + // There might be types stored just for relationship sake, no real writer, ignoring those + if (handlersMap.containsKey(writerType)) { + builder.put(writerType, handlersMap.get(writerType)); + } + }); + + // TODO we could optimize subtree handlers, if there is a dedicated handler for a node managed by a subtree + // handler, recreate the subtree handler with a subset of handled child nodes + // This way it is not necessary to change the configuration of subtree writer, just to add a dedicated child + // writer. This will be needed if we ever switch to annotations for reader/writer hierarchy initialization + + return builder.build(); + } + + @Override + public void close() throws Exception { + handlersMap.clear(); + // Wrap sets into another set to avoid concurrent modification ex in graph + handlersRelations.removeAllEdges(Sets.newHashSet(handlersRelations.edgeSet())); + handlersRelations.removeAllVertices(Sets.newHashSet(handlersRelations.vertexSet())); + } + + // Represents edges in graph + private class Order {} +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/JsonUtils.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/JsonUtils.java new file mode 100644 index 000000000..a26334454 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/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.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 final 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 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, Charsets.UTF_8)); + jsonParser.parse(reader); + + return builder.build(); + } + + private static void writeChildren(final NormalizedNodeWriter nnWriter, final ContainerNode data) throws IOException { + for(final DataContainerChild 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/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/RWUtils.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/RWUtils.java new file mode 100644 index 000000000..695ce6806 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/RWUtils.java @@ -0,0 +1,186 @@ +/* + * 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.translate.util; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import io.fd.honeycomb.translate.SubtreeManager; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class RWUtils { + + private RWUtils() {} + + /** + * Collector expecting only a single resulting item from a stream + */ + public static Collector singleItemCollector() { + return Collectors.collectingAndThen( + Collectors.toList(), + list -> { + if (list.size() != 1) { + throw new IllegalStateException("Unexpected size of list: " + list + ". Single item expected"); + } + return list.get(0); + } + ); + } + + /** + * Find next item in ID after provided type + */ + @Nonnull + public static InstanceIdentifier.PathArgument getNextId(@Nonnull final InstanceIdentifier id, + @Nonnull final InstanceIdentifier type) { + // TODO this is inefficient(maybe, depending on actual Iterable type) + final Iterable pathArguments = id.getPathArguments(); + final int i = Iterables.indexOf(pathArguments, new Predicate() { + @Override + public boolean apply(final InstanceIdentifier.PathArgument input) { + return input.getType().isAssignableFrom(type.getTargetType()); + } + }); + Preconditions.checkArgument(i >= 0, "Unable to find %s type in %s", type.getTargetType(), id); + return Iterables.get(pathArguments, i + 1); + } + + /** + * Replace last item in ID with a provided IdentifiableItem of the same type + */ + @SuppressWarnings("unchecked") + @Nonnull + public static , K extends Identifier> InstanceIdentifier replaceLastInId( + @Nonnull final InstanceIdentifier id, final InstanceIdentifier.IdentifiableItem currentBdItem) { + + final Iterable pathArguments = id.getPathArguments(); + final Iterable withoutCurrent = + Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1); + final Iterable concat = + Iterables.concat(withoutCurrent, Collections.singleton(currentBdItem)); + return (InstanceIdentifier) InstanceIdentifier.create(concat); + } + + /** + * Create IdentifiableItem from target type of provided ID with provided key + */ + @Nonnull + public static , K extends Identifier> InstanceIdentifier.IdentifiableItem getCurrentIdItem( + @Nonnull final InstanceIdentifier id, final K key) { + return new InstanceIdentifier.IdentifiableItem<>(id.getTargetType(), key); + } + + /** + * Trim InstanceIdentifier at indexOf(type) + */ + @SuppressWarnings("unchecked") + @Nonnull + public static InstanceIdentifier cutId(@Nonnull final InstanceIdentifier id, + @Nonnull final InstanceIdentifier type) { + final Iterable pathArguments = id.getPathArguments(); + final int i = Iterables.indexOf(pathArguments, new Predicate() { + @Override + public boolean apply(final InstanceIdentifier.PathArgument input) { + return input.getType().equals(type.getTargetType()); + } + }); + Preconditions.checkArgument(i >= 0, "ID %s does not contain %s", id, type); + return (InstanceIdentifier) InstanceIdentifier.create(Iterables.limit(pathArguments, i + 1)); + } + + /** + * Create an ordered map from a collection, checking for duplicity in the process. + */ + @Nonnull + public static Map uniqueLinkedIndex(@Nonnull final Collection values, @Nonnull final Function keyFunction) { + final Map objectObjectLinkedHashMap = Maps.newLinkedHashMap(); + for (V value : values) { + final K key = keyFunction.apply(value); + Preconditions.checkArgument(objectObjectLinkedHashMap.put(key, value) == null, + "Duplicate key detected : %s", key); + } + return objectObjectLinkedHashMap; + } + + public static final Function, Class> + MANAGER_CLASS_FUNCTION = new Function, Class>() { + @Override + public Class apply(final SubtreeManager input) { + return input.getManagedDataObjectType().getTargetType(); + } + }; + + public static final Function>, Class> + MANAGER_CLASS_AUG_FUNCTION = new Function>, Class>() { + + @Override + @SuppressWarnings("unchecked") + public Class apply(final SubtreeManager> input) { + final Class> targetType = input.getManagedDataObjectType().getTargetType(); + Preconditions.checkArgument(DataObject.class.isAssignableFrom(targetType)); + return (Class) targetType; + } + }; + + /** + * Transform a keyed instance identifier into a wildcarded one. + *

+ * ! This has to be called also for wildcarded List instance identifiers + * due to weird behavior of equals in InstanceIdentifier ! + */ + @SuppressWarnings("unchecked") + public static InstanceIdentifier makeIidWildcarded(final InstanceIdentifier id) { + final List transformedPathArguments = + StreamSupport.stream(id.getPathArguments().spliterator(), false) + .map(RWUtils::cleanPathArgumentFromKeys) + .collect(Collectors.toList()); + return (InstanceIdentifier) InstanceIdentifier.create(transformedPathArguments); + } + + /** + * Transform a keyed instance identifier into a wildcarded one, keeping keys except the last item. + */ + @SuppressWarnings("unchecked") + public static InstanceIdentifier makeIidLastWildcarded(final InstanceIdentifier id) { + final InstanceIdentifier.Item wildcardedItem = new InstanceIdentifier.Item<>(id.getTargetType()); + final Iterable pathArguments = id.getPathArguments(); + return (InstanceIdentifier) InstanceIdentifier.create( + Iterables.concat( + Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1), + Collections.singleton(wildcardedItem))); + } + + private static InstanceIdentifier.PathArgument cleanPathArgumentFromKeys(final InstanceIdentifier.PathArgument pathArgument) { + return pathArgument instanceof InstanceIdentifier.IdentifiableItem + ? new InstanceIdentifier.Item<>(pathArgument.getType()) + : pathArgument; + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/ReflectionUtils.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/ReflectionUtils.java new file mode 100644 index 000000000..74c7be97c --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/ReflectionUtils.java @@ -0,0 +1,79 @@ +/* + * 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.translate.util; + +import com.google.common.base.Optional; +import java.lang.reflect.Method; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Reflection based utilities + */ +public final class ReflectionUtils { + + private ReflectionUtils() {} + + /** + * Find a specific method using reflection + * + * @param managedType Class object to find method in + * @param prefix Method name prefix used when finding the method. Case does not matter. + * @param paramTypes List of input argument types + * @param retType Return type + * + * @return Found method or Optional.absent() if there's no such method + */ + @Nonnull + public static Optional findMethodReflex(@Nonnull final Class managedType, + @Nonnull final String prefix, + @Nonnull final List> paramTypes, + @Nonnull final Class retType) { + for (Method method : managedType.getMethods()) { + if (isMethodMatch(prefix, paramTypes, retType, method)) { + return Optional.of(method); + } + } + + return Optional.absent(); + } + + private static boolean isMethodMatch(final @Nonnull String prefix, + final @Nonnull List> paramTypes, + final @Nonnull Class retType, final Method method) { + if (!method.getName().toLowerCase().startsWith(prefix.toLowerCase())) { + return false; + } + + final Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length != paramTypes.size()) { + return false; + } + + for (int i = 0; i < parameterTypes.length; i++) { + if (!parameterTypes[i].isAssignableFrom(paramTypes.get(i))) { + return false; + } + } + + if (!method.getReturnType().equals(retType)) { + return false; + } + + return true; + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/TransactionMappingContext.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/TransactionMappingContext.java new file mode 100644 index 000000000..1b6504c78 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/TransactionMappingContext.java @@ -0,0 +1,75 @@ +/* + * 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.translate.util; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.translate.MappingContext; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Binding Transaction backed mapping context. + */ +public class TransactionMappingContext implements MappingContext { + + private final ReadWriteTransaction readWriteTransaction; + + // TODO make async + + public TransactionMappingContext(final ReadWriteTransaction readWriteTransaction) { + this.readWriteTransaction = readWriteTransaction; + } + + @Override + public Optional read(@Nonnull final InstanceIdentifier currentId) { + try { + return readWriteTransaction.read(LogicalDatastoreType.OPERATIONAL, currentId).checkedGet(); + } catch (ReadFailedException e) { + throw new IllegalStateException("Unable to perform read", e); + } + } + + @Override + public void delete(final InstanceIdentifier path) { + readWriteTransaction.delete(LogicalDatastoreType.OPERATIONAL, path); + } + + @Override + public void merge(final InstanceIdentifier path, T data) { + readWriteTransaction.merge(LogicalDatastoreType.OPERATIONAL, path, data, true); + } + + @Override + public void put(final InstanceIdentifier path, T data) { + readWriteTransaction.put(LogicalDatastoreType.OPERATIONAL, path, data, true); + } + + public CheckedFuture submit() { + return readWriteTransaction.submit(); + } + + @Override + public void close() { + readWriteTransaction.cancel(); + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/AbstractGenericReader.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/AbstractGenericReader.java new file mode 100644 index 000000000..75a2a673c --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/AbstractGenericReader.java @@ -0,0 +1,90 @@ +/* + * 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.translate.util.read; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.read.ReadFailedException; +import javax.annotation.Nonnull; +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; + +@Beta +public abstract class AbstractGenericReader> implements Reader { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractGenericReader.class); + + private final InstanceIdentifier instanceIdentifier; + + protected AbstractGenericReader(final InstanceIdentifier managedDataObjectType) { + this.instanceIdentifier = RWUtils.makeIidWildcarded(managedDataObjectType); + } + + @Nonnull + @Override + public final InstanceIdentifier getManagedDataObjectType() { + return instanceIdentifier; + } + + /** + * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. + * + */ + protected Optional readCurrent(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + LOG.debug("{}: Reading current: {}", this, id); + final B builder = getBuilder(id); + // Cache empty value to determine if anything has changed later TODO cache in a field + final D emptyValue = builder.build(); + + LOG.trace("{}: Reading current attributes", this); + readCurrentAttributes(id, builder, ctx); + + // Need to check whether anything was filled in to determine if data is present or not. + final D built = builder.build(); + final Optional read = built.equals(emptyValue) + ? Optional.absent() + : Optional.of(built); + + LOG.debug("{}: Current node read successfully. Result: {}", this, read); + return read; + } + + @Nonnull + @Override + @SuppressWarnings("unchecked") + public Optional read(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + LOG.trace("{}: Reading : {}", this, id); + checkArgument(id.getTargetType().equals(getManagedDataObjectType().getTargetType())); + return readCurrent((InstanceIdentifier) id, ctx); + } + + @Override + public String toString() { + return String.format("Reader[%s]", getManagedDataObjectType().getTargetType().getSimpleName()); + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/BindingBrokerReader.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/BindingBrokerReader.java new file mode 100644 index 000000000..03df15175 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/BindingBrokerReader.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.translate.util.read; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.read.ReadFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Simple DataBroker backed reader allowing to delegate reads to different brokers. + */ +public final class BindingBrokerReader> + implements Reader, AutoCloseable { + + private final InstanceIdentifier instanceIdentifier; + private final DataBroker dataBroker; + private final LogicalDatastoreType datastoreType; + private final ReflexiveReaderCustomizer reflexiveReaderCustomizer; + + public BindingBrokerReader(final InstanceIdentifier instanceIdentifier, + final DataBroker dataBroker, + final LogicalDatastoreType datastoreType, + final Class builderClass) { + this.reflexiveReaderCustomizer = new ReflexiveReaderCustomizer<>(instanceIdentifier.getTargetType(), builderClass); + this.instanceIdentifier = instanceIdentifier; + this.dataBroker = dataBroker; + this.datastoreType = datastoreType; + } + + @Nonnull + @Override + public Optional read(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + try (final ReadOnlyTransaction readOnlyTransaction = dataBroker.newReadOnlyTransaction()) { + final CheckedFuture, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> + read = readOnlyTransaction.read(datastoreType, id); + try { + return read.checkedGet(); + } catch (org.opendaylight.controller.md.sal.common.api.data.ReadFailedException e) { + throw new ReadFailedException(id, e); + } + } + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final D readValue) { + reflexiveReaderCustomizer.merge(parentBuilder, readValue); + } + + @Nonnull + @Override + public B getBuilder(final InstanceIdentifier id) { + return reflexiveReaderCustomizer.getBuilder(id); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final B builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + throw new UnsupportedOperationException("Not supported"); + } + + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + return instanceIdentifier; + } + + @Override + public void close() throws Exception { + // Noop + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/KeepaliveReaderWrapper.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/KeepaliveReaderWrapper.java new file mode 100644 index 000000000..f8d1458c0 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/KeepaliveReaderWrapper.java @@ -0,0 +1,173 @@ +/* + * 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.translate.util.read; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadFailedException; +import java.io.Closeable; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +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; + +/** + * Reader wrapper that periodically invokes a read to determine whether reads are still fully functional. + * In case a specific error occurs, Keep-alive failure listener gets notified. + */ +public final class KeepaliveReaderWrapper> implements Reader, Runnable, Closeable { + + private static final Logger LOG = LoggerFactory.getLogger(KeepaliveReaderWrapper.class); + + private static final NoopReadContext CTX = new NoopReadContext(); + + private final Reader delegate; + private final Class exceptionType; + private final KeepaliveFailureListener failureListener; + private final ScheduledFuture scheduledFuture; + + /** + * Create new Keepalive wrapper + * + * @param delegate underlying reader performing actual reads + * @param executor scheduled executor service to schedule keepalive calls + * @param exception type of exception used to differentiate keepalive exception from other exceptions + * @param delayInSeconds number of seconds to wait between keepalive calls + * @param failureListener listener to be called whenever a keepalive failure is detected + */ + public KeepaliveReaderWrapper(@Nonnull final Reader delegate, + @Nonnull final ScheduledExecutorService executor, + @Nonnull final Class exception, + @Nonnegative final int delayInSeconds, + @Nonnull final KeepaliveFailureListener failureListener) { + this.delegate = delegate; + this.exceptionType = exception; + this.failureListener = failureListener; + Preconditions.checkArgument(delayInSeconds > 0, "Delay cannot be < 0"); + LOG.debug("Starting keep-alive execution on top of: {} with delay of: {} seconds", delegate, delayInSeconds); + scheduledFuture = executor.scheduleWithFixedDelay(this, delayInSeconds, delayInSeconds, TimeUnit.SECONDS); + } + + @Nonnull + public Optional read(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + return delegate.read(id, ctx); + } + + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final B builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + delegate.readCurrentAttributes(id, builder, ctx); + } + + @Nonnull + public B getBuilder(final InstanceIdentifier id) { + return delegate.getBuilder(id); + } + + public void merge(@Nonnull final Builder parentBuilder, + @Nonnull final D readValue) { + delegate.merge(parentBuilder, readValue); + } + + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + return delegate.getManagedDataObjectType(); + } + + @Override + public void run() { + LOG.trace("Invoking keepalive"); + try { + final Optional read = read(delegate.getManagedDataObjectType(), CTX); + LOG.debug("Keepalive executed successfully with data: {}", read); + } catch (Exception e) { + if (exceptionType.isAssignableFrom(e.getClass())) { + LOG.warn("Keepalive failed. Notifying listener", e); + failureListener.onKeepaliveFailure(); + } + LOG.warn("Keepalive failed unexpectedly", e); + throw new IllegalArgumentException("Unexpected failure during keep-alive execution", e); + } + } + + @Override + public void close() { + // Do not interrupt, it's not our executor + scheduledFuture.cancel(false); + } + + /** + * Listener that gets called whenever keepalive fails as expected + */ + public interface KeepaliveFailureListener { + + void onKeepaliveFailure(); + } + + private static final class NoopMappingContext implements MappingContext { + @Override + public Optional read(@Nonnull final InstanceIdentifier currentId) { + return Optional.absent(); + } + + @Override + public void delete(final InstanceIdentifier path) {} + + @Override + public void merge(final InstanceIdentifier path, final T data) {} + + @Override + public void put(final InstanceIdentifier path, final T data) {} + + @Override + public void close() {} + } + + private static class NoopReadContext implements ReadContext { + + private final ModificationCache modificationCache = new ModificationCache(); + + @Nonnull + @Override + public ModificationCache getModificationCache() { + return modificationCache; + } + + @Nonnull + @Override + public MappingContext getMappingContext() { + return new NoopMappingContext(); + } + + @Override + public void close() { + + } + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/NoopReaderCustomizer.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/NoopReaderCustomizer.java new file mode 100644 index 000000000..66bff9383 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/NoopReaderCustomizer.java @@ -0,0 +1,34 @@ +/* + * 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.translate.util.read; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public abstract class NoopReaderCustomizer> implements + ReaderCustomizer { + + @Override + public void readCurrentAttributes(InstanceIdentifier id, final B builder, final ReadContext context) throws + ReadFailedException { + // Noop + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveListReaderCustomizer.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveListReaderCustomizer.java new file mode 100644 index 000000000..bf2d109c7 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveListReaderCustomizer.java @@ -0,0 +1,65 @@ +/* + * 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.translate.util.read; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.util.ReflectionUtils; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; + +/** + * Might be slow ! + */ +public abstract class ReflexiveListReaderCustomizer, K extends Identifier, B extends Builder> + extends ReflexiveReaderCustomizer + implements ListReaderCustomizer { + + + public ReflexiveListReaderCustomizer(final Class typeClass, final Class builderClass) { + super(typeClass, builderClass); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue) { + merge(parentBuilder, Collections.singletonList(readValue)); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final List readData) { + final Optional method = + ReflectionUtils.findMethodReflex(parentBuilder.getClass(), "set" + getTypeClass().getSimpleName(), + Collections.singletonList(List.class), parentBuilder.getClass()); + + checkArgument(method.isPresent(), "Unable to set %s to %s", readData, parentBuilder); + + try { + method.get().invoke(parentBuilder, readData); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException("Unable to set " + readData + " to " + parentBuilder, e); + } + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveReader.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveReader.java new file mode 100644 index 000000000..2aa35514e --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveReader.java @@ -0,0 +1,57 @@ +/* + * 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.translate.util.read; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Reader that performs no read operation on its own, just fills in the hierarchy. + *

+ * Might be slow due to reflection ! + */ +public class ReflexiveReader> extends AbstractGenericReader { + + private final ReflexiveReaderCustomizer customizer; + + public ReflexiveReader(final InstanceIdentifier identifier, final Class builderClass) { + super(identifier); + this.customizer = new ReflexiveReaderCustomizer<>(identifier.getTargetType(), builderClass); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + customizer.readCurrentAttributes(id, builder, ctx); + } + + @Nonnull + @Override + public B getBuilder(final InstanceIdentifier id) { + return customizer.getBuilder(id); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue) { + customizer.merge(parentBuilder, readValue); + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveReaderCustomizer.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveReaderCustomizer.java new file mode 100644 index 000000000..6ceb7a2b1 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/ReflexiveReaderCustomizer.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.translate.util.read; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import io.fd.honeycomb.translate.util.ReflectionUtils; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Might be slow ! + */ +class ReflexiveReaderCustomizer> extends NoopReaderCustomizer { + + private final Class typeClass; + private final Class builderClass; + + public ReflexiveReaderCustomizer(final Class typeClass, final Class builderClass) { + this.typeClass = typeClass; + this.builderClass = builderClass; + } + + protected Class getTypeClass() { + return typeClass; + } + + protected Class getBuilderClass() { + return builderClass; + } + + @Nonnull + @Override + public B getBuilder(@Nonnull InstanceIdentifier id) { + try { + return builderClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException("Unable to instantiate " + builderClass, e); + } + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue) { + if (Augmentation.class.isAssignableFrom(typeClass)) { + mergeAugmentation(parentBuilder, (Class>) typeClass, readValue); + } else { + mergeRegular(parentBuilder, readValue); + } + } + + private static void mergeRegular(@Nonnull final Builder parentBuilder, + @Nonnull final DataObject readValue) { + final Optional method = + ReflectionUtils.findMethodReflex(parentBuilder.getClass(), "set", + Collections.singletonList(readValue.getClass()), parentBuilder.getClass()); + + checkArgument(method.isPresent(), "Unable to set %s to %s", readValue, parentBuilder); + + try { + method.get().invoke(parentBuilder, readValue); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException("Unable to set " + readValue + " to " + parentBuilder, e); + } + } + + private static void mergeAugmentation(@Nonnull final Builder parentBuilder, + @Nonnull final Class> typeClass, + @Nonnull final DataObject readValue) { + final Optional method = + ReflectionUtils.findMethodReflex(parentBuilder.getClass(), "addAugmentation", + Lists.newArrayList(Class.class, Augmentation.class), parentBuilder.getClass()); + + checkArgument(method.isPresent(), "Not possible to add augmentations to builder: %s", parentBuilder); + try { + method.get().invoke(parentBuilder, typeClass, readValue); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException("Unable to set " + readValue + " to " + parentBuilder, e); + } + } + +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReader.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReader.java new file mode 100644 index 000000000..91a195f44 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReader.java @@ -0,0 +1,202 @@ +/* + * 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.translate.util.read.registry; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import io.fd.honeycomb.translate.read.ListReader; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.util.read.AbstractGenericReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class CompositeReader> extends AbstractGenericReader { + + private static final Logger LOG = LoggerFactory.getLogger(CompositeReader.class); + + private final Reader delegate; + private final ImmutableMap, Reader>> childReaders; + + private CompositeReader(final Reader reader, + final ImmutableMap, Reader>> childReaders) { + super(reader.getManagedDataObjectType()); + this.delegate = reader; + this.childReaders = childReaders; + } + + @VisibleForTesting + ImmutableMap, Reader>> getChildReaders() { + return childReaders; + } + + @SuppressWarnings("unchecked") + public static InstanceIdentifier appendTypeToId( + final InstanceIdentifier parentId, final InstanceIdentifier type) { + final InstanceIdentifier.PathArgument t = new InstanceIdentifier.Item<>(type.getTargetType()); + return (InstanceIdentifier) InstanceIdentifier.create(Iterables.concat( + parentId.getPathArguments(), Collections.singleton(t))); + } + + @Nonnull + @Override + public Optional read(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + if (shouldReadCurrent(id)) { + LOG.trace("{}: Reading current: {}", this, id); + return readCurrent((InstanceIdentifier) id, ctx); + } else if (shouldDelegateToChild(id)) { + LOG.trace("{}: Reading child: {}", this, id); + return readSubtree(id, ctx); + } else { + // Fallback + LOG.trace("{}: Delegating read: {}", this, id); + return delegate.read(id, ctx); + } + } + + private boolean shouldReadCurrent(@Nonnull final InstanceIdentifier id) { + return id.getTargetType().equals(getManagedDataObjectType().getTargetType()); + } + + private boolean shouldDelegateToChild(@Nonnull final InstanceIdentifier id) { + return childReaders.containsKey(RWUtils.getNextId(id, getManagedDataObjectType()).getType()); + } + + private Optional readSubtree(final InstanceIdentifier id, + final ReadContext ctx) throws ReadFailedException { + final InstanceIdentifier.PathArgument nextId = RWUtils.getNextId(id, getManagedDataObjectType()); + final Reader> nextReader = childReaders.get(nextId.getType()); + checkArgument(nextReader != null, "Unable to read: %s. No delegate present, available readers at next level: %s", + id, childReaders.keySet()); + return nextReader.read(id, ctx); + } + + @SuppressWarnings("unchecked") + private void readChildren(final InstanceIdentifier id, @Nonnull final ReadContext ctx, final B builder) + throws ReadFailedException { + LOG.debug("{}: Reading children: {}", this, childReaders.keySet()); + for (Reader child : childReaders.values()) { + final InstanceIdentifier childId = appendTypeToId(id, child.getManagedDataObjectType()); + + LOG.debug("{}: Reading child from: {}", this, child); + if (child instanceof ListReader) { + final List list = ((ListReader) child).readList(childId, ctx); + ((ListReader) child).merge(builder, list); + } else { + final Optional read = child.read(childId, ctx); + if (read.isPresent()) { + child.merge(builder, read.get()); + } + } + } + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + delegate.readCurrentAttributes(id, builder, ctx); + readChildren(id, ctx, builder); + } + + @Nonnull + @Override + public B getBuilder(final InstanceIdentifier id) { + return delegate.getBuilder(id); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final D readValue) { + delegate.merge(parentBuilder, readValue); + } + + /** + * Wrap a Reader as a Composite Reader. + */ + static > Reader createForReader( + @Nonnull final Reader reader, + @Nonnull final ImmutableMap, Reader>> childReaders) { + + return (reader instanceof ListReader) + ? new CompositeListReader<>((ListReader) reader, childReaders) + : new CompositeReader<>(reader, childReaders); + } + + private static class CompositeListReader, B extends Builder, K extends Identifier> + extends CompositeReader + implements ListReader { + + private final ListReader delegate; + + private CompositeListReader(final ListReader reader, + final ImmutableMap, Reader>> childReaders) { + super(reader, childReaders); + this.delegate = reader; + } + + @Nonnull + @Override + public List readList(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext ctx) + throws ReadFailedException { + LOG.trace("{}: Reading all list entries", this); + final List allIds = delegate.getAllIds(id, ctx); + LOG.debug("{}: Reading list entries for: {}", this, allIds); + + // Override read list in order to perform readCurrent + readChildren here + final ArrayList allEntries = new ArrayList<>(allIds.size()); + for (K key : allIds) { + final InstanceIdentifier.IdentifiableItem currentBdItem = RWUtils.getCurrentIdItem(id, key); + final InstanceIdentifier keyedId = RWUtils.replaceLastInId(id, currentBdItem); + final Optional read = readCurrent(keyedId, ctx); + if (read.isPresent()) { + final DataObject singleItem = read.get(); + checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(singleItem.getClass())); + allEntries.add(getManagedDataObjectType().getTargetType().cast(singleItem)); + } + } + return allEntries; + } + + @Override + public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { + delegate.merge(builder, readData); + } + + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + return delegate.getAllIds(id, ctx); + } + } + +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistry.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistry.java new file mode 100644 index 000000000..ec3ce0605 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistry.java @@ -0,0 +1,117 @@ +/* + * 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.translate.util.read.registry; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; +import com.google.common.collect.Iterables; +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Multimap; +import io.fd.honeycomb.translate.read.ListReader; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +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; + +/** + * Simple reader registry able to perform and aggregated read (ROOT read) on top of all provided readers. Also able to + * delegate a specific read to one of the delegate readers. + *

+ * This could serve as a utility to hold & hide all available readers in upper layers. + */ +public final class CompositeReaderRegistry implements ReaderRegistry { + + private static final Logger LOG = LoggerFactory.getLogger(CompositeReaderRegistry.class); + + private final Map, Reader>> rootReaders; + + /** + * Create new {@link CompositeReaderRegistry}. + * + * @param rootReaders List of delegate readers + */ + public CompositeReaderRegistry(@Nonnull final List>> rootReaders) { + this.rootReaders = RWUtils.uniqueLinkedIndex(checkNotNull(rootReaders), RWUtils.MANAGER_CLASS_FUNCTION); + } + + @VisibleForTesting + Map, Reader>> getRootReaders() { + return rootReaders; + } + + @Override + @Nonnull + public Multimap, ? extends DataObject> readAll( + @Nonnull final ReadContext ctx) throws ReadFailedException { + + LOG.debug("Reading from all delegates: {}", this); + LOG.trace("Reading from all delegates: {}", rootReaders.values()); + + final Multimap, DataObject> objects = LinkedListMultimap.create(); + for (Reader> rootReader : rootReaders.values()) { + LOG.debug("Reading from delegate: {}", rootReader); + + if (rootReader instanceof ListReader) { + final List listEntries = + ((ListReader) rootReader).readList(rootReader.getManagedDataObjectType(), ctx); + if (!listEntries.isEmpty()) { + objects.putAll(rootReader.getManagedDataObjectType(), listEntries); + } + } else { + final Optional read = rootReader.read(rootReader.getManagedDataObjectType(), ctx); + if (read.isPresent()) { + objects.putAll(rootReader.getManagedDataObjectType(), Collections.singletonList(read.get())); + } + } + } + + return objects; + } + + @Nonnull + @Override + public Optional read(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + final InstanceIdentifier.PathArgument first = checkNotNull( + Iterables.getFirst(id.getPathArguments(), null), "Empty id"); + final Reader> reader = rootReaders.get(first.getType()); + checkNotNull(reader, + "Unable to read %s. Missing reader. Current readers for: %s", id, rootReaders.keySet()); + LOG.debug("Reading from delegate: {}", reader); + return reader.read(id, ctx); + } + + @Override + public String toString() { + return getClass().getSimpleName() + + rootReaders.keySet().stream().map(Class::getSimpleName).collect(Collectors.toList()); + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistryBuilder.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistryBuilder.java new file mode 100644 index 000000000..3e21bfca3 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistryBuilder.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.translate.util.read.registry; + +import com.google.common.collect.ImmutableMap; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.honeycomb.translate.read.registry.ReaderRegistryBuilder; +import io.fd.honeycomb.translate.util.read.ReflexiveReader; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import io.fd.honeycomb.translate.util.AbstractSubtreeManagerRegistryBuilderBuilder; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.NotThreadSafe; +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; + +@NotThreadSafe +public final class CompositeReaderRegistryBuilder + extends AbstractSubtreeManagerRegistryBuilderBuilder>, ReaderRegistry> + implements ModifiableReaderRegistryBuilder, ReaderRegistryBuilder { + + private static final Logger LOG = LoggerFactory.getLogger(CompositeReaderRegistryBuilder.class); + + @Override + protected Reader> getSubtreeHandler(@Nonnull final Set> handledChildren, + @Nonnull final Reader> reader) { + return SubtreeReader.createForReader(handledChildren, reader); + } + + @Override + public void addStructuralReader(@Nonnull InstanceIdentifier id, + @Nonnull Class> builderType) { + add(new ReflexiveReader<>(id, builderType)); + } + + /** + * Create {@link CompositeReaderRegistry} with Readers ordered according to submitted relationships. + *

+ * Note: The ordering only applies between nodes on the same level, inter-level and inter-subtree relationships are + * ignored. + */ + @Override + public ReaderRegistry build() { + ImmutableMap, Reader>> mappedReaders = + getMappedHandlers(); + LOG.debug("Building Reader registry with Readers: {}", + mappedReaders.keySet().stream() + .map(InstanceIdentifier::getTargetType) + .map(Class::getSimpleName) + .collect(Collectors.joining(", "))); + + LOG.trace("Building Reader registry with Readers: {}", mappedReaders); + final List> readerOrder = new ArrayList<>(mappedReaders.keySet()); + + // Wrap readers into composite readers recursively, collect roots and create registry + final TypeHierarchy typeHierarchy = TypeHierarchy.create(mappedReaders.keySet()); + final List>> orderedRootReaders = + typeHierarchy.getRoots().stream() + .map(rootId -> toCompositeReader(rootId, mappedReaders, typeHierarchy)) + .collect(Collectors.toList()); + + // We are violating the ordering from mappedReaders, since we are forming a composite structure + // but at least order root writers + orderedRootReaders.sort((reader1, reader2) -> readerOrder.indexOf(reader1.getManagedDataObjectType()) + - readerOrder.indexOf(reader2.getManagedDataObjectType())); + + return new CompositeReaderRegistry(orderedRootReaders); + } + + private Reader> toCompositeReader( + final InstanceIdentifier instanceIdentifier, + final ImmutableMap, Reader>> mappedReaders, + final TypeHierarchy typeHierarchy) { + + // Order child readers according to the mappedReadersCollection + final ImmutableMap.Builder, Reader>> childReadersMapB = ImmutableMap.builder(); + for (InstanceIdentifier childId : mappedReaders.keySet()) { + if (typeHierarchy.getDirectChildren(instanceIdentifier).contains(childId)) { + childReadersMapB.put(childId.getTargetType(), toCompositeReader(childId, mappedReaders, typeHierarchy)); + } + } + + final ImmutableMap, Reader>> childReadersMap = childReadersMapB.build(); + return childReadersMap.isEmpty() + ? mappedReaders.get(instanceIdentifier) + : CompositeReader.createForReader(mappedReaders.get(instanceIdentifier), childReadersMap); + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/SubtreeReader.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/SubtreeReader.java new file mode 100644 index 000000000..720bd0b11 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/SubtreeReader.java @@ -0,0 +1,250 @@ +/* + * 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.translate.util.read.registry; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import io.fd.honeycomb.translate.read.ListReader; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.util.ReflectionUtils; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Simple Reader delegate for subtree Readers (Readers handling also children nodes) providing a list of all the + * children nodes being handled. + */ +class SubtreeReader> implements Reader { + + private static final Logger LOG = LoggerFactory.getLogger(SubtreeReader.class); + + private final Reader delegate; + private final Set> handledChildTypes = new HashSet<>(); + + private SubtreeReader(final Reader delegate, Set> handledTypes) { + this.delegate = delegate; + for (InstanceIdentifier handledType : handledTypes) { + // Iid has to start with Reader's handled root type + checkArgument(delegate.getManagedDataObjectType().getTargetType().equals( + handledType.getPathArguments().iterator().next().getType()), + "Handled node from subtree has to be identified by an instance identifier starting from: %s." + + "Instance identifier was: %s", getManagedDataObjectType().getTargetType(), handledType); + checkArgument(Iterables.size(handledType.getPathArguments()) > 1, + "Handled node from subtree identifier too short: %s", handledType); + handledChildTypes.add(InstanceIdentifier.create(Iterables.concat( + getManagedDataObjectType().getPathArguments(), Iterables.skip(handledType.getPathArguments(), 1)))); + } + } + + /** + * Return set of types also handled by this Reader. All of the types are children of the type managed by this Reader + * excluding the type of this Reader. + */ + Set> getHandledChildTypes() { + return handledChildTypes; + } + + @Override + @Nonnull + public Optional read( + @Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + final InstanceIdentifier wildcarded = RWUtils.makeIidWildcarded(id); + + // Reading entire subtree and filtering if is current reader responsible + if (getHandledChildTypes().contains(wildcarded)) { + LOG.debug("{}: Subtree node managed by this writer requested: {}. Reading current and filtering", this, id); + // If there's no dedicated reader, use read current + final InstanceIdentifier currentId = RWUtils.cutId(id, getManagedDataObjectType()); + final Optional current = delegate.read(currentId, ctx); + // then perform post-reading filtering (return only requested sub-node) + final Optional readSubtree = current.isPresent() + ? filterSubtree(current.get(), id, getManagedDataObjectType().getTargetType()) + : current; + + LOG.debug("{}: Subtree: {} read successfully. Result: {}", this, id, readSubtree); + return readSubtree; + + // Fallback solution, try delegate, maybe it can read the ID + } else { + return delegate.read(id, ctx); + } + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + delegate.readCurrentAttributes(id, builder, ctx); + } + + @Nonnull + @Override + public B getBuilder(final InstanceIdentifier id) { + return delegate.getBuilder(id); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final D readValue) { + delegate.merge(parentBuilder, readValue); + } + + @Nonnull + private static Optional filterSubtree(@Nonnull final DataObject parent, + @Nonnull final InstanceIdentifier absolutPath, + @Nonnull final Class managedType) { + final InstanceIdentifier.PathArgument nextId = + RWUtils.getNextId(absolutPath, InstanceIdentifier.create(parent.getClass())); + + final Optional nextParent = findNextParent(parent, nextId, managedType); + + if (Iterables.getLast(absolutPath.getPathArguments()).equals(nextId)) { + return nextParent; // we found the dataObject identified by absolutePath + } else if (nextParent.isPresent()) { + return filterSubtree(nextParent.get(), absolutPath, nextId.getType()); + } else { + return nextParent; // we can't go further, return Optional.absent() + } + } + + private static Optional findNextParent(@Nonnull final DataObject parent, + @Nonnull final InstanceIdentifier.PathArgument nextId, + @Nonnull final Class managedType) { + // TODO is there a better way than reflection ? e.g. convert into NN and filter out with a utility + Optional method = ReflectionUtils.findMethodReflex(managedType, "get", + Collections.emptyList(), nextId.getType()); + + if (method.isPresent()) { + return Optional.fromNullable(filterSingle(parent, nextId, method.get())); + } else { + // List child nodes + method = ReflectionUtils.findMethodReflex(managedType, + "get" + nextId.getType().getSimpleName(), Collections.emptyList(), List.class); + + if (method.isPresent()) { + return filterList(parent, nextId, method.get()); + } else { + throw new IllegalStateException( + "Unable to filter " + nextId + " from " + parent + " getters not found using reflexion"); + } + } + } + + @SuppressWarnings("unchecked") + private static Optional filterList(final DataObject parent, + final InstanceIdentifier.PathArgument nextId, + final Method method) { + final List invoke = (List) invoke(method, nextId, parent); + + checkArgument(nextId instanceof InstanceIdentifier.IdentifiableItem, + "Unable to perform wildcarded read for %s", nextId); + final Identifier key = ((InstanceIdentifier.IdentifiableItem) nextId).getKey(); + // TODO replace with stream().filter().findFirst() when we switch to using java's Optional instead of Guava's + // because now we would have to do awkward Optional transformation since findFirstReturns guava's optional + return Iterables.tryFind(invoke, new Predicate() { + + @Override + public boolean apply(@Nullable final DataObject input) { + final Optional keyGetter = ReflectionUtils.findMethodReflex(nextId.getType(), "get", + Collections.emptyList(), key.getClass()); + final Object actualKey; + actualKey = invoke(keyGetter.get(), nextId, input); + return key.equals(actualKey); + } + }); + } + + private static DataObject filterSingle(final DataObject parent, + final InstanceIdentifier.PathArgument nextId, final Method method) { + return nextId.getType().cast(invoke(method, nextId, parent)); + } + + private static Object invoke(final Method method, + final InstanceIdentifier.PathArgument nextId, final DataObject parent) { + try { + return method.invoke(parent); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException("Unable to get " + nextId + " from " + parent, e); + } + } + + @Override + @Nonnull + public InstanceIdentifier getManagedDataObjectType() { + return delegate.getManagedDataObjectType(); + } + + /** + * Wrap a Reader as a subtree Reader. + */ + static > Reader createForReader(@Nonnull final Set> handledChildren, + @Nonnull final Reader reader) { + return (reader instanceof ListReader) + ? new SubtreeListReader<>((ListReader) reader, handledChildren) + : new SubtreeReader<>(reader, handledChildren); + } + + private static final class SubtreeListReader, B extends Builder, K extends Identifier> + extends SubtreeReader implements ListReader { + + private final ListReader delegate; + + private SubtreeListReader(final ListReader delegate, + final Set> handledTypes) { + super(delegate, handledTypes); + this.delegate = delegate; + } + + @Nonnull + @Override + public List readList(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext ctx) + throws ReadFailedException { + return delegate.readList(id, ctx); + } + + @Override + public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { + delegate.merge(builder, readData); + } + + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + return delegate.getAllIds(id, ctx); + } + } + +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/TypeHierarchy.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/TypeHierarchy.java new file mode 100644 index 000000000..a30663221 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/read/registry/TypeHierarchy.java @@ -0,0 +1,101 @@ +/* + * 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.translate.util.read.registry; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.collect.Iterables; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.jgrapht.experimental.dag.DirectedAcyclicGraph; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +final class TypeHierarchy { + private final DirectedAcyclicGraph, Parent> hierarchy; + + private TypeHierarchy(@Nonnull final DirectedAcyclicGraph, Parent> hierarchy) { + this.hierarchy = hierarchy; + } + + Set> getAllChildren(InstanceIdentifier id) { + final HashSet> instanceIdentifiers = new HashSet<>(); + for (InstanceIdentifier childId : getDirectChildren(id)) { + instanceIdentifiers.add(childId); + instanceIdentifiers.addAll(getAllChildren(childId)); + } + return instanceIdentifiers; + } + + Set> getDirectChildren(InstanceIdentifier id) { + checkArgument(hierarchy.vertexSet().contains(id), + "Unknown reader: %s. Known readers: %s", id, hierarchy.vertexSet()); + + return hierarchy.outgoingEdgesOf(id).stream() + .map(hierarchy::getEdgeTarget) + .collect(Collectors.toSet()); + } + + Set> getRoots() { + return hierarchy.vertexSet().stream() + .filter(vertex -> hierarchy.incomingEdgesOf(vertex).size() == 0) + .collect(Collectors.toSet()); + } + + /** + * Create reader hierarchy from a flat set of instance identifiers. + * + * @param allIds Set of unkeyed instance identifiers + */ + static TypeHierarchy create(@Nonnull Set> allIds) { + final DirectedAcyclicGraph, Parent> + readersHierarchy = new DirectedAcyclicGraph<>((sourceVertex, targetVertex) -> new Parent()); + + for (InstanceIdentifier allId : allIds) { + checkArgument(!Iterables.isEmpty(allId.getPathArguments()), "Empty ID detected"); + + if (Iterables.size(allId.getPathArguments()) == 1) { + readersHierarchy.addVertex(allId); + } + + List pathArgs = new LinkedList<>(); + pathArgs.add(allId.getPathArguments().iterator().next()); + + for (InstanceIdentifier.PathArgument pathArgument : Iterables.skip(allId.getPathArguments(), 1)) { + final InstanceIdentifier previous = InstanceIdentifier.create(pathArgs); + pathArgs.add(pathArgument); + final InstanceIdentifier current = InstanceIdentifier.create(pathArgs); + + readersHierarchy.addVertex(previous); + readersHierarchy.addVertex(current); + + try { + readersHierarchy.addDagEdge(previous, current); + } catch (DirectedAcyclicGraph.CycleFoundException e) { + throw new IllegalArgumentException("Loop in hierarchy detected", e); + } + } + } + + return new TypeHierarchy(readersHierarchy); + } + + private static final class Parent{} +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/AbstractGenericWriter.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/AbstractGenericWriter.java new file mode 100644 index 000000000..ff2174ed2 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/AbstractGenericWriter.java @@ -0,0 +1,137 @@ +/* + * 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.translate.util.write; + +import static com.google.common.base.Preconditions.checkArgument; + +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.write.Writer; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractGenericWriter implements Writer { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractGenericWriter.class); + + private final InstanceIdentifier instanceIdentifier; + + protected AbstractGenericWriter(final InstanceIdentifier type) { + this.instanceIdentifier = RWUtils.makeIidWildcarded(type); + } + + protected void writeCurrent(final InstanceIdentifier id, final D data, final WriteContext ctx) + throws WriteFailedException { + LOG.debug("{}: Writing current: {} data: {}", this, id, data); + writeCurrentAttributes(id, data, ctx); + LOG.debug("{}: Current node written successfully", this); + } + + protected void updateCurrent(final InstanceIdentifier id, final D dataBefore, final D dataAfter, + final WriteContext ctx) throws WriteFailedException { + LOG.debug("{}: Updating current: {} dataBefore: {}, datAfter: {}", this, id, dataBefore, dataAfter); + + if (dataBefore.equals(dataAfter)) { + LOG.debug("{}: Skipping current(no update): {}", this, id); + // No change, ignore + return; + } + updateCurrentAttributes(id, dataBefore, dataAfter, ctx); + LOG.debug("{}: Current node updated successfully", this); + } + + protected void deleteCurrent(final InstanceIdentifier id, final D dataBefore, final WriteContext ctx) + throws WriteFailedException { + LOG.debug("{}: Deleting current: {} dataBefore: {}", this, id, dataBefore); + deleteCurrentAttributes(id, dataBefore, ctx); + } + + @SuppressWarnings("unchecked") + @Override + public void update(@Nonnull final InstanceIdentifier id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter, + @Nonnull final WriteContext ctx) throws WriteFailedException { + LOG.debug("{}: Updating : {}", this, id); + LOG.trace("{}: Updating : {}, from: {} to: {}", this, id, dataBefore, dataAfter); + + checkArgument(idPointsToCurrent(id), "Cannot handle data: %s. Only: %s can be handled by writer: %s", + id, getManagedDataObjectType(), this); + + if (isWrite(dataBefore, dataAfter)) { + writeCurrent((InstanceIdentifier) id, castToManaged(dataAfter), ctx); + } else if (isDelete(dataBefore, dataAfter)) { + deleteCurrent((InstanceIdentifier) id, castToManaged(dataBefore), ctx); + } else { + checkArgument(dataBefore != null && dataAfter != null, "No data to process"); + updateCurrent((InstanceIdentifier) id, castToManaged(dataBefore), castToManaged(dataAfter), ctx); + } + } + + private void checkDataType(@Nonnull final DataObject dataAfter) { + checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(dataAfter.getClass())); + } + + private D castToManaged(final DataObject data) { + checkDataType(data); + return getManagedDataObjectType().getTargetType().cast(data); + } + + private static boolean isWrite(final DataObject dataBefore, + final DataObject dataAfter) { + return dataBefore == null && dataAfter != null; + } + + private static boolean isDelete(final DataObject dataBefore, + final DataObject dataAfter) { + return dataAfter == null && dataBefore != null; + } + + private boolean idPointsToCurrent(final @Nonnull InstanceIdentifier id) { + return id.getTargetType().equals(getManagedDataObjectType().getTargetType()); + } + + protected abstract void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D data, + @Nonnull final WriteContext ctx) throws WriteFailedException; + + protected abstract void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataBefore, + @Nonnull final WriteContext ctx) throws WriteFailedException; + + protected abstract void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataBefore, + @Nonnull final D dataAfter, + @Nonnull final WriteContext ctx) throws WriteFailedException; + + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + return instanceIdentifier; + } + + + @Override + public String toString() { + return String.format("Writer[%s]", getManagedDataObjectType().getTargetType().getSimpleName()); + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/NoopWriterRegistry.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/NoopWriterRegistry.java new file mode 100644 index 000000000..8f15c6f8d --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/NoopWriterRegistry.java @@ -0,0 +1,40 @@ +/* + * 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.translate.util.write; + +import io.fd.honeycomb.translate.TranslationException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import javax.annotation.Nonnull; + +/** + * Empty registry that does not perform any changes. Can be used in data layer, if we want to disable passing data to + * translation layer. + */ +public class NoopWriterRegistry implements WriterRegistry, AutoCloseable { + + @Override + public void update(@Nonnull final DataObjectUpdates updates, + @Nonnull final WriteContext ctx) throws TranslationException { + // NOOP + } + + @Override + public void close() throws Exception { + // NOOP + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/TransactionWriteContext.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/TransactionWriteContext.java new file mode 100644 index 000000000..51f999294 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/TransactionWriteContext.java @@ -0,0 +1,121 @@ +/* + * 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.translate.util.write; + +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.write.WriteContext; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Transaction based WriteContext + */ +public final class TransactionWriteContext implements WriteContext { + + private final DOMDataReadOnlyTransaction beforeTx; + private final DOMDataReadOnlyTransaction afterTx; + private final ModificationCache ctx; + private final BindingNormalizedNodeSerializer serializer; + private final MappingContext mappingContext; + + public TransactionWriteContext(final BindingNormalizedNodeSerializer serializer, + final DOMDataReadOnlyTransaction beforeTx, + final DOMDataReadOnlyTransaction afterTx, + final MappingContext mappingContext) { + this.serializer = serializer; + // TODO do we have a BA transaction adapter ? If so, use it here and don't pass serializer + this.beforeTx = beforeTx; + this.afterTx = afterTx; + this.mappingContext = mappingContext; + this.ctx = new ModificationCache(); + } + + // TODO make this asynchronous + + @Override + public Optional readBefore(@Nonnull final InstanceIdentifier currentId) { + return read(currentId, beforeTx); + } + + @Override + public Optional readAfter(@Nonnull final InstanceIdentifier currentId) { + return read(currentId, afterTx); + } + + + private Optional read(final InstanceIdentifier currentId, + final DOMDataReadOnlyTransaction tx) { + final YangInstanceIdentifier path = serializer.toYangInstanceIdentifier(currentId); + + final CheckedFuture>, ReadFailedException> read = + tx.read(LogicalDatastoreType.CONFIGURATION, path); + + try { + // TODO once the APIs are asynchronous use just Futures.transform + final Optional> optional = read.checkedGet(); + + if (!optional.isPresent()) { + return Optional.absent(); + } + + final NormalizedNode data = optional.get(); + final Map.Entry, DataObject> entry = serializer.fromNormalizedNode(path, data); + + final Class targetType = currentId.getTargetType(); + checkState(targetType.isAssignableFrom(entry.getValue().getClass()), + "Unexpected data object type, should be: %s, but was: %s", targetType, entry.getValue().getClass()); + return Optional.of(targetType.cast(entry.getValue())); + } catch (ReadFailedException e) { + throw new IllegalStateException("Unable to perform read", e); + } + } + + @Nonnull + @Override + public ModificationCache getModificationCache() { + return ctx; + } + + @Nonnull + @Override + public MappingContext getMappingContext() { + return mappingContext; + } + + /** + * Does not close the transactions + */ + @Override + public void close() { + ctx.close(); + beforeTx.close(); + afterTx.close(); + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistry.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistry.java new file mode 100644 index 000000000..df8ec107b --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistry.java @@ -0,0 +1,315 @@ +/* + * 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.translate.util.write.registry; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.base.Optional; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; +import io.fd.honeycomb.translate.TranslationException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.write.DataObjectUpdate; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.write.Writer; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Flat writer registry, delegating updates to writers in the order writers were submitted. + */ +@ThreadSafe +final class FlatWriterRegistry implements WriterRegistry { + + private static final Logger LOG = LoggerFactory.getLogger(FlatWriterRegistry.class); + + // All types handled by writers directly or as children + private final ImmutableSet> handledTypes; + + private final Set> writersOrderReversed; + private final Set> writersOrder; + private final Map, Writer> writers; + + /** + * Create flat registry instance. + * + * @param writers immutable, ordered map of writers to use to process updates. Order of the writers has to be + * one in which create and update operations should be handled. Deletes will be handled in reversed + * order. All deletes are handled before handling all the updates. + */ + FlatWriterRegistry(@Nonnull final ImmutableMap, Writer> writers) { + this.writers = writers; + this.writersOrderReversed = Sets.newLinkedHashSet(Lists.reverse(Lists.newArrayList(writers.keySet()))); + this.writersOrder = writers.keySet(); + this.handledTypes = getAllHandledTypes(writers); + } + + private static ImmutableSet> getAllHandledTypes( + @Nonnull final ImmutableMap, Writer> writers) { + final ImmutableSet.Builder> handledTypesBuilder = ImmutableSet.builder(); + for (Map.Entry, Writer> writerEntry : writers.entrySet()) { + final InstanceIdentifier writerType = writerEntry.getKey(); + final Writer writer = writerEntry.getValue(); + handledTypesBuilder.add(writerType); + if (writer instanceof SubtreeWriter) { + handledTypesBuilder.addAll(((SubtreeWriter) writer).getHandledChildTypes()); + } + } + return handledTypesBuilder.build(); + } + + @Override + public void update(@Nonnull final DataObjectUpdates updates, + @Nonnull final WriteContext ctx) throws TranslationException { + if (updates.isEmpty()) { + return; + } + + // Optimization + if (updates.containsOnlySingleType()) { + // First process delete + singleUpdate(updates.getDeletes(), ctx); + // Next is update + singleUpdate(updates.getUpdates(), ctx); + } else { + // First process deletes + bulkUpdate(updates.getDeletes(), ctx, true, writersOrderReversed); + // Next are updates + bulkUpdate(updates.getUpdates(), ctx, true, writersOrder); + } + + LOG.debug("Update successful for types: {}", updates.getTypeIntersection()); + LOG.trace("Update successful for: {}", updates); + } + + private void singleUpdate(@Nonnull final Multimap, ? extends DataObjectUpdate> updates, + @Nonnull final WriteContext ctx) throws WriteFailedException { + if (updates.isEmpty()) { + return; + } + + final InstanceIdentifier singleType = updates.keySet().iterator().next(); + LOG.debug("Performing single type update for: {}", singleType); + Collection singleTypeUpdates = updates.get(singleType); + Writer writer = getWriter(singleType); + + if (writer == null) { + // This node must be handled by a subtree writer, find it and call it or else fail + checkArgument(handledTypes.contains(singleType), "Unable to process update. Missing writers for: %s", + singleType); + writer = getSubtreeWriterResponsible(singleType); + singleTypeUpdates = getParentDataObjectUpdate(ctx, updates, writer); + } + + LOG.trace("Performing single type update with writer: {}", writer); + for (DataObjectUpdate singleUpdate : singleTypeUpdates) { + writer.update(singleUpdate.getId(), singleUpdate.getDataBefore(), singleUpdate.getDataAfter(), ctx); + } + } + + private Writer getSubtreeWriterResponsible(final InstanceIdentifier singleType) { + final Writer writer;// This is slow ( minor TODO-perf ) + writer = writers.values().stream() + .filter(w -> w instanceof SubtreeWriter) + .filter(w -> ((SubtreeWriter) w).getHandledChildTypes().contains(singleType)) + .findFirst() + .get(); + return writer; + } + + private Collection getParentDataObjectUpdate(final WriteContext ctx, + final Multimap, ? extends DataObjectUpdate> updates, + final Writer writer) { + // Now read data for subtree reader root, but first keyed ID is needed and that ID can be cut from updates + InstanceIdentifier firstAffectedChildId = ((SubtreeWriter) writer).getHandledChildTypes().stream() + .filter(updates::containsKey) + .map(unkeyedId -> updates.get(unkeyedId)) + .flatMap(doUpdates -> doUpdates.stream()) + .map(DataObjectUpdate::getId) + .findFirst() + .get(); + + final InstanceIdentifier parentKeyedId = + RWUtils.cutId(firstAffectedChildId, writer.getManagedDataObjectType()); + + final Optional parentBefore = ctx.readBefore(parentKeyedId); + final Optional parentAfter = ctx.readAfter(parentKeyedId); + return Collections.singleton( + DataObjectUpdate.create(parentKeyedId, parentBefore.orNull(), parentAfter.orNull())); + } + + private void bulkUpdate(@Nonnull final Multimap, ? extends DataObjectUpdate> updates, + @Nonnull final WriteContext ctx, + final boolean attemptRevert, + @Nonnull final Set> writersOrder) throws BulkUpdateException { + if (updates.isEmpty()) { + return; + } + + LOG.debug("Performing bulk update with revert attempt: {} for: {}", attemptRevert, updates.keySet()); + + // Check that all updates can be handled + checkAllTypesCanBeHandled(updates); + + // Capture all changes successfully processed in case revert is needed + final Set> processedNodes = new HashSet<>(); + + // Iterate over all writers and call update if there are any related updates + for (InstanceIdentifier writerType : writersOrder) { + Collection writersData = updates.get(writerType); + final Writer writer = getWriter(writerType); + + if (writersData.isEmpty()) { + // If there are no data for current writer, but it is a SubtreeWriter and there are updates to + // its children, still invoke it with its root data + if (writer instanceof SubtreeWriter && isAffected(((SubtreeWriter) writer), updates)) { + // Provide parent data for SubtreeWriter for further processing + writersData = getParentDataObjectUpdate(ctx, updates, writer); + } else { + // Skipping unaffected writer + // Alternative to this would be modification sort according to the order of writers + continue; + } + } + + LOG.debug("Performing update for: {}", writerType); + LOG.trace("Performing update with writer: {}", writer); + + for (DataObjectUpdate singleUpdate : writersData) { + try { + writer.update(singleUpdate.getId(), singleUpdate.getDataBefore(), singleUpdate.getDataAfter(), ctx); + processedNodes.add(singleUpdate.getId()); + LOG.trace("Update successful for type: {}", writerType); + LOG.debug("Update successful for: {}", singleUpdate); + } catch (Exception e) { + LOG.error("Error while processing data change of: {} (updates={})", writerType, writersData, e); + + final Reverter reverter = attemptRevert + ? new ReverterImpl(processedNodes, updates, writersOrder, ctx) + : () -> {}; // NOOP reverter + + // Find out which changes left unprocessed + final Set> unprocessedChanges = updates.values().stream() + .map(DataObjectUpdate::getId) + .filter(id -> !processedNodes.contains(id)) + .collect(Collectors.toSet()); + throw new BulkUpdateException(unprocessedChanges, reverter, e); + } + } + } + } + + private void checkAllTypesCanBeHandled( + @Nonnull final Multimap, ? extends DataObjectUpdate> updates) { + if (!handledTypes.containsAll(updates.keySet())) { + final Sets.SetView> missingWriters = Sets.difference(updates.keySet(), handledTypes); + LOG.warn("Unable to process update. Missing writers for: {}", missingWriters); + throw new IllegalArgumentException("Unable to process update. Missing writers for: " + missingWriters); + } + } + + /** + * Check whether {@link SubtreeWriter} is affected by the updates. + * + * @return true if there are any updates to SubtreeWriter's child nodes (those marked by SubtreeWriter + * as being taken care of) + * */ + private static boolean isAffected(final SubtreeWriter writer, + final Multimap, ? extends DataObjectUpdate> updates) { + return !Sets.intersection(writer.getHandledChildTypes(), updates.keySet()).isEmpty(); + } + + @Nullable + private Writer getWriter(@Nonnull final InstanceIdentifier singleType) { + return writers.get(singleType); + } + + // FIXME unit test + private final class ReverterImpl implements Reverter { + + private final Collection> processedNodes; + private final Multimap, ? extends DataObjectUpdate> updates; + private final Set> revertDeleteOrder; + private final WriteContext ctx; + + ReverterImpl(final Collection> processedNodes, + final Multimap, ? extends DataObjectUpdate> updates, + final Set> writersOrderOriginal, + final WriteContext ctx) { + this.processedNodes = processedNodes; + this.updates = updates; + // Use opposite ordering when executing revert + this.revertDeleteOrder = writersOrderOriginal == FlatWriterRegistry.this.writersOrder + ? FlatWriterRegistry.this.writersOrderReversed + : FlatWriterRegistry.this.writersOrder; + this.ctx = ctx; + } + + @Override + public void revert() throws RevertFailedException { + Multimap, DataObjectUpdate> updatesToRevert = + filterAndRevertProcessed(updates, processedNodes); + + LOG.info("Attempting revert for changes: {}", updatesToRevert); + try { + // Perform reversed bulk update without revert attempt + bulkUpdate(updatesToRevert, ctx, true, revertDeleteOrder); + LOG.info("Revert successful"); + } catch (BulkUpdateException e) { + LOG.error("Revert failed", e); + throw new RevertFailedException(e.getFailedIds(), e); + } + } + + /** + * Create new updates map, but only keep already processed changes. Switching before and after data for each + * update. + */ + private Multimap, DataObjectUpdate> filterAndRevertProcessed( + final Multimap, ? extends DataObjectUpdate> updates, + final Collection> processedNodes) { + final Multimap, DataObjectUpdate> filtered = HashMultimap.create(); + for (InstanceIdentifier processedNode : processedNodes) { + final InstanceIdentifier wildcardedIid = RWUtils.makeIidWildcarded(processedNode); + if (updates.containsKey(wildcardedIid)) { + updates.get(wildcardedIid).stream() + .filter(dataObjectUpdate -> processedNode.contains(dataObjectUpdate.getId())) + .forEach(dataObjectUpdate -> filtered.put(processedNode, dataObjectUpdate.reverse())); + } + } + return filtered; + } + } + +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryBuilder.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryBuilder.java new file mode 100644 index 000000000..0f75de7e7 --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryBuilder.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.translate.util.write.registry; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableMap; +import io.fd.honeycomb.translate.write.registry.WriterRegistryBuilder; +import io.fd.honeycomb.translate.util.AbstractSubtreeManagerRegistryBuilderBuilder; +import io.fd.honeycomb.translate.write.Writer; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.NotThreadSafe; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Builder for {@link FlatWriterRegistry} allowing users to specify inter-writer relationships. + */ +@NotThreadSafe +public final class FlatWriterRegistryBuilder + extends AbstractSubtreeManagerRegistryBuilderBuilder, WriterRegistry> + implements ModifiableWriterRegistryBuilder, WriterRegistryBuilder { + + private static final Logger LOG = LoggerFactory.getLogger(FlatWriterRegistryBuilder.class); + + @Override + protected Writer getSubtreeHandler(final @Nonnull Set> handledChildren, + final @Nonnull Writer writer) { + return SubtreeWriter.createForWriter(handledChildren, writer); + } + + /** + * Create FlatWriterRegistry with writers ordered according to submitted relationships. + */ + @Override + public WriterRegistry build() { + final ImmutableMap, Writer> mappedWriters = getMappedHandlers(); + LOG.debug("Building writer registry with writers: {}", + mappedWriters.keySet().stream() + .map(InstanceIdentifier::getTargetType) + .map(Class::getSimpleName) + .collect(Collectors.joining(", "))); + LOG.trace("Building writer registry with writers: {}", mappedWriters); + return new FlatWriterRegistry(mappedWriters); + } + + @VisibleForTesting + @Override + protected ImmutableMap, Writer> getMappedHandlers() { + return super.getMappedHandlers(); + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/SubtreeWriter.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/SubtreeWriter.java new file mode 100644 index 000000000..bab1da16f --- /dev/null +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/registry/SubtreeWriter.java @@ -0,0 +1,85 @@ +/* + * 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.translate.util.write.registry; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.collect.Iterables; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.write.Writer; +import java.util.HashSet; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Simple writer delegate for subtree writers (writers handling also children nodes) providing a list of all the + * children nodes being handled. + */ +final class SubtreeWriter implements Writer { + + private final Writer delegate; + private final Set> handledChildTypes = new HashSet<>(); + + private SubtreeWriter(final Writer delegate, Set> handledTypes) { + this.delegate = delegate; + for (InstanceIdentifier handledType : handledTypes) { + // Iid has to start with writer's handled root type + checkArgument(delegate.getManagedDataObjectType().getTargetType().equals( + handledType.getPathArguments().iterator().next().getType()), + "Handled node from subtree has to be identified by an instance identifier starting from: %s." + + "Instance identifier was: %s", getManagedDataObjectType().getTargetType(), handledType); + checkArgument(Iterables.size(handledType.getPathArguments()) > 1, + "Handled node from subtree identifier too short: %s", handledType); + handledChildTypes.add(InstanceIdentifier.create(Iterables.concat( + getManagedDataObjectType().getPathArguments(), Iterables.skip(handledType.getPathArguments(), 1)))); + } + } + + /** + * Return set of types also handled by this writer. All of the types are children of the type managed by this + * writer excluding the type of this writer. + */ + Set> getHandledChildTypes() { + return handledChildTypes; + } + + @Override + public void update( + @Nonnull final InstanceIdentifier id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter, @Nonnull final WriteContext ctx) throws WriteFailedException { + delegate.update(id, dataBefore, dataAfter, ctx); + } + + @Override + @Nonnull + public InstanceIdentifier getManagedDataObjectType() { + return delegate.getManagedDataObjectType(); + } + + /** + * Wrap a writer as a subtree writer. + */ + static Writer createForWriter(@Nonnull final Set> handledChildren, + @Nonnull final Writer writer) { + return new SubtreeWriter<>(writer, handledChildren); + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java deleted file mode 100644 index 23a66337f..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * 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.Preconditions; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.ModifiableSubtreeManagerRegistryBuilder; -import io.fd.honeycomb.v3po.translate.SubtreeManager; -import io.fd.honeycomb.v3po.translate.SubtreeManagerRegistryBuilder; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import javax.annotation.Nonnull; -import org.jgrapht.experimental.dag.DirectedAcyclicGraph; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public abstract class AbstractSubtreeManagerRegistryBuilderBuilder, R> - implements ModifiableSubtreeManagerRegistryBuilder, SubtreeManagerRegistryBuilder, AutoCloseable { - - // Using directed acyclic graph to represent the ordering relationships between writers - private final DirectedAcyclicGraph, Order> - handlersRelations = new DirectedAcyclicGraph<>((sourceVertex, targetVertex) -> new Order()); - private final Map, S> handlersMap = new HashMap<>(); - - /** - * Add handler without any special relationship to any other type. - */ - @Override - public AbstractSubtreeManagerRegistryBuilderBuilder add(@Nonnull final S handler) { - // Make IID wildcarded just in case - // + the way InstanceIdentifier.create + equals work for Identifiable items is unexpected, meaning updates would - // not be matched to writers in registry - final InstanceIdentifier targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType()); - checkWriterNotPresentYet(targetType); - handlersRelations.addVertex(targetType); - handlersMap.put(targetType, handler); - return this; - } - - /** - * Add handler without any special relationship to any other type. - */ - @Override - public AbstractSubtreeManagerRegistryBuilderBuilder subtreeAdd(@Nonnull final Set> handledChildren, - @Nonnull final S handler) { - add(getSubtreeHandler(handledChildren, handler)); - return this; - } - - private void checkWriterNotPresentYet(final InstanceIdentifier targetType) { - Preconditions.checkArgument(!handlersMap.containsKey(targetType), - "Writer for type: %s already present: %s", targetType, handlersMap.get(targetType)); - } - - /** - * Add handler with relationship: to be executed before handler handling relatedType. - */ - @Override - public AbstractSubtreeManagerRegistryBuilderBuilder addBefore(@Nonnull final S handler, - @Nonnull final InstanceIdentifier relatedType) { - final InstanceIdentifier targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType()); - final InstanceIdentifier wildcardedRelatedType = RWUtils.makeIidWildcarded(relatedType); - checkWriterNotPresentYet(targetType); - handlersRelations.addVertex(targetType); - handlersRelations.addVertex(wildcardedRelatedType); - addEdge(targetType, wildcardedRelatedType); - handlersMap.put(targetType, handler); - return this; - } - - @Override - public AbstractSubtreeManagerRegistryBuilderBuilder addBefore(@Nonnull final S handler, - @Nonnull final Collection> relatedTypes) { - final InstanceIdentifier targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType()); - checkWriterNotPresentYet(targetType); - handlersRelations.addVertex(targetType); - relatedTypes.stream() - .map(RWUtils::makeIidWildcarded) - .forEach(handlersRelations::addVertex); - relatedTypes.stream() - .map(RWUtils::makeIidWildcarded) - .forEach(type -> addEdge(targetType, type)); - handlersMap.put(targetType, handler); - return this; - } - - @Override - public AbstractSubtreeManagerRegistryBuilderBuilder subtreeAddBefore( - @Nonnull final Set> handledChildren, - @Nonnull final S handler, - @Nonnull final InstanceIdentifier relatedType) { - return addBefore(getSubtreeHandler(handledChildren, handler), relatedType); - } - - @Override - public AbstractSubtreeManagerRegistryBuilderBuilder subtreeAddBefore( - @Nonnull final Set> handledChildren, - @Nonnull final S handler, - @Nonnull final Collection> relatedTypes) { - return addBefore(getSubtreeHandler(handledChildren, handler), relatedTypes); - } - - protected abstract S getSubtreeHandler(@Nonnull final Set> handledChildren, - @Nonnull final S handler); - - /** - * Add handler with relationship: to be executed after handler handling relatedType. - */ - @Override - public AbstractSubtreeManagerRegistryBuilderBuilder addAfter(@Nonnull final S handler, - @Nonnull final InstanceIdentifier relatedType) { - final InstanceIdentifier targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType()); - final InstanceIdentifier wildcardedRelatedType = RWUtils.makeIidWildcarded(relatedType); - checkWriterNotPresentYet(targetType); - handlersRelations.addVertex(targetType); - handlersRelations.addVertex(wildcardedRelatedType); - // set edge to indicate before relationship, just reversed - addEdge(wildcardedRelatedType, targetType); - handlersMap.put(targetType, handler); - return this; - } - - @Override - public AbstractSubtreeManagerRegistryBuilderBuilder addAfter(@Nonnull final S handler, - @Nonnull final Collection> relatedTypes) { - final InstanceIdentifier targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType()); - checkWriterNotPresentYet(targetType); - handlersRelations.addVertex(targetType); - relatedTypes.stream() - .map(RWUtils::makeIidWildcarded) - .forEach(handlersRelations::addVertex); - // set edge to indicate before relationship, just reversed - relatedTypes.stream() - .map(RWUtils::makeIidWildcarded) - .forEach(type -> addEdge(type, targetType)); - handlersMap.put(targetType, handler); - return this; - } - - @Override - public AbstractSubtreeManagerRegistryBuilderBuilder subtreeAddAfter( - @Nonnull final Set> handledChildren, - @Nonnull final S handler, - @Nonnull final InstanceIdentifier relatedType) { - return addAfter(getSubtreeHandler(handledChildren, handler), relatedType); - } - - @Override - public AbstractSubtreeManagerRegistryBuilderBuilder subtreeAddAfter( - @Nonnull final Set> handledChildren, - @Nonnull final S handler, - @Nonnull final Collection> relatedTypes) { - return addAfter(getSubtreeHandler(handledChildren, handler), relatedTypes); - } - - - private void addEdge(final InstanceIdentifier targetType, - final InstanceIdentifier relatedType) { - try { - handlersRelations.addDagEdge(targetType, relatedType); - } catch (DirectedAcyclicGraph.CycleFoundException e) { - throw new IllegalArgumentException(String.format( - "Unable to add writer with relation: %s -> %s. Loop detected", targetType, relatedType), e); - } - } - - protected ImmutableMap, S> getMappedHandlers() { - final ImmutableMap.Builder, S> builder = ImmutableMap.builder(); - // Iterate writer types according to their relationships from graph - handlersRelations.iterator() - .forEachRemaining(writerType -> { - // There might be types stored just for relationship sake, no real writer, ignoring those - if (handlersMap.containsKey(writerType)) { - builder.put(writerType, handlersMap.get(writerType)); - } - }); - - // TODO we could optimize subtree handlers, if there is a dedicated handler for a node managed by a subtree - // handler, recreate the subtree handler with a subset of handled child nodes - // This way it is not necessary to change the configuration of subtree writer, just to add a dedicated child - // writer. This will be needed if we ever switch to annotations for reader/writer hierarchy initialization - - return builder.build(); - } - - @Override - public void close() throws Exception { - handlersMap.clear(); - // Wrap sets into another set to avoid concurrent modification ex in graph - handlersRelations.removeAllEdges(Sets.newHashSet(handlersRelations.edgeSet())); - handlersRelations.removeAllVertices(Sets.newHashSet(handlersRelations.vertexSet())); - } - - // Represents edges in graph - private class Order {} -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/JsonUtils.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/JsonUtils.java deleted file mode 100644 index d9798d07d..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/JsonUtils.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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 final 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 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, Charsets.UTF_8)); - jsonParser.parse(reader); - - return builder.build(); - } - - private static void writeChildren(final NormalizedNodeWriter nnWriter, final ContainerNode data) throws IOException { - for(final DataContainerChild 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/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/RWUtils.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/RWUtils.java deleted file mode 100644 index 2a565d9f2..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/RWUtils.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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.Function; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; -import io.fd.honeycomb.v3po.translate.SubtreeManager; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collector; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public final class RWUtils { - - private RWUtils() {} - - /** - * Collector expecting only a single resulting item from a stream - */ - public static Collector singleItemCollector() { - return Collectors.collectingAndThen( - Collectors.toList(), - list -> { - if (list.size() != 1) { - throw new IllegalStateException("Unexpected size of list: " + list + ". Single item expected"); - } - return list.get(0); - } - ); - } - - /** - * Find next item in ID after provided type - */ - @Nonnull - public static InstanceIdentifier.PathArgument getNextId(@Nonnull final InstanceIdentifier id, - @Nonnull final InstanceIdentifier type) { - // TODO this is inefficient(maybe, depending on actual Iterable type) - final Iterable pathArguments = id.getPathArguments(); - final int i = Iterables.indexOf(pathArguments, new Predicate() { - @Override - public boolean apply(final InstanceIdentifier.PathArgument input) { - return input.getType().isAssignableFrom(type.getTargetType()); - } - }); - Preconditions.checkArgument(i >= 0, "Unable to find %s type in %s", type.getTargetType(), id); - return Iterables.get(pathArguments, i + 1); - } - - /** - * Replace last item in ID with a provided IdentifiableItem of the same type - */ - @SuppressWarnings("unchecked") - @Nonnull - public static , K extends Identifier> InstanceIdentifier replaceLastInId( - @Nonnull final InstanceIdentifier id, final InstanceIdentifier.IdentifiableItem currentBdItem) { - - final Iterable pathArguments = id.getPathArguments(); - final Iterable withoutCurrent = - Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1); - final Iterable concat = - Iterables.concat(withoutCurrent, Collections.singleton(currentBdItem)); - return (InstanceIdentifier) InstanceIdentifier.create(concat); - } - - /** - * Create IdentifiableItem from target type of provided ID with provided key - */ - @Nonnull - public static , K extends Identifier> InstanceIdentifier.IdentifiableItem getCurrentIdItem( - @Nonnull final InstanceIdentifier id, final K key) { - return new InstanceIdentifier.IdentifiableItem<>(id.getTargetType(), key); - } - - /** - * Trim InstanceIdentifier at indexOf(type) - */ - @SuppressWarnings("unchecked") - @Nonnull - public static InstanceIdentifier cutId(@Nonnull final InstanceIdentifier id, - @Nonnull final InstanceIdentifier type) { - final Iterable pathArguments = id.getPathArguments(); - final int i = Iterables.indexOf(pathArguments, new Predicate() { - @Override - public boolean apply(final InstanceIdentifier.PathArgument input) { - return input.getType().equals(type.getTargetType()); - } - }); - Preconditions.checkArgument(i >= 0, "ID %s does not contain %s", id, type); - return (InstanceIdentifier) InstanceIdentifier.create(Iterables.limit(pathArguments, i + 1)); - } - - /** - * Create an ordered map from a collection, checking for duplicity in the process. - */ - @Nonnull - public static Map uniqueLinkedIndex(@Nonnull final Collection values, @Nonnull final Function keyFunction) { - final Map objectObjectLinkedHashMap = Maps.newLinkedHashMap(); - for (V value : values) { - final K key = keyFunction.apply(value); - Preconditions.checkArgument(objectObjectLinkedHashMap.put(key, value) == null, - "Duplicate key detected : %s", key); - } - return objectObjectLinkedHashMap; - } - - public static final Function, Class> - MANAGER_CLASS_FUNCTION = new Function, Class>() { - @Override - public Class apply(final SubtreeManager input) { - return input.getManagedDataObjectType().getTargetType(); - } - }; - - public static final Function>, Class> - MANAGER_CLASS_AUG_FUNCTION = new Function>, Class>() { - - @Override - @SuppressWarnings("unchecked") - public Class apply(final SubtreeManager> input) { - final Class> targetType = input.getManagedDataObjectType().getTargetType(); - Preconditions.checkArgument(DataObject.class.isAssignableFrom(targetType)); - return (Class) targetType; - } - }; - - /** - * Transform a keyed instance identifier into a wildcarded one. - *

- * ! This has to be called also for wildcarded List instance identifiers - * due to weird behavior of equals in InstanceIdentifier ! - */ - @SuppressWarnings("unchecked") - public static InstanceIdentifier makeIidWildcarded(final InstanceIdentifier id) { - final List transformedPathArguments = - StreamSupport.stream(id.getPathArguments().spliterator(), false) - .map(RWUtils::cleanPathArgumentFromKeys) - .collect(Collectors.toList()); - return (InstanceIdentifier) InstanceIdentifier.create(transformedPathArguments); - } - - /** - * Transform a keyed instance identifier into a wildcarded one, keeping keys except the last item. - */ - @SuppressWarnings("unchecked") - public static InstanceIdentifier makeIidLastWildcarded(final InstanceIdentifier id) { - final InstanceIdentifier.Item wildcardedItem = new InstanceIdentifier.Item<>(id.getTargetType()); - final Iterable pathArguments = id.getPathArguments(); - return (InstanceIdentifier) InstanceIdentifier.create( - Iterables.concat( - Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1), - Collections.singleton(wildcardedItem))); - } - - private static InstanceIdentifier.PathArgument cleanPathArgumentFromKeys(final InstanceIdentifier.PathArgument pathArgument) { - return pathArgument instanceof InstanceIdentifier.IdentifiableItem - ? new InstanceIdentifier.Item<>(pathArgument.getType()) - : pathArgument; - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/ReflectionUtils.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/ReflectionUtils.java deleted file mode 100644 index 728c4f80d..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/ReflectionUtils.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.Optional; -import java.lang.reflect.Method; -import java.util.List; -import javax.annotation.Nonnull; - -/** - * Reflection based utilities - */ -public final class ReflectionUtils { - - private ReflectionUtils() {} - - /** - * Find a specific method using reflection - * - * @param managedType Class object to find method in - * @param prefix Method name prefix used when finding the method. Case does not matter. - * @param paramTypes List of input argument types - * @param retType Return type - * - * @return Found method or Optional.absent() if there's no such method - */ - @Nonnull - public static Optional findMethodReflex(@Nonnull final Class managedType, - @Nonnull final String prefix, - @Nonnull final List> paramTypes, - @Nonnull final Class retType) { - for (Method method : managedType.getMethods()) { - if (isMethodMatch(prefix, paramTypes, retType, method)) { - return Optional.of(method); - } - } - - return Optional.absent(); - } - - private static boolean isMethodMatch(final @Nonnull String prefix, - final @Nonnull List> paramTypes, - final @Nonnull Class retType, final Method method) { - if (!method.getName().toLowerCase().startsWith(prefix.toLowerCase())) { - return false; - } - - final Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length != paramTypes.size()) { - return false; - } - - for (int i = 0; i < parameterTypes.length; i++) { - if (!parameterTypes[i].isAssignableFrom(paramTypes.get(i))) { - return false; - } - } - - if (!method.getReturnType().equals(retType)) { - return false; - } - - return true; - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/TransactionMappingContext.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/TransactionMappingContext.java deleted file mode 100644 index 6abc3b1eb..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/TransactionMappingContext.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.translate.MappingContext; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Binding Transaction backed mapping context. - */ -public class TransactionMappingContext implements MappingContext { - - private final ReadWriteTransaction readWriteTransaction; - - // TODO make async - - public TransactionMappingContext(final ReadWriteTransaction readWriteTransaction) { - this.readWriteTransaction = readWriteTransaction; - } - - @Override - public Optional read(@Nonnull final InstanceIdentifier currentId) { - try { - return readWriteTransaction.read(LogicalDatastoreType.OPERATIONAL, currentId).checkedGet(); - } catch (ReadFailedException e) { - throw new IllegalStateException("Unable to perform read", e); - } - } - - @Override - public void delete(final InstanceIdentifier path) { - readWriteTransaction.delete(LogicalDatastoreType.OPERATIONAL, path); - } - - @Override - public void merge(final InstanceIdentifier path, T data) { - readWriteTransaction.merge(LogicalDatastoreType.OPERATIONAL, path, data, true); - } - - @Override - public void put(final InstanceIdentifier path, T data) { - readWriteTransaction.put(LogicalDatastoreType.OPERATIONAL, path, data, true); - } - - public CheckedFuture submit() { - return readWriteTransaction.submit(); - } - - @Override - public void close() { - readWriteTransaction.cancel(); - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/AbstractGenericReader.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/AbstractGenericReader.java deleted file mode 100644 index 9bfbc2450..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/AbstractGenericReader.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.read; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import javax.annotation.Nonnull; -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; - -@Beta -public abstract class AbstractGenericReader> implements Reader { - - private static final Logger LOG = LoggerFactory.getLogger(AbstractGenericReader.class); - - private final InstanceIdentifier instanceIdentifier; - - protected AbstractGenericReader(final InstanceIdentifier managedDataObjectType) { - this.instanceIdentifier = RWUtils.makeIidWildcarded(managedDataObjectType); - } - - @Nonnull - @Override - public final InstanceIdentifier getManagedDataObjectType() { - return instanceIdentifier; - } - - /** - * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. - * - */ - protected Optional readCurrent(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - LOG.debug("{}: Reading current: {}", this, id); - final B builder = getBuilder(id); - // Cache empty value to determine if anything has changed later TODO cache in a field - final D emptyValue = builder.build(); - - LOG.trace("{}: Reading current attributes", this); - readCurrentAttributes(id, builder, ctx); - - // Need to check whether anything was filled in to determine if data is present or not. - final D built = builder.build(); - final Optional read = built.equals(emptyValue) - ? Optional.absent() - : Optional.of(built); - - LOG.debug("{}: Current node read successfully. Result: {}", this, read); - return read; - } - - @Nonnull - @Override - @SuppressWarnings("unchecked") - public Optional read(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - LOG.trace("{}: Reading : {}", this, id); - checkArgument(id.getTargetType().equals(getManagedDataObjectType().getTargetType())); - return readCurrent((InstanceIdentifier) id, ctx); - } - - @Override - public String toString() { - return String.format("Reader[%s]", getManagedDataObjectType().getTargetType().getSimpleName()); - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/BindingBrokerReader.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/BindingBrokerReader.java deleted file mode 100644 index 68aa3956e..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/BindingBrokerReader.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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.read; - -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.Reader; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Simple DataBroker backed reader allowing to delegate reads to different brokers. - */ -public final class BindingBrokerReader> - implements Reader, AutoCloseable { - - private final InstanceIdentifier instanceIdentifier; - private final DataBroker dataBroker; - private final LogicalDatastoreType datastoreType; - private final ReflexiveReaderCustomizer reflexiveReaderCustomizer; - - public BindingBrokerReader(final InstanceIdentifier instanceIdentifier, - final DataBroker dataBroker, - final LogicalDatastoreType datastoreType, - final Class builderClass) { - this.reflexiveReaderCustomizer = new ReflexiveReaderCustomizer<>(instanceIdentifier.getTargetType(), builderClass); - this.instanceIdentifier = instanceIdentifier; - this.dataBroker = dataBroker; - this.datastoreType = datastoreType; - } - - @Nonnull - @Override - public Optional read(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - try (final ReadOnlyTransaction readOnlyTransaction = dataBroker.newReadOnlyTransaction()) { - final CheckedFuture, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> - read = readOnlyTransaction.read(datastoreType, id); - try { - return read.checkedGet(); - } catch (org.opendaylight.controller.md.sal.common.api.data.ReadFailedException e) { - throw new ReadFailedException(id, e); - } - } - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final D readValue) { - reflexiveReaderCustomizer.merge(parentBuilder, readValue); - } - - @Nonnull - @Override - public B getBuilder(final InstanceIdentifier id) { - return reflexiveReaderCustomizer.getBuilder(id); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final B builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - throw new UnsupportedOperationException("Not supported"); - } - - @Nonnull - @Override - public InstanceIdentifier getManagedDataObjectType() { - return instanceIdentifier; - } - - @Override - public void close() throws Exception { - // Noop - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/KeepaliveReaderWrapper.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/KeepaliveReaderWrapper.java deleted file mode 100644 index d782bcc7f..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/KeepaliveReaderWrapper.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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.read; - -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.Reader; -import java.io.Closeable; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; -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; - -/** - * Reader wrapper that periodically invokes a read to determine whether reads are still fully functional. - * In case a specific error occurs, Keep-alive failure listener gets notified. - */ -public final class KeepaliveReaderWrapper> implements Reader, Runnable, Closeable { - - private static final Logger LOG = LoggerFactory.getLogger(KeepaliveReaderWrapper.class); - - private static final NoopReadContext CTX = new NoopReadContext(); - - private final Reader delegate; - private final Class exceptionType; - private final KeepaliveFailureListener failureListener; - private final ScheduledFuture scheduledFuture; - - /** - * Create new Keepalive wrapper - * - * @param delegate underlying reader performing actual reads - * @param executor scheduled executor service to schedule keepalive calls - * @param exception type of exception used to differentiate keepalive exception from other exceptions - * @param delayInSeconds number of seconds to wait between keepalive calls - * @param failureListener listener to be called whenever a keepalive failure is detected - */ - public KeepaliveReaderWrapper(@Nonnull final Reader delegate, - @Nonnull final ScheduledExecutorService executor, - @Nonnull final Class exception, - @Nonnegative final int delayInSeconds, - @Nonnull final KeepaliveFailureListener failureListener) { - this.delegate = delegate; - this.exceptionType = exception; - this.failureListener = failureListener; - Preconditions.checkArgument(delayInSeconds > 0, "Delay cannot be < 0"); - LOG.debug("Starting keep-alive execution on top of: {} with delay of: {} seconds", delegate, delayInSeconds); - scheduledFuture = executor.scheduleWithFixedDelay(this, delayInSeconds, delayInSeconds, TimeUnit.SECONDS); - } - - @Nonnull - public Optional read(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - return delegate.read(id, ctx); - } - - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final B builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - delegate.readCurrentAttributes(id, builder, ctx); - } - - @Nonnull - public B getBuilder(final InstanceIdentifier id) { - return delegate.getBuilder(id); - } - - public void merge(@Nonnull final Builder parentBuilder, - @Nonnull final D readValue) { - delegate.merge(parentBuilder, readValue); - } - - @Nonnull - @Override - public InstanceIdentifier getManagedDataObjectType() { - return delegate.getManagedDataObjectType(); - } - - @Override - public void run() { - LOG.trace("Invoking keepalive"); - try { - final Optional read = read(delegate.getManagedDataObjectType(), CTX); - LOG.debug("Keepalive executed successfully with data: {}", read); - } catch (Exception e) { - if (exceptionType.isAssignableFrom(e.getClass())) { - LOG.warn("Keepalive failed. Notifying listener", e); - failureListener.onKeepaliveFailure(); - } - LOG.warn("Keepalive failed unexpectedly", e); - throw new IllegalArgumentException("Unexpected failure during keep-alive execution", e); - } - } - - @Override - public void close() { - // Do not interrupt, it's not our executor - scheduledFuture.cancel(false); - } - - /** - * Listener that gets called whenever keepalive fails as expected - */ - public interface KeepaliveFailureListener { - - void onKeepaliveFailure(); - } - - private static final class NoopMappingContext implements MappingContext { - @Override - public Optional read(@Nonnull final InstanceIdentifier currentId) { - return Optional.absent(); - } - - @Override - public void delete(final InstanceIdentifier path) {} - - @Override - public void merge(final InstanceIdentifier path, final T data) {} - - @Override - public void put(final InstanceIdentifier path, final T data) {} - - @Override - public void close() {} - } - - private static class NoopReadContext implements ReadContext { - - private final ModificationCache modificationCache = new ModificationCache(); - - @Nonnull - @Override - public ModificationCache getModificationCache() { - return modificationCache; - } - - @Nonnull - @Override - public MappingContext getMappingContext() { - return new NoopMappingContext(); - } - - @Override - public void close() { - - } - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/NoopReaderCustomizer.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/NoopReaderCustomizer.java deleted file mode 100644 index a4de9febb..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/NoopReaderCustomizer.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.read; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public abstract class NoopReaderCustomizer> implements - ReaderCustomizer { - - @Override - public void readCurrentAttributes(InstanceIdentifier id, final B builder, final ReadContext context) throws - ReadFailedException { - // Noop - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveListReaderCustomizer.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveListReaderCustomizer.java deleted file mode 100644 index 8ad323cc3..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveListReaderCustomizer.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.read; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.util.ReflectionUtils; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; - -/** - * Might be slow ! - */ -public abstract class ReflexiveListReaderCustomizer, K extends Identifier, B extends Builder> - extends ReflexiveReaderCustomizer - implements ListReaderCustomizer { - - - public ReflexiveListReaderCustomizer(final Class typeClass, final Class builderClass) { - super(typeClass, builderClass); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue) { - merge(parentBuilder, Collections.singletonList(readValue)); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final List readData) { - final Optional method = - ReflectionUtils.findMethodReflex(parentBuilder.getClass(), "set" + getTypeClass().getSimpleName(), - Collections.singletonList(List.class), parentBuilder.getClass()); - - checkArgument(method.isPresent(), "Unable to set %s to %s", readData, parentBuilder); - - try { - method.get().invoke(parentBuilder, readData); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalArgumentException("Unable to set " + readData + " to " + parentBuilder, e); - } - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReader.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReader.java deleted file mode 100644 index 2b2d9300b..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReader.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.read; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Reader that performs no read operation on its own, just fills in the hierarchy. - *

- * Might be slow due to reflection ! - */ -public class ReflexiveReader> extends AbstractGenericReader { - - private final ReflexiveReaderCustomizer customizer; - - public ReflexiveReader(final InstanceIdentifier identifier, final Class builderClass) { - super(identifier); - this.customizer = new ReflexiveReaderCustomizer<>(identifier.getTargetType(), builderClass); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - customizer.readCurrentAttributes(id, builder, ctx); - } - - @Nonnull - @Override - public B getBuilder(final InstanceIdentifier id) { - return customizer.getBuilder(id); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue) { - customizer.merge(parentBuilder, readValue); - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReaderCustomizer.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReaderCustomizer.java deleted file mode 100644 index a6b9bf08e..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReaderCustomizer.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.read; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.translate.util.ReflectionUtils; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Collections; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Might be slow ! - */ -class ReflexiveReaderCustomizer> extends NoopReaderCustomizer { - - private final Class typeClass; - private final Class builderClass; - - public ReflexiveReaderCustomizer(final Class typeClass, final Class builderClass) { - this.typeClass = typeClass; - this.builderClass = builderClass; - } - - protected Class getTypeClass() { - return typeClass; - } - - protected Class getBuilderClass() { - return builderClass; - } - - @Nonnull - @Override - public B getBuilder(@Nonnull InstanceIdentifier id) { - try { - return builderClass.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - throw new IllegalStateException("Unable to instantiate " + builderClass, e); - } - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue) { - if (Augmentation.class.isAssignableFrom(typeClass)) { - mergeAugmentation(parentBuilder, (Class>) typeClass, readValue); - } else { - mergeRegular(parentBuilder, readValue); - } - } - - private static void mergeRegular(@Nonnull final Builder parentBuilder, - @Nonnull final DataObject readValue) { - final Optional method = - ReflectionUtils.findMethodReflex(parentBuilder.getClass(), "set", - Collections.singletonList(readValue.getClass()), parentBuilder.getClass()); - - checkArgument(method.isPresent(), "Unable to set %s to %s", readValue, parentBuilder); - - try { - method.get().invoke(parentBuilder, readValue); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalArgumentException("Unable to set " + readValue + " to " + parentBuilder, e); - } - } - - private static void mergeAugmentation(@Nonnull final Builder parentBuilder, - @Nonnull final Class> typeClass, - @Nonnull final DataObject readValue) { - final Optional method = - ReflectionUtils.findMethodReflex(parentBuilder.getClass(), "addAugmentation", - Lists.newArrayList(Class.class, Augmentation.class), parentBuilder.getClass()); - - checkArgument(method.isPresent(), "Not possible to add augmentations to builder: %s", parentBuilder); - try { - method.get().invoke(parentBuilder, typeClass, readValue); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalArgumentException("Unable to set " + readValue + " to " + parentBuilder, e); - } - } - -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReader.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReader.java deleted file mode 100644 index aa9b2dc92..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReader.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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.read.registry; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import io.fd.honeycomb.v3po.translate.read.ListReader; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.util.read.AbstractGenericReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class CompositeReader> extends AbstractGenericReader { - - private static final Logger LOG = LoggerFactory.getLogger(CompositeReader.class); - - private final Reader delegate; - private final ImmutableMap, Reader>> childReaders; - - private CompositeReader(final Reader reader, - final ImmutableMap, Reader>> childReaders) { - super(reader.getManagedDataObjectType()); - this.delegate = reader; - this.childReaders = childReaders; - } - - @VisibleForTesting - ImmutableMap, Reader>> getChildReaders() { - return childReaders; - } - - @SuppressWarnings("unchecked") - public static InstanceIdentifier appendTypeToId( - final InstanceIdentifier parentId, final InstanceIdentifier type) { - final InstanceIdentifier.PathArgument t = new InstanceIdentifier.Item<>(type.getTargetType()); - return (InstanceIdentifier) InstanceIdentifier.create(Iterables.concat( - parentId.getPathArguments(), Collections.singleton(t))); - } - - @Nonnull - @Override - public Optional read(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - if (shouldReadCurrent(id)) { - LOG.trace("{}: Reading current: {}", this, id); - return readCurrent((InstanceIdentifier) id, ctx); - } else if (shouldDelegateToChild(id)) { - LOG.trace("{}: Reading child: {}", this, id); - return readSubtree(id, ctx); - } else { - // Fallback - LOG.trace("{}: Delegating read: {}", this, id); - return delegate.read(id, ctx); - } - } - - private boolean shouldReadCurrent(@Nonnull final InstanceIdentifier id) { - return id.getTargetType().equals(getManagedDataObjectType().getTargetType()); - } - - private boolean shouldDelegateToChild(@Nonnull final InstanceIdentifier id) { - return childReaders.containsKey(RWUtils.getNextId(id, getManagedDataObjectType()).getType()); - } - - private Optional readSubtree(final InstanceIdentifier id, - final ReadContext ctx) throws ReadFailedException { - final InstanceIdentifier.PathArgument nextId = RWUtils.getNextId(id, getManagedDataObjectType()); - final Reader> nextReader = childReaders.get(nextId.getType()); - checkArgument(nextReader != null, "Unable to read: %s. No delegate present, available readers at next level: %s", - id, childReaders.keySet()); - return nextReader.read(id, ctx); - } - - @SuppressWarnings("unchecked") - private void readChildren(final InstanceIdentifier id, @Nonnull final ReadContext ctx, final B builder) - throws ReadFailedException { - LOG.debug("{}: Reading children: {}", this, childReaders.keySet()); - for (Reader child : childReaders.values()) { - final InstanceIdentifier childId = appendTypeToId(id, child.getManagedDataObjectType()); - - LOG.debug("{}: Reading child from: {}", this, child); - if (child instanceof ListReader) { - final List list = ((ListReader) child).readList(childId, ctx); - ((ListReader) child).merge(builder, list); - } else { - final Optional read = child.read(childId, ctx); - if (read.isPresent()) { - child.merge(builder, read.get()); - } - } - } - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - delegate.readCurrentAttributes(id, builder, ctx); - readChildren(id, ctx, builder); - } - - @Nonnull - @Override - public B getBuilder(final InstanceIdentifier id) { - return delegate.getBuilder(id); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final D readValue) { - delegate.merge(parentBuilder, readValue); - } - - /** - * Wrap a Reader as a Composite Reader. - */ - static > Reader createForReader( - @Nonnull final Reader reader, - @Nonnull final ImmutableMap, Reader>> childReaders) { - - return (reader instanceof ListReader) - ? new CompositeListReader<>((ListReader) reader, childReaders) - : new CompositeReader<>(reader, childReaders); - } - - private static class CompositeListReader, B extends Builder, K extends Identifier> - extends CompositeReader - implements ListReader { - - private final ListReader delegate; - - private CompositeListReader(final ListReader reader, - final ImmutableMap, Reader>> childReaders) { - super(reader, childReaders); - this.delegate = reader; - } - - @Nonnull - @Override - public List readList(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext ctx) - throws ReadFailedException { - LOG.trace("{}: Reading all list entries", this); - final List allIds = delegate.getAllIds(id, ctx); - LOG.debug("{}: Reading list entries for: {}", this, allIds); - - // Override read list in order to perform readCurrent + readChildren here - final ArrayList allEntries = new ArrayList<>(allIds.size()); - for (K key : allIds) { - final InstanceIdentifier.IdentifiableItem currentBdItem = RWUtils.getCurrentIdItem(id, key); - final InstanceIdentifier keyedId = RWUtils.replaceLastInId(id, currentBdItem); - final Optional read = readCurrent(keyedId, ctx); - if (read.isPresent()) { - final DataObject singleItem = read.get(); - checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(singleItem.getClass())); - allEntries.add(getManagedDataObjectType().getTargetType().cast(singleItem)); - } - } - return allEntries; - } - - @Override - public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { - delegate.merge(builder, readData); - } - - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - return delegate.getAllIds(id, ctx); - } - } - -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistry.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistry.java deleted file mode 100644 index a9f606ae2..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistry.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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.read.registry; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; -import com.google.common.collect.Iterables; -import com.google.common.collect.LinkedListMultimap; -import com.google.common.collect.Multimap; -import io.fd.honeycomb.v3po.translate.read.ListReader; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -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; - -/** - * Simple reader registry able to perform and aggregated read (ROOT read) on top of all provided readers. Also able to - * delegate a specific read to one of the delegate readers. - *

- * This could serve as a utility to hold & hide all available readers in upper layers. - */ -public final class CompositeReaderRegistry implements ReaderRegistry { - - private static final Logger LOG = LoggerFactory.getLogger(CompositeReaderRegistry.class); - - private final Map, Reader>> rootReaders; - - /** - * Create new {@link CompositeReaderRegistry}. - * - * @param rootReaders List of delegate readers - */ - public CompositeReaderRegistry(@Nonnull final List>> rootReaders) { - this.rootReaders = RWUtils.uniqueLinkedIndex(checkNotNull(rootReaders), RWUtils.MANAGER_CLASS_FUNCTION); - } - - @VisibleForTesting - Map, Reader>> getRootReaders() { - return rootReaders; - } - - @Override - @Nonnull - public Multimap, ? extends DataObject> readAll( - @Nonnull final ReadContext ctx) throws ReadFailedException { - - LOG.debug("Reading from all delegates: {}", this); - LOG.trace("Reading from all delegates: {}", rootReaders.values()); - - final Multimap, DataObject> objects = LinkedListMultimap.create(); - for (Reader> rootReader : rootReaders.values()) { - LOG.debug("Reading from delegate: {}", rootReader); - - if (rootReader instanceof ListReader) { - final List listEntries = - ((ListReader) rootReader).readList(rootReader.getManagedDataObjectType(), ctx); - if (!listEntries.isEmpty()) { - objects.putAll(rootReader.getManagedDataObjectType(), listEntries); - } - } else { - final Optional read = rootReader.read(rootReader.getManagedDataObjectType(), ctx); - if (read.isPresent()) { - objects.putAll(rootReader.getManagedDataObjectType(), Collections.singletonList(read.get())); - } - } - } - - return objects; - } - - @Nonnull - @Override - public Optional read(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - final InstanceIdentifier.PathArgument first = checkNotNull( - Iterables.getFirst(id.getPathArguments(), null), "Empty id"); - final Reader> reader = rootReaders.get(first.getType()); - checkNotNull(reader, - "Unable to read %s. Missing reader. Current readers for: %s", id, rootReaders.keySet()); - LOG.debug("Reading from delegate: {}", reader); - return reader.read(id, ctx); - } - - @Override - public String toString() { - return getClass().getSimpleName() - + rootReaders.keySet().stream().map(Class::getSimpleName).collect(Collectors.toList()); - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilder.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilder.java deleted file mode 100644 index 3adda713d..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilder.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.read.registry; - -import com.google.common.collect.ImmutableMap; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder; -import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry; -import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistryBuilder; -import io.fd.honeycomb.v3po.translate.util.AbstractSubtreeManagerRegistryBuilderBuilder; -import io.fd.honeycomb.v3po.translate.util.read.ReflexiveReader; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.NotThreadSafe; -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; - -@NotThreadSafe -public final class CompositeReaderRegistryBuilder - extends AbstractSubtreeManagerRegistryBuilderBuilder>, ReaderRegistry> - implements ModifiableReaderRegistryBuilder, ReaderRegistryBuilder { - - private static final Logger LOG = LoggerFactory.getLogger(CompositeReaderRegistryBuilder.class); - - @Override - protected Reader> getSubtreeHandler(@Nonnull final Set> handledChildren, - @Nonnull final Reader> reader) { - return SubtreeReader.createForReader(handledChildren, reader); - } - - @Override - public void addStructuralReader(@Nonnull InstanceIdentifier id, - @Nonnull Class> builderType) { - add(new ReflexiveReader<>(id, builderType)); - } - - /** - * Create {@link CompositeReaderRegistry} with Readers ordered according to submitted relationships. - *

- * Note: The ordering only applies between nodes on the same level, inter-level and inter-subtree relationships are - * ignored. - */ - @Override - public ReaderRegistry build() { - ImmutableMap, Reader>> mappedReaders = - getMappedHandlers(); - LOG.debug("Building Reader registry with Readers: {}", - mappedReaders.keySet().stream() - .map(InstanceIdentifier::getTargetType) - .map(Class::getSimpleName) - .collect(Collectors.joining(", "))); - - LOG.trace("Building Reader registry with Readers: {}", mappedReaders); - final List> readerOrder = new ArrayList<>(mappedReaders.keySet()); - - // Wrap readers into composite readers recursively, collect roots and create registry - final TypeHierarchy typeHierarchy = TypeHierarchy.create(mappedReaders.keySet()); - final List>> orderedRootReaders = - typeHierarchy.getRoots().stream() - .map(rootId -> toCompositeReader(rootId, mappedReaders, typeHierarchy)) - .collect(Collectors.toList()); - - // We are violating the ordering from mappedReaders, since we are forming a composite structure - // but at least order root writers - orderedRootReaders.sort((reader1, reader2) -> readerOrder.indexOf(reader1.getManagedDataObjectType()) - - readerOrder.indexOf(reader2.getManagedDataObjectType())); - - return new CompositeReaderRegistry(orderedRootReaders); - } - - private Reader> toCompositeReader( - final InstanceIdentifier instanceIdentifier, - final ImmutableMap, Reader>> mappedReaders, - final TypeHierarchy typeHierarchy) { - - // Order child readers according to the mappedReadersCollection - final ImmutableMap.Builder, Reader>> childReadersMapB = ImmutableMap.builder(); - for (InstanceIdentifier childId : mappedReaders.keySet()) { - if (typeHierarchy.getDirectChildren(instanceIdentifier).contains(childId)) { - childReadersMapB.put(childId.getTargetType(), toCompositeReader(childId, mappedReaders, typeHierarchy)); - } - } - - final ImmutableMap, Reader>> childReadersMap = childReadersMapB.build(); - return childReadersMap.isEmpty() - ? mappedReaders.get(instanceIdentifier) - : CompositeReader.createForReader(mappedReaders.get(instanceIdentifier), childReadersMap); - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReader.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReader.java deleted file mode 100644 index 50a20656e..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReader.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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.read.registry; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import io.fd.honeycomb.v3po.translate.read.ListReader; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.util.ReflectionUtils; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Simple Reader delegate for subtree Readers (Readers handling also children nodes) providing a list of all the - * children nodes being handled. - */ -class SubtreeReader> implements Reader { - - private static final Logger LOG = LoggerFactory.getLogger(SubtreeReader.class); - - private final Reader delegate; - private final Set> handledChildTypes = new HashSet<>(); - - private SubtreeReader(final Reader delegate, Set> handledTypes) { - this.delegate = delegate; - for (InstanceIdentifier handledType : handledTypes) { - // Iid has to start with Reader's handled root type - checkArgument(delegate.getManagedDataObjectType().getTargetType().equals( - handledType.getPathArguments().iterator().next().getType()), - "Handled node from subtree has to be identified by an instance identifier starting from: %s." - + "Instance identifier was: %s", getManagedDataObjectType().getTargetType(), handledType); - checkArgument(Iterables.size(handledType.getPathArguments()) > 1, - "Handled node from subtree identifier too short: %s", handledType); - handledChildTypes.add(InstanceIdentifier.create(Iterables.concat( - getManagedDataObjectType().getPathArguments(), Iterables.skip(handledType.getPathArguments(), 1)))); - } - } - - /** - * Return set of types also handled by this Reader. All of the types are children of the type managed by this Reader - * excluding the type of this Reader. - */ - Set> getHandledChildTypes() { - return handledChildTypes; - } - - @Override - @Nonnull - public Optional read( - @Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - final InstanceIdentifier wildcarded = RWUtils.makeIidWildcarded(id); - - // Reading entire subtree and filtering if is current reader responsible - if (getHandledChildTypes().contains(wildcarded)) { - LOG.debug("{}: Subtree node managed by this writer requested: {}. Reading current and filtering", this, id); - // If there's no dedicated reader, use read current - final InstanceIdentifier currentId = RWUtils.cutId(id, getManagedDataObjectType()); - final Optional current = delegate.read(currentId, ctx); - // then perform post-reading filtering (return only requested sub-node) - final Optional readSubtree = current.isPresent() - ? filterSubtree(current.get(), id, getManagedDataObjectType().getTargetType()) - : current; - - LOG.debug("{}: Subtree: {} read successfully. Result: {}", this, id, readSubtree); - return readSubtree; - - // Fallback solution, try delegate, maybe it can read the ID - } else { - return delegate.read(id, ctx); - } - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - delegate.readCurrentAttributes(id, builder, ctx); - } - - @Nonnull - @Override - public B getBuilder(final InstanceIdentifier id) { - return delegate.getBuilder(id); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final D readValue) { - delegate.merge(parentBuilder, readValue); - } - - @Nonnull - private static Optional filterSubtree(@Nonnull final DataObject parent, - @Nonnull final InstanceIdentifier absolutPath, - @Nonnull final Class managedType) { - final InstanceIdentifier.PathArgument nextId = - RWUtils.getNextId(absolutPath, InstanceIdentifier.create(parent.getClass())); - - final Optional nextParent = findNextParent(parent, nextId, managedType); - - if (Iterables.getLast(absolutPath.getPathArguments()).equals(nextId)) { - return nextParent; // we found the dataObject identified by absolutePath - } else if (nextParent.isPresent()) { - return filterSubtree(nextParent.get(), absolutPath, nextId.getType()); - } else { - return nextParent; // we can't go further, return Optional.absent() - } - } - - private static Optional findNextParent(@Nonnull final DataObject parent, - @Nonnull final InstanceIdentifier.PathArgument nextId, - @Nonnull final Class managedType) { - // TODO is there a better way than reflection ? e.g. convert into NN and filter out with a utility - Optional method = ReflectionUtils.findMethodReflex(managedType, "get", - Collections.emptyList(), nextId.getType()); - - if (method.isPresent()) { - return Optional.fromNullable(filterSingle(parent, nextId, method.get())); - } else { - // List child nodes - method = ReflectionUtils.findMethodReflex(managedType, - "get" + nextId.getType().getSimpleName(), Collections.emptyList(), List.class); - - if (method.isPresent()) { - return filterList(parent, nextId, method.get()); - } else { - throw new IllegalStateException( - "Unable to filter " + nextId + " from " + parent + " getters not found using reflexion"); - } - } - } - - @SuppressWarnings("unchecked") - private static Optional filterList(final DataObject parent, - final InstanceIdentifier.PathArgument nextId, - final Method method) { - final List invoke = (List) invoke(method, nextId, parent); - - checkArgument(nextId instanceof InstanceIdentifier.IdentifiableItem, - "Unable to perform wildcarded read for %s", nextId); - final Identifier key = ((InstanceIdentifier.IdentifiableItem) nextId).getKey(); - // TODO replace with stream().filter().findFirst() when we switch to using java's Optional instead of Guava's - // because now we would have to do awkward Optional transformation since findFirstReturns guava's optional - return Iterables.tryFind(invoke, new Predicate() { - - @Override - public boolean apply(@Nullable final DataObject input) { - final Optional keyGetter = ReflectionUtils.findMethodReflex(nextId.getType(), "get", - Collections.emptyList(), key.getClass()); - final Object actualKey; - actualKey = invoke(keyGetter.get(), nextId, input); - return key.equals(actualKey); - } - }); - } - - private static DataObject filterSingle(final DataObject parent, - final InstanceIdentifier.PathArgument nextId, final Method method) { - return nextId.getType().cast(invoke(method, nextId, parent)); - } - - private static Object invoke(final Method method, - final InstanceIdentifier.PathArgument nextId, final DataObject parent) { - try { - return method.invoke(parent); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalArgumentException("Unable to get " + nextId + " from " + parent, e); - } - } - - @Override - @Nonnull - public InstanceIdentifier getManagedDataObjectType() { - return delegate.getManagedDataObjectType(); - } - - /** - * Wrap a Reader as a subtree Reader. - */ - static > Reader createForReader(@Nonnull final Set> handledChildren, - @Nonnull final Reader reader) { - return (reader instanceof ListReader) - ? new SubtreeListReader<>((ListReader) reader, handledChildren) - : new SubtreeReader<>(reader, handledChildren); - } - - private static final class SubtreeListReader, B extends Builder, K extends Identifier> - extends SubtreeReader implements ListReader { - - private final ListReader delegate; - - private SubtreeListReader(final ListReader delegate, - final Set> handledTypes) { - super(delegate, handledTypes); - this.delegate = delegate; - } - - @Nonnull - @Override - public List readList(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext ctx) - throws ReadFailedException { - return delegate.readList(id, ctx); - } - - @Override - public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { - delegate.merge(builder, readData); - } - - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - return delegate.getAllIds(id, ctx); - } - } - -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/TypeHierarchy.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/TypeHierarchy.java deleted file mode 100644 index 005e3bc8d..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/TypeHierarchy.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.read.registry; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.collect.Iterables; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.jgrapht.experimental.dag.DirectedAcyclicGraph; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -final class TypeHierarchy { - private final DirectedAcyclicGraph, Parent> hierarchy; - - private TypeHierarchy(@Nonnull final DirectedAcyclicGraph, Parent> hierarchy) { - this.hierarchy = hierarchy; - } - - Set> getAllChildren(InstanceIdentifier id) { - final HashSet> instanceIdentifiers = new HashSet<>(); - for (InstanceIdentifier childId : getDirectChildren(id)) { - instanceIdentifiers.add(childId); - instanceIdentifiers.addAll(getAllChildren(childId)); - } - return instanceIdentifiers; - } - - Set> getDirectChildren(InstanceIdentifier id) { - checkArgument(hierarchy.vertexSet().contains(id), - "Unknown reader: %s. Known readers: %s", id, hierarchy.vertexSet()); - - return hierarchy.outgoingEdgesOf(id).stream() - .map(hierarchy::getEdgeTarget) - .collect(Collectors.toSet()); - } - - Set> getRoots() { - return hierarchy.vertexSet().stream() - .filter(vertex -> hierarchy.incomingEdgesOf(vertex).size() == 0) - .collect(Collectors.toSet()); - } - - /** - * Create reader hierarchy from a flat set of instance identifiers. - * - * @param allIds Set of unkeyed instance identifiers - */ - static TypeHierarchy create(@Nonnull Set> allIds) { - final DirectedAcyclicGraph, Parent> - readersHierarchy = new DirectedAcyclicGraph<>((sourceVertex, targetVertex) -> new Parent()); - - for (InstanceIdentifier allId : allIds) { - checkArgument(!Iterables.isEmpty(allId.getPathArguments()), "Empty ID detected"); - - if (Iterables.size(allId.getPathArguments()) == 1) { - readersHierarchy.addVertex(allId); - } - - List pathArgs = new LinkedList<>(); - pathArgs.add(allId.getPathArguments().iterator().next()); - - for (InstanceIdentifier.PathArgument pathArgument : Iterables.skip(allId.getPathArguments(), 1)) { - final InstanceIdentifier previous = InstanceIdentifier.create(pathArgs); - pathArgs.add(pathArgument); - final InstanceIdentifier current = InstanceIdentifier.create(pathArgs); - - readersHierarchy.addVertex(previous); - readersHierarchy.addVertex(current); - - try { - readersHierarchy.addDagEdge(previous, current); - } catch (DirectedAcyclicGraph.CycleFoundException e) { - throw new IllegalArgumentException("Loop in hierarchy detected", e); - } - } - } - - return new TypeHierarchy(readersHierarchy); - } - - private static final class Parent{} -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/AbstractGenericWriter.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/AbstractGenericWriter.java deleted file mode 100644 index 44b36edae..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/AbstractGenericWriter.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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.write; - -import static com.google.common.base.Preconditions.checkArgument; - -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import io.fd.honeycomb.v3po.translate.write.Writer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class AbstractGenericWriter implements Writer { - - private static final Logger LOG = LoggerFactory.getLogger(AbstractGenericWriter.class); - - private final InstanceIdentifier instanceIdentifier; - - protected AbstractGenericWriter(final InstanceIdentifier type) { - this.instanceIdentifier = RWUtils.makeIidWildcarded(type); - } - - protected void writeCurrent(final InstanceIdentifier id, final D data, final WriteContext ctx) - throws WriteFailedException { - LOG.debug("{}: Writing current: {} data: {}", this, id, data); - writeCurrentAttributes(id, data, ctx); - LOG.debug("{}: Current node written successfully", this); - } - - protected void updateCurrent(final InstanceIdentifier id, final D dataBefore, final D dataAfter, - final WriteContext ctx) throws WriteFailedException { - LOG.debug("{}: Updating current: {} dataBefore: {}, datAfter: {}", this, id, dataBefore, dataAfter); - - if (dataBefore.equals(dataAfter)) { - LOG.debug("{}: Skipping current(no update): {}", this, id); - // No change, ignore - return; - } - updateCurrentAttributes(id, dataBefore, dataAfter, ctx); - LOG.debug("{}: Current node updated successfully", this); - } - - protected void deleteCurrent(final InstanceIdentifier id, final D dataBefore, final WriteContext ctx) - throws WriteFailedException { - LOG.debug("{}: Deleting current: {} dataBefore: {}", this, id, dataBefore); - deleteCurrentAttributes(id, dataBefore, ctx); - } - - @SuppressWarnings("unchecked") - @Override - public void update(@Nonnull final InstanceIdentifier id, - @Nullable final DataObject dataBefore, - @Nullable final DataObject dataAfter, - @Nonnull final WriteContext ctx) throws WriteFailedException { - LOG.debug("{}: Updating : {}", this, id); - LOG.trace("{}: Updating : {}, from: {} to: {}", this, id, dataBefore, dataAfter); - - checkArgument(idPointsToCurrent(id), "Cannot handle data: %s. Only: %s can be handled by writer: %s", - id, getManagedDataObjectType(), this); - - if (isWrite(dataBefore, dataAfter)) { - writeCurrent((InstanceIdentifier) id, castToManaged(dataAfter), ctx); - } else if (isDelete(dataBefore, dataAfter)) { - deleteCurrent((InstanceIdentifier) id, castToManaged(dataBefore), ctx); - } else { - checkArgument(dataBefore != null && dataAfter != null, "No data to process"); - updateCurrent((InstanceIdentifier) id, castToManaged(dataBefore), castToManaged(dataAfter), ctx); - } - } - - private void checkDataType(@Nonnull final DataObject dataAfter) { - checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(dataAfter.getClass())); - } - - private D castToManaged(final DataObject data) { - checkDataType(data); - return getManagedDataObjectType().getTargetType().cast(data); - } - - private static boolean isWrite(final DataObject dataBefore, - final DataObject dataAfter) { - return dataBefore == null && dataAfter != null; - } - - private static boolean isDelete(final DataObject dataBefore, - final DataObject dataAfter) { - return dataAfter == null && dataBefore != null; - } - - private boolean idPointsToCurrent(final @Nonnull InstanceIdentifier id) { - return id.getTargetType().equals(getManagedDataObjectType().getTargetType()); - } - - protected abstract void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D data, - @Nonnull final WriteContext ctx) throws WriteFailedException; - - protected abstract void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final WriteContext ctx) throws WriteFailedException; - - protected abstract void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final D dataAfter, - @Nonnull final WriteContext ctx) throws WriteFailedException; - - @Nonnull - @Override - public InstanceIdentifier getManagedDataObjectType() { - return instanceIdentifier; - } - - - @Override - public String toString() { - return String.format("Writer[%s]", getManagedDataObjectType().getTargetType().getSimpleName()); - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/NoopWriterRegistry.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/NoopWriterRegistry.java deleted file mode 100644 index 7c45fcd82..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/NoopWriterRegistry.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.write; - -import io.fd.honeycomb.v3po.translate.TranslationException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry; -import javax.annotation.Nonnull; - -/** - * Empty registry that does not perform any changes. Can be used in data layer, if we want to disable passing data to - * translation layer. - */ -public class NoopWriterRegistry implements WriterRegistry, AutoCloseable { - - @Override - public void update(@Nonnull final DataObjectUpdates updates, - @Nonnull final WriteContext ctx) throws TranslationException { - // NOOP - } - - @Override - public void close() throws Exception { - // NOOP - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/TransactionWriteContext.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/TransactionWriteContext.java deleted file mode 100644 index 47498f594..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/TransactionWriteContext.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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.write; - -import static com.google.common.base.Preconditions.checkState; - -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import java.util.Map; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -/** - * Transaction based WriteContext - */ -public final class TransactionWriteContext implements WriteContext { - - private final DOMDataReadOnlyTransaction beforeTx; - private final DOMDataReadOnlyTransaction afterTx; - private final ModificationCache ctx; - private final BindingNormalizedNodeSerializer serializer; - private final MappingContext mappingContext; - - public TransactionWriteContext(final BindingNormalizedNodeSerializer serializer, - final DOMDataReadOnlyTransaction beforeTx, - final DOMDataReadOnlyTransaction afterTx, - final MappingContext mappingContext) { - this.serializer = serializer; - // TODO do we have a BA transaction adapter ? If so, use it here and don't pass serializer - this.beforeTx = beforeTx; - this.afterTx = afterTx; - this.mappingContext = mappingContext; - this.ctx = new ModificationCache(); - } - - // TODO make this asynchronous - - @Override - public Optional readBefore(@Nonnull final InstanceIdentifier currentId) { - return read(currentId, beforeTx); - } - - @Override - public Optional readAfter(@Nonnull final InstanceIdentifier currentId) { - return read(currentId, afterTx); - } - - - private Optional read(final InstanceIdentifier currentId, - final DOMDataReadOnlyTransaction tx) { - final YangInstanceIdentifier path = serializer.toYangInstanceIdentifier(currentId); - - final CheckedFuture>, ReadFailedException> read = - tx.read(LogicalDatastoreType.CONFIGURATION, path); - - try { - // TODO once the APIs are asynchronous use just Futures.transform - final Optional> optional = read.checkedGet(); - - if (!optional.isPresent()) { - return Optional.absent(); - } - - final NormalizedNode data = optional.get(); - final Map.Entry, DataObject> entry = serializer.fromNormalizedNode(path, data); - - final Class targetType = currentId.getTargetType(); - checkState(targetType.isAssignableFrom(entry.getValue().getClass()), - "Unexpected data object type, should be: %s, but was: %s", targetType, entry.getValue().getClass()); - return Optional.of(targetType.cast(entry.getValue())); - } catch (ReadFailedException e) { - throw new IllegalStateException("Unable to perform read", e); - } - } - - @Nonnull - @Override - public ModificationCache getModificationCache() { - return ctx; - } - - @Nonnull - @Override - public MappingContext getMappingContext() { - return mappingContext; - } - - /** - * Does not close the transactions - */ - @Override - public void close() { - ctx.close(); - beforeTx.close(); - afterTx.close(); - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistry.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistry.java deleted file mode 100644 index 7433de813..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistry.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * 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.write.registry; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.base.Optional; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.TranslationException; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import io.fd.honeycomb.v3po.translate.write.Writer; -import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Flat writer registry, delegating updates to writers in the order writers were submitted. - */ -@ThreadSafe -final class FlatWriterRegistry implements WriterRegistry { - - private static final Logger LOG = LoggerFactory.getLogger(FlatWriterRegistry.class); - - // All types handled by writers directly or as children - private final ImmutableSet> handledTypes; - - private final Set> writersOrderReversed; - private final Set> writersOrder; - private final Map, Writer> writers; - - /** - * Create flat registry instance. - * - * @param writers immutable, ordered map of writers to use to process updates. Order of the writers has to be - * one in which create and update operations should be handled. Deletes will be handled in reversed - * order. All deletes are handled before handling all the updates. - */ - FlatWriterRegistry(@Nonnull final ImmutableMap, Writer> writers) { - this.writers = writers; - this.writersOrderReversed = Sets.newLinkedHashSet(Lists.reverse(Lists.newArrayList(writers.keySet()))); - this.writersOrder = writers.keySet(); - this.handledTypes = getAllHandledTypes(writers); - } - - private static ImmutableSet> getAllHandledTypes( - @Nonnull final ImmutableMap, Writer> writers) { - final ImmutableSet.Builder> handledTypesBuilder = ImmutableSet.builder(); - for (Map.Entry, Writer> writerEntry : writers.entrySet()) { - final InstanceIdentifier writerType = writerEntry.getKey(); - final Writer writer = writerEntry.getValue(); - handledTypesBuilder.add(writerType); - if (writer instanceof SubtreeWriter) { - handledTypesBuilder.addAll(((SubtreeWriter) writer).getHandledChildTypes()); - } - } - return handledTypesBuilder.build(); - } - - @Override - public void update(@Nonnull final DataObjectUpdates updates, - @Nonnull final WriteContext ctx) throws TranslationException { - if (updates.isEmpty()) { - return; - } - - // Optimization - if (updates.containsOnlySingleType()) { - // First process delete - singleUpdate(updates.getDeletes(), ctx); - // Next is update - singleUpdate(updates.getUpdates(), ctx); - } else { - // First process deletes - bulkUpdate(updates.getDeletes(), ctx, true, writersOrderReversed); - // Next are updates - bulkUpdate(updates.getUpdates(), ctx, true, writersOrder); - } - - LOG.debug("Update successful for types: {}", updates.getTypeIntersection()); - LOG.trace("Update successful for: {}", updates); - } - - private void singleUpdate(@Nonnull final Multimap, ? extends DataObjectUpdate> updates, - @Nonnull final WriteContext ctx) throws WriteFailedException { - if (updates.isEmpty()) { - return; - } - - final InstanceIdentifier singleType = updates.keySet().iterator().next(); - LOG.debug("Performing single type update for: {}", singleType); - Collection singleTypeUpdates = updates.get(singleType); - Writer writer = getWriter(singleType); - - if (writer == null) { - // This node must be handled by a subtree writer, find it and call it or else fail - checkArgument(handledTypes.contains(singleType), "Unable to process update. Missing writers for: %s", - singleType); - writer = getSubtreeWriterResponsible(singleType); - singleTypeUpdates = getParentDataObjectUpdate(ctx, updates, writer); - } - - LOG.trace("Performing single type update with writer: {}", writer); - for (DataObjectUpdate singleUpdate : singleTypeUpdates) { - writer.update(singleUpdate.getId(), singleUpdate.getDataBefore(), singleUpdate.getDataAfter(), ctx); - } - } - - private Writer getSubtreeWriterResponsible(final InstanceIdentifier singleType) { - final Writer writer;// This is slow ( minor TODO-perf ) - writer = writers.values().stream() - .filter(w -> w instanceof SubtreeWriter) - .filter(w -> ((SubtreeWriter) w).getHandledChildTypes().contains(singleType)) - .findFirst() - .get(); - return writer; - } - - private Collection getParentDataObjectUpdate(final WriteContext ctx, - final Multimap, ? extends DataObjectUpdate> updates, - final Writer writer) { - // Now read data for subtree reader root, but first keyed ID is needed and that ID can be cut from updates - InstanceIdentifier firstAffectedChildId = ((SubtreeWriter) writer).getHandledChildTypes().stream() - .filter(updates::containsKey) - .map(unkeyedId -> updates.get(unkeyedId)) - .flatMap(doUpdates -> doUpdates.stream()) - .map(DataObjectUpdate::getId) - .findFirst() - .get(); - - final InstanceIdentifier parentKeyedId = - RWUtils.cutId(firstAffectedChildId, writer.getManagedDataObjectType()); - - final Optional parentBefore = ctx.readBefore(parentKeyedId); - final Optional parentAfter = ctx.readAfter(parentKeyedId); - return Collections.singleton( - DataObjectUpdate.create(parentKeyedId, parentBefore.orNull(), parentAfter.orNull())); - } - - private void bulkUpdate(@Nonnull final Multimap, ? extends DataObjectUpdate> updates, - @Nonnull final WriteContext ctx, - final boolean attemptRevert, - @Nonnull final Set> writersOrder) throws BulkUpdateException { - if (updates.isEmpty()) { - return; - } - - LOG.debug("Performing bulk update with revert attempt: {} for: {}", attemptRevert, updates.keySet()); - - // Check that all updates can be handled - checkAllTypesCanBeHandled(updates); - - // Capture all changes successfully processed in case revert is needed - final Set> processedNodes = new HashSet<>(); - - // Iterate over all writers and call update if there are any related updates - for (InstanceIdentifier writerType : writersOrder) { - Collection writersData = updates.get(writerType); - final Writer writer = getWriter(writerType); - - if (writersData.isEmpty()) { - // If there are no data for current writer, but it is a SubtreeWriter and there are updates to - // its children, still invoke it with its root data - if (writer instanceof SubtreeWriter && isAffected(((SubtreeWriter) writer), updates)) { - // Provide parent data for SubtreeWriter for further processing - writersData = getParentDataObjectUpdate(ctx, updates, writer); - } else { - // Skipping unaffected writer - // Alternative to this would be modification sort according to the order of writers - continue; - } - } - - LOG.debug("Performing update for: {}", writerType); - LOG.trace("Performing update with writer: {}", writer); - - for (DataObjectUpdate singleUpdate : writersData) { - try { - writer.update(singleUpdate.getId(), singleUpdate.getDataBefore(), singleUpdate.getDataAfter(), ctx); - processedNodes.add(singleUpdate.getId()); - LOG.trace("Update successful for type: {}", writerType); - LOG.debug("Update successful for: {}", singleUpdate); - } catch (Exception e) { - LOG.error("Error while processing data change of: {} (updates={})", writerType, writersData, e); - - final Reverter reverter = attemptRevert - ? new ReverterImpl(processedNodes, updates, writersOrder, ctx) - : () -> {}; // NOOP reverter - - // Find out which changes left unprocessed - final Set> unprocessedChanges = updates.values().stream() - .map(DataObjectUpdate::getId) - .filter(id -> !processedNodes.contains(id)) - .collect(Collectors.toSet()); - throw new BulkUpdateException(unprocessedChanges, reverter, e); - } - } - } - } - - private void checkAllTypesCanBeHandled( - @Nonnull final Multimap, ? extends DataObjectUpdate> updates) { - if (!handledTypes.containsAll(updates.keySet())) { - final Sets.SetView> missingWriters = Sets.difference(updates.keySet(), handledTypes); - LOG.warn("Unable to process update. Missing writers for: {}", missingWriters); - throw new IllegalArgumentException("Unable to process update. Missing writers for: " + missingWriters); - } - } - - /** - * Check whether {@link SubtreeWriter} is affected by the updates. - * - * @return true if there are any updates to SubtreeWriter's child nodes (those marked by SubtreeWriter - * as being taken care of) - * */ - private static boolean isAffected(final SubtreeWriter writer, - final Multimap, ? extends DataObjectUpdate> updates) { - return !Sets.intersection(writer.getHandledChildTypes(), updates.keySet()).isEmpty(); - } - - @Nullable - private Writer getWriter(@Nonnull final InstanceIdentifier singleType) { - return writers.get(singleType); - } - - // FIXME unit test - private final class ReverterImpl implements Reverter { - - private final Collection> processedNodes; - private final Multimap, ? extends DataObjectUpdate> updates; - private final Set> revertDeleteOrder; - private final WriteContext ctx; - - ReverterImpl(final Collection> processedNodes, - final Multimap, ? extends DataObjectUpdate> updates, - final Set> writersOrderOriginal, - final WriteContext ctx) { - this.processedNodes = processedNodes; - this.updates = updates; - // Use opposite ordering when executing revert - this.revertDeleteOrder = writersOrderOriginal == FlatWriterRegistry.this.writersOrder - ? FlatWriterRegistry.this.writersOrderReversed - : FlatWriterRegistry.this.writersOrder; - this.ctx = ctx; - } - - @Override - public void revert() throws RevertFailedException { - Multimap, DataObjectUpdate> updatesToRevert = - filterAndRevertProcessed(updates, processedNodes); - - LOG.info("Attempting revert for changes: {}", updatesToRevert); - try { - // Perform reversed bulk update without revert attempt - bulkUpdate(updatesToRevert, ctx, true, revertDeleteOrder); - LOG.info("Revert successful"); - } catch (BulkUpdateException e) { - LOG.error("Revert failed", e); - throw new RevertFailedException(e.getFailedIds(), e); - } - } - - /** - * Create new updates map, but only keep already processed changes. Switching before and after data for each - * update. - */ - private Multimap, DataObjectUpdate> filterAndRevertProcessed( - final Multimap, ? extends DataObjectUpdate> updates, - final Collection> processedNodes) { - final Multimap, DataObjectUpdate> filtered = HashMultimap.create(); - for (InstanceIdentifier processedNode : processedNodes) { - final InstanceIdentifier wildcardedIid = RWUtils.makeIidWildcarded(processedNode); - if (updates.containsKey(wildcardedIid)) { - updates.get(wildcardedIid).stream() - .filter(dataObjectUpdate -> processedNode.contains(dataObjectUpdate.getId())) - .forEach(dataObjectUpdate -> filtered.put(processedNode, dataObjectUpdate.reverse())); - } - } - return filtered; - } - } - -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryBuilder.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryBuilder.java deleted file mode 100644 index bfac2eedd..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryBuilder.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.write.registry; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableMap; -import io.fd.honeycomb.v3po.translate.util.AbstractSubtreeManagerRegistryBuilderBuilder; -import io.fd.honeycomb.v3po.translate.write.Writer; -import io.fd.honeycomb.v3po.translate.write.registry.ModifiableWriterRegistryBuilder; -import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry; -import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistryBuilder; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.NotThreadSafe; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Builder for {@link FlatWriterRegistry} allowing users to specify inter-writer relationships. - */ -@NotThreadSafe -public final class FlatWriterRegistryBuilder - extends AbstractSubtreeManagerRegistryBuilderBuilder, WriterRegistry> - implements ModifiableWriterRegistryBuilder, WriterRegistryBuilder { - - private static final Logger LOG = LoggerFactory.getLogger(FlatWriterRegistryBuilder.class); - - @Override - protected Writer getSubtreeHandler(final @Nonnull Set> handledChildren, - final @Nonnull Writer writer) { - return SubtreeWriter.createForWriter(handledChildren, writer); - } - - /** - * Create FlatWriterRegistry with writers ordered according to submitted relationships. - */ - @Override - public WriterRegistry build() { - final ImmutableMap, Writer> mappedWriters = getMappedHandlers(); - LOG.debug("Building writer registry with writers: {}", - mappedWriters.keySet().stream() - .map(InstanceIdentifier::getTargetType) - .map(Class::getSimpleName) - .collect(Collectors.joining(", "))); - LOG.trace("Building writer registry with writers: {}", mappedWriters); - return new FlatWriterRegistry(mappedWriters); - } - - @VisibleForTesting - @Override - protected ImmutableMap, Writer> getMappedHandlers() { - return super.getMappedHandlers(); - } -} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/SubtreeWriter.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/SubtreeWriter.java deleted file mode 100644 index e395b29da..000000000 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/SubtreeWriter.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.write.registry; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.collect.Iterables; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import io.fd.honeycomb.v3po.translate.write.Writer; -import java.util.HashSet; -import java.util.Set; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Simple writer delegate for subtree writers (writers handling also children nodes) providing a list of all the - * children nodes being handled. - */ -final class SubtreeWriter implements Writer { - - private final Writer delegate; - private final Set> handledChildTypes = new HashSet<>(); - - private SubtreeWriter(final Writer delegate, Set> handledTypes) { - this.delegate = delegate; - for (InstanceIdentifier handledType : handledTypes) { - // Iid has to start with writer's handled root type - checkArgument(delegate.getManagedDataObjectType().getTargetType().equals( - handledType.getPathArguments().iterator().next().getType()), - "Handled node from subtree has to be identified by an instance identifier starting from: %s." - + "Instance identifier was: %s", getManagedDataObjectType().getTargetType(), handledType); - checkArgument(Iterables.size(handledType.getPathArguments()) > 1, - "Handled node from subtree identifier too short: %s", handledType); - handledChildTypes.add(InstanceIdentifier.create(Iterables.concat( - getManagedDataObjectType().getPathArguments(), Iterables.skip(handledType.getPathArguments(), 1)))); - } - } - - /** - * Return set of types also handled by this writer. All of the types are children of the type managed by this - * writer excluding the type of this writer. - */ - Set> getHandledChildTypes() { - return handledChildTypes; - } - - @Override - public void update( - @Nonnull final InstanceIdentifier id, - @Nullable final DataObject dataBefore, - @Nullable final DataObject dataAfter, @Nonnull final WriteContext ctx) throws WriteFailedException { - delegate.update(id, dataBefore, dataAfter, ctx); - } - - @Override - @Nonnull - public InstanceIdentifier getManagedDataObjectType() { - return delegate.getManagedDataObjectType(); - } - - /** - * Wrap a writer as a subtree writer. - */ - static Writer createForWriter(@Nonnull final Set> handledChildren, - @Nonnull final Writer writer) { - return new SubtreeWriter<>(writer, handledChildren); - } -} diff --git a/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingReaderRegistryModule.java b/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingReaderRegistryModule.java index e1f04ebe2..99feb57f9 100644 --- a/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingReaderRegistryModule.java +++ b/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingReaderRegistryModule.java @@ -1,6 +1,6 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.translate.utils.rev160406; -import io.fd.honeycomb.v3po.translate.util.read.registry.CompositeReaderRegistryBuilder; +import io.fd.honeycomb.translate.util.read.registry.CompositeReaderRegistryBuilder; public class DelegatingReaderRegistryModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.translate.utils.rev160406.AbstractDelegatingReaderRegistryModule { public DelegatingReaderRegistryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { diff --git a/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingWriterRegistryModule.java b/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingWriterRegistryModule.java index 7eadde80e..5ce89b355 100644 --- a/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingWriterRegistryModule.java +++ b/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingWriterRegistryModule.java @@ -1,6 +1,6 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.translate.utils.rev160406; -import io.fd.honeycomb.v3po.translate.util.write.registry.FlatWriterRegistryBuilder; +import io.fd.honeycomb.translate.util.write.registry.FlatWriterRegistryBuilder; public class DelegatingWriterRegistryModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.translate.utils.rev160406.AbstractDelegatingWriterRegistryModule { public DelegatingWriterRegistryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { diff --git a/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/NoopWriterRegistryModule.java b/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/NoopWriterRegistryModule.java index 0f72df9da..be6bb9270 100644 --- a/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/NoopWriterRegistryModule.java +++ b/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/NoopWriterRegistryModule.java @@ -1,8 +1,8 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.translate.utils.rev160406; -import io.fd.honeycomb.v3po.translate.util.write.NoopWriterRegistry; -import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry; -import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistryBuilder; +import io.fd.honeycomb.translate.util.write.NoopWriterRegistry; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import io.fd.honeycomb.translate.write.registry.WriterRegistryBuilder; public class NoopWriterRegistryModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.translate.utils.rev160406.AbstractNoopWriterRegistryModule { public NoopWriterRegistryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { diff --git a/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/RealtimeMappingContextModule.java b/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/RealtimeMappingContextModule.java index 99cf4b4e1..d245682d0 100644 --- a/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/RealtimeMappingContextModule.java +++ b/infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/RealtimeMappingContextModule.java @@ -1,7 +1,7 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.translate.utils.rev160406; import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.MappingContext; +import io.fd.honeycomb.translate.MappingContext; import javax.annotation.Nonnull; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/impl/write/util/TransactionWriteContextTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/impl/write/util/TransactionWriteContextTest.java new file mode 100644 index 000000000..001e5567a --- /dev/null +++ b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/impl/write/util/TransactionWriteContextTest.java @@ -0,0 +1,131 @@ +/* + * 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.translate.impl.write.util; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.Futures; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.util.DataObjects; +import io.fd.honeycomb.translate.util.write.TransactionWriteContext; +import io.fd.honeycomb.translate.MappingContext; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public class TransactionWriteContextTest { + + @Mock + private BindingNormalizedNodeSerializer serializer; + @Mock + private DOMDataReadOnlyTransaction beforeTx; + @Mock + private DOMDataReadOnlyTransaction afterTx; + @Mock + private Map.Entry entry; + @Mock + private MappingContext contextBroker; + + private TransactionWriteContext transactionWriteContext; + + @Before + public void setUp() { + initMocks(this); + transactionWriteContext = new TransactionWriteContext(serializer, beforeTx, afterTx, contextBroker); + } + + @Test + public void testReadBeforeNoData() throws Exception { + when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( + Futures.immediateCheckedFuture(Optional.absent())); + + final InstanceIdentifier instanceId = + InstanceIdentifier.create(DataObjects.DataObject1.class); + + final Optional dataObjects = transactionWriteContext.readBefore(instanceId); + assertNotNull(dataObjects); + assertFalse(dataObjects.isPresent()); + + verify(serializer).toYangInstanceIdentifier(instanceId); + verify(serializer, never()).fromNormalizedNode(any(YangInstanceIdentifier.class), any(NormalizedNode.class)); + } + + @Test + public void testReadBefore() throws Exception { + when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( + Futures.immediateCheckedFuture(Optional.of(mock(NormalizedNode.class)))); + + final InstanceIdentifier instanceId = + InstanceIdentifier.create(DataObjects.DataObject1.class); + final YangInstanceIdentifier yangId = YangInstanceIdentifier.builder().node(QName.create("n", "d")).build(); + when(serializer.toYangInstanceIdentifier(any(InstanceIdentifier.class))).thenReturn(yangId); + when(serializer.fromNormalizedNode(eq(yangId), any(NormalizedNode.class))).thenReturn(entry); + when(entry.getValue()).thenReturn(mock(DataObjects.DataObject1.class)); + + final Optional dataObjects = transactionWriteContext.readBefore(instanceId); + assertNotNull(dataObjects); + assertTrue(dataObjects.isPresent()); + + verify(serializer).toYangInstanceIdentifier(instanceId); + verify(serializer).fromNormalizedNode(eq(yangId), any(NormalizedNode.class)); + } + + @Test(expected = IllegalStateException.class) + public void testReadBeforeFailed() throws Exception { + when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( + Futures.immediateFailedCheckedFuture(mock(ReadFailedException.class))); + transactionWriteContext.readBefore(mock(InstanceIdentifier.class)); + } + + @Test(expected = IllegalStateException.class) + public void testReadAfterFailed() throws Exception { + when(afterTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( + Futures.immediateFailedCheckedFuture(mock(ReadFailedException.class))); + transactionWriteContext.readAfter(mock(InstanceIdentifier.class)); + } + + @Test + public void testGetContext() throws Exception { + assertNotNull(transactionWriteContext.getModificationCache()); + } + + @Test + public void testClose() throws Exception { + final ModificationCache context = transactionWriteContext.getModificationCache(); + transactionWriteContext.close(); + // TODO verify context was closed + } +} \ No newline at end of file diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/DataObjects.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/DataObjects.java new file mode 100644 index 000000000..e602adbb6 --- /dev/null +++ b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/DataObjects.java @@ -0,0 +1,52 @@ +/* + * 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.translate.util; + +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class DataObjects { + public interface DataObject1 extends DataObject { + InstanceIdentifier IID = InstanceIdentifier.create(DataObject1.class); + } + + public interface DataObject2 extends DataObject { + InstanceIdentifier IID = InstanceIdentifier.create(DataObject2.class); + } + + public interface DataObject3 extends DataObject { + InstanceIdentifier IID = InstanceIdentifier.create(DataObject3.class); + interface DataObject31 extends DataObject, ChildOf { + InstanceIdentifier IID = DataObject3.IID.child(DataObject31.class); + } + } + + public interface DataObject4 extends DataObject { + InstanceIdentifier IID = InstanceIdentifier.create(DataObject4.class); + interface DataObject41 extends DataObject, ChildOf { + InstanceIdentifier IID = DataObject4.IID.child(DataObject41.class); + interface DataObject411 extends DataObject, ChildOf { + InstanceIdentifier IID = DataObject41.IID.child(DataObject411.class); + } + } + + interface DataObject42 extends DataObject, ChildOf { + InstanceIdentifier IID = DataObject4.IID.child(DataObject42.class); + } + } +} diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/JsonUtilsTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/JsonUtilsTest.java new file mode 100644 index 000000000..9c97ac503 --- /dev/null +++ b/infra/translate-utils/src/test/java/io/fd/honeycomb/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.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/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java new file mode 100644 index 000000000..d742575be --- /dev/null +++ b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java @@ -0,0 +1,114 @@ +/* + * 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.translate.util.read.registry; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import io.fd.honeycomb.translate.util.DataObjects; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.mockito.Mockito; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class CompositeReaderRegistryBuilderTest { + + private Reader> reader1 = + mock(DataObjects.DataObject1.class); + private Reader> reader2 = + mock(DataObjects.DataObject2.class); + private Reader> reader3 = + mock(DataObjects.DataObject3.class); + private Reader> reader31 = + mock(DataObjects.DataObject3.DataObject31.class); + + private Reader> reader4 = + mock(DataObjects.DataObject4.class); + private Reader> reader41 = + mock(DataObjects.DataObject4.DataObject41.class); + private Reader> reader411 = + mock(DataObjects.DataObject4.DataObject41.DataObject411.class); + private Reader> reader42 = + mock(DataObjects.DataObject4.DataObject42.class); + + @SuppressWarnings("unchecked") + private Reader> mock(final Class dataObjectType) { + final Reader> mock = Mockito.mock(Reader.class); + try { + when(mock.getManagedDataObjectType()) + .thenReturn(((InstanceIdentifier) dataObjectType.getDeclaredField("IID").get(null))); + } catch (IllegalAccessException | NoSuchFieldException e) { + throw new RuntimeException(e); + } + return mock; + } + + @Test + public void testCompositeStructure() throws Exception { + final CompositeReaderRegistryBuilder compositeReaderRegistryBuilder = new CompositeReaderRegistryBuilder(); + /* + Composite reader structure ordered left from right + + 1, 2, 3, 4 + 31 42, 41 + 411 + */ + compositeReaderRegistryBuilder.add(reader1); + compositeReaderRegistryBuilder.addAfter(reader2, reader1.getManagedDataObjectType()); + compositeReaderRegistryBuilder.addAfter(reader3, reader2.getManagedDataObjectType()); + compositeReaderRegistryBuilder.addAfter(reader31, reader1.getManagedDataObjectType()); + compositeReaderRegistryBuilder.addAfter(reader4, reader3.getManagedDataObjectType()); + compositeReaderRegistryBuilder.add(reader41); + compositeReaderRegistryBuilder.addBefore(reader42, reader41.getManagedDataObjectType()); + compositeReaderRegistryBuilder.add(reader411); + + final ReaderRegistry build = compositeReaderRegistryBuilder.build(); + + final Map, Reader>> rootReaders = + ((CompositeReaderRegistry) build).getRootReaders(); + final List> rootReaderOrder = Lists.newArrayList(rootReaders.keySet()); + + assertEquals(reader1.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(0)); + assertEquals(reader2.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(1)); + assertEquals(reader3.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(2)); + assertEquals(reader4.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(3)); + + assertFalse(rootReaders.get(DataObjects.DataObject1.class) instanceof CompositeReader); + assertFalse(rootReaders.get(DataObjects.DataObject2.class) instanceof CompositeReader); + assertTrue(rootReaders.get(DataObjects.DataObject3.class) instanceof CompositeReader); + assertTrue(rootReaders.get(DataObjects.DataObject4.class) instanceof CompositeReader); + + final ImmutableMap, Reader>> childReaders = + ((CompositeReader>) rootReaders + .get(DataObjects.DataObject4.class)).getChildReaders(); + final List> orderedChildReaders = Lists.newArrayList(childReaders.keySet()); + + assertEquals(reader42.getManagedDataObjectType().getTargetType(), orderedChildReaders.get(0)); + assertEquals(reader41.getManagedDataObjectType().getTargetType(), orderedChildReaders.get(1)); + assertTrue(childReaders.get(DataObjects.DataObject4.DataObject41.class) instanceof CompositeReader); + assertFalse(childReaders.get(DataObjects.DataObject4.DataObject42.class) instanceof CompositeReader); + } +} \ No newline at end of file diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/SubtreeReaderTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/SubtreeReaderTest.java new file mode 100644 index 000000000..799b9553f --- /dev/null +++ b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/SubtreeReaderTest.java @@ -0,0 +1,124 @@ +/* + * 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.translate.util.read.registry; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import com.google.common.base.Optional; +import com.google.common.collect.Sets; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.Reader; +import io.fd.honeycomb.translate.util.DataObjects; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class SubtreeReaderTest { + + @Mock + private Reader> delegate; + @Mock + private Reader> delegateLocal; + @Mock + private ReadContext ctx; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn(DataObjects.DataObject4.IID).when(delegate).getManagedDataObjectType(); + doReturn(DataObject1.IID).when(delegateLocal).getManagedDataObjectType(); + } + + @Test + public void testCreate() throws Exception { + final Reader> subtreeR = + SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID), delegate); + + subtreeR.getBuilder(DataObjects.DataObject4.IID); + verify(delegate).getBuilder(DataObjects.DataObject4.IID); + + subtreeR.getManagedDataObjectType(); + verify(delegate, atLeastOnce()).getManagedDataObjectType(); + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateInvalid() throws Exception { + SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject1.IID), delegate); + } + + @Test(expected = IllegalStateException.class) + public void testReadOnlySubtreeCannotFilter() throws Exception { + final Reader> subtreeR = + SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID), delegate); + + doReturn(Optional.fromNullable(mock(DataObjects.DataObject4.class))).when(delegate).read(DataObjects.DataObject4.IID, ctx); + subtreeR.read(DataObjects.DataObject4.DataObject41.IID, ctx); + } + + @Test + public void testReadOnlySubtreeNotPresent() throws Exception { + final Reader> subtreeR = + SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID), delegate); + + doReturn(Optional.absent()).when(delegate).read(DataObjects.DataObject4.IID, ctx); + assertFalse(subtreeR.read(DataObjects.DataObject4.DataObject41.IID, ctx).isPresent()); + } + + @Test + public void testReadOnlySubtreeChild() throws Exception { + final Reader> subtreeR = + SubtreeReader.createForReader(Sets.newHashSet(DataObject1.DataObject11.IID), delegateLocal); + + final DataObject1 mock = mock(DataObject1.class); + final DataObject1.DataObject11 mock11 = mock(DataObject1.DataObject11.class); + doReturn(mock11).when(mock).getDataObject11(); + doReturn(Optional.fromNullable(mock)).when(delegateLocal).read(DataObject1.IID, ctx); + assertEquals(mock11, subtreeR.read(DataObject1.DataObject11.IID, ctx).get()); + } + + @Test + public void testReadEntireSubtree() throws Exception { + final Reader> subtreeR = + SubtreeReader.createForReader(Sets.newHashSet(DataObject1.DataObject11.IID), delegateLocal); + + final DataObject1 mock = mock(DataObject1.class); + final DataObject1.DataObject11 mock11 = mock(DataObject1.DataObject11.class); + doReturn(mock11).when(mock).getDataObject11(); + doReturn(Optional.fromNullable(mock)).when(delegateLocal).read(DataObject1.IID, ctx); + assertEquals(mock, subtreeR.read(DataObject1.IID, ctx).get()); + } + + public abstract static class DataObject1 implements DataObject { + public static InstanceIdentifier IID = InstanceIdentifier.create(DataObject1.class); + + public abstract DataObject11 getDataObject11(); + + public abstract static class DataObject11 implements DataObject, ChildOf { + public static InstanceIdentifier IID = DataObject1.IID.child(DataObject11.class); + } + } +} diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/TypeHierarchyTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/TypeHierarchyTest.java new file mode 100644 index 000000000..3b3ea3a35 --- /dev/null +++ b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/read/registry/TypeHierarchyTest.java @@ -0,0 +1,72 @@ +/* + * 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.translate.util.read.registry; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import com.google.common.collect.Sets; +import io.fd.honeycomb.translate.util.DataObjects; +import org.hamcrest.CoreMatchers; +import org.junit.Test; + +public class TypeHierarchyTest { + + @Test + public void testHierarchy() throws Exception { + final TypeHierarchy typeHierarchy = TypeHierarchy.create(Sets.newHashSet( + DataObjects.DataObject4.DataObject41.DataObject411.IID, + DataObjects.DataObject4.DataObject41.IID,/* Included in previous already */ + DataObjects.DataObject1.IID, + DataObjects.DataObject3.DataObject31.IID)); + + // Roots + assertThat(typeHierarchy.getRoots().size(), is(3)); + assertThat(typeHierarchy.getRoots(), CoreMatchers + .hasItems(DataObjects.DataObject1.IID, DataObjects.DataObject3.IID, DataObjects.DataObject4.IID)); + + // Leaves + assertThat(typeHierarchy.getDirectChildren(DataObjects.DataObject1.IID).size(), is(0)); + assertThat(typeHierarchy.getDirectChildren(DataObjects.DataObject3.DataObject31.IID).size(), is(0)); + assertThat(typeHierarchy.getDirectChildren(DataObjects.DataObject4.DataObject41.DataObject411.IID).size(), is(0)); + + // Intermediate leaves + assertThat(typeHierarchy.getDirectChildren(DataObjects.DataObject3.IID).size(), is(1)); + assertThat(typeHierarchy.getDirectChildren(DataObjects.DataObject3.IID), CoreMatchers + .hasItem(DataObjects.DataObject3.DataObject31.IID)); + assertEquals(typeHierarchy.getDirectChildren(DataObjects.DataObject3.IID), typeHierarchy.getAllChildren( + DataObjects.DataObject3.IID)); + + assertThat(typeHierarchy.getDirectChildren(DataObjects.DataObject4.DataObject41.IID).size(), is(1)); + assertThat(typeHierarchy.getDirectChildren(DataObjects.DataObject4.DataObject41.IID), CoreMatchers.hasItem( + DataObjects.DataObject4.DataObject41.DataObject411.IID)); + assertEquals(typeHierarchy.getDirectChildren(DataObjects.DataObject4.DataObject41.IID), typeHierarchy.getAllChildren( + DataObjects.DataObject4.DataObject41.IID)); + + assertThat(typeHierarchy.getDirectChildren(DataObjects.DataObject4.IID).size(), is(1)); + assertThat(typeHierarchy.getDirectChildren(DataObjects.DataObject4.IID), CoreMatchers + .hasItem(DataObjects.DataObject4.DataObject41.IID)); + assertThat(typeHierarchy.getAllChildren(DataObjects.DataObject4.IID).size(), is(2)); + assertTrue(typeHierarchy.getAllChildren(DataObjects.DataObject4.IID).contains(DataObjects.DataObject4.DataObject41.IID)); + assertTrue(typeHierarchy.getAllChildren(DataObjects.DataObject4.IID).contains(DataObjects.DataObject4.DataObject41.DataObject411.IID)); + } +} + diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryBuilderTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryBuilderTest.java new file mode 100644 index 000000000..79590a5a0 --- /dev/null +++ b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryBuilderTest.java @@ -0,0 +1,131 @@ +package io.fd.honeycomb.translate.util.write.registry; + +import static org.hamcrest.CoreMatchers.anyOf; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import io.fd.honeycomb.translate.util.DataObjects; +import io.fd.honeycomb.translate.write.Writer; +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class FlatWriterRegistryBuilderTest { + + + @Test + public void testRelationsBefore() throws Exception { + final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(); + /* + 1 -> 2 -> 3 + -> 4 + */ + flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject3.class)); + flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject4.class)); + flatWriterRegistryBuilder.addBefore(mockWriter(DataObjects.DataObject2.class), + Lists.newArrayList(DataObjects.DataObject3.IID, DataObjects.DataObject4.IID)); + flatWriterRegistryBuilder.addBefore(mockWriter(DataObjects.DataObject1.class), DataObjects.DataObject2.IID); + final ImmutableMap, Writer> mappedWriters = + flatWriterRegistryBuilder.getMappedHandlers(); + + final ArrayList> typesInList = Lists.newArrayList(mappedWriters.keySet()); + assertEquals(DataObjects.DataObject1.IID, typesInList.get(0)); + assertEquals(DataObjects.DataObject2.IID, typesInList.get(1)); + assertThat(typesInList.get(2), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID))); + assertThat(typesInList.get(3), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID))); + } + + @Test + public void testRelationsAfter() throws Exception { + final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(); + /* + 1 -> 2 -> 3 + -> 4 + */ + flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class)); + flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject2.class), DataObjects.DataObject1.IID); + flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject3.class), DataObjects.DataObject2.IID); + flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject4.class), DataObjects.DataObject2.IID); + final ImmutableMap, Writer> mappedWriters = + flatWriterRegistryBuilder.getMappedHandlers(); + + final List> typesInList = Lists.newArrayList(mappedWriters.keySet()); + assertEquals(DataObjects.DataObject1.IID, typesInList.get(0)); + assertEquals(DataObjects.DataObject2.IID, typesInList.get(1)); + assertThat(typesInList.get(2), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID))); + assertThat(typesInList.get(3), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID))); + } + + @Test(expected = IllegalArgumentException.class) + public void testRelationsLoop() throws Exception { + final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(); + /* + 1 -> 2 -> 1 + */ + flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class)); + flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject2.class), DataObjects.DataObject1.IID); + flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject1.class), DataObjects.DataObject2.IID); + } + + @Test(expected = IllegalArgumentException.class) + public void testAddWriterTwice() throws Exception { + final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(); + flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class)); + flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class)); + } + + @Test + public void testAddSubtreeWriter() throws Exception { + final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(); + flatWriterRegistryBuilder.subtreeAdd( + Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID, + DataObjects.DataObject4.DataObject41.IID), + mockWriter(DataObjects.DataObject4.class)); + final ImmutableMap, Writer> mappedWriters = + flatWriterRegistryBuilder.getMappedHandlers(); + final ArrayList> typesInList = Lists.newArrayList(mappedWriters.keySet()); + + assertEquals(DataObjects.DataObject4.IID, typesInList.get(0)); + assertEquals(1, typesInList.size()); + } + + @Test + public void testCreateSubtreeWriter() throws Exception { + final Writer forWriter = SubtreeWriter.createForWriter(Sets.newHashSet( + DataObjects.DataObject4.DataObject41.IID, + DataObjects.DataObject4.DataObject41.DataObject411.IID, + DataObjects.DataObject4.DataObject42.IID), + mockWriter(DataObjects.DataObject4.class)); + assertThat(forWriter, instanceOf(SubtreeWriter.class)); + assertThat(((SubtreeWriter) forWriter).getHandledChildTypes().size(), is(3)); + assertThat(((SubtreeWriter) forWriter).getHandledChildTypes(), hasItems(DataObjects.DataObject4.DataObject41.IID, + DataObjects.DataObject4.DataObject42.IID, DataObjects.DataObject4.DataObject41.DataObject411.IID)); + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateInvalidSubtreeWriter() throws Exception { + SubtreeWriter.createForWriter(Sets.newHashSet( + InstanceIdentifier.create(DataObjects.DataObject3.class).child(DataObjects.DataObject3.DataObject31.class)), + mockWriter(DataObjects.DataObject4.class)); + } + + @SuppressWarnings("unchecked") + private Writer mockWriter(final Class doClass) + throws NoSuchFieldException, IllegalAccessException { + final Writer mock = mock(Writer.class); + when(mock.getManagedDataObjectType()).thenReturn((InstanceIdentifier) doClass.getDeclaredField("IID").get(null)); + return mock; + } + +} \ No newline at end of file diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryTest.java new file mode 100644 index 000000000..6b75f923e --- /dev/null +++ b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/FlatWriterRegistryTest.java @@ -0,0 +1,265 @@ +package io.fd.honeycomb.translate.util.write.registry; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Multimap; +import io.fd.honeycomb.translate.util.DataObjects; +import io.fd.honeycomb.translate.write.DataObjectUpdate; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.Writer; +import io.fd.honeycomb.translate.util.DataObjects.DataObject1; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import org.hamcrest.CoreMatchers; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class FlatWriterRegistryTest { + + @Mock + private Writer writer1; + @Mock + private Writer writer2; + @Mock + private Writer writer3; + @Mock + private WriteContext ctx; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(writer1.getManagedDataObjectType()).thenReturn(DataObjects.DataObject1.IID); + when(writer2.getManagedDataObjectType()).thenReturn(DataObjects.DataObject2.IID); + when(writer3.getManagedDataObjectType()).thenReturn(DataObjects.DataObject3.IID); + } + + @Test + public void testMultipleUpdatesForSingleWriter() throws Exception { + final FlatWriterRegistry flatWriterRegistry = + new FlatWriterRegistry(ImmutableMap.of(DataObjects.DataObject1.IID, writer1, DataObjects.DataObject2.IID, writer2)); + + final Multimap, DataObjectUpdate> updates = HashMultimap.create(); + final InstanceIdentifier iid = InstanceIdentifier.create(DataObjects.DataObject1.class); + final InstanceIdentifier iid2 = InstanceIdentifier.create(DataObjects.DataObject1.class); + final DataObjects.DataObject1 dataObject = mock(DataObjects.DataObject1.class); + updates.put(DataObjects.DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject)); + updates.put(DataObjects.DataObject1.IID, DataObjectUpdate.create(iid2, dataObject, dataObject)); + flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); + + verify(writer1).update(iid, dataObject, dataObject, ctx); + verify(writer1).update(iid2, dataObject, dataObject, ctx); + // Invoked when registry is being created + verifyNoMoreInteractions(writer1); + verifyZeroInteractions(writer2); + } + + @Test + public void testMultipleUpdatesForMultipleWriters() throws Exception { + final FlatWriterRegistry flatWriterRegistry = + new FlatWriterRegistry(ImmutableMap.of(DataObjects.DataObject1.IID, writer1, DataObjects.DataObject2.IID, writer2)); + + final Multimap, DataObjectUpdate> updates = HashMultimap.create(); + final InstanceIdentifier iid = InstanceIdentifier.create(DataObjects.DataObject1.class); + final DataObjects.DataObject1 dataObject = mock(DataObjects.DataObject1.class); + updates.put(DataObjects.DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject)); + final InstanceIdentifier iid2 = InstanceIdentifier.create(DataObjects.DataObject2.class); + final DataObjects.DataObject2 dataObject2 = mock(DataObjects.DataObject2.class); + updates.put(DataObjects.DataObject2.IID, DataObjectUpdate.create(iid2, dataObject2, dataObject2)); + flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); + + final InOrder inOrder = inOrder(writer1, writer2); + inOrder.verify(writer1).update(iid, dataObject, dataObject, ctx); + inOrder.verify(writer2).update(iid2, dataObject2, dataObject2, ctx); + + verifyNoMoreInteractions(writer1); + verifyNoMoreInteractions(writer2); + } + + @Test + public void testMultipleDeletesForMultipleWriters() throws Exception { + final FlatWriterRegistry flatWriterRegistry = + new FlatWriterRegistry(ImmutableMap.of(DataObjects.DataObject1.IID, writer1, DataObjects.DataObject2.IID, writer2)); + + final Multimap, DataObjectUpdate.DataObjectDelete> deletes = HashMultimap.create(); + final InstanceIdentifier iid = InstanceIdentifier.create(DataObjects.DataObject1.class); + final DataObjects.DataObject1 dataObject = mock(DataObjects.DataObject1.class); + deletes.put(DataObjects.DataObject1.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid, dataObject, null))); + final InstanceIdentifier iid2 = InstanceIdentifier.create(DataObjects.DataObject2.class); + final DataObjects.DataObject2 dataObject2 = mock(DataObjects.DataObject2.class); + deletes.put(DataObjects.DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null))); + flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(ImmutableMultimap.of(), deletes), ctx); + + final InOrder inOrder = inOrder(writer1, writer2); + // Reversed order of invocation, first writer2 and then writer1 + inOrder.verify(writer2).update(iid2, dataObject2, null, ctx); + inOrder.verify(writer1).update(iid, dataObject, null, ctx); + + verifyNoMoreInteractions(writer1); + verifyNoMoreInteractions(writer2); + } + + @Test + public void testMultipleUpdatesAndDeletesForMultipleWriters() throws Exception { + final FlatWriterRegistry flatWriterRegistry = + new FlatWriterRegistry(ImmutableMap.of(DataObjects.DataObject1.IID, writer1, DataObjects.DataObject2.IID, writer2)); + + final Multimap, DataObjectUpdate.DataObjectDelete> deletes = HashMultimap.create(); + final Multimap, DataObjectUpdate> updates = HashMultimap.create(); + final InstanceIdentifier iid = InstanceIdentifier.create(DataObjects.DataObject1.class); + final DataObjects.DataObject1 dataObject = mock(DataObjects.DataObject1.class); + // Writer 1 delete + deletes.put(DataObjects.DataObject1.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid, dataObject, null))); + // Writer 1 update + updates.put(DataObjects.DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject)); + final InstanceIdentifier iid2 = InstanceIdentifier.create(DataObjects.DataObject2.class); + final DataObjects.DataObject2 dataObject2 = mock(DataObjects.DataObject2.class); + // Writer 2 delete + deletes.put(DataObjects.DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null))); + // Writer 2 update + updates.put(DataObjects.DataObject2.IID, DataObjectUpdate.create(iid2, dataObject2, dataObject2)); + flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, deletes), ctx); + + final InOrder inOrder = inOrder(writer1, writer2); + // Reversed order of invocation, first writer2 and then writer1 for deletes + inOrder.verify(writer2).update(iid2, dataObject2, null, ctx); + inOrder.verify(writer1).update(iid, dataObject, null, ctx); + // Then also updates are processed + inOrder.verify(writer1).update(iid, dataObject, dataObject, ctx); + inOrder.verify(writer2).update(iid2, dataObject2, dataObject2, ctx); + + verifyNoMoreInteractions(writer1); + verifyNoMoreInteractions(writer2); + } + + @Test(expected = IllegalArgumentException.class) + public void testMultipleUpdatesOneMissing() throws Exception { + final FlatWriterRegistry flatWriterRegistry = + new FlatWriterRegistry(ImmutableMap.of(DataObjects.DataObject1.IID, writer1)); + + final Multimap, DataObjectUpdate> updates = HashMultimap.create(); + addUpdate(updates, DataObjects.DataObject1.class); + addUpdate(updates, DataObjects.DataObject2.class); + flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); + } + + @Test + public void testMultipleUpdatesOneFailing() throws Exception { + final FlatWriterRegistry flatWriterRegistry = + new FlatWriterRegistry(ImmutableMap.of(DataObjects.DataObject1.IID, writer1, DataObjects.DataObject2.IID, writer2)); + + // Writer1 always fails + doThrow(new RuntimeException()).when(writer1) + .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); + + final Multimap, DataObjectUpdate> updates = HashMultimap.create(); + addUpdate(updates, DataObjects.DataObject1.class); + addUpdate(updates, DataObjects.DataObject2.class); + + try { + flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); + fail("Bulk update should have failed on writer1"); + } catch (WriterRegistry.BulkUpdateException e) { + assertThat(e.getFailedIds().size(), is(2)); + assertThat(e.getFailedIds(), CoreMatchers.hasItem(InstanceIdentifier.create(DataObjects.DataObject2.class))); + assertThat(e.getFailedIds(), CoreMatchers.hasItem(InstanceIdentifier.create(DataObjects.DataObject1.class))); + } + } + + @Test + public void testMultipleUpdatesOneFailingThenRevertWithSuccess() throws Exception { + final FlatWriterRegistry flatWriterRegistry = + new FlatWriterRegistry( + ImmutableMap.of(DataObjects.DataObject1.IID, writer1, DataObjects.DataObject2.IID, writer2, DataObjects.DataObject3.IID, writer3)); + + // Writer1 always fails + doThrow(new RuntimeException()).when(writer3) + .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); + + final Multimap, DataObjectUpdate> updates = HashMultimap.create(); + addUpdate(updates, DataObjects.DataObject1.class); + addUpdate(updates, DataObjects.DataObject3.class); + final InstanceIdentifier iid2 = InstanceIdentifier.create(DataObjects.DataObject2.class); + final DataObjects.DataObject2 before2 = mock(DataObjects.DataObject2.class); + final DataObjects.DataObject2 after2 = mock(DataObjects.DataObject2.class); + updates.put(DataObjects.DataObject2.IID, DataObjectUpdate.create(iid2, before2, after2)); + + try { + flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); + fail("Bulk update should have failed on writer1"); + } catch (WriterRegistry.BulkUpdateException e) { + assertThat(e.getFailedIds().size(), is(1)); + + final InOrder inOrder = inOrder(writer1, writer2, writer3); + inOrder.verify(writer1) + .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); + inOrder.verify(writer2) + .update(iid2, before2, after2, ctx); + inOrder.verify(writer3) + .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); + + e.revertChanges(); + // Revert changes. Successful updates are iterated in reverse + inOrder.verify(writer2) + .update(iid2, after2, before2, ctx); + inOrder.verify(writer1) + .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); + verifyNoMoreInteractions(writer3); + } + } + + @Test + public void testMultipleUpdatesOneFailingThenRevertWithFail() throws Exception { + final FlatWriterRegistry flatWriterRegistry = + new FlatWriterRegistry( + ImmutableMap.of(DataObjects.DataObject1.IID, writer1, DataObjects.DataObject2.IID, writer2, DataObjects.DataObject3.IID, writer3)); + + // Writer1 always fails + doThrow(new RuntimeException()).when(writer3) + .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); + + final Multimap, DataObjectUpdate> updates = HashMultimap.create(); + addUpdate(updates, DataObjects.DataObject1.class); + addUpdate(updates, DataObjects.DataObject2.class); + addUpdate(updates, DataObjects.DataObject3.class); + + try { + flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); + fail("Bulk update should have failed on writer1"); + } catch (WriterRegistry.BulkUpdateException e) { + // Writer1 always fails from now + doThrow(new RuntimeException()).when(writer1) + .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); + try { + e.revertChanges(); + } catch (WriterRegistry.Reverter.RevertFailedException e1) { + assertThat(e1.getNotRevertedChanges().size(), is(1)); + assertThat(e1.getNotRevertedChanges(), CoreMatchers + .hasItem(InstanceIdentifier.create(DataObjects.DataObject1.class))); + } + } + } + + private void addUpdate(final Multimap, DataObjectUpdate> updates, + final Class type) throws Exception { + final InstanceIdentifier iid = (InstanceIdentifier) type.getDeclaredField("IID").get(null); + updates.put(iid, DataObjectUpdate.create(iid, mock(type), mock(type))); + } +} \ No newline at end of file diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/SubtreeWriterTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/SubtreeWriterTest.java new file mode 100644 index 000000000..313dd34a8 --- /dev/null +++ b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/write/registry/SubtreeWriterTest.java @@ -0,0 +1,84 @@ +/* + * 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.translate.util.write.registry; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; + +import com.google.common.collect.Sets; +import io.fd.honeycomb.translate.util.DataObjects; +import io.fd.honeycomb.translate.write.Writer; +import java.util.Collections; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class SubtreeWriterTest { + + @Mock + Writer writer; + @Mock + Writer writer11; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(writer.getManagedDataObjectType()).thenReturn(DataObjects.DataObject4.IID); + when(writer11.getManagedDataObjectType()).thenReturn(DataObjects.DataObject4.DataObject41.IID); + } + + @Test(expected = IllegalArgumentException.class) + public void testSubtreeWriterCreationFail() throws Exception { + // The subtree node identified by IID.c(DataObject.class) is not a child of writer.getManagedDataObjectType + SubtreeWriter.createForWriter(Collections.singleton(InstanceIdentifier.create(DataObject.class)), writer); + } + + @Test(expected = IllegalArgumentException.class) + public void testSubtreeWriterCreationFailInvalidIid() throws Exception { + // The subtree node identified by IID.c(DataObject.class) is not a child of writer.getManagedDataObjectType + SubtreeWriter.createForWriter(Collections.singleton(DataObjects.DataObject4.IID), writer); + } + + @Test + public void testSubtreeWriterCreation() throws Exception { + final SubtreeWriter forWriter = (SubtreeWriter) SubtreeWriter.createForWriter(Sets.newHashSet( + DataObjects.DataObject4.DataObject41.IID, + DataObjects.DataObject4.DataObject41.DataObject411.IID, + DataObjects.DataObject4.DataObject42.IID), + writer); + + assertEquals(writer.getManagedDataObjectType(), forWriter.getManagedDataObjectType()); + assertEquals(3, forWriter.getHandledChildTypes().size()); + } + + @Test + public void testSubtreeWriterHandledTypes() throws Exception { + final SubtreeWriter forWriter = (SubtreeWriter) SubtreeWriter.createForWriter(Sets.newHashSet( + DataObjects.DataObject4.DataObject41.DataObject411.IID), + writer); + + assertEquals(writer.getManagedDataObjectType(), forWriter.getManagedDataObjectType()); + assertEquals(1, forWriter.getHandledChildTypes().size()); + assertThat(forWriter.getHandledChildTypes(), hasItem(DataObjects.DataObject4.DataObject41.DataObject411.IID)); + } + +} \ No newline at end of file diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/util/TransactionWriteContextTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/util/TransactionWriteContextTest.java deleted file mode 100644 index 7c93e992a..000000000 --- a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/util/TransactionWriteContextTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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.impl.write.util; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import com.google.common.util.concurrent.Futures; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.util.DataObjects; -import io.fd.honeycomb.v3po.translate.util.write.TransactionWriteContext; -import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -public class TransactionWriteContextTest { - - @Mock - private BindingNormalizedNodeSerializer serializer; - @Mock - private DOMDataReadOnlyTransaction beforeTx; - @Mock - private DOMDataReadOnlyTransaction afterTx; - @Mock - private Map.Entry entry; - @Mock - private MappingContext contextBroker; - - private TransactionWriteContext transactionWriteContext; - - @Before - public void setUp() { - initMocks(this); - transactionWriteContext = new TransactionWriteContext(serializer, beforeTx, afterTx, contextBroker); - } - - @Test - public void testReadBeforeNoData() throws Exception { - when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( - Futures.immediateCheckedFuture(Optional.absent())); - - final InstanceIdentifier instanceId = - InstanceIdentifier.create(DataObjects.DataObject1.class); - - final Optional dataObjects = transactionWriteContext.readBefore(instanceId); - assertNotNull(dataObjects); - assertFalse(dataObjects.isPresent()); - - verify(serializer).toYangInstanceIdentifier(instanceId); - verify(serializer, never()).fromNormalizedNode(any(YangInstanceIdentifier.class), any(NormalizedNode.class)); - } - - @Test - public void testReadBefore() throws Exception { - when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( - Futures.immediateCheckedFuture(Optional.of(mock(NormalizedNode.class)))); - - final InstanceIdentifier instanceId = - InstanceIdentifier.create(DataObjects.DataObject1.class); - final YangInstanceIdentifier yangId = YangInstanceIdentifier.builder().node(QName.create("n", "d")).build(); - when(serializer.toYangInstanceIdentifier(any(InstanceIdentifier.class))).thenReturn(yangId); - when(serializer.fromNormalizedNode(eq(yangId), any(NormalizedNode.class))).thenReturn(entry); - when(entry.getValue()).thenReturn(mock(DataObjects.DataObject1.class)); - - final Optional dataObjects = transactionWriteContext.readBefore(instanceId); - assertNotNull(dataObjects); - assertTrue(dataObjects.isPresent()); - - verify(serializer).toYangInstanceIdentifier(instanceId); - verify(serializer).fromNormalizedNode(eq(yangId), any(NormalizedNode.class)); - } - - @Test(expected = IllegalStateException.class) - public void testReadBeforeFailed() throws Exception { - when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( - Futures.immediateFailedCheckedFuture(mock(ReadFailedException.class))); - transactionWriteContext.readBefore(mock(InstanceIdentifier.class)); - } - - @Test(expected = IllegalStateException.class) - public void testReadAfterFailed() throws Exception { - when(afterTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn( - Futures.immediateFailedCheckedFuture(mock(ReadFailedException.class))); - transactionWriteContext.readAfter(mock(InstanceIdentifier.class)); - } - - @Test - public void testGetContext() throws Exception { - assertNotNull(transactionWriteContext.getModificationCache()); - } - - @Test - public void testClose() throws Exception { - final ModificationCache context = transactionWriteContext.getModificationCache(); - transactionWriteContext.close(); - // TODO verify context was closed - } -} \ No newline at end of file diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/DataObjects.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/DataObjects.java deleted file mode 100644 index d823465bd..000000000 --- a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/DataObjects.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 org.opendaylight.yangtools.yang.binding.ChildOf; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class DataObjects { - public interface DataObject1 extends DataObject { - InstanceIdentifier IID = InstanceIdentifier.create(DataObject1.class); - } - - public interface DataObject2 extends DataObject { - InstanceIdentifier IID = InstanceIdentifier.create(DataObject2.class); - } - - public interface DataObject3 extends DataObject { - InstanceIdentifier IID = InstanceIdentifier.create(DataObject3.class); - interface DataObject31 extends DataObject, ChildOf { - InstanceIdentifier IID = DataObject3.IID.child(DataObject31.class); - } - } - - public interface DataObject4 extends DataObject { - InstanceIdentifier IID = InstanceIdentifier.create(DataObject4.class); - interface DataObject41 extends DataObject, ChildOf { - InstanceIdentifier IID = DataObject4.IID.child(DataObject41.class); - interface DataObject411 extends DataObject, ChildOf { - InstanceIdentifier IID = DataObject41.IID.child(DataObject411.class); - } - } - - interface DataObject42 extends DataObject, ChildOf { - InstanceIdentifier IID = DataObject4.IID.child(DataObject42.class); - } - } -} diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/JsonUtilsTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/JsonUtilsTest.java deleted file mode 100644 index bd48cb446..000000000 --- a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/JsonUtilsTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java deleted file mode 100644 index e57dcee43..000000000 --- a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.read.registry; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.when; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry; -import io.fd.honeycomb.v3po.translate.util.DataObjects; -import java.util.List; -import java.util.Map; -import org.junit.Test; -import org.mockito.Mockito; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class CompositeReaderRegistryBuilderTest { - - private Reader> reader1 = - mock(DataObjects.DataObject1.class); - private Reader> reader2 = - mock(DataObjects.DataObject2.class); - private Reader> reader3 = - mock(DataObjects.DataObject3.class); - private Reader> reader31 = - mock(DataObjects.DataObject3.DataObject31.class); - - private Reader> reader4 = - mock(DataObjects.DataObject4.class); - private Reader> reader41 = - mock(DataObjects.DataObject4.DataObject41.class); - private Reader> reader411 = - mock(DataObjects.DataObject4.DataObject41.DataObject411.class); - private Reader> reader42 = - mock(DataObjects.DataObject4.DataObject42.class); - - @SuppressWarnings("unchecked") - private Reader> mock(final Class dataObjectType) { - final Reader> mock = Mockito.mock(Reader.class); - try { - when(mock.getManagedDataObjectType()) - .thenReturn(((InstanceIdentifier) dataObjectType.getDeclaredField("IID").get(null))); - } catch (IllegalAccessException | NoSuchFieldException e) { - throw new RuntimeException(e); - } - return mock; - } - - @Test - public void testCompositeStructure() throws Exception { - final CompositeReaderRegistryBuilder compositeReaderRegistryBuilder = new CompositeReaderRegistryBuilder(); - /* - Composite reader structure ordered left from right - - 1, 2, 3, 4 - 31 42, 41 - 411 - */ - compositeReaderRegistryBuilder.add(reader1); - compositeReaderRegistryBuilder.addAfter(reader2, reader1.getManagedDataObjectType()); - compositeReaderRegistryBuilder.addAfter(reader3, reader2.getManagedDataObjectType()); - compositeReaderRegistryBuilder.addAfter(reader31, reader1.getManagedDataObjectType()); - compositeReaderRegistryBuilder.addAfter(reader4, reader3.getManagedDataObjectType()); - compositeReaderRegistryBuilder.add(reader41); - compositeReaderRegistryBuilder.addBefore(reader42, reader41.getManagedDataObjectType()); - compositeReaderRegistryBuilder.add(reader411); - - final ReaderRegistry build = compositeReaderRegistryBuilder.build(); - - final Map, Reader>> rootReaders = - ((CompositeReaderRegistry) build).getRootReaders(); - final List> rootReaderOrder = Lists.newArrayList(rootReaders.keySet()); - - assertEquals(reader1.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(0)); - assertEquals(reader2.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(1)); - assertEquals(reader3.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(2)); - assertEquals(reader4.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(3)); - - assertFalse(rootReaders.get(DataObjects.DataObject1.class) instanceof CompositeReader); - assertFalse(rootReaders.get(DataObjects.DataObject2.class) instanceof CompositeReader); - assertTrue(rootReaders.get(DataObjects.DataObject3.class) instanceof CompositeReader); - assertTrue(rootReaders.get(DataObjects.DataObject4.class) instanceof CompositeReader); - - final ImmutableMap, Reader>> childReaders = - ((CompositeReader>) rootReaders - .get(DataObjects.DataObject4.class)).getChildReaders(); - final List> orderedChildReaders = Lists.newArrayList(childReaders.keySet()); - - assertEquals(reader42.getManagedDataObjectType().getTargetType(), orderedChildReaders.get(0)); - assertEquals(reader41.getManagedDataObjectType().getTargetType(), orderedChildReaders.get(1)); - assertTrue(childReaders.get(DataObjects.DataObject4.DataObject41.class) instanceof CompositeReader); - assertFalse(childReaders.get(DataObjects.DataObject4.DataObject42.class) instanceof CompositeReader); - } -} \ No newline at end of file diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReaderTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReaderTest.java deleted file mode 100644 index 324d71daa..000000000 --- a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReaderTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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.read.registry; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import com.google.common.base.Optional; -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.util.DataObjects; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class SubtreeReaderTest { - - @Mock - private Reader> delegate; - @Mock - private Reader> delegateLocal; - @Mock - private ReadContext ctx; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - doReturn(DataObjects.DataObject4.IID).when(delegate).getManagedDataObjectType(); - doReturn(DataObject1.IID).when(delegateLocal).getManagedDataObjectType(); - } - - @Test - public void testCreate() throws Exception { - final Reader> subtreeR = - SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID), delegate); - - subtreeR.getBuilder(DataObjects.DataObject4.IID); - verify(delegate).getBuilder(DataObjects.DataObject4.IID); - - subtreeR.getManagedDataObjectType(); - verify(delegate, atLeastOnce()).getManagedDataObjectType(); - } - - @Test(expected = IllegalArgumentException.class) - public void testCreateInvalid() throws Exception { - SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject1.IID), delegate); - } - - @Test(expected = IllegalStateException.class) - public void testReadOnlySubtreeCannotFilter() throws Exception { - final Reader> subtreeR = - SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID), delegate); - - doReturn(Optional.fromNullable(mock(DataObjects.DataObject4.class))).when(delegate).read(DataObjects.DataObject4.IID, ctx); - subtreeR.read(DataObjects.DataObject4.DataObject41.IID, ctx); - } - - @Test - public void testReadOnlySubtreeNotPresent() throws Exception { - final Reader> subtreeR = - SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID), delegate); - - doReturn(Optional.absent()).when(delegate).read(DataObjects.DataObject4.IID, ctx); - assertFalse(subtreeR.read(DataObjects.DataObject4.DataObject41.IID, ctx).isPresent()); - } - - @Test - public void testReadOnlySubtreeChild() throws Exception { - final Reader> subtreeR = - SubtreeReader.createForReader(Sets.newHashSet(DataObject1.DataObject11.IID), delegateLocal); - - final DataObject1 mock = mock(DataObject1.class); - final DataObject1.DataObject11 mock11 = mock(DataObject1.DataObject11.class); - doReturn(mock11).when(mock).getDataObject11(); - doReturn(Optional.fromNullable(mock)).when(delegateLocal).read(DataObject1.IID, ctx); - assertEquals(mock11, subtreeR.read(DataObject1.DataObject11.IID, ctx).get()); - } - - @Test - public void testReadEntireSubtree() throws Exception { - final Reader> subtreeR = - SubtreeReader.createForReader(Sets.newHashSet(DataObject1.DataObject11.IID), delegateLocal); - - final DataObject1 mock = mock(DataObject1.class); - final DataObject1.DataObject11 mock11 = mock(DataObject1.DataObject11.class); - doReturn(mock11).when(mock).getDataObject11(); - doReturn(Optional.fromNullable(mock)).when(delegateLocal).read(DataObject1.IID, ctx); - assertEquals(mock, subtreeR.read(DataObject1.IID, ctx).get()); - } - - public abstract static class DataObject1 implements DataObject { - public static InstanceIdentifier IID = InstanceIdentifier.create(DataObject1.class); - - public abstract DataObject11 getDataObject11(); - - public abstract static class DataObject11 implements DataObject, ChildOf { - public static InstanceIdentifier IID = DataObject1.IID.child(DataObject11.class); - } - } -} diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/TypeHierarchyTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/TypeHierarchyTest.java deleted file mode 100644 index 7a664eef1..000000000 --- a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/TypeHierarchyTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.read.registry; - -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.hasItems; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject1; -import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject3; -import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject4; -import org.junit.Test; - -public class TypeHierarchyTest { - - @Test - public void testHierarchy() throws Exception { - final TypeHierarchy typeHierarchy = TypeHierarchy.create(Sets.newHashSet( - DataObject4.DataObject41.DataObject411.IID, - DataObject4.DataObject41.IID,/* Included in previous already */ - DataObject1.IID, - DataObject3.DataObject31.IID)); - - // Roots - assertThat(typeHierarchy.getRoots().size(), is(3)); - assertThat(typeHierarchy.getRoots(), hasItems(DataObject1.IID, DataObject3.IID, DataObject4.IID)); - - // Leaves - assertThat(typeHierarchy.getDirectChildren(DataObject1.IID).size(), is(0)); - assertThat(typeHierarchy.getDirectChildren(DataObject3.DataObject31.IID).size(), is(0)); - assertThat(typeHierarchy.getDirectChildren(DataObject4.DataObject41.DataObject411.IID).size(), is(0)); - - // Intermediate leaves - assertThat(typeHierarchy.getDirectChildren(DataObject3.IID).size(), is(1)); - assertThat(typeHierarchy.getDirectChildren(DataObject3.IID), hasItem(DataObject3.DataObject31.IID)); - assertEquals(typeHierarchy.getDirectChildren(DataObject3.IID), typeHierarchy.getAllChildren(DataObject3.IID)); - - assertThat(typeHierarchy.getDirectChildren(DataObject4.DataObject41.IID).size(), is(1)); - assertThat(typeHierarchy.getDirectChildren(DataObject4.DataObject41.IID), hasItem( - DataObject4.DataObject41.DataObject411.IID)); - assertEquals(typeHierarchy.getDirectChildren(DataObject4.DataObject41.IID), typeHierarchy.getAllChildren( - DataObject4.DataObject41.IID)); - - assertThat(typeHierarchy.getDirectChildren(DataObject4.IID).size(), is(1)); - assertThat(typeHierarchy.getDirectChildren(DataObject4.IID), hasItem(DataObject4.DataObject41.IID)); - assertThat(typeHierarchy.getAllChildren(DataObject4.IID).size(), is(2)); - assertTrue(typeHierarchy.getAllChildren(DataObject4.IID).contains(DataObject4.DataObject41.IID)); - assertTrue(typeHierarchy.getAllChildren(DataObject4.IID).contains(DataObject4.DataObject41.DataObject411.IID)); - } -} - diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryBuilderTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryBuilderTest.java deleted file mode 100644 index 743d84cbf..000000000 --- a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryBuilderTest.java +++ /dev/null @@ -1,131 +0,0 @@ -package io.fd.honeycomb.v3po.translate.util.write.registry; - -import static org.hamcrest.CoreMatchers.anyOf; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.hasItems; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.util.DataObjects; -import io.fd.honeycomb.v3po.translate.write.Writer; -import java.util.ArrayList; -import java.util.List; -import org.junit.Test; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class FlatWriterRegistryBuilderTest { - - - @Test - public void testRelationsBefore() throws Exception { - final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(); - /* - 1 -> 2 -> 3 - -> 4 - */ - flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject3.class)); - flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject4.class)); - flatWriterRegistryBuilder.addBefore(mockWriter(DataObjects.DataObject2.class), - Lists.newArrayList(DataObjects.DataObject3.IID, DataObjects.DataObject4.IID)); - flatWriterRegistryBuilder.addBefore(mockWriter(DataObjects.DataObject1.class), DataObjects.DataObject2.IID); - final ImmutableMap, Writer> mappedWriters = - flatWriterRegistryBuilder.getMappedHandlers(); - - final ArrayList> typesInList = Lists.newArrayList(mappedWriters.keySet()); - assertEquals(DataObjects.DataObject1.IID, typesInList.get(0)); - assertEquals(DataObjects.DataObject2.IID, typesInList.get(1)); - assertThat(typesInList.get(2), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID))); - assertThat(typesInList.get(3), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID))); - } - - @Test - public void testRelationsAfter() throws Exception { - final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(); - /* - 1 -> 2 -> 3 - -> 4 - */ - flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class)); - flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject2.class), DataObjects.DataObject1.IID); - flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject3.class), DataObjects.DataObject2.IID); - flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject4.class), DataObjects.DataObject2.IID); - final ImmutableMap, Writer> mappedWriters = - flatWriterRegistryBuilder.getMappedHandlers(); - - final List> typesInList = Lists.newArrayList(mappedWriters.keySet()); - assertEquals(DataObjects.DataObject1.IID, typesInList.get(0)); - assertEquals(DataObjects.DataObject2.IID, typesInList.get(1)); - assertThat(typesInList.get(2), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID))); - assertThat(typesInList.get(3), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID))); - } - - @Test(expected = IllegalArgumentException.class) - public void testRelationsLoop() throws Exception { - final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(); - /* - 1 -> 2 -> 1 - */ - flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class)); - flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject2.class), DataObjects.DataObject1.IID); - flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject1.class), DataObjects.DataObject2.IID); - } - - @Test(expected = IllegalArgumentException.class) - public void testAddWriterTwice() throws Exception { - final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(); - flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class)); - flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class)); - } - - @Test - public void testAddSubtreeWriter() throws Exception { - final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(); - flatWriterRegistryBuilder.subtreeAdd( - Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID, - DataObjects.DataObject4.DataObject41.IID), - mockWriter(DataObjects.DataObject4.class)); - final ImmutableMap, Writer> mappedWriters = - flatWriterRegistryBuilder.getMappedHandlers(); - final ArrayList> typesInList = Lists.newArrayList(mappedWriters.keySet()); - - assertEquals(DataObjects.DataObject4.IID, typesInList.get(0)); - assertEquals(1, typesInList.size()); - } - - @Test - public void testCreateSubtreeWriter() throws Exception { - final Writer forWriter = SubtreeWriter.createForWriter(Sets.newHashSet( - DataObjects.DataObject4.DataObject41.IID, - DataObjects.DataObject4.DataObject41.DataObject411.IID, - DataObjects.DataObject4.DataObject42.IID), - mockWriter(DataObjects.DataObject4.class)); - assertThat(forWriter, instanceOf(SubtreeWriter.class)); - assertThat(((SubtreeWriter) forWriter).getHandledChildTypes().size(), is(3)); - assertThat(((SubtreeWriter) forWriter).getHandledChildTypes(), hasItems(DataObjects.DataObject4.DataObject41.IID, - DataObjects.DataObject4.DataObject42.IID, DataObjects.DataObject4.DataObject41.DataObject411.IID)); - } - - @Test(expected = IllegalArgumentException.class) - public void testCreateInvalidSubtreeWriter() throws Exception { - SubtreeWriter.createForWriter(Sets.newHashSet( - InstanceIdentifier.create(DataObjects.DataObject3.class).child(DataObjects.DataObject3.DataObject31.class)), - mockWriter(DataObjects.DataObject4.class)); - } - - @SuppressWarnings("unchecked") - private Writer mockWriter(final Class doClass) - throws NoSuchFieldException, IllegalAccessException { - final Writer mock = mock(Writer.class); - when(mock.getManagedDataObjectType()).thenReturn((InstanceIdentifier) doClass.getDeclaredField("IID").get(null)); - return mock; - } - -} \ No newline at end of file diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryTest.java deleted file mode 100644 index a72cb4fa7..000000000 --- a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryTest.java +++ /dev/null @@ -1,264 +0,0 @@ -package io.fd.honeycomb.v3po.translate.util.write.registry; - -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimap; -import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject1; -import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject2; -import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject3; -import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.Writer; -import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class FlatWriterRegistryTest { - - @Mock - private Writer writer1; - @Mock - private Writer writer2; - @Mock - private Writer writer3; - @Mock - private WriteContext ctx; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - when(writer1.getManagedDataObjectType()).thenReturn(DataObject1.IID); - when(writer2.getManagedDataObjectType()).thenReturn(DataObject2.IID); - when(writer3.getManagedDataObjectType()).thenReturn(DataObject3.IID); - } - - @Test - public void testMultipleUpdatesForSingleWriter() throws Exception { - final FlatWriterRegistry flatWriterRegistry = - new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2)); - - final Multimap, DataObjectUpdate> updates = HashMultimap.create(); - final InstanceIdentifier iid = InstanceIdentifier.create(DataObject1.class); - final InstanceIdentifier iid2 = InstanceIdentifier.create(DataObject1.class); - final DataObject1 dataObject = mock(DataObject1.class); - updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject)); - updates.put(DataObject1.IID, DataObjectUpdate.create(iid2, dataObject, dataObject)); - flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); - - verify(writer1).update(iid, dataObject, dataObject, ctx); - verify(writer1).update(iid2, dataObject, dataObject, ctx); - // Invoked when registry is being created - verifyNoMoreInteractions(writer1); - verifyZeroInteractions(writer2); - } - - @Test - public void testMultipleUpdatesForMultipleWriters() throws Exception { - final FlatWriterRegistry flatWriterRegistry = - new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2)); - - final Multimap, DataObjectUpdate> updates = HashMultimap.create(); - final InstanceIdentifier iid = InstanceIdentifier.create(DataObject1.class); - final DataObject1 dataObject = mock(DataObject1.class); - updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject)); - final InstanceIdentifier iid2 = InstanceIdentifier.create(DataObject2.class); - final DataObject2 dataObject2 = mock(DataObject2.class); - updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, dataObject2, dataObject2)); - flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); - - final InOrder inOrder = inOrder(writer1, writer2); - inOrder.verify(writer1).update(iid, dataObject, dataObject, ctx); - inOrder.verify(writer2).update(iid2, dataObject2, dataObject2, ctx); - - verifyNoMoreInteractions(writer1); - verifyNoMoreInteractions(writer2); - } - - @Test - public void testMultipleDeletesForMultipleWriters() throws Exception { - final FlatWriterRegistry flatWriterRegistry = - new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2)); - - final Multimap, DataObjectUpdate.DataObjectDelete> deletes = HashMultimap.create(); - final InstanceIdentifier iid = InstanceIdentifier.create(DataObject1.class); - final DataObject1 dataObject = mock(DataObject1.class); - deletes.put(DataObject1.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid, dataObject, null))); - final InstanceIdentifier iid2 = InstanceIdentifier.create(DataObject2.class); - final DataObject2 dataObject2 = mock(DataObject2.class); - deletes.put(DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null))); - flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(ImmutableMultimap.of(), deletes), ctx); - - final InOrder inOrder = inOrder(writer1, writer2); - // Reversed order of invocation, first writer2 and then writer1 - inOrder.verify(writer2).update(iid2, dataObject2, null, ctx); - inOrder.verify(writer1).update(iid, dataObject, null, ctx); - - verifyNoMoreInteractions(writer1); - verifyNoMoreInteractions(writer2); - } - - @Test - public void testMultipleUpdatesAndDeletesForMultipleWriters() throws Exception { - final FlatWriterRegistry flatWriterRegistry = - new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2)); - - final Multimap, DataObjectUpdate.DataObjectDelete> deletes = HashMultimap.create(); - final Multimap, DataObjectUpdate> updates = HashMultimap.create(); - final InstanceIdentifier iid = InstanceIdentifier.create(DataObject1.class); - final DataObject1 dataObject = mock(DataObject1.class); - // Writer 1 delete - deletes.put(DataObject1.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid, dataObject, null))); - // Writer 1 update - updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject)); - final InstanceIdentifier iid2 = InstanceIdentifier.create(DataObject2.class); - final DataObject2 dataObject2 = mock(DataObject2.class); - // Writer 2 delete - deletes.put(DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null))); - // Writer 2 update - updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, dataObject2, dataObject2)); - flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, deletes), ctx); - - final InOrder inOrder = inOrder(writer1, writer2); - // Reversed order of invocation, first writer2 and then writer1 for deletes - inOrder.verify(writer2).update(iid2, dataObject2, null, ctx); - inOrder.verify(writer1).update(iid, dataObject, null, ctx); - // Then also updates are processed - inOrder.verify(writer1).update(iid, dataObject, dataObject, ctx); - inOrder.verify(writer2).update(iid2, dataObject2, dataObject2, ctx); - - verifyNoMoreInteractions(writer1); - verifyNoMoreInteractions(writer2); - } - - @Test(expected = IllegalArgumentException.class) - public void testMultipleUpdatesOneMissing() throws Exception { - final FlatWriterRegistry flatWriterRegistry = - new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1)); - - final Multimap, DataObjectUpdate> updates = HashMultimap.create(); - addUpdate(updates, DataObject1.class); - addUpdate(updates, DataObject2.class); - flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); - } - - @Test - public void testMultipleUpdatesOneFailing() throws Exception { - final FlatWriterRegistry flatWriterRegistry = - new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2)); - - // Writer1 always fails - doThrow(new RuntimeException()).when(writer1) - .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); - - final Multimap, DataObjectUpdate> updates = HashMultimap.create(); - addUpdate(updates, DataObject1.class); - addUpdate(updates, DataObject2.class); - - try { - flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); - fail("Bulk update should have failed on writer1"); - } catch (WriterRegistry.BulkUpdateException e) { - assertThat(e.getFailedIds().size(), is(2)); - assertThat(e.getFailedIds(), hasItem(InstanceIdentifier.create(DataObject2.class))); - assertThat(e.getFailedIds(), hasItem(InstanceIdentifier.create(DataObject1.class))); - } - } - - @Test - public void testMultipleUpdatesOneFailingThenRevertWithSuccess() throws Exception { - final FlatWriterRegistry flatWriterRegistry = - new FlatWriterRegistry( - ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2, DataObject3.IID, writer3)); - - // Writer1 always fails - doThrow(new RuntimeException()).when(writer3) - .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); - - final Multimap, DataObjectUpdate> updates = HashMultimap.create(); - addUpdate(updates, DataObject1.class); - addUpdate(updates, DataObject3.class); - final InstanceIdentifier iid2 = InstanceIdentifier.create(DataObject2.class); - final DataObject2 before2 = mock(DataObject2.class); - final DataObject2 after2 = mock(DataObject2.class); - updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, before2, after2)); - - try { - flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); - fail("Bulk update should have failed on writer1"); - } catch (WriterRegistry.BulkUpdateException e) { - assertThat(e.getFailedIds().size(), is(1)); - - final InOrder inOrder = inOrder(writer1, writer2, writer3); - inOrder.verify(writer1) - .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); - inOrder.verify(writer2) - .update(iid2, before2, after2, ctx); - inOrder.verify(writer3) - .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); - - e.revertChanges(); - // Revert changes. Successful updates are iterated in reverse - inOrder.verify(writer2) - .update(iid2, after2, before2, ctx); - inOrder.verify(writer1) - .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); - verifyNoMoreInteractions(writer3); - } - } - - @Test - public void testMultipleUpdatesOneFailingThenRevertWithFail() throws Exception { - final FlatWriterRegistry flatWriterRegistry = - new FlatWriterRegistry( - ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2, DataObject3.IID, writer3)); - - // Writer1 always fails - doThrow(new RuntimeException()).when(writer3) - .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); - - final Multimap, DataObjectUpdate> updates = HashMultimap.create(); - addUpdate(updates, DataObject1.class); - addUpdate(updates, DataObject2.class); - addUpdate(updates, DataObject3.class); - - try { - flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx); - fail("Bulk update should have failed on writer1"); - } catch (WriterRegistry.BulkUpdateException e) { - // Writer1 always fails from now - doThrow(new RuntimeException()).when(writer1) - .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class)); - try { - e.revertChanges(); - } catch (WriterRegistry.Reverter.RevertFailedException e1) { - assertThat(e1.getNotRevertedChanges().size(), is(1)); - assertThat(e1.getNotRevertedChanges(), hasItem(InstanceIdentifier.create(DataObject1.class))); - } - } - } - - private void addUpdate(final Multimap, DataObjectUpdate> updates, - final Class type) throws Exception { - final InstanceIdentifier iid = (InstanceIdentifier) type.getDeclaredField("IID").get(null); - updates.put(iid, DataObjectUpdate.create(iid, mock(type), mock(type))); - } -} \ No newline at end of file diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/SubtreeWriterTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/SubtreeWriterTest.java deleted file mode 100644 index 627c69c92..000000000 --- a/infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/SubtreeWriterTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.write.registry; - -import static org.hamcrest.CoreMatchers.hasItem; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.when; - -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.util.DataObjects; -import io.fd.honeycomb.v3po.translate.write.Writer; -import java.util.Collections; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class SubtreeWriterTest { - - @Mock - Writer writer; - @Mock - Writer writer11; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - when(writer.getManagedDataObjectType()).thenReturn(DataObjects.DataObject4.IID); - when(writer11.getManagedDataObjectType()).thenReturn(DataObjects.DataObject4.DataObject41.IID); - } - - @Test(expected = IllegalArgumentException.class) - public void testSubtreeWriterCreationFail() throws Exception { - // The subtree node identified by IID.c(DataObject.class) is not a child of writer.getManagedDataObjectType - SubtreeWriter.createForWriter(Collections.singleton(InstanceIdentifier.create(DataObject.class)), writer); - } - - @Test(expected = IllegalArgumentException.class) - public void testSubtreeWriterCreationFailInvalidIid() throws Exception { - // The subtree node identified by IID.c(DataObject.class) is not a child of writer.getManagedDataObjectType - SubtreeWriter.createForWriter(Collections.singleton(DataObjects.DataObject4.IID), writer); - } - - @Test - public void testSubtreeWriterCreation() throws Exception { - final SubtreeWriter forWriter = (SubtreeWriter) SubtreeWriter.createForWriter(Sets.newHashSet( - DataObjects.DataObject4.DataObject41.IID, - DataObjects.DataObject4.DataObject41.DataObject411.IID, - DataObjects.DataObject4.DataObject42.IID), - writer); - - assertEquals(writer.getManagedDataObjectType(), forWriter.getManagedDataObjectType()); - assertEquals(3, forWriter.getHandledChildTypes().size()); - } - - @Test - public void testSubtreeWriterHandledTypes() throws Exception { - final SubtreeWriter forWriter = (SubtreeWriter) SubtreeWriter.createForWriter(Sets.newHashSet( - DataObjects.DataObject4.DataObject41.DataObject411.IID), - writer); - - assertEquals(writer.getManagedDataObjectType(), forWriter.getManagedDataObjectType()); - assertEquals(1, forWriter.getHandledChildTypes().size()); - assertThat(forWriter.getHandledChildTypes(), hasItem(DataObjects.DataObject4.DataObject41.DataObject411.IID)); - } - -} \ No newline at end of file diff --git a/v3po/postman_rest_collection.json b/v3po/postman_rest_collection.json new file mode 100644 index 000000000..3adf19582 --- /dev/null +++ b/v3po/postman_rest_collection.json @@ -0,0 +1,1386 @@ +{ + "id": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "name": "Honeycomb RESTCONF calls", + "description": "Common mgmt operations on VPP using Honeycomb REST interface", + "order": [ + "286f2d2d-88eb-ad68-7c6f-43caecc6073e", + "d27322b8-59d5-a2dc-a7a2-8f7197057164", + "5dc1d9f4-e7ae-bb21-e558-8a56ac825922", + "2f1d8e0d-4961-4b7f-50ad-0210e52e59aa", + "93022e97-24fa-5784-1e59-94674817215f", + "8b867c90-459f-68f6-4b2e-fa653098c28d", + "e611d23a-c205-192b-e8f9-dd99fa169274", + "3fccc4cd-f14b-0333-83d5-924afe3938e4" + ], + "folders": [ + { + "id": "7a914134-23ea-3154-1557-d29dc8d464e7", + "name": "IP", + "description": "", + "order": [ + "014dcd2b-1024-37a3-bc85-c18b0fdc0e8c", + "eb4852a6-ff3a-f9f4-4332-6677a93fcd2a", + "dc22d351-497a-4f01-52c1-6f01c76cf80b", + "69a05849-026d-f120-5c6a-f3e2b0884d88", + "b10169c2-ae0e-bb1c-3dea-ca06839c6c9c", + "8d49cf41-facc-c4ac-cee7-475d50e2a0be", + "70835949-7252-a3cc-491b-f8aa69286399", + "d5a90cfd-fd7e-63b6-e1f1-16fc0671b0e1", + "3f7ee49b-ae11-b032-915f-a14bf838246f", + "345ba26c-60cf-5fa1-37d0-f5af7a8c33bf" + ], + "owner": "45557" + }, + { + "id": "3d67940d-3c7a-8127-3965-6aee160e6b6f", + "name": "L2 FIB", + "description": "", + "order": [ + "76e9ee89-1594-ff38-ffff-ffc8de5d4054", + "dfbcc9e8-6f3d-b1c2-8bf6-989b1b1b3196", + "e2ff4db0-c013-cf89-d7b5-66de22bc7115", + "a937f1fc-10d5-bc19-ad5f-ac91fc007779", + "cf177689-9dd7-bcfe-d490-e9de6bde4dbb", + "0b63013d-3958-b427-2288-380019800468", + "99674f70-ec54-99f2-9300-545a031d5bab", + "f624bc96-502b-685c-1596-672ad5fcf6a9", + "0a1d6c0d-fe5e-1e1d-2471-96d7a4683e2f", + "d752fed9-127a-9289-71f3-90ba2b459d77", + "5c800144-cf89-7b77-1dd2-f488101ca441" + ], + "owner": "45557", + "collectionId": "e9ba4e80-fb4d-1eae-07e7-97b323164130" + }, + { + "id": "f91a6422-9724-e504-a94c-c5a953315b6f", + "name": "ACL", + "description": "", + "order": [ + "d7cb3d97-fc40-f471-33f3-07aad557777d", + "c067f721-6b1c-f205-799d-720b242f8592", + "5ab03c5f-03c5-8d42-bf65-024239049857", + "4f11c937-9562-3377-d03b-a9829b25f688", + "491ee2b7-88bf-3a71-282d-a16a62996026", + "fa63c194-ea7a-51ad-a6d8-d7485ed67f2e", + "b9931024-fa86-4e04-e2a4-4feeaa9e99e1", + "d39e4c39-90b6-072c-44b8-d909cac53a5b", + "2ce36b98-d7a9-fe37-80f6-f3a4abf25103", + "d0984799-d321-d1e0-a855-cc434519bef0", + "be223323-bf59-9c4f-f896-ff74c03b01a1", + "ee11f1c0-a1fe-51a6-a5e5-fcdcfc2b620a" + ], + "owner": "45557", + "collectionId": "e9ba4e80-fb4d-1eae-07e7-97b323164130" + }, + { + "id": "60596aab-a4f1-bb64-d701-816de9482201", + "name": "TAP", + "description": "", + "order": [ + "3f9588e4-885f-3792-bdf4-d0f10704ae4d", + "27106942-aff5-6ab5-07ae-5315135297a1", + "4db9b360-0d57-6ce6-7e3c-a6acfe17d512", + "5995dcf7-51c0-42ef-448b-a70bb68735d5" + ], + "owner": "45557" + }, + { + "id": "c97b9ad9-64e6-5de3-09b8-851c1189d767", + "name": "VHOST", + "description": "", + "order": [ + "7f312f15-a81e-b513-83b7-a5f7755eae67", + "ac161bec-e046-4bb7-d695-60bdfb0c6cea", + "55102dbd-1fc9-5f91-2082-40a2dc311f4f" + ], + "owner": "45557" + }, + { + "id": "37fd9569-06e3-1f08-fbcc-4b1462107a32", + "name": "VLAN", + "description": "", + "order": [ + "2ca639f4-f4a4-07c7-9419-79fd66061458", + "27eb70b8-a191-dd5c-f106-6693086ce872", + "f2e9a3cb-f3cc-f501-6015-8ebf7d8b2c3e", + "cbb77318-52e0-5647-cd1c-8c679ea7b830", + "8b339568-b60a-715f-d4fd-416bafe981a9", + "bd2897c6-5fc7-bec5-87be-4fd52bb8e471", + "44de3eff-ace5-90a9-dd16-af3f5f13daad", + "b08a0677-6b59-74ea-e5c6-7383194b19dd" + ], + "owner": "45557", + "collectionId": "e9ba4e80-fb4d-1eae-07e7-97b323164130" + }, + { + "id": "288569d0-e425-7877-4fd9-a82e8a340ade", + "name": "VXLAN-GPE-TUNNEL", + "description": "", + "order": [ + "0f223706-ca7f-fb8f-60ed-2b18e769e344", + "203ea32c-e43a-669c-4f28-232926df6928" + ], + "owner": "45557" + }, + { + "id": "3868e66d-0ee5-bd4d-6b35-075c4841b5c1", + "name": "VXLAN-TUNNEL", + "description": "", + "order": [ + "f014ab21-8e40-c344-a68b-0f1b86578bd8", + "4f15d0e9-8530-157e-0fe8-d24034bc31df" + ], + "owner": "45557" + } + ], + "timestamp": 1460119141419, + "owner": "45557", + "remoteLink": "", + "public": false, + "requests": [ + { + "id": "0f223706-ca7f-fb8f-60ed-2b18e769e344", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanGpeTun3", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1464768006369, + "name": "Add vxlan-gpe - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vxlanGpeTun3\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vxlan-gpe-tunnel\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"routing\" : {\r\n \"vrf-id\" : \"0\"\r\n },\r\n \"vxlan-gpe\" : {\r\n \"local\" : \"192.168.50.76\",\r\n \"remote\" : \"192.168.50.71\",\r\n \"vni\" : \"9\",\r\n \"next-protocol\" : \"ethernet\",\r\n \"encap-vrf-id\" : \"0\",\r\n \"decap-vrf-id\" : \"0\"\r\n }\r\n }\r\n ]\r\n \r\n}", + "folder": "288569d0-e425-7877-4fd9-a82e8a340ade" + }, + { + "id": "203ea32c-e43a-669c-4f28-232926df6928", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanGpeTun3", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1464764638498, + "name": "Delete vxlan-gpe - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "", + "folder": "288569d0-e425-7877-4fd9-a82e8a340ade" + }, + { + "id": "27106942-aff5-6ab5-07ae-5315135297a1", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp2", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1462796722186, + "name": "Add complex tap ifc - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"tapp2\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:tap\",\r\n \"tap\" :{\r\n \"tap-name\" : \"tapp2\",\r\n \"mac\" : \"00:ff:ff:ff:ff:ff\",\r\n \"device-instance\" : 55\r\n }\r\n }\r\n ]\r\n \r\n}", + "folder": "60596aab-a4f1-bb64-d701-816de9482201" + }, + { + "id": "27eb70b8-a191-dd5c-f106-6693086ce872", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1464804325716, + "name": "Enable GigabitEthernet0/9/0 interface - cfg", + "description": "Enables GigabitEthernet0/9/0 interface. Equivalent vppctl command:\n\nvppctl set in state GigabitEthernet0/9/0 up\n\nNeeded to enable sub interface.\n\nTo verify invoke:\n\nvppctl show int", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"GigabitEthernet0/9/0\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"v3po:ethernet\": {\r\n \"mtu\": 9216\r\n },\r\n \"enabled\": true,\r\n \"vpp-vlan:sub-interfaces\": {\r\n \"sub-interface\": [\r\n {\r\n \"identifier\": 1,\r\n \"vlan-type\": \"802dot1q\",\r\n \"tags\": {\r\n \"tag\": [\r\n {\r\n \"index\": 1,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": \"any\"\r\n }\r\n },\r\n {\r\n \"index\": 0,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": \"100\"\r\n }\r\n }\r\n ]\r\n },\r\n \"match\": {\r\n \"vlan-tagged\": {\r\n \"match-exact-tags\": true\r\n }\r\n },\r\n \"enabled\": false\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "286f2d2d-88eb-ad68-7c6f-43caecc6073e", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1460539962712, + "name": "List ifcs - cfg", + "description": "List ifcs - cfg", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "014dcd2b-1024-37a3-bc85-c18b0fdc0e8c", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F8%2F0/ipv4/neighbor/172.16.0.2", + "preRequestScript": null, + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1466498440466, + "name": "Ip Neighbour Get", + "description": "This call returns data stored in honeycomb,to verify actual data stored by vpp, call vppctl show ip fib|arp", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\n \n \"interface\":{\n \"name\":\"GigabitEthernet0/8/0\",\n \"type\": \"iana-if-type:ethernetCsmacd\",\n \"enabled\":\"true\",\n \"ipv4\":{\n \"neighbor\":{\n \"ip\":\"172.16.0.2\",\n \"link-layer-address\":\"00:01:11:00:02:02\"\n }\n }\n }\n}\n" + }, + { + "id": "dc22d351-497a-4f01-52c1-6f01c76cf80b", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F8%2F0/ipv4/neighbor/172.16.0.2", + "preRequestScript": null, + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1466498502212, + "name": "Ip Neighbour Delete", + "description": "Verify this call by invoking vppctl show ip fib|arp", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\n \"neighbor\":{\n \"ip\":\"172.16.0.2\",\n \"link-layer-address\":\"00:01:11:00:02:02\"\n }\n}\n" + }, + { + "id": "eb4852a6-ff3a-f9f4-4332-6677a93fcd2a", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F8%2F0/ipv4/neighbor/172.16.0.2", + "preRequestScript": null, + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1466498409820, + "name": "Ip Neighbour Add", + "description": "This call doesnt have respective dump call,because of performance issues(dump for this can contain millions of entries). Data inserted throught this call can be verified by calling vppctl show ip fib|arp", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\n \n \"neighbor\":{\n \"ip\":\"172.16.0.2\",\n \"link-layer-address\":\"00:01:11:00:02:02\"\n }\n \n}\n" + }, + { + "id": "2ca639f4-f4a4-07c7-9419-79fd66061458", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1464804304987, + "name": "Add sub interface - cfg", + "description": "Adds sub interface. Corresponsing vpp cli command:\n\nvppctl create sub GigabitEthernet0/9/0 1 dot1q 100 inner-dot1q any\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", + "rawModeData": "{\r\n \"sub-interface\": [\r\n {\r\n \"identifier\": \"1\",\r\n \"vlan-type\": \"802dot1q\",\r\n \"tags\": {\r\n \"tag\": [\r\n {\r\n \"index\": \"0\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": \"100\"\r\n }\r\n },\r\n {\r\n \"index\": \"1\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": \"any\"\r\n }\r\n }\r\n ]\r\n },\r\n \"match\": {\r\n \"vlan-tagged\": {\r\n \"match-exact-tags\": \"true\"\r\n }\r\n },\r\n \"enabled\": \"false\"\r\n }\r\n ]\r\n}" + }, + { + "id": "2f1d8e0d-4961-4b7f-50ad-0210e52e59aa", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/v3po:vpp", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1460540006597, + "name": "Read vpp - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "76e9ee89-1594-ff38-ffff-ffc8de5d4054", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD", + "pathVariables": {}, + "preRequestScript": "", + "method": "PUT", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "data": [], + "dataMode": "raw", + "name": "Create bridge domain - cfg", + "description": "Creates bridgfe domain. Corresponds to invoking:\n\nvat# bridge_domain_add_del bd_id [bd_id] learn 0 forward 0 uu-flood 0 flood 1 arp-term 0\n\nTo verify run:\n\nvppctl show bridge-domain [bd_id] detail", + "descriptionFormat": "html", + "time": 1465805138795, + "version": 2, + "responses": [], + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "folder": "3d67940d-3c7a-8127-3965-6aee160e6b6f", + "rawModeData": "{\r\n \"bridge-domain\": [\r\n {\r\n \"name\": \"testBD\",\r\n \"flood\": \"true\",\r\n \"forward\": \"false\",\r\n \"learn\": \"false\",\r\n \"unknown-unicast-flood\": \"false\",\r\n \"arp-termination\": \"false\"\r\n }\r\n ]\r\n}" + }, + { + "id": "dfbcc9e8-6f3d-b1c2-8bf6-989b1b1b3196", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465806733493, + "name": "Show bridge domain - cfg", + "description": "Shows testBD bridge domain configuration.", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \"bridge-domain\": [\r\n {\r\n \"name\": \"testBD\",\r\n \"flood\": \"true\",\r\n \"forward\": \"false\",\r\n \"learn\": \"false\",\r\n \"unknown-unicast-flood\": \"false\",\r\n \"arp-termination\": \"false\"\r\n }\r\n ]\r\n}" + }, + { + "id": "e2ff4db0-c013-cf89-d7b5-66de22bc7115", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/operational/v3po:vpp-state/bridge-domains/bridge-domain/testBD", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465806752970, + "name": "Show bridge domain - oper", + "description": "Shows testBD bridge domain operational state.\nCorresponds to invoking:\n\nvppctl show bridge-domain [bd_id] detail", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \"bridge-domain\": [\r\n {\r\n \"name\": \"testBD\",\r\n \"flood\": \"true\",\r\n \"forward\": \"false\",\r\n \"learn\": \"false\",\r\n \"unknown-unicast-flood\": \"false\",\r\n \"arp-termination\": \"false\"\r\n }\r\n ]\r\n}" + }, + { + "id": "a937f1fc-10d5-bc19-ad5f-ac91fc007779", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:l2", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465805545425, + "name": "Add local0 to bridge domain", + "description": "Adds l2 interconnection of bridge-based type to local0 interface.\nCorresponds to the following command:\n\nvppctl set interface l2 bridge local0 [bd_id]\n\nTo verify invoke:\n\nvppctl show bridge-domain [bd_id] detail", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \"l2\": {\r\n \"bridge-domain\": \"testBD\",\r\n \"split-horizon-group\": 1,\r\n \"bridged-virtual-interface\": \"false\"\r\n }\r\n}" + }, + { + "id": "cf177689-9dd7-bcfe-d490-e9de6bde4dbb", + "headers": "", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/", + "preRequestScript": null, + "pathVariables": {}, + "method": "GET", + "data": null, + "dataMode": "params", + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465805728052, + "name": "Show local0 - cfg", + "description": "Shows local0 interface configuration", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [] + }, + { + "id": "0b63013d-3958-b427-2288-380019800468", + "headers": "", + "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0/", + "pathVariables": {}, + "preRequestScript": null, + "method": "GET", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "data": null, + "dataMode": "params", + "name": "Show local0 - oper", + "description": "Shows local0 interface operational state", + "descriptionFormat": "html", + "time": 1465805719840, + "version": 2, + "responses": [], + "tests": null, + "currentHelper": "normal", + "helperAttributes": {}, + "folder": "3d67940d-3c7a-8127-3965-6aee160e6b6f" + }, + { + "id": "99674f70-ec54-99f2-9300-545a031d5bab", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/aa:bb:cc:dd:ee:ff", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465806456783, + "name": "Add L2 FIB entry (forward)", + "description": "Adds L2 FIB static entry. Corresponds to invoking:\n\nvppctl l2fib add aa:bb:cc:dd:ee:ff [bd_id] local0\n\nTo verify run:\n\nvppctl show l2fib verbose", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\n \"l2-fib-entry\": [\n {\n \"phys-address\": \"aa:bb:cc:dd:ee:ff\",\n \"outgoing-interface\": \"local0\",\n \"action\": \"l2-fib-forward\"\n }\n ]\n}" + }, + { + "id": "f624bc96-502b-685c-1596-672ad5fcf6a9", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/aa:bb:cc:dd:ee:ff", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465806577485, + "name": "Delete L2 FIB entry", + "description": "Removes L2 FIB entry. Corresponds to invoking:\n\nvppctl l2fib del aa:bb:cc:dd:ee:ff [bd_id]\n\nTo verify run:\n\nvppctl show l2fib verbose", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "" + }, + { + "id": "0a1d6c0d-fe5e-1e1d-2471-96d7a4683e2f", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/11:22:33:44:55:66", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465806064247, + "name": "Add L2 FIB entry (static, forward)", + "description": "Adds L2 FIB static entry. Corresponds to invoking:\n\nvppctl l2fib add 11:22:33:44:55:66 [bd_id] local0 static\n\nTo verify run:\n\nvppctl show l2fib verbose", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\n \"l2-fib-entry\": [\n {\n \"phys-address\": \"11:22:33:44:55:66\",\n \"outgoing-interface\": \"local0\",\n \"static-config\": \"true\",\n \"action\": \"l2-fib-forward\"\n }\n ]\n}" + }, + { + "id": "d752fed9-127a-9289-71f3-90ba2b459d77", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/00:01:02:03:04:05", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465814845273, + "name": "Add L2 FIB entry (filter)", + "description": "Adds L2 FIB static entry. Corresponds to invoking:\n\nvppctl l2fib add 00:01:02:03:04:05 [bd_id] filter\n\nTo verify run:\n\nvppctl show l2fib verbose", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\n \"l2-fib-entry\": [\n {\n \"phys-address\": \"00:01:02:03:04:05\",\n \"outgoing-interface\": \"local0\",\n \"static-config\": \"true\",\n \"action\": \"l2-fib-filter\"\n }\n ]\n}" + }, + { + "id": "5c800144-cf89-7b77-1dd2-f488101ca441", + "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:l2", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465984375972, + "name": "Remove local0 from bridge domain", + "description": "Removes l2 interconnection of bridge-based type from local0 interface.\nCorresponds to the following VAT command:\n\nvat# sw_interface_set_l2_bridge sw_if_index 0 bd_id 1 disable\n\nVerification in VAT:\n\nvat# bridge_domain_dump", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "" + }, + { + "id": "d7cb3d97-fc40-f471-33f3-07aad557777d", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1467377260818, + "name": "Get classify tables - cfg", + "description": "Shows classify table configuration.", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "" + }, + { + "id": "c067f721-6b1c-f205-799d-720b242f8592", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/operational/vpp-classifier:vpp-classifier-state/", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1467377066230, + "name": "Get classify tables - oper", + "description": "Shows classify tables configured in the VPP.\n\nCorresponds to:\n\nvppctl sh class table verbose", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "" + }, + { + "id": "5ab03c5f-03c5-8d42-bf65-024239049857", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1468493354688, + "name": "Add classify table0", + "description": "Adds classify table0. Corresponding vpp cli command:\n\nvppctl classify table mask l2 src\n\nTo verify invoke:\n\nvppctl sh class table verbose\n\nor:\n\nvat# classify_table_info table_id 0", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "{\n \"classify-table\": [\n {\n \"name\": \"table0\",\n \"nbuckets\": \"2\",\n \"memory_size\": \"1048576\",\n \"miss_next\": \"permit\",\n \"mask\": \"00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:00:00:00:00\"\n }\n ]\n}" + }, + { + "id": "4f11c937-9562-3377-d03b-a9829b25f688", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/operational/vpp-classifier:vpp-classifier-state/classify-table/table0", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1467378420028, + "name": "Get classify table - oper", + "description": "Shows classify table 0 operational state.\n\nCorresponds to:\n\nvat# classify_table_info table_id 0", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "" + }, + { + "id": "491ee2b7-88bf-3a71-282d-a16a62996026", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table1", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1468493298160, + "name": "Add classify table1", + "description": "Adds classify table1 chained to classify table0.\n\nCorresponding vpp cli command:\n\nvppctl classify table mask l2 dst next-table 0\n\nTo verify invoke:\n\nvppctl sh class table verbose\n\nor:\n\nvat# classify_table_info table_id 1", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "{\n \"classify-table\": [\n {\n \"name\": \"table1\",\n \"next_table\": \"table0\",\n \"nbuckets\": \"2\",\n \"memory_size\": \"1048576\",\n \"miss_next\": \"permit\",\n \"mask\": \"ff:ff:ff:ff:ff:ff:00:00:00:00:00:00:00:00:00:00\"\n }\n ]\n}" + }, + { + "id": "fa63c194-ea7a-51ad-a6d8-d7485ed67f2e", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0/classify-session/00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1468493546163, + "name": "Add classify session", + "description": "Adds classify session to table0. Corresponding vpp cli command:\n\nvppctl classify session acl-hit-next deny opaque-index 0 table-index 0 match l2 src 01:02:03:04:05:06\n\nTo verify invoke:\n\nvppctl sh class table verbose", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "{\n \"classify-session\": [\n {\n \"hit_next\": \"deny\",\n \"match\": \"00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00\"\n }\n ]\n}" + }, + { + "id": "b9931024-fa86-4e04-e2a4-4feeaa9e99e1", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0/classify-session/00:00:00:00:00:00:01:02:03:04:05:07:00:00:00:00", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1468493583927, + "name": "Add another classify session", + "description": "Adds second classify session to table0. Corresponding vpp cli command:\n\nvppctl classify session acl-hit-next deny opaque-index 0 table-index 0 match l2 src 01:02:03:04:05:07\n\nTo verify invoke:\n\nvppctl sh class table verbose", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "{\n \"classify-session\": [\n {\n \"hit_next\": \"deny\",\n \"match\": \"00:00:00:00:00:00:01:02:03:04:05:07:00:00:00:00\"\n }\n ]\n}" + }, + { + "id": "d39e4c39-90b6-072c-44b8-d909cac53a5b", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:acl", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1468495690154, + "name": "Enable L2 and Ipv4 ACL on local0 interface", + "description": "Enables L2 and Ipv4 ACL on local0. Corresponding vpp cli commands:\n\nset int input acl intfc local0 l2-table 0\n\nset int input acl intfc local0 ip4-table 0\n\nTo verify invoke:\n\nvppctl show inacl type l2\n\nthen:\n\nvppctl show inacl type ip4", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "{\n \"v3po:acl\": {\n \"l2-acl\": {\n \"classify-table\": \"table0\"\n },\n \"ip4-acl\": {\n \"classify-table\": \"table0\"\n }\n }\n}" + }, + { + "id": "2ce36b98-d7a9-fe37-80f6-f3a4abf25103", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:acl/", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1467380189765, + "name": "Disable ACL on local0 interface", + "description": "Disables ACL on local0. To verify invoke:\n\nvppctl show inacl type l2\n\nand:\n\nvppctl show inacl type ip4", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "" + }, + { + "id": "d0984799-d321-d1e0-a855-cc434519bef0", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0/classify-session/00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1468493934488, + "name": "Remove classify session", + "description": "Removes classify session. To verify invoke:\n\nvppctl sh class table verbose", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "" + }, + { + "id": "be223323-bf59-9c4f-f896-ff74c03b01a1", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1467377830897, + "name": "Remove classify table0", + "description": "Removes classify table0. Corresponds to the following command:\n\nvppctl classify table del table 0\n\nTo verify invoke:\n\nvppctl sh class table verbose", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "" + }, + { + "id": "ee11f1c0-a1fe-51a6-a5e5-fcdcfc2b620a", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table1", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1467377388428, + "name": "Remove classify table1", + "description": "Removes classify table1. Corresponds to the following command:\n\nvppctl classify table del table 1\n\nTo verify invoke:\n\nvppctl sh class table verbose", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "f91a6422-9724-e504-a94c-c5a953315b6f", + "rawModeData": "" + }, + { + "id": "3f9588e4-885f-3792-bdf4-d0f10704ae4d", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1462535811974, + "name": "Add simple tap ifc -cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "60596aab-a4f1-bb64-d701-816de9482201", + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"tapp\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:tap\",\r\n \"tap\" :{\r\n \"tap-name\" : \"tapp\"\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "3fccc4cd-f14b-0333-83d5-924afe3938e4", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1460640004531, + "name": "Set vrf id for local0 - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"local0\",\r\n \"description\": \"for testing purposes only\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"routing\" : {\r\n \"vrf-id\" : \"7\"\r\n },\r\n \"v3po:ethernet\": {\r\n \"mtu\": 64\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "44de3eff-ace5-90a9-dd16-af3f5f13daad", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1464805188780, + "name": "Enable tag-rewrite translate 1-2 - cfg", + "description": "Enables tag-rewrite translate 1-2 operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 translate 1-2 dot1q 111 222\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", + "rawModeData": "{\r\n \"rewrite\": {\r\n \"vlan-type\": \"vpp-vlan:802dot1q\",\r\n \"pop-tags\": \"1\",\r\n \"push-tags\": [\r\n {\r\n \"index\": 0,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": 111\r\n }\r\n },\r\n {\r\n \"index\": 1,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": 222\r\n }\r\n }\r\n ]\r\n }\r\n}" + }, + { + "id": "4db9b360-0d57-6ce6-7e3c-a6acfe17d512", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp2", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1462796801468, + "name": "Modify complex tap ifc - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"tapp2\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:tap\",\r\n \"tap\" :{\r\n \"tap-name\" : \"tapp2\",\r\n \"mac\" : \"00:ff:ff:ff:ff:ae\",\r\n \"device-instance\" : 77\r\n }\r\n }\r\n ]\r\n \r\n}", + "folder": "60596aab-a4f1-bb64-d701-816de9482201" + }, + { + "id": "4f15d0e9-8530-157e-0fe8-d24034bc31df", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanTun1", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": "{}", + "time": 1462892071867, + "name": "Delete virtual ifc - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "3868e66d-0ee5-bd4d-6b35-075c4841b5c1", + "timestamp": null, + "rawModeData": "" + }, + { + "id": "55102dbd-1fc9-5f91-2082-40a2dc311f4f", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vhost1", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": "{}", + "time": 1462891488523, + "name": "Delete vhost user ifc - cfg", + "description": "Deletes vhost user interface.\nCorresponding vpp CLI command:\n\nvppctl delete vhost-user sw_if_index [index]\n\nTo verify invoke:\n\nvppctl show vhost-user\n\nor\n\nvppctl show int", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "c97b9ad9-64e6-5de3-09b8-851c1189d767", + "rawModeData": "", + "descriptionFormat": null + }, + { + "id": "5995dcf7-51c0-42ef-448b-a70bb68735d5", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp2", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1462796994090, + "name": "Delete complex tap ifc - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "", + "folder": "60596aab-a4f1-bb64-d701-816de9482201" + }, + { + "id": "5dc1d9f4-e7ae-bb21-e558-8a56ac825922", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/operational/v3po:vpp-state", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1460539994330, + "name": "Read vpp-state - oper", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "7f312f15-a81e-b513-83b7-a5f7755eae67", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vhost1", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1462891472552, + "name": "Add vhost user ifc - cfg", + "description": "Adds vhost-user interface.\nCorresponsing vpp cli command:\n\ncreate vhost-user socket /tmp/soc1 server\n\nTo verify invoke:\n\nvppctl show vhost-user\n\nor\n\nvppctl show int", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vhost1\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vhost-user\",\r\n \"enabled\": \"true\",\r\n \"vhost-user\" : {\r\n \"socket\": \"/tmp/soc1\",\r\n \"role\": \"server\"\r\n }\r\n }\r\n ]\r\n \r\n}", + "folder": "c97b9ad9-64e6-5de3-09b8-851c1189d767" + }, + { + "id": "8b339568-b60a-715f-d4fd-416bafe981a9", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": "{}", + "time": 1464803940412, + "name": "Enable tag-rewrite push - cfg", + "description": "Enables tag-rewrite push operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 push dot1q 123 456\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", + "timestamp": null, + "rawModeData": "{\r\n \"rewrite\": {\r\n \"vlan-type\": \"vpp-vlan:802dot1q\",\r\n \"push-tags\": [\r\n {\r\n \"index\": 0,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": 123\r\n }\r\n },\r\n {\r\n \"index\": 1,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": 456\r\n }\r\n }\r\n ]\r\n }\r\n}" + }, + { + "id": "8b867c90-459f-68f6-4b2e-fa653098c28d", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1460540047356, + "name": "Enable local0 interface - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"local0\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"v3po:ethernet\": {\r\n \"mtu\": 64\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "93022e97-24fa-5784-1e59-94674817215f", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/operational/naming-context:contexts", + "pathVariables": {}, + "preRequestScript": "", + "method": "GET", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "data": [], + "dataMode": "raw", + "name": "List naming contexts - context", + "description": "List mapping context stored in context datastore", + "descriptionFormat": "html", + "time": 1463556756647, + "version": 2, + "responses": [], + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "69a05849-026d-f120-5c6a-f3e2b0884d88", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465472429324, + "name": "Read local0 - oper", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "b10169c2-ae0e-bb1c-3dea-ca06839c6c9c", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1466496859574, + "name": "Set ipv4 local0 interface - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", + "rawModeData": "{\r\n \"address\": [{\r\n \"ip\" : \"127.0.0.1\",\r\n \"prefix-length\" : \"24\"\r\n }]\r\n}" + }, + { + "id": "8d49cf41-facc-c4ac-cee7-475d50e2a0be", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1466497187475, + "name": "Remove ipv4 from local0 interface - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", + "rawModeData": "" + }, + { + "id": "70835949-7252-a3cc-491b-f8aa69286399", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1466497176571, + "name": "Set ipv4 local0 interface - cfg netmask", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", + "rawModeData": "{\r\n \"address\": [{\r\n \"ip\" : \"127.0.0.1\",\r\n \"netmask\": \"255.255.255.128\"\r\n }]\r\n}" + }, + { + "id": "d5a90cfd-fd7e-63b6-e1f1-16fc0671b0e1", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0/ipv4", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465473594194, + "name": "Read local0/ipv4 - oper", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "3f7ee49b-ae11-b032-915f-a14bf838246f", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1466497212835, + "name": "Read local0/ipv4 - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "345ba26c-60cf-5fa1-37d0-f5af7a8c33bf", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/ipv4/address/1.2.3.4", + "pathVariables": {}, + "preRequestScript": "", + "method": "PUT", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "data": [], + "dataMode": "raw", + "name": "Set ipv4 for sub-interface - cfg", + "description": "Correponds to the following command:\n\nvppctl set interface ip address GigabitEthernet0/9/0.1 1.2.3.4/8\n\nTo verify invoke:\nvppctl show int", + "descriptionFormat": "html", + "time": 1467117222646, + "version": 2, + "responses": [], + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", + "rawModeData": "{\r\n \"address\": [{\r\n \"ip\" : \"1.2.3.4\",\r\n \"prefix-length\" : \"8\"\r\n }]\r\n}" + }, + { + "id": "ac161bec-e046-4bb7-d695-60bdfb0c6cea", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vhost1", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1462891483790, + "name": "Modify vhost user ifc - cfg", + "description": "Modifies vhost-user interface socket.\nTo verify invoke:\n\nvppctl show vhost-user", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vhost1\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vhost-user\",\r\n \"enabled\": \"true\",\r\n \"vhost-user\" : {\r\n \"socket\": \"/tmp/soc2\",\r\n \"role\": \"server\"\r\n }\r\n }\r\n ]\r\n \r\n}", + "folder": "c97b9ad9-64e6-5de3-09b8-851c1189d767" + }, + { + "id": "b08a0677-6b59-74ea-e5c6-7383194b19dd", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1464804511683, + "name": "Disable tag-rewrite - cfg", + "description": "Disables tag-rewrite operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 disable\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", + "rawModeData": "" + }, + { + "id": "bd2897c6-5fc7-bec5-87be-4fd52bb8e471", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1464805111410, + "name": "Enable tag-rewrite pop 1 - cfg", + "description": "Enables tag-rewrite pop 1 operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 pop 1\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", + "rawModeData": "{\r\n \"rewrite\": {\r\n \"pop-tags\": \"1\"\r\n }\r\n}" + }, + { + "id": "cbb77318-52e0-5647-cd1c-8c679ea7b830", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1464813539029, + "name": "Add sub interface to bridge-domain", + "description": "Adds sub interface to bridge domain. Corresponsing vpp cli command:\n\nvppctl set interface l2 bridge GigabitEthernet0/9/0.1 1 1\n\nTo verify invoke:\nvppctl show bridge-domain 1 detail", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", + "rawModeData": "{\r\n \"l2\": {\r\n \"bridge-domain\": \"testBD\",\r\n \"split-horizon-group\": 1,\r\n \"bridged-virtual-interface\": \"false\"\r\n }\r\n}" + }, + { + "id": "d27322b8-59d5-a2dc-a7a2-8f7197057164", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1460539972177, + "name": "List ifcs - oper", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "e611d23a-c205-192b-e8f9-dd99fa169274", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1460636113690, + "name": "Set interfaces bulk edit - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\n \"interfaces\": {\n \"interface\": [\n {\n \"name\": \"pg/stream-2\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n },\n {\n \"name\": \"pg/stream-3\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n },\n {\n \"name\": \"pg/stream-0\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n },\n {\n \"name\": \"local0\",\n \"description\": \"for testing purposes\",\n \"type\": \"iana-if-type:ethernetCsmacd\",\n \"enabled\": true\n },\n {\n \"name\": \"pg/stream-1\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n }\n ]\n }\n}" + }, + { + "id": "f014ab21-8e40-c344-a68b-0f1b86578bd8", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanTun1", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1464767860505, + "name": "Add virtual ifc - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vxlanTun1\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vxlan-tunnel\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"routing\" : {\r\n \"vrf-id\" : \"0\"\r\n },\r\n \"vxlan\" : {\r\n \"src\" : \"192.168.1.6\",\r\n \"dst\" : \"192.168.1.9\",\r\n \"vni\" : \"88\",\r\n \"encap-vrf-id\" : \"0\"\r\n }\r\n }\r\n ]\r\n \r\n}", + "folder": "3868e66d-0ee5-bd4d-6b35-075c4841b5c1" + }, + { + "id": "f2e9a3cb-f3cc-f501-6015-8ebf7d8b2c3e", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1464804333865, + "name": "Enable GigabitEthernet0/9/0.1 interface - cfg", + "description": "Enables GigabitEthernet0/9/0.1 sub interface. Equivalent vppctl command:\n\nvppctl set in state GigabitEthernet0/9/0.1 up\n\nTo enable sub interface, super interface should be enabled first.\n\nTo verify invoke:\n\nvppctl show int", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32", + "rawModeData": "{\r\n \"sub-interface\": [\r\n {\r\n \"identifier\": \"1\",\r\n \"vlan-type\": \"802dot1q\",\r\n \"tags\": {\r\n \"tag\": [\r\n {\r\n \"index\": \"0\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": \"100\"\r\n }\r\n },\r\n {\r\n \"index\": \"1\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": \"any\"\r\n }\r\n }\r\n ]\r\n },\r\n \"match\": {\r\n \"vlan-tagged\": {\r\n \"match-exact-tags\": \"true\"\r\n }\r\n },\r\n \"enabled\": \"true\"\r\n }\r\n ]\r\n}" + } + ] +} diff --git a/v3po/v3po2vpp/src/main/config/default-config.xml b/v3po/v3po2vpp/src/main/config/default-config.xml index b6a73824c..e17d7295c 100644 --- a/v3po/v3po2vpp/src/main/config/default-config.xml +++ b/v3po/v3po2vpp/src/main/config/default-config.xml @@ -247,18 +247,18 @@ - prefix:cfg-initializer-registry + prefix:cfg-initializer-registry initializer-registry - prefix:cfg-initializer + prefix:cfg-initializer vpp-cfg-initializer - prefix:cfg-initializer + prefix:cfg-initializer interfaces-cfg-initializer - prefix:cfg-initializer + prefix:cfg-initializer vpp-classifier-cfg-initializer @@ -323,7 +323,7 @@ - prefix:cfg-initializer + prefix:cfg-initializer vpp-cfg-initializer /modules/module[type='vpp-cfg-initializer'][name='vpp-cfg-initializer'] diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java new file mode 100644 index 000000000..1d58bd18d --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializer.java @@ -0,0 +1,282 @@ +/* + * 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.translate.v3po.initializers; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; +import io.fd.honeycomb.data.init.AbstractDataTreeConverter; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Neighbor; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.NeighborBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeVni; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.AclBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.EthernetBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.TapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Tap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUser; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBased; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBased; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBasedBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Initializes ietf-interfaces config data based on operational state + */ +public class InterfacesInitializer extends AbstractDataTreeConverter { + private static final Logger LOG = LoggerFactory.getLogger(InterfacesInitializer.class); + + public InterfacesInitializer(@Nonnull final DataBroker bindingDataBroker) { + super(bindingDataBroker, InstanceIdentifier.create(InterfacesState.class), + InstanceIdentifier.create(Interfaces.class)); + } + + @Override + protected Interfaces convert(final InterfacesState operationalData) { + LOG.debug("InterfacesInitializer.convert()"); + InterfacesBuilder interfacesBuilder = new InterfacesBuilder(); + interfacesBuilder + .setInterface(Lists.transform(operationalData.getInterface(), InterfacesInitializer::initialize)); + return interfacesBuilder.build(); + } + + // FIXME https://jira.fd.io/browse/HONEYCOMB-73 this kind of initialization/transformation is bad + // There is no relation to readers, it cannot be extended (readers can) and its hard to keep in sync with readers + + // TODO add IP v4/ v6 initializer + + private static Interface initialize( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input) { + InterfaceBuilder builder = new InterfaceBuilder(); + builder.setKey(new InterfaceKey(input.getKey().getName())); + builder.setName(input.getName()); + builder.setType(input.getType()); + builder.setEnabled(AdminStatus.Up.equals(input.getAdminStatus())); + // builder.setLinkUpDownTrapEnable(); TODO not present in interfaces-state + + initializeVppInterfaceStateAugmentation(input, builder); + SubInterfaceInitializationUtils.initializeSubinterfaceStateAugmentation(input, builder); + initializeIetfIpAugmentation(input, builder); + + return builder.build(); + } + + private static void initializeVppInterfaceStateAugmentation( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, + final InterfaceBuilder builder) { + final VppInterfaceStateAugmentation vppIfcAugmentation = + input.getAugmentation(VppInterfaceStateAugmentation.class); + if (vppIfcAugmentation != null) { + final VppInterfaceAugmentationBuilder augmentBuilder = new VppInterfaceAugmentationBuilder(); + builder.setDescription(vppIfcAugmentation.getDescription()); + + final Vxlan vxlan = vppIfcAugmentation.getVxlan(); + if (vxlan != null) { + setVxlan(augmentBuilder, vxlan); + } + + final VxlanGpe vxlanGpe = vppIfcAugmentation.getVxlanGpe(); + if (vxlanGpe != null) { + setVxlanGpe(augmentBuilder, vxlanGpe); + } + + final Tap tap = vppIfcAugmentation.getTap(); + if (tap != null) { + setTap(input, augmentBuilder, tap); + } + + final VhostUser vhostUser = vppIfcAugmentation.getVhostUser(); + if (vhostUser != null) { + setVhostUser(augmentBuilder, vhostUser); + } + + final L2 l2 = vppIfcAugmentation.getL2(); + if (l2 != null) { + setL2(augmentBuilder, l2); + } + + final Ethernet ethernet = vppIfcAugmentation.getEthernet(); + if (ethernet != null) { + setEthernet(augmentBuilder, ethernet); + } + + final Acl acl = vppIfcAugmentation.getAcl(); + if (acl != null) { + setAcl(augmentBuilder, acl); + } + + // TODO set routing, not present in interface-state + + builder.addAugmentation(VppInterfaceAugmentation.class, augmentBuilder.build()); + } + } + + private static void initializeIetfIpAugmentation( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, + final InterfaceBuilder builder) { + final Interface2 ietfIpAugmentation = input.getAugmentation(Interface2.class); + if (ietfIpAugmentation != null) { + final Interface1Builder augmentBuilder = new Interface1Builder(); + + final Ipv4 ipv4 = ietfIpAugmentation.getIpv4(); + if (ipv4 != null) { + final List + collect = + ipv4.getAddress().stream() + .map( + address -> new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder() + .setIp(address.getIp()) + .setSubnet(getSubnet(address)) + .build()) + .collect(Collectors.toList()); + + final List neighbors = ipv4.getNeighbor().stream() + .map(neighbor -> new NeighborBuilder().setIp(neighbor.getIp()) + .setLinkLayerAddress(neighbor.getLinkLayerAddress()).build()) + .collect(Collectors.toList()); + + augmentBuilder.setIpv4(new Ipv4Builder().setAddress(collect).setNeighbor(neighbors).build()); + } + + // TODO ipv6 + + builder.addAugmentation(Interface1.class, augmentBuilder.build()); + } + } + + private static Subnet getSubnet(final Address address) { + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.Subnet + subnet = address.getSubnet(); + + // TODO only prefix length supported + Preconditions.checkArgument( + subnet instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLength); + + return new PrefixLengthBuilder().setPrefixLength( + ((org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLength) subnet) + .getPrefixLength()).build(); + } + + private static void setEthernet(final VppInterfaceAugmentationBuilder augmentBuilder, final Ethernet ethernet) { + final EthernetBuilder ethernetBuilder = new EthernetBuilder(); + ethernetBuilder.setMtu(ethernet.getMtu()); + augmentBuilder.setEthernet(ethernetBuilder.build()); + } + + private static void setAcl(final VppInterfaceAugmentationBuilder augmentBuilder, final Acl acl) { + final AclBuilder aclBuilder = new AclBuilder(); + aclBuilder.setL2Acl(acl.getL2Acl()); + aclBuilder.setIp4Acl(acl.getIp4Acl()); + aclBuilder.setIp6Acl(acl.getIp6Acl()); + augmentBuilder.setAcl(aclBuilder.build()); + } + + private static void setL2(final VppInterfaceAugmentationBuilder augmentBuilder, final L2 l2) { + final L2Builder l2Builder = new L2Builder(); + + final Interconnection interconnection = l2.getInterconnection(); + if (interconnection != null) { + if (interconnection instanceof XconnectBased) { + final XconnectBasedBuilder xconnectBasedBuilder = new XconnectBasedBuilder(); + xconnectBasedBuilder.setXconnectOutgoingInterface( + ((XconnectBased) interconnection).getXconnectOutgoingInterface()); + l2Builder.setInterconnection(xconnectBasedBuilder.build()); + } else if (interconnection instanceof BridgeBased) { + final BridgeBasedBuilder bridgeBasedBuilder = new BridgeBasedBuilder(); + bridgeBasedBuilder.setBridgeDomain(((BridgeBased) interconnection).getBridgeDomain()); + bridgeBasedBuilder + .setBridgedVirtualInterface(((BridgeBased) interconnection).isBridgedVirtualInterface()); + bridgeBasedBuilder.setSplitHorizonGroup(((BridgeBased) interconnection).getSplitHorizonGroup()); + l2Builder.setInterconnection(bridgeBasedBuilder.build()); + } + } + + augmentBuilder.setL2(l2Builder.build()); + } + + private static void setVhostUser(final VppInterfaceAugmentationBuilder augmentBuilder, final VhostUser vhostUser) { + final VhostUserBuilder vhostUserBuilder = new VhostUserBuilder(); + vhostUserBuilder.setRole(vhostUser.getRole()); + vhostUserBuilder.setSocket(vhostUser.getSocket()); + augmentBuilder.setVhostUser(vhostUserBuilder.build()); + } + + private static void setTap( + final @Nonnull org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, + final VppInterfaceAugmentationBuilder augmentBuilder, + final Tap tap) { + final TapBuilder tapBuilder = new TapBuilder(); + tapBuilder.setMac(input.getPhysAddress()); + tapBuilder.setTapName(tap.getTapName()); +// tapBuilder.setDeviceInstance(); + augmentBuilder.setTap(tapBuilder.build()); + } + + private static void setVxlan(final VppInterfaceAugmentationBuilder augmentBuilder, final Vxlan vxlan) { + final VxlanBuilder vxlanBuilder = new VxlanBuilder(); + vxlanBuilder.setDst(vxlan.getDst()); + vxlanBuilder.setSrc(vxlan.getSrc()); + vxlanBuilder.setEncapVrfId(vxlan.getEncapVrfId()); + vxlanBuilder.setVni(new VxlanVni(vxlan.getVni())); + augmentBuilder.setVxlan(vxlanBuilder.build()); + } + + private static void setVxlanGpe(final VppInterfaceAugmentationBuilder augmentBuilder, final VxlanGpe vxlanGpe) { + final VxlanGpeBuilder vxlanGpeBuilder = new VxlanGpeBuilder(); + vxlanGpeBuilder.setLocal(vxlanGpe.getLocal()); + vxlanGpeBuilder.setRemote(vxlanGpe.getRemote()); + vxlanGpeBuilder.setVni(new VxlanGpeVni(vxlanGpe.getVni())); + vxlanGpeBuilder.setNextProtocol(vxlanGpe.getNextProtocol()); + vxlanGpeBuilder.setEncapVrfId(vxlanGpe.getEncapVrfId()); + vxlanGpeBuilder.setDecapVrfId(vxlanGpe.getDecapVrfId()); + augmentBuilder.setVxlanGpe(vxlanGpeBuilder.build()); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/SubInterfaceInitializationUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/SubInterfaceInitializationUtils.java new file mode 100644 index 000000000..7acc75bcd --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/SubInterfaceInitializationUtils.java @@ -0,0 +1,92 @@ +/* + * 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.translate.v3po.initializers; + +import com.google.common.collect.Lists; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubInterfaceStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfaces; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.AclBuilder; + +/** + * Utility class for sub interface initialization + */ +final class SubInterfaceInitializationUtils { + + private SubInterfaceInitializationUtils() { + throw new UnsupportedOperationException("Utility class cannot be instantiated"); + } + + static void initializeSubinterfaceStateAugmentation( + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, + final InterfaceBuilder builder) { + final SubinterfaceStateAugmentation subIfcAugmentation = + input.getAugmentation(SubinterfaceStateAugmentation.class); + if (subIfcAugmentation != null) { + final SubinterfaceAugmentationBuilder augmentBuilder = new SubinterfaceAugmentationBuilder(); + + final SubInterfaces subInterfaces = subIfcAugmentation.getSubInterfaces(); + if (subInterfaces != null) { + setSubInterfaces(augmentBuilder, subInterfaces); + } + + builder.addAugmentation(SubinterfaceAugmentation.class, augmentBuilder.build()); + } + } + + private static void setSubInterfaces(final SubinterfaceAugmentationBuilder augmentBuilder, + final SubInterfaces operationalData) { + + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfacesBuilder + subInterfacesCfgBuilder = + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfacesBuilder(); + subInterfacesCfgBuilder.setSubInterface(Lists.transform(operationalData.getSubInterface(), + SubInterfaceInitializationUtils::convertSubInterface)); + augmentBuilder.setSubInterfaces(subInterfacesCfgBuilder.build()); + } + + private static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface convertSubInterface( + final SubInterface operationalData) { + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceBuilder subInterfaceCfgBuilder = + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceBuilder(); + + subInterfaceCfgBuilder.setEnabled(SubInterfaceStatus.Up.equals(operationalData.getAdminStatus())); + subInterfaceCfgBuilder.setIdentifier(operationalData.getIdentifier()); + subInterfaceCfgBuilder.setKey(new SubInterfaceKey(operationalData.getIdentifier())); + subInterfaceCfgBuilder.setL2(operationalData.getL2()); + subInterfaceCfgBuilder.setMatch(operationalData.getMatch()); + subInterfaceCfgBuilder.setTags(operationalData.getTags()); + subInterfaceCfgBuilder.setVlanType(operationalData.getVlanType()); + subInterfaceCfgBuilder.setIpv4(operationalData.getIpv4()); + subInterfaceCfgBuilder.setIpv6(operationalData.getIpv6()); + + if (operationalData.getAcl() != null) { + final AclBuilder aclBuilder = new AclBuilder(); + aclBuilder.setL2Acl(operationalData.getAcl().getL2Acl()); + aclBuilder.setIp4Acl(operationalData.getAcl().getIp4Acl()); + aclBuilder.setIp6Acl(operationalData.getAcl().getIp6Acl()); + subInterfaceCfgBuilder.setAcl(aclBuilder.build()); + } + + return subInterfaceCfgBuilder.build(); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppClasifierInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppClasifierInitializer.java new file mode 100644 index 000000000..42d1c59dc --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppClasifierInitializer.java @@ -0,0 +1,49 @@ +/* + * 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.translate.v3po.initializers; + +import io.fd.honeycomb.data.init.AbstractDataTreeConverter; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Initializes vpp-classfier node in config data tree based on operational state. + */ +public class VppClasifierInitializer extends AbstractDataTreeConverter { + private static final InstanceIdentifier OPER_ID = + InstanceIdentifier.create(VppClassifierState.class); + private static final InstanceIdentifier CFG_ID = InstanceIdentifier.create(VppClassifier.class); + + public VppClasifierInitializer(@Nonnull final DataBroker bindingDataBroker) { + super(bindingDataBroker, OPER_ID, CFG_ID); + } + + @Override + protected VppClassifier convert(final VppClassifierState operationalData) { + final VppClassifierBuilder builder = new VppClassifierBuilder(); + builder.setClassifyTable(operationalData.getClassifyTable().stream() + .map(oper -> new ClassifyTableBuilder(oper).setName(oper.getName()).build()) + .collect(Collectors.toList())); + return builder.build(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializer.java new file mode 100644 index 000000000..370de347b --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializer.java @@ -0,0 +1,97 @@ +/* + * 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.translate.v3po.initializers; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import io.fd.honeycomb.data.init.AbstractDataTreeConverter; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Initializes vpp node in config data tree based on operational state. + */ +public class VppInitializer extends AbstractDataTreeConverter { + private static final Logger LOG = LoggerFactory.getLogger(VppInitializer.class); + + public VppInitializer(@Nonnull final DataBroker bindingDataBroker) { + 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()"); + + VppBuilder vppBuilder = new VppBuilder(); + BridgeDomainsBuilder bdsBuilder = new BridgeDomainsBuilder(); + bdsBuilder.setBridgeDomain(Lists.transform(operationalData.getBridgeDomains().getBridgeDomain(), CONVERT_BD)); + vppBuilder.setBridgeDomains(bdsBuilder.build()); + return vppBuilder.build(); + } + + private static final Function + CONVERT_BD = + new Function() { + @Nullable + @Override + public BridgeDomain apply( + @Nullable final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain input) { + final BridgeDomainBuilder builder = new BridgeDomainBuilder(); + builder.setLearn(input.isLearn()); + builder.setUnknownUnicastFlood(input.isUnknownUnicastFlood()); + builder.setArpTermination(input.isArpTermination()); + builder.setFlood(input.isFlood()); + builder.setForward(input.isForward()); + builder.setKey(new BridgeDomainKey(input.getKey().getName())); + builder.setName(input.getName()); + setL2FibTable(builder, input.getL2FibTable()); + return builder.build(); + } + }; + + private static void setL2FibTable(@Nonnull final BridgeDomainBuilder builder, + @Nullable final L2FibTable l2FibTable) { + if (l2FibTable == null) { + return; + } + final L2FibTableBuilder tableBuilder = new L2FibTableBuilder() + .setL2FibEntry( + l2FibTable.getL2FibEntry().stream() + // Convert operational object to config. VPP does not support setting BVI (see v3po.yang) + .map(oper -> new L2FibEntryBuilder(oper).setBridgedVirtualInterface(null).build()) + .collect(Collectors.toList())); + builder.setL2FibTable(tableBuilder.build()); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java new file mode 100644 index 000000000..c292073e3 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizer.java @@ -0,0 +1,91 @@ +/* + * 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.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for enabling/disabling ACLs on given interface. + */ +public class AclCustomizer extends FutureJVppCustomizer implements WriterCustomizer, AclWriter { + + private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class); + private final NamingContext interfaceContext; + private final NamingContext classifyTableContext; + + public AclCustomizer(@Nonnull final FutureJVpp vppApi, @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext classifyTableContext) { + super(vppApi); + this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); + this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + try { + setAcl(true, id, dataAfter, writeContext); + } catch (VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, + @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + throw new UnsupportedOperationException("Acl update is not supported. Please delete Acl container first."); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + try { + setAcl(false, id, dataBefore, writeContext); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier id, @Nonnull final Acl acl, + @Nonnull final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + final String ifName = id.firstKeyOf(Interface.class).getName(); + final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext()); + + LOG.debug("Setting ACL(isAdd={}) on interface={}(id={}): {}", isAdd, ifName, ifIndex, acl); + + inputAclSetInterface(getFutureJVpp(), isAdd, id, acl, ifIndex, classifyTableContext, + writeContext.getMappingContext()); + LOG.debug("Successfully set ACL(isAdd={}) on interface={}(id={}): {}", isAdd, ifName, ifIndex, acl); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclWriter.java new file mode 100644 index 000000000..1d538ac3f --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/AclWriter.java @@ -0,0 +1,74 @@ +/* + * 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.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.AclBaseAttributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.InputAclSetInterface; +import org.openvpp.jvpp.dto.InputAclSetInterfaceReply; +import org.openvpp.jvpp.future.FutureJVpp; + +interface AclWriter { + + default void inputAclSetInterface(@Nonnull final FutureJVpp futureJvpp, final boolean isAdd, + @Nonnull final InstanceIdentifier id, @Nonnull final AclBaseAttributes acl, + @Nonnegative final int ifIndex, @Nonnull final NamingContext classifyTableContext, + @Nonnull final MappingContext mappingContext) + throws VppBaseCallException, WriteTimeoutException { + final InputAclSetInterface request = new InputAclSetInterface(); + request.isAdd = booleanToByte(isAdd); + request.swIfIndex = ifIndex; + request.l2TableIndex = ~0; // skip + request.ip4TableIndex = ~0; // skip + request.ip6TableIndex = ~0; // skip + + final L2Acl l2Acl = acl.getL2Acl(); + if (l2Acl != null) { + final String tableName = checkNotNull(l2Acl.getClassifyTable(), "L2 classify table is null"); + request.l2TableIndex = classifyTableContext.getIndex(tableName, mappingContext); + } + final Ip4Acl ip4Acl = acl.getIp4Acl(); + if (ip4Acl != null) { + final String tableName = checkNotNull(ip4Acl.getClassifyTable(), "IPv4 classify table is null"); + request.ip4TableIndex = classifyTableContext.getIndex(tableName, mappingContext); + } + final Ip6Acl ip6Acl = acl.getIp6Acl(); + if (ip6Acl != null) { + final String tableName = checkNotNull(ip6Acl.getClassifyTable(), "IPv6 classify table is null"); + request.ip6TableIndex = classifyTableContext.getIndex(tableName, mappingContext); + } + + final CompletionStage inputAclSetInterfaceReplyCompletionStage = + futureJvpp.inputAclSetInterface(request); + + TranslateUtils.getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/EthernetCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/EthernetCustomizer.java new file mode 100644 index 000000000..2dd0dbd00 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/EthernetCustomizer.java @@ -0,0 +1,61 @@ +/* + * 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.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EthernetCustomizer extends FutureJVppCustomizer implements WriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(EthernetCustomizer.class); + + public EthernetCustomizer(final FutureJVpp vppApi) { + super(vppApi); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ethernet dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + // TODO + LOG.warn("Unsupported, ignoring configuration {}", dataAfter); + // VPP API does not support setting MTU + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ethernet dataBefore, @Nonnull final Ethernet dataAfter, + @Nonnull final WriteContext writeContext) { + // TODO + LOG.warn("Unsupported, ignoring configuration {}", dataAfter); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ethernet dataBefore, @Nonnull final WriteContext writeContext) { + // TODO + LOG.warn("Unsupported, ignoring configuration delete {}", id); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterconnectionWriteUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterconnectionWriteUtils.java new file mode 100644 index 000000000..ecaaa4717 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterconnectionWriteUtils.java @@ -0,0 +1,175 @@ +/* + * 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.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; + +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBased; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBased; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceSetL2Bridge; +import org.openvpp.jvpp.dto.SwInterfaceSetL2BridgeReply; +import org.openvpp.jvpp.dto.SwInterfaceSetL2Xconnect; +import org.openvpp.jvpp.dto.SwInterfaceSetL2XconnectReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class providing Interconnection CUD support. + */ +final class InterconnectionWriteUtils { + + private static final Logger LOG = LoggerFactory.getLogger(InterconnectionWriteUtils.class); + + private final FutureJVpp futureJvpp; + private final NamingContext interfaceContext; + private final NamingContext bridgeDomainContext; + + InterconnectionWriteUtils(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext bridgeDomainContext) { + this.futureJvpp = requireNonNull(futureJvpp, "futureJvpp should not be null"); + this.interfaceContext = requireNonNull(interfaceContext, "interfaceContext should not be null"); + this.bridgeDomainContext = requireNonNull(bridgeDomainContext, "bridgeDomainContext should not be null"); + } + + void setInterconnection(final InstanceIdentifier id, final int swIfIndex, + final String ifcName, final Interconnection ic, final WriteContext writeContext) + throws WriteFailedException { + try { + if (ic == null) { // TODO in case of update we should delete interconnection + LOG.trace("Interconnection is not set. Skipping"); + } else if (ic instanceof XconnectBased) { + setXconnectBasedL2(id, swIfIndex, ifcName, (XconnectBased) ic, writeContext, (byte) 1 /*enable*/); + } else if (ic instanceof BridgeBased) { + setBridgeBasedL2(id, swIfIndex, ifcName, (BridgeBased) ic, writeContext, (byte) 1 /*enable*/); + } else { + // FIXME how does choice extensibility work + // FIXME it is not even possible to create a dedicated customizer for Interconnection, since it's not a DataObject + // FIXME we might need a choice customizer + // THis choice is already from augment, so its probably not possible to augment augmented choice + LOG.error("Unable to handle Interconnection of type {}", ic.getClass()); + throw new WriteFailedException(id, "Unable to handle Interconnection of type " + ic.getClass()); + } + } catch (VppBaseCallException e) { + LOG.warn("Failed to update bridge/xconnect based interconnection flags for: {}, interconnection: {}", + ifcName, ic); + throw new WriteFailedException(id, "Unable to handle Interconnection of type " + ic.getClass(), e); + } + } + + void deleteInterconnection(final InstanceIdentifier id, final int swIfIndex, + final String ifcName, final Interconnection ic, final WriteContext writeContext) + throws WriteFailedException { + try { + if (ic == null) { // TODO in case of update we should delete interconnection + LOG.trace("Interconnection is not set. Skipping"); + } else if (ic instanceof XconnectBased) { + setXconnectBasedL2(id, swIfIndex, ifcName, (XconnectBased) ic, writeContext, (byte) 0 /*disable*/); + } else if (ic instanceof BridgeBased) { + setBridgeBasedL2(id, swIfIndex, ifcName, (BridgeBased) ic, writeContext, (byte) 0 /*disable*/); + } else { + LOG.error("Unable to delete Interconnection of type {}", ic.getClass()); + throw new WriteFailedException(id, "Unable to delete Interconnection of type " + ic.getClass()); + } + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete bridge/xconnect based interconnection flags for: {}, interconnection: {}", + ifcName, ic); + throw new WriteFailedException(id, "Unable to delete Interconnection of type " + ic.getClass(), e); + } + } + + private void setBridgeBasedL2(final InstanceIdentifier id, final int swIfIndex, + final String ifcName, final BridgeBased bb, + final WriteContext writeContext, final byte enabled) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Setting bridge based interconnection(bridge-domain={}) for interface: {}", bb.getBridgeDomain(), + ifcName); + + String bdName = bb.getBridgeDomain(); + + int bdId = bridgeDomainContext.getIndex(bdName, writeContext.getMappingContext()); + checkArgument(bdId > 0, "Unable to set Interconnection for Interface: %s, bridge domain: %s does not exist", + ifcName, bdName); + + byte bvi = bb.isBridgedVirtualInterface() + ? (byte) 1 + : (byte) 0; + byte shg = 0; + if (bb.getSplitHorizonGroup() != null) { + shg = bb.getSplitHorizonGroup().byteValue(); + } + + final CompletionStage swInterfaceSetL2BridgeReplyCompletionStage = futureJvpp + .swInterfaceSetL2Bridge(getL2BridgeRequest(swIfIndex, bdId, shg, bvi, enabled)); + TranslateUtils.getReplyForWrite(swInterfaceSetL2BridgeReplyCompletionStage.toCompletableFuture(), id); + + LOG.debug("Bridge based interconnection updated successfully for: {}, interconnection: {}", ifcName, bb); + } + + private SwInterfaceSetL2Bridge getL2BridgeRequest(final int swIfIndex, final int bdId, final byte shg, + final byte bvi, final byte enabled) { + final SwInterfaceSetL2Bridge swInterfaceSetL2Bridge = new SwInterfaceSetL2Bridge(); + swInterfaceSetL2Bridge.rxSwIfIndex = swIfIndex; + swInterfaceSetL2Bridge.bdId = bdId; + swInterfaceSetL2Bridge.shg = shg; + swInterfaceSetL2Bridge.bvi = bvi; + swInterfaceSetL2Bridge.enable = enabled; + return swInterfaceSetL2Bridge; + } + + private void setXconnectBasedL2(final InstanceIdentifier id, final int swIfIndex, + final String ifcName, final XconnectBased ic, + final WriteContext writeContext, final byte enabled) + throws VppBaseCallException, WriteTimeoutException { + String outSwIfName = ic.getXconnectOutgoingInterface(); + LOG.debug("Setting xconnect based interconnection(outgoing ifc={}) for interface: {}", outSwIfName, ifcName); + + int outSwIfIndex = interfaceContext.getIndex(outSwIfName, writeContext.getMappingContext()); + checkArgument(outSwIfIndex > 0, + "Unable to set Interconnection for Interface: %s, outgoing interface: %s does not exist", + ifcName, outSwIfIndex); + + final CompletionStage swInterfaceSetL2XconnectReplyCompletionStage = + futureJvpp + .swInterfaceSetL2Xconnect(getL2XConnectRequest(swIfIndex, outSwIfIndex, enabled)); + TranslateUtils.getReplyForWrite(swInterfaceSetL2XconnectReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Xconnect based interconnection updated successfully for: {}, interconnection: {}", ifcName, ic); + } + + private SwInterfaceSetL2Xconnect getL2XConnectRequest(final int rxIfc, final int txIfc, + final byte enabled) { + + final SwInterfaceSetL2Xconnect swInterfaceSetL2Xconnect = new SwInterfaceSetL2Xconnect(); + swInterfaceSetL2Xconnect.enable = enabled; + swInterfaceSetL2Xconnect.rxSwIfIndex = rxIfc; + swInterfaceSetL2Xconnect.txSwIfIndex = txIfc; + return swInterfaceSetL2Xconnect; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizer.java new file mode 100644 index 000000000..1bad2cdca --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceCustomizer.java @@ -0,0 +1,132 @@ +/* + * 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.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceSetFlags; +import org.openvpp.jvpp.dto.SwInterfaceSetFlagsReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Ietf interface write customizer that only caches interface objects for child writers + */ +public class InterfaceCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class); + private final NamingContext interfaceContext; + + public InterfaceCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Interface dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + + try { + setInterface(id, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Update of VppInterfaceAugment failed", 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 { + + try { + updateInterface(id, dataBefore, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Update of VppInterfaceAugment failed", e); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Interface dataBefore, + @Nonnull final WriteContext writeContext) { + + // TODO Handle deletes + } + + private void setInterface(final InstanceIdentifier id, final Interface swIf, + final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Setting interface: {} to: {}", id, swIf); + setInterfaceAttributes(id, swIf, swIf.getName(), writeContext); + } + + private void setInterfaceAttributes(final InstanceIdentifier id, final Interface swIf, + final String swIfName, final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + + setInterfaceFlags(id, swIfName, interfaceContext.getIndex(swIfName, writeContext.getMappingContext()), + swIf.isEnabled() ? (byte) 1 : (byte) 0); + } + + private void updateInterface(final InstanceIdentifier id, + final Interface dataBefore, + final Interface dataAfter, final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Updating interface:{} to: {}", id, dataAfter); + setInterfaceAttributes(id, dataAfter, dataAfter.getName(), writeContext); + } + + private void setInterfaceFlags(final InstanceIdentifier id, final String swIfName, final int swIfIndex, + final byte enabled) + throws VppBaseCallException, WriteTimeoutException { + final CompletionStage swInterfaceSetFlagsReplyFuture = getFutureJVpp().swInterfaceSetFlags( + getSwInterfaceSetFlagsInput(swIfIndex, enabled, (byte) 0 /* deleted */)); + + LOG.debug("Updating interface flags for: {}, index: {}, enabled: {}", swIfName, swIfIndex, enabled); + + TranslateUtils.getReplyForWrite(swInterfaceSetFlagsReplyFuture.toCompletableFuture(), id); + LOG.debug("Interface flags updated successfully for: {}, index: {}, enabled: {}", + swIfName, swIfIndex, enabled); + } + + private SwInterfaceSetFlags getSwInterfaceSetFlagsInput(final int swIfIndex, final byte enabled, final byte deleted) { + final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags(); + swInterfaceSetFlags.swIfIndex = swIfIndex; + swInterfaceSetFlags.adminUpDown = enabled; + swInterfaceSetFlags.linkUpDown = enabled; + swInterfaceSetFlags.deleted = deleted; + return swInterfaceSetFlags; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/L2Customizer.java new file mode 100644 index 000000000..881c82b53 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/L2Customizer.java @@ -0,0 +1,89 @@ +/* + * 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.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class L2Customizer extends FutureJVppCustomizer implements WriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class); + private final NamingContext interfaceContext; + private final InterconnectionWriteUtils icWriteUtils; + + public L2Customizer(final FutureJVpp vppApi, final NamingContext interfaceContext, + final NamingContext bridgeDomainContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + this.icWriteUtils = new InterconnectionWriteUtils(vppApi, interfaceContext, bridgeDomainContext); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + + final String ifcName = id.firstKeyOf(Interface.class).getName(); + final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); + setL2(id, swIfc, ifcName, dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, + @Nonnull final L2 dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + + final String ifcName = id.firstKeyOf(Interface.class).getName(); + final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); + // TODO handle update properly (if possible) + setL2(id, swIfc, ifcName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + final String ifcName = id.firstKeyOf(Interface.class).getName(); + final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); + deleteL2(id, swIfc, ifcName, dataBefore, writeContext); + } + + private void setL2(final InstanceIdentifier id, final int swIfIndex, final String ifcName, final L2 l2, + final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Setting L2 for interface: {}", ifcName); + // Nothing besides interconnection here + icWriteUtils.setInterconnection(id, swIfIndex, ifcName, l2.getInterconnection(), writeContext); + } + + private void deleteL2(final InstanceIdentifier id, final int swIfIndex, final String ifcName, final L2 l2Before, + final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Deleting L2 for interface: {}", ifcName); + // Nothing besides interconnection here + icWriteUtils.deleteInterconnection(id, swIfIndex, ifcName, l2Before.getInterconnection(), writeContext); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizer.java new file mode 100644 index 000000000..86af47709 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizer.java @@ -0,0 +1,154 @@ +/* + * 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.translate.v3po.interfaces; + +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import io.fd.honeycomb.translate.v3po.util.TagRewriteOperation; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.List; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1q; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTags; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewrite; +import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writer Customizer responsible for vlan tag rewrite.
Sends {@code l2_interface_vlan_tag_rewrite} message to + * VPP.
Equivalent of invoking {@code vppctl set interface l2 tag-rewrite} command. + */ +public class RewriteCustomizer extends FutureJVppCustomizer implements WriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(RewriteCustomizer.class); + private final NamingContext interfaceContext; + + public RewriteCustomizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void writeCurrentAttributes(final InstanceIdentifier id, final Rewrite dataAfter, + final WriteContext writeContext) + throws WriteFailedException { + final String subifName = getSubInterfaceName(id); + try { + setTagRewrite(id, subifName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to write interface {}(id=): {}", subifName, writeContext, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + private static String getSubInterfaceName(final InstanceIdentifier id) { + return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), + Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier())); + } + + private void setTagRewrite(final InstanceIdentifier id, final String ifname, final Rewrite rewrite, + final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + final int swIfIndex = interfaceContext.getIndex(ifname, writeContext.getMappingContext()); + LOG.debug("Setting tag rewrite for interface {}(id=): {}", ifname, swIfIndex, rewrite); + + final CompletionStage replyCompletionStage = + getFutureJVpp().l2InterfaceVlanTagRewrite(getTagRewriteRequest(swIfIndex, rewrite)); + + TranslateUtils.getReplyForWrite(replyCompletionStage.toCompletableFuture(), id); + LOG.debug("Tag rewrite for interface {}(id=) set successfully: {}", ifname, swIfIndex, rewrite); + } + + private L2InterfaceVlanTagRewrite getTagRewriteRequest(final int swIfIndex, final Rewrite rewrite) { + final L2InterfaceVlanTagRewrite request = new L2InterfaceVlanTagRewrite(); + request.swIfIndex = swIfIndex; + request.pushDot1Q = booleanToByte(_802dot1q.class == rewrite.getVlanType()); + + final List pushTags = rewrite.getPushTags(); + final Short popTags = rewrite.getPopTags(); + + final int numberOfTagsToPop = popTags == null + ? 0 + : popTags.intValue(); + final int numberOfTagsToPush = pushTags == null + ? 0 + : pushTags.size(); + + request.vtrOp = TagRewriteOperation.get(numberOfTagsToPop, numberOfTagsToPush).ordinal(); + + if (numberOfTagsToPush > 0) { + for (final PushTags tag : pushTags) { + if (tag.getIndex() == 0) { + request.tag1 = tag.getDot1qTag().getVlanId().getValue(); + } else { + request.tag2 = tag.getDot1qTag().getVlanId().getValue(); + } + } + } + + LOG.debug("Generated tag rewrite request: {}", ReflectionToStringBuilder.toString(request)); + return request; + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Rewrite dataBefore, + @Nonnull final Rewrite dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String subifName = getSubInterfaceName(id); + try { + setTagRewrite(id, subifName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to update interface {}(id=): {}", subifName, writeContext, dataAfter); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Rewrite dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String subifName = getSubInterfaceName(id); + try { + LOG.debug("Disabling tag rewrite for interface {}", subifName); + final Rewrite rewrite = new RewriteBuilder().build(); // rewrite without push and pops will cause delete + setTagRewrite(id, subifName, rewrite, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete interface {}(id=): {}", subifName, writeContext, dataBefore); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizer.java new file mode 100644 index 000000000..fe7b7263e --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/RoutingCustomizer.java @@ -0,0 +1,108 @@ +/* + * 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.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Routing; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceSetTable; +import org.openvpp.jvpp.dto.SwInterfaceSetTableReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RoutingCustomizer extends FutureJVppCustomizer implements WriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(RoutingCustomizer.class); + private final NamingContext interfaceContext; + + public RoutingCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Routing dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + + final String ifName = id.firstKeyOf(Interface.class).getName(); + try { + setRouting(id, ifName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set routing for interface: {}, {}, vxlan: {}", ifName, writeContext, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Routing dataBefore, @Nonnull final Routing dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + + final String ifName = id.firstKeyOf(Interface.class).getName(); + try { + // TODO handle updates properly + setRouting(id, ifName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to update routing for interface: {}, {}, vxlan: {}", ifName, writeContext, dataAfter); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Routing dataBefore, @Nonnull final WriteContext writeContext) { + // TODO implement delete + } + + private void setRouting(final InstanceIdentifier id, final String name, final Routing rt, + final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException { + final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext()); + LOG.debug("Setting routing for interface: {}, {}. Routing: {}", name, swIfc, rt); + + int vrfId = (rt != null) + ? rt.getVrfId().intValue() + : 0; + + if (vrfId != 0) { + final CompletionStage swInterfaceSetTableReplyCompletionStage = + getFutureJVpp().swInterfaceSetTable(getInterfaceSetTableRequest(swIfc, (byte) 0, /* isIpv6 */ vrfId)); + TranslateUtils.getReplyForWrite(swInterfaceSetTableReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Routing set successfully for interface: {}, {}, routing: {}", name, swIfc, rt); + } + } + + private SwInterfaceSetTable getInterfaceSetTableRequest(final int swIfc, final byte isIpv6, final int vrfId) { + final SwInterfaceSetTable swInterfaceSetTable = new SwInterfaceSetTable(); + swInterfaceSetTable.isIpv6 = isIpv6; + swInterfaceSetTable.swIfIndex = swIfc; + swInterfaceSetTable.vrfId = vrfId; + return swInterfaceSetTable; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java new file mode 100644 index 000000000..45b2a480d --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java @@ -0,0 +1,100 @@ +/* + * 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.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for enabling/disabling ACLs on given sub-interface. + */ +public class SubInterfaceAclCustomizer extends FutureJVppCustomizer + implements WriterCustomizer, AclWriter { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class); + private final NamingContext interfaceContext; + private final NamingContext classifyTableContext; + + public SubInterfaceAclCustomizer(@Nonnull final FutureJVpp vppApi, @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext classifyTableContext) { + super(vppApi); + this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); + this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + try { + setAcl(true, id, dataAfter, writeContext); + } catch (VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, + @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + throw new UnsupportedOperationException("Acl update is not supported. Please delete Acl container first."); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + try { + setAcl(false, id, dataBefore, writeContext); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier id, @Nonnull final Acl acl, + @Nonnull final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); + final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); + final String subInterfaceName = SubInterfaceUtils + .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); + + LOG.debug("Setting ACL(isAdd={}) on sub-interface={}(id={}): {}", + isAdd, subInterfaceName, subInterfaceIndex, acl); + inputAclSetInterface(getFutureJVpp(), isAdd, id, acl, subInterfaceIndex, classifyTableContext, + writeContext.getMappingContext()); + LOG.debug("Successfully set ACL(isAdd={}) on sub-interface={}(id={}): {}", + isAdd, subInterfaceName, subInterfaceIndex, acl); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java new file mode 100644 index 000000000..6af19cb89 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java @@ -0,0 +1,223 @@ +/* + * 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.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1ad; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.MatchType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.Default; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.vlan.tagged.VlanTagged; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.CreateSubif; +import org.openvpp.jvpp.dto.CreateSubifReply; +import org.openvpp.jvpp.dto.SwInterfaceSetFlags; +import org.openvpp.jvpp.dto.SwInterfaceSetFlagsReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writer Customizer responsible for sub interface creation.
Sends {@code create_subif} message to VPP.
+ * Equivalent of invoking {@code vppclt create subif} command. + */ +public class SubInterfaceCustomizer extends FutureJVppCustomizer + implements ListWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceCustomizer.class); + private final NamingContext interfaceContext; + + public SubInterfaceCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final SubInterface dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String superIfName = id.firstKeyOf(Interface.class).getName(); + try { + createSubInterface(id, superIfName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to create sub interface for: {}, subInterface: {}", superIfName, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + private void createSubInterface(final InstanceIdentifier id, @Nonnull final String superIfName, + @Nonnull final SubInterface subInterface, + final WriteContext writeContext) throws VppBaseCallException, + WriteTimeoutException { + final int superIfIndex = interfaceContext.getIndex(superIfName, writeContext.getMappingContext()); + final CompletionStage createSubifReplyCompletionStage = + getFutureJVpp().createSubif(getCreateSubifRequest(subInterface, superIfIndex)); + + final CreateSubifReply reply = + TranslateUtils.getReplyForWrite(createSubifReplyCompletionStage.toCompletableFuture(), id); + + setInterfaceState(id, reply.swIfIndex, booleanToByte(subInterface.isEnabled())); + interfaceContext.addName(reply.swIfIndex, + getSubInterfaceName(superIfName, Math.toIntExact(subInterface.getIdentifier())), + writeContext.getMappingContext()); + LOG.debug("Sub interface created successfully for: {}, subInterface: {}", superIfName, subInterface); + } + + private CreateSubif getCreateSubifRequest(@Nonnull final SubInterface subInterface, final int swIfIndex) { + // TODO add validation + CreateSubif request = new CreateSubif(); + request.subId = Math.toIntExact(subInterface.getIdentifier().intValue()); + request.swIfIndex = swIfIndex; + + final int numberOfTags = getNumberOfTags(subInterface); + switch (numberOfTags) { + case 0: + request.noTags = 1; + break; + case 1: + request.oneTag = 1; + break; + case 2: + request.twoTags = 1; + break; + } + request.dot1Ad = booleanToByte(_802dot1ad.class == subInterface.getVlanType()); + + final MatchType matchType = subInterface.getMatch().getMatchType(); // todo match should be mandatory + request.exactMatch = + booleanToByte(matchType instanceof VlanTagged && ((VlanTagged) matchType).isMatchExactTags()); + request.defaultSub = booleanToByte(matchType instanceof Default); + + if (numberOfTags > 0) { + for (final Tag tag : subInterface.getTags().getTag()) { + if (tag.getIndex() == 0) { + setOuterTag(request, tag); + } else if (tag.getIndex() == 1) { + setInnerTag(request, tag); + } + } + } + return request; + } + + private void setOuterTag(final CreateSubif request, final Tag outerTag) { + checkState(SVlan.class == outerTag.getDot1qTag().getTagType(), "Service Tag expected at index 0"); + final Dot1qTag.VlanId vlanId = outerTag.getDot1qTag().getVlanId(); + + request.outerVlanId = dot1qVlanIdToShort(vlanId.getDot1qVlanId()); + request.outerVlanIdAny = booleanToByte(Dot1qTag.VlanId.Enumeration.Any.equals(vlanId.getEnumeration())); + } + + private void setInnerTag(final CreateSubif request, final Tag innerTag) { + checkState(CVlan.class == innerTag.getDot1qTag().getTagType(), "Customer Tag expected at index 1"); + final Dot1qTag.VlanId vlanId = innerTag.getDot1qTag().getVlanId(); + + request.innerVlanId = dot1qVlanIdToShort(vlanId.getDot1qVlanId()); + request.innerVlanIdAny = booleanToByte(Dot1qTag.VlanId.Enumeration.Any.equals(vlanId.getEnumeration())); + } + + private static int getNumberOfTags(@Nonnull final SubInterface subInterface) { + final Tags tags = subInterface.getTags(); + if (tags == null) { + return 0; + } + final List tagList = tags.getTag(); + if (tagList == null) { + return 0; + } + return tagList.size(); + } + + private static short dot1qVlanIdToShort(@Nullable Dot1qVlanId dot1qVlanId) { + if (dot1qVlanId == null) { + return 0; // tell VPP that optional argument is missing + } else { + return dot1qVlanId.getValue().shortValue(); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final SubInterface dataBefore, @Nonnull final SubInterface dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + if (Objects.equals(dataBefore.isEnabled(), dataAfter.isEnabled())) { + LOG.debug("No state update will be performed. Ignoring config"); + return; // TODO shouldn't we throw exception here (if there will be dedicated L2 customizer)? + } + final String subIfaceName = getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), + Math.toIntExact(dataAfter.getIdentifier())); + try { + setInterfaceState(id, interfaceContext.getIndex(subIfaceName, writeContext.getMappingContext()), + booleanToByte(dataAfter.isEnabled())); + } catch (VppBaseCallException e) { + LOG.warn("Failed to update interface state for: interface if={}, enabled: {}", + subIfaceName, booleanToByte(dataAfter.isEnabled())); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + private void setInterfaceState(final InstanceIdentifier id, final int swIfIndex, final byte enabled) + throws VppBaseCallException, WriteTimeoutException { + final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags(); + swInterfaceSetFlags.swIfIndex = swIfIndex; + swInterfaceSetFlags.adminUpDown = enabled; + + final CompletionStage swInterfaceSetFlagsReplyFuture = + getFutureJVpp().swInterfaceSetFlags(swInterfaceSetFlags); + + LOG.debug("Updating interface state for interface if={}, enabled: {}", swIfIndex, enabled); + + SwInterfaceSetFlagsReply reply = + TranslateUtils.getReplyForWrite(swInterfaceSetFlagsReplyFuture.toCompletableFuture(), id); + LOG.debug("Interface state updated successfully for interface index: {}, enabled: {}, ctxId: {}", + swIfIndex, enabled, reply.context); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final SubInterface dataBefore, + @Nonnull final WriteContext writeContext) + throws WriteFailedException.DeleteFailedException { + throw new UnsupportedOperationException("Sub interface delete is not supported"); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2Customizer.java new file mode 100644 index 000000000..b420e73e3 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceL2Customizer.java @@ -0,0 +1,100 @@ +/* + * 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.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for writing vlan sub interface l2 configuration + */ +public class SubInterfaceL2Customizer extends FutureJVppCustomizer implements WriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceL2Customizer.class); + private final NamingContext interfaceContext; + private final InterconnectionWriteUtils icWriterUtils; + + public SubInterfaceL2Customizer(final FutureJVpp vppApi, final NamingContext interfaceContext, + final NamingContext bridgeDomainContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + this.icWriterUtils = new InterconnectionWriteUtils(vppApi, interfaceContext, bridgeDomainContext); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); + setL2(id, subInterfaceIndex, subInterfaceName, dataAfter, writeContext); + } + + private String getSubInterfaceName(@Nonnull final InstanceIdentifier id) { + final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); + final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); + return SubInterfaceUtils + .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, + @Nonnull final L2 dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); + // TODO handle update properly (if possible) + setL2(id, subInterfaceIndex, subInterfaceName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); + deleteL2(id, subInterfaceIndex, subInterfaceName, dataBefore, writeContext); + } + + private void setL2(final InstanceIdentifier id, final int swIfIndex, final String ifcName, final L2 l2, + final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Setting L2 for sub-interface: {}", ifcName); + icWriterUtils.setInterconnection(id, swIfIndex, ifcName, l2.getInterconnection(), writeContext); + } + + private void deleteL2(final InstanceIdentifier id, final int swIfIndex, final String ifcName, final L2 l2Before, + final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Deleting L2 for sub-interface: {}", ifcName); + icWriterUtils.deleteInterconnection(id, swIfIndex, ifcName, l2Before.getInterconnection(), writeContext); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizer.java new file mode 100644 index 000000000..b90e2c304 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizer.java @@ -0,0 +1,197 @@ +/* + * 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.translate.v3po.interfaces; + +import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Tap; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.TapConnect; +import org.openvpp.jvpp.dto.TapConnectReply; +import org.openvpp.jvpp.dto.TapDelete; +import org.openvpp.jvpp.dto.TapDeleteReply; +import org.openvpp.jvpp.dto.TapModify; +import org.openvpp.jvpp.dto.TapModifyReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TapCustomizer extends AbstractInterfaceTypeCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(TapCustomizer.class); + private final NamingContext interfaceContext; + + public TapCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + protected Class getExpectedInterfaceType() { + return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap.class; + } + + @Override + protected final void writeInterface(@Nonnull final InstanceIdentifier id, @Nonnull final Tap dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifcName = id.firstKeyOf(Interface.class).getName(); + try { + createTap(id, ifcName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set tap interface: {}, tap: {}", ifcName, dataAfter, e); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Tap dataBefore, + @Nonnull final Tap dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifcName = id.firstKeyOf(Interface.class).getName(); + + final int index; + try { + index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); + } catch (IllegalArgumentException e) { + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + + try { + modifyTap(id, ifcName, index, dataAfter); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set tap interface: {}, tap: {}", ifcName, dataAfter, e); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Tap dataBefore, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifcName = id.firstKeyOf(Interface.class).getName(); + + final int index; + try { + index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); + } catch (IllegalArgumentException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + + try { + deleteTap(id, ifcName, index, dataBefore, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete tap interface: {}, tap: {}", ifcName, dataBefore.getTapName(), e); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void createTap(final InstanceIdentifier id, final String swIfName, final Tap tap, + final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Setting tap interface: {}. Tap: {}", swIfName, tap); + final CompletionStage tapConnectFuture = + getFutureJVpp().tapConnect(getTapConnectRequest(tap.getTapName(), tap.getMac(), tap.getDeviceInstance())); + final TapConnectReply reply = + TranslateUtils.getReplyForWrite(tapConnectFuture.toCompletableFuture(), id); + LOG.debug("Tap set successfully for: {}, tap: {}", swIfName, tap); + // Add new interface to our interface context + interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); + } + + private void modifyTap(final InstanceIdentifier id, final String swIfName, final int index, final Tap tap) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Modifying tap interface: {}. Tap: {}", swIfName, tap); + final CompletionStage vxlanAddDelTunnelReplyCompletionStage = + getFutureJVpp().tapModify(getTapModifyRequest(tap.getTapName(), index, tap.getMac(), tap.getDeviceInstance())); + TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Tap modified successfully for: {}, tap: {}", swIfName, tap); + } + + private void deleteTap(final InstanceIdentifier id, final String swIfName, final int index, + final Tap dataBefore, + final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Deleting tap interface: {}. Tap: {}", swIfName, dataBefore); + final CompletionStage vxlanAddDelTunnelReplyCompletionStage = + getFutureJVpp().tapDelete(getTapDeleteRequest(index)); + TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Tap deleted successfully for: {}, tap: {}", swIfName, dataBefore); + // Remove deleted interface from interface context + interfaceContext.removeName(swIfName, writeContext.getMappingContext()); + } + + private TapConnect getTapConnectRequest(final String tapName, final PhysAddress mac, final Long deviceInstance) { + final TapConnect tapConnect = new TapConnect(); + tapConnect.tapName = tapName.getBytes(); + + if(mac == null) { + tapConnect.useRandomMac = 1; + tapConnect.macAddress = new byte[6]; + } else { + tapConnect.useRandomMac = 0; + tapConnect.macAddress = TranslateUtils.parseMac(mac.getValue()); + } + + if(deviceInstance == null) { + tapConnect.renumber = 0; + } else { + tapConnect.renumber = 1; + tapConnect.customDevInstance = Math.toIntExact(deviceInstance); + } + + return tapConnect; + } + + private TapModify getTapModifyRequest(final String tapName, final int swIndex, final PhysAddress mac, final Long deviceInstance) { + final TapModify tapConnect = new TapModify(); + tapConnect.tapName = tapName.getBytes(); + tapConnect.swIfIndex = swIndex; + + if(mac == null) { + tapConnect.useRandomMac = 1; + tapConnect.macAddress = new byte[6]; + } else { + tapConnect.useRandomMac = 0; + tapConnect.macAddress = TranslateUtils.parseMac(mac.getValue()); + } + + if(deviceInstance == null) { + tapConnect.renumber = 0; + } else { + tapConnect.renumber = 1; + tapConnect.customDevInstance = Math.toIntExact(deviceInstance); + } + + return tapConnect; + } + + private TapDelete getTapDeleteRequest(final int swIndex) { + final TapDelete tapConnect = new TapDelete(); + tapConnect.swIfIndex = swIndex; + return tapConnect; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizer.java new file mode 100644 index 000000000..6f30b41c5 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizer.java @@ -0,0 +1,167 @@ +/* + * 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.translate.v3po.interfaces; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.CreateVhostUserIf; +import org.openvpp.jvpp.dto.CreateVhostUserIfReply; +import org.openvpp.jvpp.dto.DeleteVhostUserIf; +import org.openvpp.jvpp.dto.DeleteVhostUserIfReply; +import org.openvpp.jvpp.dto.ModifyVhostUserIf; +import org.openvpp.jvpp.dto.ModifyVhostUserIfReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writer Customizer responsible for passing vhost user interface CRD operations to VPP + */ +public class VhostUserCustomizer extends AbstractInterfaceTypeCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(VhostUserCustomizer.class); + private final NamingContext interfaceContext; + + public VhostUserCustomizer(@Nonnull final FutureJVpp vppApi, @Nonnull final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + protected Class getExpectedInterfaceType() { + return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class; + } + + @Override + protected final void writeInterface(@Nonnull final InstanceIdentifier id, + @Nonnull final VhostUser dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + try { + createVhostUserIf(id, swIfName, dataAfter, writeContext); + } catch (VppBaseCallException | IllegalInterfaceTypeException e) { + LOG.debug("Failed to create vhost user interface: {}, vhostUser: {}", swIfName, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + private void createVhostUserIf(final InstanceIdentifier id, final String swIfName, + final VhostUser vhostUser, final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Creating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser); + + final CompletionStage createVhostUserIfReplyCompletionStage = + getFutureJVpp().createVhostUserIf(getCreateVhostUserIfRequest(vhostUser)); + final CreateVhostUserIfReply reply = + TranslateUtils.getReplyForWrite(createVhostUserIfReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Vhost user interface created successfully for: {}, vhostUser: {}", swIfName, vhostUser); + // Add new interface to our interface context + interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); + } + + private CreateVhostUserIf getCreateVhostUserIfRequest(final VhostUser vhostUser) { + CreateVhostUserIf request = new CreateVhostUserIf(); + request.isServer = TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())); + request.sockFilename = vhostUser.getSocket().getBytes(); + request.renumber = 0; // TODO + request.customDevInstance = 0; // TODO + request.useCustomMac = 0; + request.macAddress = new byte[]{}; + return request; + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VhostUser dataBefore, @Nonnull final VhostUser dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + try { + modifyVhostUserIf(id, swIfName, dataAfter, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to update vhost user interface: {}, vhostUser: {}", swIfName, dataAfter); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + + private void modifyVhostUserIf(final InstanceIdentifier id, final String swIfName, + final VhostUser vhostUser, final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Updating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser); + final CompletionStage modifyVhostUserIfReplyCompletionStage = + getFutureJVpp() + .modifyVhostUserIf(getModifyVhostUserIfRequest(vhostUser, interfaceContext.getIndex(swIfName, writeContext.getMappingContext()))); + + TranslateUtils.getReplyForWrite(modifyVhostUserIfReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Vhost user interface updated successfully for: {}, vhostUser: {}", swIfName, vhostUser); + } + + private ModifyVhostUserIf getModifyVhostUserIfRequest(final VhostUser vhostUser, final int swIfIndex) { + ModifyVhostUserIf request = new ModifyVhostUserIf(); + request.isServer = TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())); + request.sockFilename = vhostUser.getSocket().getBytes(); + request.renumber = 0; // TODO + request.customDevInstance = 0; // TODO + request.swIfIndex = swIfIndex; + return request; + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VhostUser dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + try { + deleteVhostUserIf(id, swIfName, dataBefore, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete vhost user interface: {}, vhostUser: {}", swIfName, dataBefore); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void deleteVhostUserIf(final InstanceIdentifier id, final String swIfName, + final VhostUser vhostUser, final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + LOG.debug("Deleting vhost user interface: name={}, vhostUser={}", swIfName, vhostUser); + final CompletionStage deleteVhostUserIfReplyCompletionStage = + getFutureJVpp().deleteVhostUserIf(getDeleteVhostUserIfRequest(interfaceContext.getIndex(swIfName, writeContext.getMappingContext()))); + + TranslateUtils.getReplyForWrite(deleteVhostUserIfReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Vhost user interface deleted successfully for: {}, vhostUser: {}", swIfName, vhostUser); + // Remove interface from our interface context + interfaceContext.removeName(swIfName, writeContext.getMappingContext()); + } + + private DeleteVhostUserIf getDeleteVhostUserIfRequest(final int swIfIndex) { + DeleteVhostUserIf request = new DeleteVhostUserIf(); + request.swIfIndex = swIfIndex; + return request; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java new file mode 100644 index 000000000..5b424449d --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizer.java @@ -0,0 +1,177 @@ +/* + * 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.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.net.InetAddresses; +import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.net.InetAddress; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.VxlanAddDelTunnel; +import org.openvpp.jvpp.dto.VxlanAddDelTunnelReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// TODO extract common code from all Interface type specific writer customizers into a superclass +public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class); + private final NamingContext interfaceContext; + + public VxlanCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + protected Class getExpectedInterfaceType() { + return VxlanTunnel.class; + } + + @Override + protected final void writeInterface(@Nonnull final InstanceIdentifier id, @Nonnull final Vxlan dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + try { + createVxlanTunnel(id, swIfName, dataAfter, writeContext); + } catch (VppBaseCallException | IllegalInterfaceTypeException e) { + LOG.debug("Failed to set vxlan tunnel for interface: {}, vxlan: {}", swIfName, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Vxlan dataBefore, + @Nonnull final Vxlan dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException.UpdateFailedException { + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("Vxlan tunnel update is not supported")); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Vxlan dataBefore, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + try { + deleteVxlanTunnel(id, swIfName, dataBefore, writeContext); + } catch (VppBaseCallException e) { + LOG.debug("Failed to delete vxlan tunnel for interface: {}, vxlan: {}", swIfName, dataBefore); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void createVxlanTunnel(final InstanceIdentifier id, final String swIfName, final Vxlan vxlan, + final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException { + final byte isIpv6 = (byte) (isIpv6(vxlan) ? 1 : 0); + final InetAddress srcAddress = InetAddresses.forString(getAddressString(vxlan.getSrc())); + final InetAddress dstAddress = InetAddresses.forString(getAddressString(vxlan.getDst())); + + int encapVrfId = vxlan.getEncapVrfId().intValue(); + int vni = vxlan.getVni().getValue().intValue(); + + LOG.debug("Setting vxlan tunnel for interface: {}. Vxlan: {}", swIfName, vxlan); + final CompletionStage vxlanAddDelTunnelReplyCompletionStage = + getFutureJVpp().vxlanAddDelTunnel(getVxlanTunnelRequest((byte) 1 /* is add */, srcAddress.getAddress(), + dstAddress.getAddress(), encapVrfId, -1, vni, isIpv6)); + + final VxlanAddDelTunnelReply reply = + TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Vxlan tunnel set successfully for: {}, vxlan: {}", swIfName, vxlan); + if(interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) { + // VPP keeps vxlan tunnels present even after they are delete(reserving ID for next tunnel) + // This may cause inconsistencies in mapping context when configuring tunnels like this: + // 1. Add tunnel 2. Delete tunnel 3. Read interfaces (reserved mapping e.g. vxlan_tunnel0 -> 6 + // will get into mapping context) 4. Add tunnel (this will add another mapping with the same + // reserved ID and context is invalid) + // That's why a check has to be performed here removing mapping vxlan_tunnel0 -> 6 mapping and storing + // new name for that ID + final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext()); + LOG.debug("Removing updated mapping of a vxlan tunnel, id: {}, former name: {}, new name: {}", + reply.swIfIndex, formerName, swIfName); + interfaceContext.removeName(formerName, writeContext.getMappingContext()); + } + // Add new interface to our interface context + interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); + } + + private boolean isIpv6(final Vxlan vxlan) { + if (vxlan.getSrc().getIpv4Address() == null) { + checkArgument(vxlan.getDst().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", vxlan.getSrc(), + vxlan.getDst()); + return true; + } else { + checkArgument(vxlan.getDst().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", vxlan.getSrc(), + vxlan.getDst()); + return false; + } + } + + private String getAddressString(final IpAddress addr) { + return addr.getIpv4Address() == null ? addr.getIpv6Address().getValue() : addr.getIpv4Address().getValue(); + } + + private void deleteVxlanTunnel(final InstanceIdentifier id, final String swIfName, final Vxlan vxlan, + final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException { + final byte isIpv6 = (byte) (isIpv6(vxlan) ? 1 : 0); + final InetAddress srcAddress = InetAddresses.forString(getAddressString(vxlan.getSrc())); + final InetAddress dstAddress = InetAddresses.forString(getAddressString(vxlan.getDst())); + + int encapVrfId = vxlan.getEncapVrfId().intValue(); + int vni = vxlan.getVni().getValue().intValue(); + + LOG.debug("Deleting vxlan tunnel for interface: {}. Vxlan: {}", swIfName, vxlan); + final CompletionStage vxlanAddDelTunnelReplyCompletionStage = + getFutureJVpp().vxlanAddDelTunnel(getVxlanTunnelRequest((byte) 0 /* is add */, srcAddress.getAddress(), + dstAddress.getAddress(), encapVrfId, -1, vni, isIpv6)); + + TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("Vxlan tunnel deleted successfully for: {}, vxlan: {}", swIfName, vxlan); + // Remove interface from our interface context + interfaceContext.removeName(swIfName, writeContext.getMappingContext()); + } + + private static VxlanAddDelTunnel getVxlanTunnelRequest(final byte isAdd, final byte[] srcAddr, final byte[] dstAddr, + final int encapVrfId, + final int decapNextIndex, final int vni, final byte isIpv6) { + final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel(); + vxlanAddDelTunnel.isAdd = isAdd; + vxlanAddDelTunnel.srcAddress = srcAddr; + vxlanAddDelTunnel.dstAddress = dstAddr; + vxlanAddDelTunnel.encapVrfId = encapVrfId; + vxlanAddDelTunnel.vni = vni; + vxlanAddDelTunnel.decapNextIndex = decapNextIndex; + vxlanAddDelTunnel.isIpv6 = isIpv6; + return vxlanAddDelTunnel; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java new file mode 100644 index 000000000..95ed55570 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizer.java @@ -0,0 +1,176 @@ +/* + * 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.translate.v3po.interfaces; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.net.InetAddresses; +import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.net.InetAddress; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpe; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnel; +import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnelReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VxlanGpeCustomizer extends AbstractInterfaceTypeCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class); + private final NamingContext interfaceContext; + + public VxlanGpeCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + protected Class getExpectedInterfaceType() { + return VxlanGpeTunnel.class; + } + + @Override + protected final void writeInterface(@Nonnull final InstanceIdentifier id, @Nonnull final VxlanGpe dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + try { + createVxlanGpeTunnel(id, swIfName, dataAfter, writeContext); + } catch (VppBaseCallException | IllegalInterfaceTypeException e) { + LOG.warn("Failed to set VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final VxlanGpe dataBefore, + @Nonnull final VxlanGpe dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException.UpdateFailedException { + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("VxlanGpe tunnel update is not supported")); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final VxlanGpe dataBefore, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String swIfName = id.firstKeyOf(Interface.class).getName(); + try { + deleteVxlanGpeTunnel(id, swIfName, dataBefore, writeContext); + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataBefore); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void createVxlanGpeTunnel(final InstanceIdentifier id, final String swIfName, + final VxlanGpe vxlanGpe, final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + final byte isIpv6 = (byte) (isIpv6(vxlanGpe) ? 1 : 0); + final InetAddress Local = InetAddresses.forString(getAddressString(vxlanGpe.getLocal())); + final InetAddress Remote = InetAddresses.forString(getAddressString(vxlanGpe.getRemote())); + + int vni = vxlanGpe.getVni().getValue().intValue(); + byte protocol = (byte) vxlanGpe.getNextProtocol().getIntValue(); + int encapVrfId = vxlanGpe.getEncapVrfId().intValue(); + int decapVrfId = vxlanGpe.getDecapVrfId().intValue(); + + LOG.debug("Setting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, vxlanGpe); + final CompletionStage VxlanGpeAddDelTunnelReplyCompletionStage = + getFutureJVpp().vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 1 /* is add */, Local.getAddress(), + Remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6)); + + final VxlanGpeAddDelTunnelReply reply = + TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("VxlanGpe tunnel set successfully for: {}, VxlanGpe: {}", swIfName, vxlanGpe); + if(interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) { + final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext()); + LOG.debug("Removing updated mapping of a vxlan-gpe tunnel, id: {}, former name: {}, new name: {}", + reply.swIfIndex, formerName, swIfName); + interfaceContext.removeName(formerName, writeContext.getMappingContext()); + } + // Add new interface to our interface context + interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); + } + + private boolean isIpv6(final VxlanGpe VxlanGpe) { + if (VxlanGpe.getLocal().getIpv4Address() == null) { + checkArgument(VxlanGpe.getRemote().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", VxlanGpe.getLocal(), + VxlanGpe.getRemote()); + return true; + } else { + checkArgument(VxlanGpe.getRemote().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", VxlanGpe.getLocal(), + VxlanGpe.getRemote()); + return false; + } + } + + private String getAddressString(final IpAddress addr) { + return addr.getIpv4Address() == null ? addr.getIpv6Address().getValue() : addr.getIpv4Address().getValue(); + } + + private void deleteVxlanGpeTunnel(final InstanceIdentifier id, final String swIfName, + final VxlanGpe VxlanGpe, final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + final byte isIpv6 = (byte) (isIpv6(VxlanGpe) ? 1 : 0); + final InetAddress local = InetAddresses.forString(getAddressString(VxlanGpe.getLocal())); + final InetAddress remote = InetAddresses.forString(getAddressString(VxlanGpe.getRemote())); + + int vni = VxlanGpe.getVni().getValue().intValue(); + byte protocol = (byte) VxlanGpe.getNextProtocol().getIntValue(); + int encapVrfId = VxlanGpe.getEncapVrfId().intValue(); + int decapVrfId = VxlanGpe.getDecapVrfId().intValue(); + + LOG.debug("Deleting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, VxlanGpe); + final CompletionStage VxlanGpeAddDelTunnelReplyCompletionStage = + getFutureJVpp().vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 0 /* is delete */, local.getAddress(), + remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6)); + + TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); + LOG.debug("VxlanGpe tunnel deleted successfully for: {}, VxlanGpe: {}", swIfName, VxlanGpe); + // Remove interface from our interface context + interfaceContext.removeName(swIfName, writeContext.getMappingContext()); + } + + private static VxlanGpeAddDelTunnel getVxlanGpeTunnelRequest(final byte isAdd, final byte[] local, final byte[] remote, + final int vni, final byte protocol, final int encapVrfId, final int decapVrfId, + final byte isIpv6) { + final VxlanGpeAddDelTunnel VxlanGpeAddDelTunnel = new VxlanGpeAddDelTunnel(); + VxlanGpeAddDelTunnel.isAdd = isAdd; + VxlanGpeAddDelTunnel.local = local; + VxlanGpeAddDelTunnel.remote = remote; + VxlanGpeAddDelTunnel.vni = vni; + VxlanGpeAddDelTunnel.protocol = protocol; + VxlanGpeAddDelTunnel.encapVrfId = encapVrfId; + VxlanGpeAddDelTunnel.decapVrfId = decapVrfId; + VxlanGpeAddDelTunnel.isIpv6 = isIpv6; + return VxlanGpeAddDelTunnel; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java new file mode 100644 index 000000000..74d546d65 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java @@ -0,0 +1,135 @@ +/* + * 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.translate.v3po.interfaces.ip; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for writing {@link Address} + */ +public class Ipv4AddressCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class); + private final NamingContext interfaceContext; + + public Ipv4AddressCustomizer(FutureJVpp futureJvpp, NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = interfaceContext; + } + + @Override + public void writeCurrentAttributes(InstanceIdentifier

id, Address dataAfter, WriteContext writeContext) + throws WriteFailedException { + setAddress(true, id, dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(InstanceIdentifier
id, Address dataBefore, Address dataAfter, + WriteContext writeContext) throws WriteFailedException { + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("Operation not supported")); + } + + @Override + public void deleteCurrentAttributes(InstanceIdentifier
id, Address dataBefore, WriteContext writeContext) + throws WriteFailedException { + setAddress(false, id, dataBefore, writeContext); + } + + private void setAddress(boolean add, final InstanceIdentifier
id, final Address address, + final WriteContext writeContext) throws WriteFailedException { + + final String interfaceName = id.firstKeyOf(Interface.class).getName(); + final int interfaceIndex = interfaceContext.getIndex(interfaceName, writeContext.getMappingContext()); + + Subnet subnet = address.getSubnet(); + + if (subnet instanceof PrefixLength) { + setPrefixLengthSubnet(add, id, interfaceName, interfaceIndex, address, (PrefixLength) subnet); + } else if (subnet instanceof Netmask) { + setNetmaskSubnet(add, id, interfaceName, interfaceIndex, address, (Netmask) subnet); + } else { + // FIXME how does choice extensibility work + // FIXME it is not even possible to create a dedicated + // customizer for Interconnection, since it's not a DataObject + // FIXME we might need a choice customizer + // THis choice is already from augment, so its probably not + // possible to augment augmented choice + LOG.error("Unable to handle subnet of type {}", subnet.getClass()); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass()); + } + } + + private void setNetmaskSubnet(final boolean add, @Nonnull final InstanceIdentifier
id, + @Nonnull final String interfaceName, final int interfaceIndex, + @Nonnull final Address address, @Nonnull final Netmask subnet) + throws WriteFailedException { + try { + LOG.debug("Setting Subnet(subnet-mask) for interface: {}(id={}). Subnet: {}, address: {}", + interfaceName, interfaceIndex, subnet, address); + + final DottedQuad netmask = subnet.getNetmask(); + checkNotNull(netmask, "netmask value should not be null"); + + final byte subnetLength = Ipv4WriteUtils.getSubnetMaskLength(netmask.getValue()); + Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, interfaceIndex, address.getIp(), subnetLength); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set Subnet(subnet-mask) for interface: {}(id={}). Subnet: {}, address: {}", + interfaceName, interfaceIndex, subnet, address); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); + } + } + + private void setPrefixLengthSubnet(final boolean add, @Nonnull final InstanceIdentifier
id, + @Nonnull final String interfaceName, final int interfaceIndex, + @Nonnull final Address address, @Nonnull final PrefixLength subnet) + throws WriteFailedException { + try { + LOG.debug("Setting Subnet(prefix-length) for interface: {}(id={}). Subnet: {}, address: {}", + interfaceName, interfaceIndex, subnet, address); + + Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, interfaceIndex, address.getIp(), + subnet.getPrefixLength().byteValue()); + + LOG.debug("Subnet(prefix-length) set successfully for interface: {}(id={}). Subnet: {}, address: {}", + interfaceName, interfaceIndex, subnet, address); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set Subnet(prefix-length) for interface: {}(id={}). Subnet: {}, address: {}", + interfaceName, interfaceIndex, subnet, address); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4Customizer.java new file mode 100644 index 000000000..c956794ac --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4Customizer.java @@ -0,0 +1,78 @@ +/* + * 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.translate.v3po.interfaces.ip; + +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Ipv4Customizer extends FutureJVppCustomizer implements WriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(Ipv4Customizer.class); + private final NamingContext interfaceContext; + + public Ipv4Customizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { + super(vppApi); + this.interfaceContext = interfaceContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ipv4 dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifcName = id.firstKeyOf(Interface.class).getName(); + setIpv4(id, ifcName, dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ipv4 dataBefore, @Nonnull final Ipv4 dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + final String ifcName = id.firstKeyOf(Interface.class).getName(); + + // TODO handle update in a better way + setIpv4(id, ifcName, dataAfter, writeContext); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ipv4 dataBefore, @Nonnull final WriteContext writeContext) { + // TODO implement delete + } + + private void setIpv4(final InstanceIdentifier id, final String name, final Ipv4 ipv4, + final WriteContext writeContext) + throws WriteFailedException { + final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext()); + + LOG.warn("Ignoring Ipv4 leaf nodes (create/update is not supported)"); + // TODO add support for enabled leaf + // TODO add support for forwarding leaf + // TODO add support for mtu leaf + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java new file mode 100644 index 000000000..edd49f2f5 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java @@ -0,0 +1,133 @@ +/* + * 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.translate.v3po.interfaces.ip; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Neighbor; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.NeighborKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.IpNeighborAddDel; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Customizer for writing {@link Neighbor} for {@link Ipv4} + */ +public class Ipv4NeighbourCustomizer extends FutureJVppCustomizer + implements ListWriterCustomizer { + + + private static final Logger LOG = LoggerFactory.getLogger(Ipv4NeighbourCustomizer.class); + final NamingContext interfaceContext; + + public Ipv4NeighbourCustomizer(final FutureJVpp futureJvpp, final NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = interfaceContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull Neighbor dataAfter, + @Nonnull WriteContext writeContext) + throws WriteFailedException { + + checkNotNull(dataAfter, "Cannot write null neighbour"); + checkArgument(id.firstKeyOf(Interface.class) != null, "No parent interface key found"); + + LOG.debug("Processing request for Neigbour write"); + String interfaceName = id.firstKeyOf(Interface.class).getName(); + MappingContext mappingContext = writeContext.getMappingContext(); + + checkState(interfaceContext.containsIndex(interfaceName, mappingContext), + "Mapping does not contains mapping for provider interface name ".concat(interfaceName)); + + LOG.debug("Parent interface index found"); + try { + addDelNeighbourAndReply(id, true, + interfaceContext.getIndex(interfaceName, mappingContext), dataAfter); + LOG.info("Neighbour successfully written"); + } catch (VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull Neighbor dataBefore, + @Nonnull Neighbor dataAfter, + @Nonnull WriteContext writeContext) throws WriteFailedException { + throw new UnsupportedOperationException("Operation not supported"); + } + + @Override + public void deleteCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull Neighbor dataBefore, + @Nonnull WriteContext writeContext) + throws WriteFailedException { + + checkNotNull(dataBefore, "Cannot delete null neighbour"); + checkArgument(id.firstKeyOf(Interface.class) != null, "No parent interface key found"); + + LOG.debug("Processing request for Neigbour delete"); + String interfaceName = id.firstKeyOf(Interface.class).getName(); + MappingContext mappingContext = writeContext.getMappingContext(); + + checkState(interfaceContext.containsIndex(interfaceName, mappingContext), + "Mapping does not contains mapping for provider interface name %s", interfaceName); + + LOG.debug("Parent interface[{}] index found", interfaceName); + try { + addDelNeighbourAndReply(id, false, + interfaceContext.getIndex(interfaceName, mappingContext), dataBefore); + LOG.info("Neighbour {} successfully deleted", id); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void addDelNeighbourAndReply(InstanceIdentifier id, boolean add, int parentInterfaceIndex, + Neighbor data) + throws VppBaseCallException, WriteTimeoutException { + + IpNeighborAddDel request = new IpNeighborAddDel(); + + request.isAdd = TranslateUtils.booleanToByte(add); + request.isIpv6 = 0; + request.isStatic = 1; + request.dstAddress = TranslateUtils.ipv4AddressNoZoneToArray(data.getIp()); + request.macAddress = TranslateUtils.parseMac(data.getLinkLayerAddress().getValue()); + request.swIfIndex = parentInterfaceIndex; + + //TODO if it is necessary for future use ,make adjustments to be able to set vrfid + //request.vrfId + TranslateUtils.getReplyForWrite(getFutureJVpp().ipNeighborAddDel(request).toCompletableFuture(), id); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4WriteUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4WriteUtils.java new file mode 100644 index 000000000..3aeb2dfaf --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4WriteUtils.java @@ -0,0 +1,111 @@ +/* + * 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.translate.v3po.interfaces.ip; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress; +import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply; +import org.openvpp.jvpp.future.FutureJVpp; + +/** + * Utility class providing Ipv4 CUD support. + */ +// TODO replace with interface with default methods or abstract class +final class Ipv4WriteUtils { + + private static final int DOTTED_QUAD_MASK_LENGTH = 4; + private static final int IPV4_ADDRESS_PART_BITS_COUNT = 8; + private static final int NETMASK_PART_LIMIT = 256; // 2 power to 8 + + private Ipv4WriteUtils() { + throw new UnsupportedOperationException("This utility class cannot be instantiated"); + } + + static void addDelAddress(@Nonnull final FutureJVpp futureJvpp, final boolean add, final InstanceIdentifier id, + @Nonnegative final int ifaceId, + @Nonnull final Ipv4AddressNoZone address, @Nonnegative final byte prefixLength) + throws VppBaseCallException, WriteTimeoutException { + checkArgument(prefixLength > 0, "Invalid prefix length"); + checkNotNull(address, "address should not be null"); + + final byte[] addressBytes = TranslateUtils.ipv4AddressNoZoneToArray(address); + + final CompletionStage swInterfaceAddDelAddressReplyCompletionStage = + futureJvpp.swInterfaceAddDelAddress( + getSwInterfaceAddDelAddressRequest(ifaceId, TranslateUtils.booleanToByte(add) /* isAdd */, + (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, prefixLength, addressBytes)); + + TranslateUtils.getReplyForWrite(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture(), id); + } + + static SwInterfaceAddDelAddress getSwInterfaceAddDelAddressRequest(final int swIfc, final byte isAdd, + final byte ipv6, final byte deleteAll, + final byte length, final byte[] addr) { + final SwInterfaceAddDelAddress swInterfaceAddDelAddress = new SwInterfaceAddDelAddress(); + swInterfaceAddDelAddress.swIfIndex = swIfc; + swInterfaceAddDelAddress.isAdd = isAdd; + swInterfaceAddDelAddress.isIpv6 = ipv6; + swInterfaceAddDelAddress.delAll = deleteAll; + swInterfaceAddDelAddress.address = addr; + swInterfaceAddDelAddress.addressLength = length; + return swInterfaceAddDelAddress; + } + + /** + * Returns the prefix size in bits of the specified subnet mask. Example: For the subnet mask 255.255.255.128 it + * returns 25 while for 255.0.0.0 it returns 8. If the passed subnetMask array is not complete or contains not only + * leading ones, IllegalArgumentExpression is thrown + * + * @param mask the subnet mask in dot notation 255.255.255.255 + * @return the prefix length as number of bits + */ + static byte getSubnetMaskLength(final String mask) { + String[] maskParts = mask.split("\\."); + + checkArgument(maskParts.length == DOTTED_QUAD_MASK_LENGTH, + "Network mask %s is not in Quad Dotted Decimal notation!", mask); + + long maskAsNumber = 0; + for (int i = 0; i < DOTTED_QUAD_MASK_LENGTH; i++) { + maskAsNumber <<= IPV4_ADDRESS_PART_BITS_COUNT; + int value = Integer.parseInt(maskParts[i]); + checkArgument(value < NETMASK_PART_LIMIT, "Network mask %s contains invalid number(s) over 255!", mask); + checkArgument(value >= 0, "Network mask %s contains invalid negative number(s)!", mask); + maskAsNumber += value; + } + + String bits = Long.toBinaryString(maskAsNumber); + checkArgument(bits.length() == IPV4_ADDRESS_PART_BITS_COUNT * DOTTED_QUAD_MASK_LENGTH, + "Incorrect network mask %s", mask); + final int leadingOnes = bits.indexOf('0'); + checkArgument(leadingOnes != -1, "Broadcast address %s is not allowed!", mask); + checkArgument(bits.substring(leadingOnes).indexOf('1') == -1, + "Non-contiguous network mask %s is not allowed!", mask); + return (byte) leadingOnes; + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv6Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv6Customizer.java new file mode 100644 index 000000000..1e3a3e747 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv6Customizer.java @@ -0,0 +1,57 @@ +/* + * 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.translate.v3po.interfaces.ip; + +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv6; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Ipv6Customizer extends FutureJVppCustomizer implements WriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(Ipv6Customizer.class); + + public Ipv6Customizer(final FutureJVpp vppApi) { + super(vppApi); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ipv6 dataAfter, @Nonnull final WriteContext writeContext) { + // TODO + LOG.warn("Unsupported, ignoring configuration {}", dataAfter); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ipv6 dataBefore, @Nonnull final Ipv6 dataAfter, + @Nonnull final WriteContext writeContext) { + LOG.warn("Unsupported, ignoring configuration {}", dataAfter); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Ipv6 dataBefore, @Nonnull final WriteContext writeContext) { + LOG.warn("Unsupported, ignoring configuration delete {}", id); + // TODO + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java new file mode 100644 index 000000000..700139704 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java @@ -0,0 +1,150 @@ +/* + * 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.translate.v3po.interfaces.ip; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.Subnet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.Netmask; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLength; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Write customizer for sub-interface {@link Address} + */ +public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer + implements ListWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class); + private final NamingContext interfaceContext; + + public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = checkNotNull(interfaceContext, "interface context should not be null"); + } + + @Override + public void writeCurrentAttributes(InstanceIdentifier
id, Address dataAfter, WriteContext writeContext) + throws WriteFailedException { + setAddress(true, id, dataAfter, writeContext); + } + + @Override + public void updateCurrentAttributes(InstanceIdentifier
id, Address dataBefore, Address dataAfter, + WriteContext writeContext) throws WriteFailedException { + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("Operation not supported")); + } + + @Override + public void deleteCurrentAttributes(InstanceIdentifier
id, Address dataBefore, WriteContext writeContext) + throws WriteFailedException { + setAddress(false, id, dataBefore, writeContext); + } + + private void setAddress(boolean add, final InstanceIdentifier
id, final Address address, + final WriteContext writeContext) throws WriteFailedException { + + final String interfaceName = id.firstKeyOf(Interface.class).getName(); + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); + + Subnet subnet = address.getSubnet(); + + if (subnet instanceof PrefixLength) { + setPrefixLengthSubnet(add, id, interfaceName, subInterfaceIndex, address, (PrefixLength) subnet); + } else if (subnet instanceof Netmask) { + setNetmaskSubnet(add, id, interfaceName, subInterfaceIndex, address, (Netmask) subnet); + } else { + // FIXME how does choice extensibility work + // FIXME it is not even possible to create a dedicated + // customizer for Interconnection, since it's not a DataObject + // FIXME we might need a choice customizer + // THis choice is already from augment, so its probably not + // possible to augment augmented choice + LOG.error("Unable to handle subnet of type {}", subnet.getClass()); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass()); + } + } + + private String getSubInterfaceName(@Nonnull final InstanceIdentifier
id) { + final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); + final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); + return SubInterfaceUtils + .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); + } + + private void setNetmaskSubnet(final boolean add, @Nonnull final InstanceIdentifier
id, + @Nonnull final String subInterfaceName, final int subInterfaceIndex, + @Nonnull final Address address, @Nonnull final Netmask subnet) + throws WriteFailedException { + try { + LOG.debug("Setting Subnet(subnet-mask) for sub-interface: {}(id={}). Subnet: {}, address: {}", + subInterfaceName, subInterfaceIndex, subnet, address); + + final DottedQuad netmask = subnet.getNetmask(); + checkNotNull(netmask, "netmask value should not be null"); + + final byte subnetLength = Ipv4WriteUtils.getSubnetMaskLength(netmask.getValue()); + Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, subInterfaceIndex, address.getIp(), subnetLength); + + } catch (VppBaseCallException e) { + LOG.warn("Failed to set Subnet(subnet-mask) for sub-interface: {}(id={}). Subnet: {}, address: {}", + subInterfaceName, subInterfaceIndex, subnet, address); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); + } + } + + private void setPrefixLengthSubnet(final boolean add, @Nonnull final InstanceIdentifier
id, + @Nonnull final String subInterfaceName, final int subInterfaceIndex, + @Nonnull final Address address, @Nonnull final PrefixLength subnet) + throws WriteFailedException { + try { + LOG.debug("Setting Subnet(prefix-length) for sub-interface: {}(id={}). Subnet: {}, address: {}", + subInterfaceName, subInterfaceIndex, subnet, address); + + Ipv4WriteUtils.addDelAddress(getFutureJVpp(), add, id, subInterfaceIndex, address.getIp(), + subnet.getPrefixLength().byteValue()); + + LOG.debug("Subnet(prefix-length) set successfully for sub-interface: {}(id={}). Subnet: {}, address: {}", + subInterfaceName, subInterfaceIndex, subnet, address); + } catch (VppBaseCallException e) { + LOG.warn("Failed to set Subnet(prefix-length) for sub-interface: {}(id={}). Subnet: {}, address: {}", + subInterfaceName, subInterfaceIndex, subnet, address); + throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.java new file mode 100644 index 000000000..1b76a0382 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizer.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.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.AclBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyTableByInterface; +import org.openvpp.jvpp.dto.ClassifyTableByInterfaceReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for reading ACLs enabled on given interface. + */ +public class AclCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer, AclReader { + + private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class); + private final NamingContext interfaceContext; + private final NamingContext classifyTableContext; + + public AclCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext classifyTableContext) { + super(jvpp); + this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); + this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Acl readValue) { + ((VppInterfaceStateAugmentationBuilder) parentBuilder).setAcl(readValue); + } + + @Nonnull + @Override + public AclBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new AclBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final AclBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + LOG.debug("Reading attributes for interface ACL: {}", id); + final InterfaceKey interfaceKey = id.firstKeyOf(Interface.class); + checkArgument(interfaceKey != null, "No parent interface key found"); + + final ClassifyTableByInterface request = new ClassifyTableByInterface(); + request.swIfIndex = interfaceContext.getIndex(interfaceKey.getName(), ctx.getMappingContext()); + try { + final ClassifyTableByInterfaceReply reply = TranslateUtils + .getReplyForRead(getFutureJVpp().classifyTableByInterface(request).toCompletableFuture(), id); + + builder.setL2Acl(readL2Acl(reply.l2TableId, classifyTableContext, ctx.getMappingContext())); + builder.setIp4Acl(readIp4Acl(reply.ip4TableId, classifyTableContext, ctx.getMappingContext())); + builder.setIp6Acl(readIp6Acl(reply.ip6TableId, classifyTableContext, ctx.getMappingContext())); + + if (LOG.isTraceEnabled()) { + LOG.trace("Attributes for ACL {} successfully read: {}", id, builder.build()); + } + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclReader.java new file mode 100644 index 000000000..c64c096a8 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclReader.java @@ -0,0 +1,60 @@ +/* + * 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.translate.v3po.interfacesstate; + +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4AclBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6AclBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2AclBuilder; + +interface AclReader { + + @Nonnull + default L2Acl readL2Acl(final int l2TableId, @Nonnull final NamingContext classifyTableContext, + @Nonnull final MappingContext mappingContext) { + if (l2TableId == ~0) { + return null; + } + return new L2AclBuilder() + .setClassifyTable(classifyTableContext.getName(l2TableId, mappingContext)).build(); + } + + @Nonnull + default Ip4Acl readIp4Acl(final int ip4TableId, @Nonnull final NamingContext classifyTableContext, + @Nonnull final MappingContext mappingContext) { + if (ip4TableId == ~0) { + return null; + } + return new Ip4AclBuilder() + .setClassifyTable(classifyTableContext.getName(ip4TableId, mappingContext)).build(); + } + + @Nonnull + default Ip6Acl readIp6Acl(final int ip6TableId, @Nonnull final NamingContext classifyTableContext, + @Nonnull final MappingContext mappingContext) { + if (ip6TableId == ~0) { + return null; + } + return new Ip6AclBuilder() + .setClassifyTable(classifyTableContext.getName(ip6TableId, mappingContext)).build(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/EthernetCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/EthernetCustomizer.java new file mode 100644 index 000000000..30d3f6482 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/EthernetCustomizer.java @@ -0,0 +1,87 @@ +/* + * 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.translate.v3po.interfacesstate; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.EthernetBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class EthernetCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(EthernetCustomizer.class); + private NamingContext interfaceContext; + + public EthernetCustomizer(@Nonnull final FutureJVpp jvpp, + @Nonnull final NamingContext interfaceContext) { + super(jvpp); + this.interfaceContext = interfaceContext; + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, + @Nonnull final Ethernet readValue) { + ((VppInterfaceStateAugmentationBuilder) parentBuilder).setEthernet(readValue); + } + + @Nonnull + @Override + public EthernetBuilder getBuilder(@Nonnull InstanceIdentifier id) { + return new EthernetBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final EthernetBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + + final InterfaceKey key = id.firstKeyOf(Interface.class); + final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, key.getName(), + interfaceContext.getIndex(key.getName(), ctx.getMappingContext()), ctx.getModificationCache()); + + if(iface.linkMtu != 0) { + builder.setMtu((int) iface.linkMtu); + } + + switch (iface.linkDuplex) { + case 1: + builder.setDuplex(Ethernet.Duplex.Half); + break; + case 2: + builder.setDuplex(Ethernet.Duplex.Full); + break; + default: + break; + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterconnectionReadUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterconnectionReadUtils.java new file mode 100644 index 000000000..c01d27a2d --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterconnectionReadUtils.java @@ -0,0 +1,131 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.BridgeDomainDetails; +import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump; +import org.openvpp.jvpp.dto.BridgeDomainDump; +import org.openvpp.jvpp.dto.BridgeDomainSwIfDetails; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class providing Interconnection read support. + */ +// FIXME this should be customizer, but it is not possible because Interconnection is not a DataObject +final class InterconnectionReadUtils { + + private static final Logger LOG = LoggerFactory.getLogger(InterconnectionReadUtils.class); + + private final FutureJVpp futureJvpp; + private final NamingContext interfaceContext; + private final NamingContext bridgeDomainContext; + + InterconnectionReadUtils(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext bridgeDomainContext) { + this.futureJvpp = requireNonNull(futureJvpp, "futureJvpp should not be null"); + this.interfaceContext = requireNonNull(interfaceContext, "interfaceContext should not be null"); + this.bridgeDomainContext = requireNonNull(bridgeDomainContext, "bridgeDomainContext should not be null"); + } + + @Nullable + Interconnection readInterconnection(@Nonnull final InstanceIdentifier id, @Nonnull final String ifaceName, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + final int ifaceId = interfaceContext.getIndex(ifaceName, ctx.getMappingContext()); + + final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(futureJvpp, id, ifaceName, + ifaceId, ctx.getModificationCache()); + LOG.debug("Interface details for interface: {}, details: {}", ifaceName, iface); + + final BridgeDomainDetailsReplyDump dumpReply = getDumpReply(id); + final Optional bdForInterface = getBridgeDomainForInterface(ifaceId, dumpReply); + if (bdForInterface.isPresent()) { + final BridgeDomainSwIfDetails bdSwIfDetails = bdForInterface.get(); + final BridgeBasedBuilder bbBuilder = new BridgeBasedBuilder(); + bbBuilder.setBridgeDomain(bridgeDomainContext.getName(bdSwIfDetails.bdId, ctx.getMappingContext())); + + // Set BVI if the bridgeDomainDetails.bviSwIfIndex == current sw if index + final Optional bridgeDomainForInterface = + getBridgeDomainForInterface(dumpReply, bdForInterface.get().bdId); + // Since we already found an interface assigned to a bridge domain, the details for BD must be present + checkState(bridgeDomainForInterface.isPresent()); + if (bridgeDomainForInterface.get().bviSwIfIndex == ifaceId) { + bbBuilder.setBridgedVirtualInterface(true); + } else { + bbBuilder.setBridgedVirtualInterface(false); + } + + if (bdSwIfDetails.shg != 0) { + bbBuilder.setSplitHorizonGroup((short) bdSwIfDetails.shg); + } + return bbBuilder.build(); + } + // TODO is there a way to check if interconnection is XconnectBased? + + return null; + } + + private Optional getBridgeDomainForInterface(final int ifaceId, + final BridgeDomainDetailsReplyDump reply) { + if (null == reply || null == reply.bridgeDomainSwIfDetails || reply.bridgeDomainSwIfDetails.isEmpty()) { + return Optional.empty(); + } + // interface can be added to only one BD only + return reply.bridgeDomainSwIfDetails.stream().filter(a -> a.swIfIndex == ifaceId).findFirst(); + } + + private Optional getBridgeDomainForInterface(final BridgeDomainDetailsReplyDump reply, + int bdId) { + return reply.bridgeDomainDetails.stream().filter(a -> a.bdId == bdId).findFirst(); + } + + private BridgeDomainDetailsReplyDump getDumpReply(@Nonnull final InstanceIdentifier id) + throws ReadFailedException { + try { + // We need to perform full bd dump, because there is no way + // to ask VPP for BD details given interface id/name (TODO add it to vpp.api?) + // TODO cache dump result + final BridgeDomainDump request = new BridgeDomainDump(); + request.bdId = -1; + + final CompletableFuture bdCompletableFuture = + futureJvpp.bridgeDomainSwIfDump(request).toCompletableFuture(); + return TranslateUtils.getReplyForRead(bdCompletableFuture, id); + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java new file mode 100644 index 000000000..082b68559 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizer.java @@ -0,0 +1,178 @@ +/* + * 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.translate.v3po.interfacesstate; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump; +import org.openvpp.jvpp.dto.SwInterfaceDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for reading ietf-interfaces:interfaces-state/interface. + */ +public class InterfaceCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class); + public static final String DUMPED_IFCS_CONTEXT_KEY = + InterfaceCustomizer.class.getName() + "dumpedInterfacesDuringGetAllIds"; + + private final NamingContext interfaceContext; + + public InterfaceCustomizer(@Nonnull final FutureJVpp jvpp, final NamingContext interfaceContext) { + super(jvpp); + this.interfaceContext = interfaceContext; + } + + @Nonnull + @Override + public InterfaceBuilder getBuilder(@Nonnull InstanceIdentifier id) { + return new InterfaceBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull InterfaceBuilder builder, + @Nonnull ReadContext ctx) throws ReadFailedException { + LOG.debug("Reading attributes for interface: {}", id); + final String ifaceName = id.firstKeyOf(id.getTargetType()).getName(); + + // Pass cached details from getAllIds to getDetails to avoid additional dumps + final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, ifaceName, + interfaceContext.getIndex(ifaceName, ctx.getMappingContext()), ctx.getModificationCache()); + LOG.debug("Interface details for interface: {}, details: {}", ifaceName, iface); + + if (!isRegularInterface(iface)) { + LOG.debug("Interface: {} is a sub-interface. Ignoring read request.", ifaceName); + return; + } + + builder.setName(ifaceName); + builder.setType(InterfaceUtils.getInterfaceType(new String(iface.interfaceName).intern())); + builder.setIfIndex(InterfaceUtils.vppIfIndexToYang(iface.swIfIndex)); + builder.setAdminStatus(1 == iface.adminUpDown + ? AdminStatus.Up + : AdminStatus.Down); + builder.setOperStatus(1 == iface.linkUpDown + ? OperStatus.Up + : OperStatus.Down); + if (0 != iface.linkSpeed) { + builder.setSpeed(InterfaceUtils.vppInterfaceSpeedToYang(iface.linkSpeed)); + } + if (iface.l2AddressLength == 6) { + builder.setPhysAddress(new PhysAddress(InterfaceUtils.vppPhysAddrToYang(iface.l2Address))); + } + LOG.trace("Base attributes read for interface: {} as: {}", ifaceName, builder); + } + + @Nonnull + @SuppressWarnings("unchecked") + public static Map getCachedInterfaceDump(@Nonnull final ModificationCache ctx) { + return ctx.get(DUMPED_IFCS_CONTEXT_KEY) == null + ? new HashMap<>() + // allow customizers to update the cache + : (Map) ctx.get(DUMPED_IFCS_CONTEXT_KEY); + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext context) throws ReadFailedException { + try { + final List interfacesKeys; + LOG.trace("Dumping all interfaces to get all IDs"); + + final SwInterfaceDump request = new SwInterfaceDump(); + request.nameFilter = "".getBytes(); + request.nameFilterValid = 0; + + final CompletableFuture swInterfaceDetailsReplyDumpCompletableFuture = + getFutureJVpp().swInterfaceDump(request).toCompletableFuture(); + final SwInterfaceDetailsReplyDump ifaces = + TranslateUtils.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, id); + + if (null == ifaces || null == ifaces.swInterfaceDetails) { + LOG.debug("No interfaces for :{} found in VPP", id); + return Collections.emptyList(); + } + + // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes + context.getModificationCache().put(DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream() + .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails))); + + interfacesKeys = ifaces.swInterfaceDetails.stream() + .filter(elt -> elt != null) + .map((elt) -> { + // Store interface name from VPP in context if not yet present + if (!interfaceContext.containsName(elt.swIfIndex, context.getMappingContext())) { + interfaceContext.addName(elt.swIfIndex, TranslateUtils.toString(elt.interfaceName), + context.getMappingContext()); + } + LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP", + interfaceContext.getName(elt.swIfIndex, context.getMappingContext()), elt.interfaceName, + elt.swIfIndex); + + return elt; + }) + .filter(InterfaceCustomizer::isRegularInterface) // filter out sub-interfaces + .map((elt) -> new InterfaceKey(interfaceContext.getName(elt.swIfIndex, context.getMappingContext()))) + .collect(Collectors.toList()); + + LOG.debug("Interfaces found in VPP: {}", interfacesKeys); + return interfacesKeys; + } catch (VppBaseCallException e) { + LOG.warn("getAllIds for id :{} failed with exception ", id, e); + throw new ReadFailedException(id, e); + } + } + + private static boolean isRegularInterface(final SwInterfaceDetails iface) { + return iface.subId == 0; + } + + @Override + public void merge(@Nonnull final org.opendaylight.yangtools.concepts.Builder builder, + @Nonnull final List readData) { + ((InterfacesStateBuilder) builder).setInterface(readData); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java new file mode 100644 index 000000000..b7c1e518a --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtils.java @@ -0,0 +1,286 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; + +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.math.BigInteger; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CompletionStage; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Gauge64; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump; +import org.openvpp.jvpp.dto.SwInterfaceDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class InterfaceUtils { + private static final Logger LOG = LoggerFactory.getLogger(InterfaceUtils.class); + + private static final Gauge64 vppLinkSpeed0 = new Gauge64(BigInteger.ZERO); + private static final Gauge64 vppLinkSpeed1 = new Gauge64(BigInteger.valueOf(10L * 1000000)); + private static final Gauge64 vppLinkSpeed2 = new Gauge64(BigInteger.valueOf(100L * 1000000)); + private static final Gauge64 vppLinkSpeed4 = new Gauge64(BigInteger.valueOf(1000L * 1000000)); + private static final Gauge64 vppLinkSpeed8 = new Gauge64(BigInteger.valueOf(10000L * 1000000)); + private static final Gauge64 vppLinkSpeed16 = new Gauge64(BigInteger.valueOf(40000L * 1000000)); + private static final Gauge64 vppLinkSpeed32 = new Gauge64(BigInteger.valueOf(100000L * 1000000)); + + private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray(); + + private static final int PHYSICAL_ADDRESS_LENGTH = 6; + + private static final Collector SINGLE_ITEM_COLLECTOR = + RWUtils.singleItemCollector(); + + private InterfaceUtils() { + throw new UnsupportedOperationException("This utility class cannot be instantiated"); + } + + /** + * Convert VPP's link speed bitmask to Yang type. 1 = 10M, 2 = 100M, 4 = 1G, 8 = 10G, 16 = 40G, 32 = 100G + * + * @param vppLinkSpeed Link speed in bitmask format from VPP. + * @return Converted value from VPP link speed + */ + public static Gauge64 vppInterfaceSpeedToYang(byte vppLinkSpeed) { + switch (vppLinkSpeed) { + case 1: + return vppLinkSpeed1; + case 2: + return vppLinkSpeed2; + case 4: + return vppLinkSpeed4; + case 8: + return vppLinkSpeed8; + case 16: + return vppLinkSpeed16; + case 32: + return vppLinkSpeed32; + default: + return vppLinkSpeed0; + } + } + + private static final void appendHexByte(final StringBuilder sb, final byte b) { + final int v = b & 0xFF; + sb.append(HEX_CHARS[v >>> 4]); + sb.append(HEX_CHARS[v & 15]); + } + + // TODO rename and move to V3poUtils + + /** + * Reads first 6 bytes of supplied byte array and converts to string as Yang dictates

Replace later with + * https://git.opendaylight.org/gerrit/#/c/34869/10/model/ietf/ietf-type- util/src/main/ + * java/org/opendaylight/mdsal/model/ietf/util/AbstractIetfYangUtil.java + * + * @param vppPhysAddress byte array of bytes in big endian order, constructing the network IF physical address. + * @return String like "aa:bb:cc:dd:ee:ff" + * @throws NullPointerException if vppPhysAddress is null + * @throws IllegalArgumentException if vppPhysAddress.length < 6 + */ + public static String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress) { + return vppPhysAddrToYang(vppPhysAddress, 0); + } + + public static String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress, final int startIndex) { + Objects.requireNonNull(vppPhysAddress, "Empty physical address bytes"); + final int endIndex = startIndex + PHYSICAL_ADDRESS_LENGTH; + checkArgument(endIndex <= vppPhysAddress.length, + "Invalid physical address size (%s) for given startIndex (%s), expected >= %s", vppPhysAddress.length, + startIndex, endIndex); + return printHexBinary(vppPhysAddress, startIndex, endIndex); + } + + public static String printHexBinary(@Nonnull final byte[] bytes) { + Objects.requireNonNull(bytes, "bytes array should not be null"); + return printHexBinary(bytes, 0, bytes.length); + } + + private static String printHexBinary(@Nonnull final byte[] bytes, final int startIndex, final int endIndex) { + StringBuilder str = new StringBuilder(); + + appendHexByte(str, bytes[startIndex]); + for (int i = startIndex + 1; i < endIndex; i++) { + str.append(":"); + appendHexByte(str, bytes[i]); + } + + return str.toString(); + } + + /** + * VPP's interface index is counted from 0, whereas ietf-interface's if-index is from 1. This function converts from + * VPP's interface index to YANG's interface index. + * + * @param vppIfIndex the sw interface index VPP reported. + * @return VPP's interface index incremented by one + */ + public static int vppIfIndexToYang(int vppIfIndex) { + return vppIfIndex + 1; + } + + /** + * This function does the opposite of what {@link #vppIfIndexToYang(int)} does. + * + * @param yangIfIndex if-index from ietf-interfaces. + * @return VPP's representation of the if-index + */ + public static int yangIfIndexToVpp(int yangIfIndex) { + checkArgument(yangIfIndex >= 1, "YANG if-index has invalid value %s", yangIfIndex); + return yangIfIndex - 1; + } + + + /** + * Queries VPP for interface description given interface key. + * + * @param futureJvpp VPP Java Future API + * @param id InstanceIdentifier, which is passed in ReadFailedException + * @param name interface name + * @param index VPP index of the interface + * @param ctx per-tx scope context containing cached dump with all the interfaces. If the cache is not + * available or outdated, another dump will be performed. + * @return SwInterfaceDetails DTO or null if interface was not found + * @throws IllegalArgumentException If interface cannot be found + * @throws ReadFailedException If read operation had failed + */ + @Nonnull + public static SwInterfaceDetails getVppInterfaceDetails(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final InstanceIdentifier id, + @Nonnull final String name, final int index, + @Nonnull final ModificationCache ctx) + throws ReadFailedException { + requireNonNull(futureJvpp, "futureJvpp should not be null"); + requireNonNull(name, "name should not be null"); + requireNonNull(ctx, "ctx should not be null"); + + final SwInterfaceDump request = new SwInterfaceDump(); + request.nameFilter = name.getBytes(); + request.nameFilterValid = 1; + + final Map allInterfaces = InterfaceCustomizer.getCachedInterfaceDump(ctx); + + // Returned cached if available + if (allInterfaces.containsKey(index)) { + return allInterfaces.get(index); + } + + SwInterfaceDetailsReplyDump ifaces; + try { + CompletionStage requestFuture = futureJvpp.swInterfaceDump(request); + ifaces = TranslateUtils.getReplyForRead(requestFuture.toCompletableFuture(), id); + if (null == ifaces || null == ifaces.swInterfaceDetails || ifaces.swInterfaceDetails.isEmpty()) { + request.nameFilterValid = 0; + + LOG.warn("VPP returned null instead of interface by key {} and its not cached", name); + LOG.warn("Iterating through all the interfaces to find interface: {}", name); + + // Or else just perform full dump and do inefficient filtering + requestFuture = futureJvpp.swInterfaceDump(request); + ifaces = TranslateUtils.getReplyForRead(requestFuture.toCompletableFuture(), id); + + // Update the cache + allInterfaces.clear(); + allInterfaces + .putAll(ifaces.swInterfaceDetails.stream().collect(Collectors.toMap(d -> d.swIfIndex, d -> d))); + + if (allInterfaces.containsKey(index)) { + return allInterfaces.get(index); + } + throw new IllegalArgumentException("Unable to find interface " + name); + } + } catch (VppBaseCallException e) { + LOG.warn("getVppInterfaceDetails for id :{} and name :{} failed with exception :", id, name, e); + throw new ReadFailedException(id, e); + } + + // SwInterfaceDump's name filter does prefix match, so we need additional filtering: + final SwInterfaceDetails iface = + ifaces.swInterfaceDetails.stream().filter(d -> d.swIfIndex == index).collect(SINGLE_ITEM_COLLECTOR); + allInterfaces.put(index, iface); // update the cache + return iface; + } + + /** + * Determine interface type based on its VPP name (relying on VPP's interface naming conventions) + * + * @param interfaceName VPP generated interface name + * @return Interface type + */ + @Nonnull + public static Class getInterfaceType(@Nonnull final String interfaceName) { + if (interfaceName.startsWith("tap")) { + return Tap.class; + } + + if (interfaceName.startsWith("vxlan_gpe")) { + return VxlanGpeTunnel.class; + } + + if (interfaceName.startsWith("vxlan")) { + return VxlanTunnel.class; + } + + if (interfaceName.startsWith("VirtualEthernet")) { + return VhostUser.class; + } + + return EthernetCsmacd.class; + } + + /** + * Check interface type. Uses interface details from VPP to determine. Uses {@link + * #getVppInterfaceDetails(FutureJVpp, InstanceIdentifier, String, int, ModificationCache)} internally so tries to + * utilize cache before asking VPP. + */ + static boolean isInterfaceOfType(@Nonnull final FutureJVpp jvpp, + @Nonnull final ModificationCache cache, + @Nonnull final InstanceIdentifier id, + final int index, + @Nonnull final Class ifcType) throws ReadFailedException { + final String name = id.firstKeyOf(Interface.class).getName(); + final SwInterfaceDetails vppInterfaceDetails = + getVppInterfaceDetails(jvpp, id, name, index, cache); + + return isInterfaceOfType(ifcType, vppInterfaceDetails); + } + + static boolean isInterfaceOfType(final Class ifcType, + final SwInterfaceDetails cachedDetails) { + return ifcType.equals(getInterfaceType(TranslateUtils.toString(cachedDetails.interfaceName))); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2Customizer.java new file mode 100644 index 000000000..4e18c9804 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2Customizer.java @@ -0,0 +1,75 @@ +/* + * 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.translate.v3po.interfacesstate; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2Builder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nonnull; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Customizer for reading ietf-interfaces:interfaces-state/interface/iface_name/v3po:l2 + */ +public class L2Customizer extends FutureJVppCustomizer implements ReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class); + private final InterconnectionReadUtils icReadUtils; + + public L2Customizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext bridgeDomainContext) { + super(futureJvpp); + this.icReadUtils = new InterconnectionReadUtils(futureJvpp, interfaceContext, bridgeDomainContext); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final L2 readValue) { + ((VppInterfaceStateAugmentationBuilder) parentBuilder).setL2(readValue); + } + + @Nonnull + @Override + public L2Builder getBuilder(@Nonnull final InstanceIdentifier id) { + return new L2Builder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2Builder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + + LOG.debug("Reading attributes for L2: {}", id); + final InterfaceKey key = id.firstKeyOf(Interface.class); + final String ifaceName = key.getName(); + builder.setInterconnection(icReadUtils.readInterconnection(id, ifaceName, ctx)); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizer.java new file mode 100644 index 000000000..87bd1b25b --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizer.java @@ -0,0 +1,145 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import io.fd.honeycomb.translate.v3po.util.TagRewriteOperation; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qTagVlanType; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.Dot1qTagBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1ad; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1q; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTagsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTagsKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for reading vlan tag-rewrite configuration state form the VPP. + */ +public class RewriteCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(RewriteCustomizer.class); + private final NamingContext interfaceContext; + + public RewriteCustomizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, + @Nonnull final Rewrite readValue) { + ((L2Builder) parentBuilder).setRewrite(readValue); + } + + @Nonnull + @Override + public RewriteBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new RewriteBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final RewriteBuilder builder, @Nonnull final ReadContext ctx) + throws ReadFailedException { + final String subInterfaceName = getSubInterfaceName(id); + LOG.debug("Reading attributes for sub interface: {}", subInterfaceName); + + final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, subInterfaceName, + interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()), ctx.getModificationCache()); + LOG.debug("VPP sub-interface details: {}", ReflectionToStringBuilder.toString(iface)); + + checkState(iface.subId != 0, "Interface returned by the VPP is not a sub-interface"); + + final TagRewriteOperation operation = TagRewriteOperation.get(iface.vtrOp); + if (TagRewriteOperation.disabled == operation) { + LOG.debug("Tag rewrite operation is disabled for "); + return; + } + + builder.setVlanType(iface.vtrPushDot1Q == 1 + ? _802dot1q.class + : _802dot1ad.class); + + setPushTags(builder, iface); + setPopTags(builder, operation); + } + + private static String getSubInterfaceName(final InstanceIdentifier id) { + return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), + Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier())); + } + + private void setPopTags(final RewriteBuilder builder, final TagRewriteOperation operation) { + final byte numberOfTagsToPop = operation.getPopTags(); + if (numberOfTagsToPop != 0) { + builder.setPopTags(Short.valueOf(numberOfTagsToPop)); + } + } + + private void setPushTags(final RewriteBuilder builder, final SwInterfaceDetails iface) { + final List tags = new ArrayList<>(); + if (iface.vtrTag1 != 0) { + tags.add(buildTag((short) 0, SVlan.class, iface.vtrTag1)); + } + if (iface.vtrTag2 != 0) { + tags.add(buildTag((short) 1, CVlan.class, iface.vtrTag2)); + } + if (tags.size() > 0) { + builder.setPushTags(tags); + } + } + + private PushTags buildTag(final short index, final Class tagType, final int vlanId) { + final PushTagsBuilder tag = new PushTagsBuilder(); + tag.setIndex(index); + tag.setKey(new PushTagsKey(index)); + final Dot1qTagBuilder dtag = new Dot1qTagBuilder(); + dtag.setTagType(tagType); + dtag.setVlanId(new Dot1qVlanId(vlanId)); + tag.setDot1qTag(dtag.build()); + return tag.build(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java new file mode 100644 index 000000000..8c46a6a09 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.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.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.AclBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyTableByInterface; +import org.openvpp.jvpp.dto.ClassifyTableByInterfaceReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for reading ACLs enabled on given sub-interface. + */ +public class SubInterfaceAclCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer, AclReader { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class); + private final NamingContext interfaceContext; + private final NamingContext classifyTableContext; + + public SubInterfaceAclCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext classifyTableContext) { + super(jvpp); + this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); + this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Acl readValue) { + ((SubInterfaceBuilder) parentBuilder).setAcl(readValue); + } + + @Nonnull + @Override + public AclBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new AclBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final AclBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + LOG.debug("Reading attributes for sub-interface ACL: {}", id); + final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); + checkArgument(parentInterfacekey != null, "No parent interface key found"); + final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); + checkArgument(subInterfacekey != null, "No sub-interface key found"); + final String subInterfaceName = + getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); + + final ClassifyTableByInterface request = new ClassifyTableByInterface(); + request.swIfIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()); + try { + final ClassifyTableByInterfaceReply reply = TranslateUtils + .getReplyForRead(getFutureJVpp().classifyTableByInterface(request).toCompletableFuture(), id); + + builder.setL2Acl(readL2Acl(reply.l2TableId, classifyTableContext, ctx.getMappingContext())); + builder.setIp4Acl(readIp4Acl(reply.ip4TableId, classifyTableContext, ctx.getMappingContext())); + builder.setIp6Acl(readIp6Acl(reply.ip6TableId, classifyTableContext, ctx.getMappingContext())); + + if (LOG.isTraceEnabled()) { + LOG.trace("Attributes for ACL {} successfully read: {}", id, builder.build()); + } + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizer.java new file mode 100644 index 000000000..108a07a2c --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizer.java @@ -0,0 +1,241 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.byteToBoolean; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qTagVlanType; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTagBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubInterfaceStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfacesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.DefaultBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.UntaggedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.vlan.tagged.VlanTaggedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.TagsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.TagBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.TagKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump; +import org.openvpp.jvpp.dto.SwInterfaceDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for reading sub interfaces form the VPP. + */ +public class SubInterfaceCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceCustomizer.class); + private NamingContext interfaceContext; + private static final Dot1qTag.VlanId ANY_VLAN_ID = new Dot1qTag.VlanId(Dot1qTag.VlanId.Enumeration.Any); + + public SubInterfaceCustomizer(@Nonnull final FutureJVpp jvpp, + @Nonnull final NamingContext interfaceContext) { + super(jvpp); + this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext context) throws ReadFailedException { + try { + // Relying here that parent InterfaceCustomizer was invoked first (PREORDER) + // to fill in the context with initial ifc mapping + final InterfaceKey key = id.firstKeyOf(Interface.class); + final String ifaceName = key.getName(); + final int ifaceId = interfaceContext.getIndex(ifaceName, context.getMappingContext()); + + // TODO if we know that full dump was already performed we could use cache + // (checking if getCachedInterfaceDump() returns non empty map is not enough, because + // we could be part of particular iface state read + final SwInterfaceDump request = new SwInterfaceDump(); + request.nameFilter = "".getBytes(); + request.nameFilterValid = 0; + + final CompletableFuture swInterfaceDetailsReplyDumpCompletableFuture = + getFutureJVpp().swInterfaceDump(request).toCompletableFuture(); + final SwInterfaceDetailsReplyDump ifaces = + TranslateUtils.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, id); + + if (null == ifaces || null == ifaces.swInterfaceDetails) { + LOG.warn("Looking for sub-interfaces, but no interfaces found in VPP"); + return Collections.emptyList(); + } + + // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes + context.getModificationCache().put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream() + .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails))); + + final List interfacesKeys = ifaces.swInterfaceDetails.stream() + .filter(elt -> elt != null) + // accept only sub-interfaces for current iface: + .filter(elt -> elt.subId != 0 && elt.supSwIfIndex == ifaceId) + .map(details -> new SubInterfaceKey(new Long(details.subId))) + .collect(Collectors.toList()); + + LOG.debug("Sub-interfaces of {} found in VPP: {}", ifaceName, interfacesKeys); + return interfacesKeys; + } catch (VppBaseCallException e) { + throw new ReadFailedException(id,e); + } + } + + @Override + public void merge(@Nonnull final Builder builder, + @Nonnull final List readData) { + ((SubInterfacesBuilder) builder).setSubInterface(readData); + } + + @Nonnull + @Override + public SubInterfaceBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new SubInterfaceBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final SubInterfaceBuilder builder, @Nonnull final ReadContext ctx) + throws ReadFailedException { + final String subInterfaceName = getSubInterfaceName(id); + LOG.debug("Reading attributes for sub interface: {}", subInterfaceName); + + final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, subInterfaceName, + interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()), ctx.getModificationCache()); + LOG.debug("VPP sub-interface details: {}", ReflectionToStringBuilder.toString(iface)); + + checkState(iface.subId != 0, "Interface returned by the VPP is not a sub-interface"); + + builder.setIdentifier(Long.valueOf(iface.subId)); + builder.setKey(new SubInterfaceKey(builder.getIdentifier())); + + // sub-interface-base-attributes: + builder.setTags(readTags(iface)); + builder.setMatch(readMatch(iface)); + + // sub-interface-operational-attributes: + builder.setAdminStatus(1 == iface.adminUpDown + ? SubInterfaceStatus.Up + : SubInterfaceStatus.Down); + builder.setOperStatus(1 == iface.linkUpDown + ? SubInterfaceStatus.Up + : SubInterfaceStatus.Down); + builder.setIfIndex(InterfaceUtils.vppIfIndexToYang(iface.swIfIndex)); + if (iface.l2AddressLength == 6) { + builder.setPhysAddress(new PhysAddress(InterfaceUtils.vppPhysAddrToYang(iface.l2Address))); + } + if (0 != iface.linkSpeed) { + builder.setSpeed(InterfaceUtils.vppInterfaceSpeedToYang(iface.linkSpeed)); + } + } + + private static String getSubInterfaceName(final InstanceIdentifier id) { + return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), + Math.toIntExact(id.firstKeyOf(id.getTargetType()).getIdentifier())); + } + + private Tags readTags(final SwInterfaceDetails iface) { + final TagsBuilder tags = new TagsBuilder(); + final List list = new ArrayList<>(); + if (iface.subNumberOfTags > 0) { + if (iface.subOuterVlanIdAny == 1) { + list.add(buildTag((short) 0, SVlan.class, ANY_VLAN_ID)); + } else { + list.add(buildTag((short) 0, SVlan.class, buildVlanId(iface.subOuterVlanId))); + } + // inner tag (customer tag): + if (iface.subNumberOfTags == 2) { + if (iface.subInnerVlanIdAny == 1) { + list.add(buildTag((short) 1, CVlan.class, ANY_VLAN_ID)); + } else { + list.add(buildTag((short) 1, CVlan.class, buildVlanId(iface.subInnerVlanId))); + } + } + } + tags.setTag(list); + return tags.build(); + } + + private static Tag buildTag(final short index, final Class tagType, + final Dot1qTag.VlanId vlanId) { + TagBuilder tag = new TagBuilder(); + tag.setIndex(index); + tag.setKey(new TagKey(index)); + final Dot1qTagBuilder dtag = new Dot1qTagBuilder(); + dtag.setTagType(tagType); + dtag.setVlanId(vlanId); + tag.setDot1qTag(dtag.build()); + return tag.build(); + } + + private static Dot1qTag.VlanId buildVlanId(final short vlanId) { + // treat vlanId as unsigned value: + return new Dot1qTag.VlanId(new Dot1qVlanId(0xffff & vlanId)); + } + + private Match readMatch(final SwInterfaceDetails iface) { + final MatchBuilder match = new MatchBuilder(); + if (iface.subDefault == 1) { + match.setMatchType(new DefaultBuilder().build()); + } else if (iface.subNumberOfTags == 0) { + match.setMatchType(new UntaggedBuilder().build()); + } else { + final VlanTaggedBuilder tagged = new VlanTaggedBuilder(); + tagged.setMatchExactTags(byteToBoolean(iface.subExactMatch)); + match.setMatchType( + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.VlanTaggedBuilder() + .setVlanTagged(tagged.build()).build()); + } + return match.build(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java new file mode 100644 index 000000000..4855915bb --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java @@ -0,0 +1,77 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2Builder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Customizer for reading vlan sub interface L2 operational state + */ +public class SubInterfaceL2Customizer extends FutureJVppCustomizer implements ReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceL2Customizer.class); + private final InterconnectionReadUtils icReadUtils; + + public SubInterfaceL2Customizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext bridgeDomainContext) { + super(futureJvpp); + this.icReadUtils = new InterconnectionReadUtils(futureJvpp, interfaceContext, bridgeDomainContext); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final L2 readValue) { + ((SubInterfaceBuilder) parentBuilder).setL2(readValue); + } + + @Nonnull + @Override + public L2Builder getBuilder(@Nonnull final InstanceIdentifier id) { + return new L2Builder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2Builder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + LOG.debug("Reading attributes for sub-interface L2: {}", id); + final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); + final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); + final String subInterfaceName = getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); + + builder.setInterconnection(icReadUtils.readInterconnection(id, subInterfaceName, ctx)); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/TapCustomizer.java new file mode 100644 index 000000000..992912a63 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/TapCustomizer.java @@ -0,0 +1,121 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletionStage; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Tap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.TapBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceTapDetails; +import org.openvpp.jvpp.dto.SwInterfaceTapDetailsReplyDump; +import org.openvpp.jvpp.dto.SwInterfaceTapDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class TapCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(TapCustomizer.class); + public static final String DUMPED_TAPS_CONTEXT_KEY = TapCustomizer.class.getName() + "dumpedTapsDuringGetAllIds"; + private NamingContext interfaceContext; + + public TapCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) { + super(jvpp); + this.interfaceContext = interfaceContext; + } + + @Override + public void merge(@Nonnull Builder parentBuilder, @Nonnull Tap readValue) { + ((VppInterfaceStateAugmentationBuilder) parentBuilder).setTap(readValue); + } + + @Nonnull + @Override + public TapBuilder getBuilder(@Nonnull InstanceIdentifier id) { + return new TapBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final TapBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + try { + final InterfaceKey key = id.firstKeyOf(Interface.class); + final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext()); + if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap.class)) { + return; + } + + LOG.debug("Reading attributes for tap interface: {}", key.getName()); + + @SuppressWarnings("unchecked") + Map mappedTaps = + (Map) ctx.getModificationCache().get(DUMPED_TAPS_CONTEXT_KEY); + + if(mappedTaps == null) { + // Full Tap dump has to be performed here, no filter or anything is here to help so at least we cache it + final SwInterfaceTapDump request = new SwInterfaceTapDump(); + final CompletionStage swInterfaceTapDetailsReplyDumpCompletionStage = + getFutureJVpp().swInterfaceTapDump(request); + final SwInterfaceTapDetailsReplyDump reply = + TranslateUtils.getReplyForRead(swInterfaceTapDetailsReplyDumpCompletionStage.toCompletableFuture(), id); + + if(null == reply || null == reply.swInterfaceTapDetails) { + mappedTaps = Collections.emptyMap(); + } else { + final List swInterfaceTapDetails = reply.swInterfaceTapDetails; + // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes + mappedTaps = swInterfaceTapDetails.stream() + .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails)); + } + + ctx.getModificationCache().put(DUMPED_TAPS_CONTEXT_KEY, mappedTaps); + } + + final SwInterfaceTapDetails swInterfaceTapDetails = mappedTaps.get(index); + LOG.trace("Tap interface: {} attributes returned from VPP: {}", key.getName(), swInterfaceTapDetails); + + builder.setTapName(TranslateUtils.toString(swInterfaceTapDetails.devName)); + LOG.debug("Tap interface: {}, id: {} attributes read as: {}", key.getName(), index, builder); + } catch (VppBaseCallException e) { + LOG.warn("Failed to readCurrentAttributes for: {}", id, e); + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VhostUserCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VhostUserCustomizer.java new file mode 100644 index 000000000..a9bf069b2 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VhostUserCustomizer.java @@ -0,0 +1,130 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.math.BigInteger; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletionStage; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUser; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUserBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceVhostUserDetails; +import org.openvpp.jvpp.dto.SwInterfaceVhostUserDetailsReplyDump; +import org.openvpp.jvpp.dto.SwInterfaceVhostUserDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class VhostUserCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(VhostUserCustomizer.class); + public static final String DUMPED_VHOST_USERS_CONTEXT_KEY = VhostUserCustomizer.class.getName() + "dumpedVhostUsersDuringGetAllIds"; + private NamingContext interfaceContext; + + public VhostUserCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) { + super(jvpp); + this.interfaceContext = interfaceContext; + } + + @Override + public void merge(@Nonnull Builder parentBuilder, @Nonnull VhostUser readValue) { + ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVhostUser(readValue); + } + + @Nonnull + @Override + public VhostUserBuilder getBuilder(@Nonnull InstanceIdentifier id) { + return new VhostUserBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VhostUserBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + try { + final InterfaceKey key = id.firstKeyOf(Interface.class); + final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext()); + if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class)) { + return; + } + + LOG.debug("Reading attributes for vhpost user interface: {}", key.getName()); + + @SuppressWarnings("unchecked") + Map mappedVhostUsers = + (Map) ctx.getModificationCache().get(DUMPED_VHOST_USERS_CONTEXT_KEY); + + if(mappedVhostUsers == null) { + // Full VhostUser dump has to be performed here, no filter or anything is here to help so at least we cache it + final SwInterfaceVhostUserDump request = new SwInterfaceVhostUserDump(); + final CompletionStage swInterfaceVhostUserDetailsReplyDumpCompletionStage = + getFutureJVpp().swInterfaceVhostUserDump(request); + final SwInterfaceVhostUserDetailsReplyDump reply = + TranslateUtils.getReplyForRead(swInterfaceVhostUserDetailsReplyDumpCompletionStage.toCompletableFuture(), id); + + if(null == reply || null == reply.swInterfaceVhostUserDetails) { + mappedVhostUsers = Collections.emptyMap(); + } else { + final List swInterfaceVhostUserDetails = reply.swInterfaceVhostUserDetails; + // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes + mappedVhostUsers = swInterfaceVhostUserDetails.stream() + .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails)); + } + + ctx.getModificationCache().put(DUMPED_VHOST_USERS_CONTEXT_KEY, mappedVhostUsers); + } + + // Relying here that parent InterfaceCustomizer was invoked first to fill in the context with initial ifc mapping + final SwInterfaceVhostUserDetails swInterfaceVhostUserDetails = mappedVhostUsers.get(index); + LOG.trace("Vhost user interface: {} attributes returned from VPP: {}", key.getName(), swInterfaceVhostUserDetails); + + builder.setRole(swInterfaceVhostUserDetails.isServer == 1 ? VhostUserRole.Server : VhostUserRole.Client); + builder.setFeatures(BigInteger.valueOf(swInterfaceVhostUserDetails.features)); + builder.setNumMemoryRegions((long) swInterfaceVhostUserDetails.numRegions); + builder.setSocket(TranslateUtils.toString(swInterfaceVhostUserDetails.sockFilename)); + builder.setVirtioNetHdrSize((long) swInterfaceVhostUserDetails.virtioNetHdrSz); + builder.setConnectError(Integer.toString(swInterfaceVhostUserDetails.sockErrno)); + + LOG.debug("Vhost user interface: {}, id: {} attributes read as: {}", key.getName(), index, builder); + } catch (VppBaseCallException e) { + LOG.warn("Failed to readCurrentAttributes for: {}", id, e); + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizer.java new file mode 100644 index 000000000..450c75709 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizer.java @@ -0,0 +1,145 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.VxlanTunnelDetails; +import org.openvpp.jvpp.dto.VxlanTunnelDetailsReplyDump; +import org.openvpp.jvpp.dto.VxlanTunnelDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VxlanCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class); + private final NamingContext interfaceContext; + + public VxlanCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) { + super(jvpp); + this.interfaceContext = interfaceContext; + } + + @Override + public void merge(@Nonnull Builder parentBuilder, + @Nonnull Vxlan readValue) { + ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVxlan(readValue); + } + + @Nonnull + @Override + public VxlanBuilder getBuilder(@Nonnull InstanceIdentifier id) { + return new VxlanBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VxlanBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + try { + final InterfaceKey key = id.firstKeyOf(Interface.class); + final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext()); + if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, VxlanTunnel.class)) { + return; + } + + LOG.debug("Reading attributes for vxlan tunnel: {}", key.getName()); + // Dump just a single + final VxlanTunnelDump request = new VxlanTunnelDump(); + request.swIfIndex = index; + + final CompletionStage swInterfaceVxlanDetailsReplyDumpCompletionStage = + getFutureJVpp().vxlanTunnelDump(request); + final VxlanTunnelDetailsReplyDump reply = + TranslateUtils.getReplyForRead(swInterfaceVxlanDetailsReplyDumpCompletionStage.toCompletableFuture(), id); + + // VPP keeps vxlan tunnel interfaces even after they were deleted (optimization) + // However there ar no longer any vxlan tunnel specific fields assigned to it and this call + // returns nothing + if (reply == null || reply.vxlanTunnelDetails == null || reply.vxlanTunnelDetails.isEmpty()) { + LOG.debug( + "Vxlan tunnel {}, id {} has no attributes assigned in VPP. Probably is a leftover interface placeholder" + + "after delete", key.getName(), index); + return; + } + + checkState(reply.vxlanTunnelDetails.size() == 1, + "Unexpected number of returned vxlan tunnels: {} for tunnel: {}", reply.vxlanTunnelDetails, key.getName()); + LOG.trace("Vxlan tunnel: {} attributes returned from VPP: {}", key.getName(), reply); + + final VxlanTunnelDetails swInterfaceVxlanDetails = reply.vxlanTunnelDetails.get(0); + if (swInterfaceVxlanDetails.isIpv6 == 1) { + final Ipv6Address dstIpv6 = + new Ipv6Address(parseAddress(swInterfaceVxlanDetails.dstAddress).getHostAddress()); + builder.setDst(new IpAddress(dstIpv6)); + final Ipv6Address srcIpv6 = + new Ipv6Address(parseAddress(swInterfaceVxlanDetails.srcAddress).getHostAddress()); + builder.setSrc(new IpAddress(srcIpv6)); + } else { + final byte[] dstBytes = Arrays.copyOfRange(swInterfaceVxlanDetails.dstAddress, 0, 4); + final Ipv4Address dstIpv4 = new Ipv4Address(parseAddress(dstBytes).getHostAddress()); + builder.setDst(new IpAddress(dstIpv4)); + final byte[] srcBytes = Arrays.copyOfRange(swInterfaceVxlanDetails.srcAddress, 0, 4); + final Ipv4Address srcIpv4 = new Ipv4Address(parseAddress(srcBytes).getHostAddress()); + builder.setSrc(new IpAddress(srcIpv4)); + } + builder.setEncapVrfId((long) swInterfaceVxlanDetails.encapVrfId); + builder.setVni( new VxlanVni((long) swInterfaceVxlanDetails.vni)); + LOG.debug("Vxlan tunnel: {}, id: {} attributes read as: {}", key.getName(), index, builder); + } catch (VppBaseCallException e) { + LOG.warn("Failed to readCurrentAttributes for: {}", id); + throw new ReadFailedException( id, e ); + } + } + + @Nonnull + private static InetAddress parseAddress(@Nonnull final byte[] addr) { + try { + return InetAddress.getByAddress(addr); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Cannot create InetAddress from " + Arrays.toString(addr), e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizer.java new file mode 100644 index 000000000..6763aaf60 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizer.java @@ -0,0 +1,148 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeNextProtocol; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeVni; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpeBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.VxlanGpeTunnelDetails; +import org.openvpp.jvpp.dto.VxlanGpeTunnelDetailsReplyDump; +import org.openvpp.jvpp.dto.VxlanGpeTunnelDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VxlanGpeCustomizer extends FutureJVppCustomizer + implements ReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class); + private NamingContext interfaceContext; + + public VxlanGpeCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) { + super(jvpp); + this.interfaceContext = interfaceContext; + } + + @Override + public void merge(@Nonnull Builder parentBuilder, + @Nonnull VxlanGpe readValue) { + ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVxlanGpe(readValue); + } + + @Nonnull + @Override + public VxlanGpeBuilder getBuilder(@Nonnull InstanceIdentifier id) { + return new VxlanGpeBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VxlanGpeBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + try { + final InterfaceKey key = id.firstKeyOf(Interface.class); + final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext()); + if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, VxlanGpeTunnel.class)) { + return; + } + + LOG.debug("Reading attributes for VxlanGpe tunnel: {}", key.getName()); + // Dump just a single + final VxlanGpeTunnelDump request = new VxlanGpeTunnelDump(); + request.swIfIndex = index; + + final CompletionStage swInterfaceVxlanGpeDetailsReplyDumpCompletionStage = + getFutureJVpp().vxlanGpeTunnelDump(request); + final VxlanGpeTunnelDetailsReplyDump reply = + TranslateUtils.getReplyForRead(swInterfaceVxlanGpeDetailsReplyDumpCompletionStage.toCompletableFuture(), id); + + // VPP keeps VxlanGpe tunnel interfaces even after they were deleted (optimization) + // However there are no longer any VxlanGpe tunnel specific fields assigned to it and this call + // returns nothing + if (reply == null || reply.vxlanGpeTunnelDetails == null || reply.vxlanGpeTunnelDetails.isEmpty()) { + LOG.debug( + "VxlanGpe tunnel {}, id {} has no attributes assigned in VPP. Probably is a leftover interface placeholder" + + "after delete", key.getName(), index); + return; + } + + checkState(reply.vxlanGpeTunnelDetails.size() == 1, + "Unexpected number of returned VxlanGpe tunnels: {} for tunnel: {}", reply.vxlanGpeTunnelDetails, key.getName()); + LOG.trace("VxlanGpe tunnel: {} attributes returned from VPP: {}", key.getName(), reply); + + final VxlanGpeTunnelDetails swInterfaceVxlanGpeDetails = reply.vxlanGpeTunnelDetails.get(0); + if (swInterfaceVxlanGpeDetails.isIpv6 == 1) { + final Ipv6Address remote6 = + new Ipv6Address(parseAddress(swInterfaceVxlanGpeDetails.remote).getHostAddress()); + builder.setRemote(new IpAddress(remote6)); + final Ipv6Address local6 = + new Ipv6Address(parseAddress(swInterfaceVxlanGpeDetails.local).getHostAddress()); + builder.setLocal(new IpAddress(local6)); + } else { + final byte[] dstBytes = Arrays.copyOfRange(swInterfaceVxlanGpeDetails.remote, 0, 4); + final Ipv4Address remote4 = new Ipv4Address(parseAddress(dstBytes).getHostAddress()); + builder.setRemote(new IpAddress(remote4)); + final byte[] srcBytes = Arrays.copyOfRange(swInterfaceVxlanGpeDetails.local, 0, 4); + final Ipv4Address local4 = new Ipv4Address(parseAddress(srcBytes).getHostAddress()); + builder.setLocal(new IpAddress(local4)); + } + builder.setVni(new VxlanGpeVni((long) swInterfaceVxlanGpeDetails.vni)); + builder.setNextProtocol(VxlanGpeNextProtocol.forValue(swInterfaceVxlanGpeDetails.protocol)); + builder.setEncapVrfId((long) swInterfaceVxlanGpeDetails.encapVrfId); + builder.setDecapVrfId((long) swInterfaceVxlanGpeDetails.decapVrfId); + LOG.debug("VxlanGpe tunnel: {}, id: {} attributes read as: {}", key.getName(), index, builder); + } catch (VppBaseCallException e) { + LOG.warn("Failed to readCurrentAttributes for: {}", id); + throw new ReadFailedException( id, e ); + } + } + + @Nonnull + private static InetAddress parseAddress(@Nonnull final byte[] addr) { + try { + return InetAddress.getByAddress(addr); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Cannot create InetAddress from " + Arrays.toString(addr), e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java new file mode 100644 index 000000000..b4b656c52 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java @@ -0,0 +1,113 @@ +/* + * 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.translate.v3po.interfacesstate.ip; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.dumpAddresses; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.findIpAddressDetailsByIp; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.getAllIpv4AddressIds; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLengthBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.IpAddressDetails; +import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Read customizer for interface Ipv4 addresses. + */ +public class Ipv4AddressCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class); + + private final NamingContext interfaceContext; + + public Ipv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + @Nonnull + public AddressBuilder getBuilder(@Nonnull InstanceIdentifier

id) { + return new AddressBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull InstanceIdentifier
id, @Nonnull AddressBuilder builder, + @Nonnull ReadContext ctx) + throws ReadFailedException { + LOG.debug("Reading attributes for interface address: {}", id); + + final String interfaceName = id.firstKeyOf(Interface.class).getName(); + final int interfaceIndex = interfaceContext.getIndex(interfaceName, ctx.getMappingContext()); + final Optional dumpOptional = + dumpAddresses(getFutureJVpp(), id, interfaceName, interfaceIndex, ctx); + + final Optional ipAddressDetails = + findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp()); + + if (ipAddressDetails.isPresent()) { + final IpAddressDetails detail = ipAddressDetails.get(); + builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)) + .setSubnet(new PrefixLengthBuilder().setPrefixLength(Short.valueOf(detail.prefixLength)).build()); + + if (LOG.isDebugEnabled()) { + LOG.debug("Attributes for {} interface (id={}) address {} successfully read: {}", + interfaceName, interfaceIndex, id, builder.build()); + } + } + } + + @Override + public List getAllIds(@Nonnull InstanceIdentifier
id, @Nonnull ReadContext ctx) + throws ReadFailedException { + LOG.debug("Reading list of keys for interface addresses: {}", id); + + final String interfaceName = id.firstKeyOf(Interface.class).getName(); + final int interfaceIndex = interfaceContext.getIndex(interfaceName, ctx.getMappingContext()); + final Optional dumpOptional = + dumpAddresses(getFutureJVpp(), id, interfaceName, interfaceIndex, ctx); + + return getAllIpv4AddressIds(dumpOptional, AddressKey::new); + } + + @Override + public void merge(@Nonnull Builder builder, @Nonnull List
readData) { + ((Ipv4Builder) builder).setAddress(readData); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4Customizer.java new file mode 100644 index 000000000..6b890f343 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4Customizer.java @@ -0,0 +1,60 @@ +/* + * 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.translate.v3po.interfacesstate.ip; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Ipv4Customizer extends FutureJVppCustomizer implements ReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(Ipv4Customizer.class); + + public Ipv4Customizer(@Nonnull final FutureJVpp futureJvpp) { + super(futureJvpp); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Ipv4 readValue) { + ((Interface2Builder) parentBuilder).setIpv4(readValue); + } + + @Nonnull + @Override + public Ipv4Builder getBuilder(@Nonnull final InstanceIdentifier id) { + return new Ipv4Builder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Ipv4Builder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + //TODO add reading of isForwarding flag when there is dump for it + LOG.warn("Operation not supported"); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java new file mode 100644 index 000000000..3b04c5614 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java @@ -0,0 +1,73 @@ +/* + * 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.translate.v3po.interfacesstate.ip; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import java.util.Collections; +import java.util.List; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Neighbor; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.NeighborBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.NeighborKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Operational data read operation customizer for {@link Neighbor}
+ * Currently not supported in jvpp, so this is only dummy implementation
+ */ +public class Ipv4NeighbourCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(Ipv4NeighbourCustomizer.class); + + public Ipv4NeighbourCustomizer(FutureJVpp futureJvpp) { + super(futureJvpp); + } + + @Override + public NeighborBuilder getBuilder(InstanceIdentifier id) { + return new NeighborBuilder(); + } + + @Override + public void readCurrentAttributes(InstanceIdentifier id, NeighborBuilder builder, ReadContext ctx) + throws ReadFailedException { + //TODO - not supported, implement https://jira.fd.io/browse/VPP-164 first + LOG.warn("Operation not supported"); + } + + @Override + public List getAllIds(InstanceIdentifier id, ReadContext context) + throws ReadFailedException { + //TODO - not supported, implement https://jira.fd.io/browse/VPP-164 first + LOG.warn("Operation not supported,returning empty List"); + return Collections.emptyList(); + } + + @Override + public void merge(Builder builder, List readData) { + ((Ipv4Builder) builder).setNeighbor(readData); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java new file mode 100644 index 000000000..56ad73c9b --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java @@ -0,0 +1,130 @@ +/* + * 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.translate.v3po.interfacesstate.ip; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.ReadTimeoutException; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.IpAddressDetails; +import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; +import org.openvpp.jvpp.dto.IpAddressDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class providing Ipv4 read support. + */ +final class Ipv4ReadUtils { + + static final String CACHE_KEY = Ipv4ReadUtils.class.getName(); + private static final Logger LOG = LoggerFactory.getLogger(Ipv4ReadUtils.class); + + private Ipv4ReadUtils() { + throw new UnsupportedOperationException("This utility class cannot be instantiated"); + } + + // Many VPP APIs do not provide get operation for single item. Dump requests for all items are used instead. + // To improve HC performance, caching dump requests is a common pattern. + // TODO: use more generic caching implementation, once provided + static Optional dumpAddresses(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final InstanceIdentifier id, + @Nonnull final String interfaceName, + final int interfaceIndex, @Nonnull final ReadContext ctx) + throws ReadFailedException { + + final String cacheKey = CACHE_KEY + interfaceName; + Optional dumpFromCache = dumpAddressFromCache(cacheKey, ctx.getModificationCache()); + + if (dumpFromCache.isPresent()) { + return dumpFromCache; + } + + Optional dumpFromOperational; + try { + dumpFromOperational = dumpAddressFromOperationalData(futureJvpp, id, interfaceIndex); + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + + if (dumpFromOperational.isPresent()) { + ctx.getModificationCache().put(cacheKey, dumpFromOperational.get()); + } + + return dumpFromOperational; + } + + private static Optional dumpAddressFromCache(@Nonnull final String cacheKey, + @Nonnull final ModificationCache cache) { + LOG.debug("Retrieving Ipv4 addresses from cache for {}", cacheKey); + return Optional.fromNullable((IpAddressDetailsReplyDump) cache.get(cacheKey)); + } + + private static Optional dumpAddressFromOperationalData( + @Nonnull final FutureJVpp futureJvpp, @Nonnull final InstanceIdentifier id, final int interfaceIndex) + throws VppBaseCallException, ReadTimeoutException { + LOG.debug("Dumping Ipv4 addresses for interface id={}", interfaceIndex); + final IpAddressDump dumpRequest = new IpAddressDump(); + dumpRequest.isIpv6 = 0; + dumpRequest.swIfIndex = interfaceIndex; + return Optional.fromNullable( + TranslateUtils.getReplyForRead(futureJvpp.ipAddressDump(dumpRequest).toCompletableFuture(), id)); + } + + @Nonnull static List getAllIpv4AddressIds( + final Optional dumpOptional, + @Nonnull final Function keyConstructor) { + if (dumpOptional.isPresent() && dumpOptional.get().ipAddressDetails != null) { + return dumpOptional.get().ipAddressDetails.stream() + .map(detail -> keyConstructor.apply(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip))) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + static Optional findIpAddressDetailsByIp( + final Optional dump, + @Nonnull final Ipv4AddressNoZone ip) { + checkNotNull(ip, "ip address should not be null"); + + if (dump.isPresent() && dump.get().ipAddressDetails != null) { + final List details = dump.get().ipAddressDetails; + + return Optional.of(details.stream() + .filter(singleDetail -> ip.equals(TranslateUtils.arrayToIpv4AddressNoZone(singleDetail.ip))) + .collect(RWUtils.singleItemCollector())); + } + return Optional.absent(); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv6Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv6Customizer.java new file mode 100644 index 000000000..b71cca0bb --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv6Customizer.java @@ -0,0 +1,64 @@ +/* + * 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.translate.v3po.interfacesstate.ip; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6Builder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; + +public class Ipv6Customizer extends FutureJVppCustomizer implements ReaderCustomizer { + + private final NamingContext interfaceContext; + + public Ipv6Customizer(@Nonnull final FutureJVpp futureJvpp, final NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = interfaceContext; + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Ipv6 readValue) { + ((Interface2Builder) parentBuilder).setIpv6(readValue); + } + + @Nonnull + @Override + public Ipv6Builder getBuilder(@Nonnull final InstanceIdentifier id) { + return new Ipv6Builder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Ipv6Builder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + // TODO implement +// final IpAddressDump dumpRequest = new IpAddressDump(); +// dumpRequest.isIpv6 = 1; +// dumpRequest.swIfIndex = interfaceContext.getIndex(id.firstKeyOf(Interface.class).getName(), ctx.getMappingContext()); +// final CompletionStage addressDumpFuture = getFutureJVpp().ipAddressDump(dumpRequest); + // TODO consider extracting customizer for address +// final IpAddressDetailsReplyDump reply = TranslateUtils.getReply(addressDumpFuture.toCompletableFuture()); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java new file mode 100644 index 000000000..c5fa6ee8e --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java @@ -0,0 +1,120 @@ +/* + * 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.translate.v3po.interfacesstate.ip; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.dumpAddresses; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.findIpAddressDetailsByIp; +import static io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.getAllIpv4AddressIds; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLengthBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.IpAddressDetails; +import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Read customizer for sub-interface Ipv4 addresses. + */ +public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class); + + private final NamingContext interfaceContext; + + public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + @Nonnull + public AddressBuilder getBuilder(@Nonnull InstanceIdentifier
id) { + return new AddressBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull InstanceIdentifier
id, @Nonnull AddressBuilder builder, + @Nonnull ReadContext ctx) + throws ReadFailedException { + LOG.debug("Reading attributes for sub-interface address: {}", id); + + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()); + final Optional dumpOptional = + dumpAddresses(getFutureJVpp(), id, subInterfaceName, subInterfaceIndex, ctx); + + final Optional ipAddressDetails = + findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp()); + + if (ipAddressDetails.isPresent()) { + final IpAddressDetails detail = ipAddressDetails.get(); + builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)) + .setSubnet(new PrefixLengthBuilder().setPrefixLength(Short.valueOf(detail.prefixLength)).build()); + + if (LOG.isDebugEnabled()) { + LOG.debug("Attributes for {} sub-interface (id={}) address {} successfully read: {}", + subInterfaceName, subInterfaceIndex, id, builder.build()); + } + } + } + + @Override + public List getAllIds(@Nonnull InstanceIdentifier
id, @Nonnull ReadContext ctx) + throws ReadFailedException { + LOG.debug("Reading list of keys for sub-interface addresses: {}", id); + + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()); + final Optional dumpOptional = + dumpAddresses(getFutureJVpp(), id, subInterfaceName, subInterfaceIndex, ctx); + + return getAllIpv4AddressIds(dumpOptional, AddressKey::new); + } + + @Override + public void merge(@Nonnull Builder builder, @Nonnull List
readData) { + ((Ipv4Builder) builder).setAddress(readData); + } + + private static String getSubInterfaceName(@Nonnull final InstanceIdentifier
id) { + return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), + Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier())); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducer.java new file mode 100644 index 000000000..1c60ef609 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducer.java @@ -0,0 +1,153 @@ +/* + * 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.translate.v3po.notification; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import io.fd.honeycomb.notification.ManagedNotificationProducer; +import io.fd.honeycomb.notification.NotificationCollector; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeoutException; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.concurrent.NotThreadSafe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceDeleted; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceDeletedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceNameOrIndex; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStateChange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStateChangeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStatus; +import org.opendaylight.yangtools.yang.binding.Notification; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceSetFlagsNotification; +import org.openvpp.jvpp.dto.WantInterfaceEvents; +import org.openvpp.jvpp.dto.WantInterfaceEventsReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Notification producer for interface events. It starts interface notification stream and for every + * received notification, it transforms it into its BA equivalent and pushes into HC's notification collector. + */ +@NotThreadSafe +public final class InterfaceChangeNotificationProducer implements ManagedNotificationProducer { + + private static final Logger LOG = LoggerFactory.getLogger(InterfaceChangeNotificationProducer.class); + + private final FutureJVpp jvpp; + private final NamingContext interfaceContext; + private final MappingContext mappingContext; + @Nullable + private AutoCloseable notificationListenerReg; + + public InterfaceChangeNotificationProducer(@Nonnull final FutureJVpp jvpp, + @Nonnull final NamingContext interfaceContext, + @Nonnull final MappingContext mappingContext) { + this.jvpp = jvpp; + this.interfaceContext = interfaceContext; + this.mappingContext = mappingContext; + } + + @Override + public void start(final NotificationCollector collector) { + LOG.trace("Starting interface notifications"); + enableDisableIfcNotifications(1); + LOG.debug("Interface notifications started successfully"); + notificationListenerReg = jvpp.getNotificationRegistry().registerSwInterfaceSetFlagsNotificationCallback( + swInterfaceSetFlagsNotification -> { + LOG.trace("Interface notification received: {}", swInterfaceSetFlagsNotification); + // TODO this should be lazy + collector.onNotification(transformNotification(swInterfaceSetFlagsNotification)); + } + ); + } + + private Notification transformNotification(final SwInterfaceSetFlagsNotification swInterfaceSetFlagsNotification) { + if (swInterfaceSetFlagsNotification.deleted == 1) { + return new InterfaceDeletedBuilder().setName(getIfcName(swInterfaceSetFlagsNotification)).build(); + } else { + return new InterfaceStateChangeBuilder() + .setName(getIfcName(swInterfaceSetFlagsNotification)) + .setAdminStatus(swInterfaceSetFlagsNotification.adminUpDown == 1 ? InterfaceStatus.Up : InterfaceStatus.Down) + .setOperStatus(swInterfaceSetFlagsNotification.linkUpDown == 1 ? InterfaceStatus.Up : InterfaceStatus.Down) + .build(); + } + } + + /** + * Get mapped name for the interface. Best effort only! The mapping might not yet be stored in context + * data tree (write transaction is still in progress and context changes have not been committed yet, or + * VPP sends the notification before it returns create request(that would store mapping)). + *

+ * In case mapping is not available, index is used as name. TODO inconsistent behavior, maybe just use indices ? + */ + private InterfaceNameOrIndex getIfcName(final SwInterfaceSetFlagsNotification swInterfaceSetFlagsNotification) { + final Optional optionalName = + interfaceContext.getNameIfPresent(swInterfaceSetFlagsNotification.swIfIndex, mappingContext); + return optionalName.isPresent() + ? new InterfaceNameOrIndex(optionalName.get()) + : new InterfaceNameOrIndex((long) swInterfaceSetFlagsNotification.swIfIndex); + } + + @Override + public void stop() { + LOG.trace("Stopping interface notifications"); + enableDisableIfcNotifications(0); + LOG.debug("Interface notifications stopped successfully"); + try { + if (notificationListenerReg != null) { + notificationListenerReg.close(); + } + } catch (Exception e) { + LOG.warn("Unable to properly close notification registration: {}", notificationListenerReg, e); + } + } + + private void enableDisableIfcNotifications(int enableDisable) { + final WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents(); + wantInterfaceEvents.pid = 1; + wantInterfaceEvents.enableDisable = enableDisable; + final CompletionStage wantInterfaceEventsReplyCompletionStage; + try { + wantInterfaceEventsReplyCompletionStage = jvpp.wantInterfaceEvents(wantInterfaceEvents); + TranslateUtils.getReply(wantInterfaceEventsReplyCompletionStage.toCompletableFuture()); + } catch (VppBaseCallException | TimeoutException e) { + LOG.warn("Unable to {} interface notifications", enableDisable == 1 ? "enable" : "disable", e); + throw new IllegalStateException("Unable to control interface notifications", e); + } + } + + @Nonnull + @Override + public Collection> getNotificationTypes() { + final ArrayList> classes = Lists.newArrayList(); + classes.add(InterfaceStateChange.class); + classes.add(InterfaceDeleted.class); + return classes; + } + + @Override + public void close() throws Exception { + LOG.trace("Closing interface notifications producer"); + stop(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizer.java new file mode 100644 index 000000000..d148bc20c --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizer.java @@ -0,0 +1,144 @@ +/* + * 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.translate.v3po.vpp; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.BridgeDomainAddDel; +import org.openvpp.jvpp.dto.BridgeDomainAddDelReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BridgeDomainCustomizer + extends FutureJVppCustomizer + implements ListWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class); + + private static final byte ADD_OR_UPDATE_BD = (byte) 1; + private final NamingContext bdContext; + + public BridgeDomainCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext bdContext) { + super(futureJvpp); + this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null"); + } + + private BridgeDomainAddDelReply addOrUpdateBridgeDomain(@Nonnull final InstanceIdentifier id, + final int bdId, @Nonnull final BridgeDomain bd) + throws VppBaseCallException, WriteTimeoutException { + final BridgeDomainAddDelReply reply; + final BridgeDomainAddDel request = new BridgeDomainAddDel(); + request.bdId = bdId; + request.flood = booleanToByte(bd.isFlood()); + request.forward = booleanToByte(bd.isForward()); + request.learn = booleanToByte(bd.isLearn()); + request.uuFlood = booleanToByte(bd.isUnknownUnicastFlood()); + request.arpTerm = booleanToByte(bd.isArpTermination()); + request.isAdd = ADD_OR_UPDATE_BD; + + reply = TranslateUtils.getReplyForWrite(getFutureJVpp().bridgeDomainAddDel(request).toCompletableFuture(), id); + LOG.debug("Bridge domain {} (id={}) add/update successful", bd.getName(), bdId); + return reply; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomain dataBefore, + @Nonnull final WriteContext ctx) + throws WriteFailedException { + LOG.debug("writeCurrentAttributes: id={}, current={}, ctx={}", id, dataBefore, ctx); + final String bdName = dataBefore.getName(); + + try { + int index; + if (bdContext.containsIndex(bdName, ctx.getMappingContext())) { + index = bdContext.getIndex(bdName, ctx.getMappingContext()); + } else { + // FIXME we need the bd index to be returned by VPP or we should have a counter field + // (maybe in context similar to artificial name) + // Here we assign the next available ID from bdContext's perspective + index = 1; + while (bdContext.containsName(index, ctx.getMappingContext())) { + index++; + } + } + addOrUpdateBridgeDomain(id, index, dataBefore); + bdContext.addName(index, bdName, ctx.getMappingContext()); + } catch (VppBaseCallException e) { + LOG.warn("Failed to create bridge domain", e); + throw new WriteFailedException.CreateFailedException(id, dataBefore, e); + } + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomain dataBefore, + @Nonnull final WriteContext ctx) + throws WriteFailedException { + LOG.debug("deleteCurrentAttributes: id={}, dataBefore={}, ctx={}", id, dataBefore, ctx); + final String bdName = id.firstKeyOf(BridgeDomain.class).getName(); + int bdId = bdContext.getIndex(bdName, ctx.getMappingContext()); + try { + + final BridgeDomainAddDel request = new BridgeDomainAddDel(); + request.bdId = bdId; + + TranslateUtils.getReplyForWrite(getFutureJVpp().bridgeDomainAddDel(request).toCompletableFuture(), id); + LOG.debug("Bridge domain {} (id={}) deleted successfully", bdName, bdId); + } catch (VppBaseCallException e) { + LOG.warn("Bridge domain {} (id={}) delete failed", bdName, bdId); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomain dataBefore, @Nonnull final BridgeDomain dataAfter, + @Nonnull final WriteContext ctx) + throws WriteFailedException { + LOG.debug("updateCurrentAttributes: id={}, dataBefore={}, dataAfter={}, ctx={}", id, dataBefore, dataAfter, + ctx); + + final String bdName = checkNotNull(dataAfter.getName()); + checkArgument(bdName.equals(dataBefore.getName()), + "BridgeDomain name changed. It should be deleted and then created."); + + try { + addOrUpdateBridgeDomain(id, bdContext.getIndex(bdName, ctx.getMappingContext()), dataAfter); + } catch (VppBaseCallException e) { + LOG.warn("Failed to create bridge domain", e); + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); + } + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizer.java new file mode 100644 index 000000000..0e4b90a56 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizer.java @@ -0,0 +1,141 @@ +/* + * 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.translate.v3po.vpp; + +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.parseMac; + +import com.google.common.base.Preconditions; +import com.google.common.primitives.Longs; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibFilter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.L2FibAddDel; +import org.openvpp.jvpp.dto.L2FibAddDelReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writer Customizer responsible for L2 FIB create/delete operations.
Sends {@code l2_fib_add_del} message to + * VPP.
Equivalent of invoking {@code vppctl l2fib add/del} command. + */ +public class L2FibEntryCustomizer extends FutureJVppCustomizer + implements ListWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(L2FibEntryCustomizer.class); + + private final NamingContext bdContext; + private final NamingContext interfaceContext; + + public L2FibEntryCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext bdContext, + @Nonnull final NamingContext interfaceContext) { + super(futureJvpp); + this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null"); + this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final L2FibEntry dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + try { + LOG.debug("Creating L2 FIB entry: {} {}", id, dataAfter); + l2FibAddDel(id, dataAfter, writeContext, true); + LOG.debug("L2 FIB entry created successfully: {} {}", id, dataAfter); + } catch (VppBaseCallException e) { + LOG.warn("Failed to create L2 FIB entry: {} {}", id, dataAfter); + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final L2FibEntry dataBefore, @Nonnull final L2FibEntry dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + throw new UnsupportedOperationException( + "L2 FIB entry update is not supported. It has to be deleted and then created."); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final L2FibEntry dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + try { + LOG.debug("Deleting L2 FIB entry: {} {}", id, dataBefore); + l2FibAddDel(id, dataBefore, writeContext, false); + LOG.debug("L2 FIB entry deleted successfully: {} {}", id, dataBefore); + } catch (VppBaseCallException e) { + LOG.warn("Failed to delete L2 FIB entry: {} {}", id, dataBefore); + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void l2FibAddDel(@Nonnull final InstanceIdentifier id, @Nonnull final L2FibEntry entry, + final WriteContext writeContext, boolean isAdd) + throws VppBaseCallException, WriteTimeoutException { + final String bdName = id.firstKeyOf(BridgeDomain.class).getName(); + final int bdId = bdContext.getIndex(bdName, writeContext.getMappingContext()); + + int swIfIndex = -1; + final String swIfName = entry.getOutgoingInterface(); + if (swIfName != null) { + swIfIndex = interfaceContext.getIndex(swIfName, writeContext.getMappingContext()); + } + + final L2FibAddDel l2FibRequest = createL2FibRequest(entry, bdId, swIfIndex, isAdd); + LOG.debug("Sending l2FibAddDel request: {}", ReflectionToStringBuilder.toString(l2FibRequest)); + final CompletionStage l2FibAddDelReplyCompletionStage = + getFutureJVpp().l2FibAddDel(l2FibRequest); + + TranslateUtils.getReplyForWrite(l2FibAddDelReplyCompletionStage.toCompletableFuture(), id); + } + + private L2FibAddDel createL2FibRequest(final L2FibEntry entry, final int bdId, final int swIfIndex, boolean isAdd) { + final L2FibAddDel request = new L2FibAddDel(); + request.mac = macToLong(entry.getPhysAddress().getValue()); + request.bdId = bdId; + request.swIfIndex = swIfIndex; + request.isAdd = booleanToByte(isAdd); + if (isAdd) { + request.staticMac = booleanToByte(entry.isStaticConfig()); + request.filterMac = booleanToByte(L2FibFilter.class == entry.getAction()); + } + return request; + } + + // mac address is string of the form: 11:22:33:44:55:66 + // but VPP expects long value in the format 11:22:33:44:55:66:XX:XX + private static long macToLong(final String macAddress) { + final byte[] mac = parseMac(macAddress); + return Longs.fromBytes(mac[0], mac[1], mac[2], mac[3], + mac[4], mac[5], (byte) 0, (byte) 0); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java new file mode 100644 index 000000000..8027968f1 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReader.java @@ -0,0 +1,202 @@ +/* + * 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.translate.v3po.vppclassifier; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary; + +import com.google.common.base.Optional; +import com.google.common.primitives.UnsignedInts; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.xml.bind.DatatypeConverter; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifySessionDetails; +import org.openvpp.jvpp.dto.ClassifySessionDetailsReplyDump; +import org.openvpp.jvpp.dto.ClassifySessionDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Reader customizer responsible for classify session read.
to VPP.
Equivalent to invoking {@code vppctl show + * class table verbose} command. + */ +public class ClassifySessionReader extends FutureJVppCustomizer + implements ListReaderCustomizer, VppNodeReader { + + private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionReader.class); + static final String CACHE_KEY = ClassifySessionReader.class.getName(); + + private final NamingContext classifyTableContext; + + public ClassifySessionReader(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext classifyTableContext) { + super(futureJvpp); + this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); + } + + @Override + public void merge(@Nonnull final Builder builder, + @Nonnull final List readData) { + ((ClassifyTableBuilder) builder).setClassifySession(readData); + } + + @Nonnull + @Override + public ClassifySessionBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new ClassifySessionBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final ClassifySessionBuilder builder, @Nonnull final ReadContext ctx) + throws ReadFailedException { + LOG.debug("Reading attributes for classify session: {}", id); + + final ClassifySessionKey key = id.firstKeyOf(ClassifySession.class); + checkArgument(key != null, "could not find ClassifySession key in {}", id); + + final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx); + final byte[] match = DatatypeConverter.parseHexBinary(key.getMatch().getValue().replace(":", "")); + final Optional classifySession = + findClassifySessionDetailsByMatch(classifySessionDump, match); + + if (classifySession.isPresent()) { + final ClassifySessionDetails detail = classifySession.get(); + builder.setHitNext(readVppNode(detail.hitNextIndex, LOG)); + if (detail.opaqueIndex != ~0) { + // value is specified: + builder.setOpaqueIndex(readOpaqueIndex(detail.opaqueIndex)); + } + builder.setAdvance(detail.advance); + builder.setMatch(key.getMatch()); + + if (LOG.isTraceEnabled()) { + LOG.trace("Attributes for classify session {} successfully read: {}", id, builder.build()); + } + } + } + + private OpaqueIndex readOpaqueIndex(final int opaqueIndex) { + // We first try to map the value to a vpp node, if that fails, simply wrap the u32 value + // FIXME: the approach might fail if the opaqueIndex contains small value that collides + // with some of the adjacent nodes + final VppNode node = readVppNode(opaqueIndex, LOG); + if (node != null) { + return new OpaqueIndex(node); + } else { + return new OpaqueIndex(UnsignedInts.toLong(opaqueIndex)); + } + } + + @Nullable + private ClassifySessionDetailsReplyDump dumpClassifySessions(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class); + checkArgument(tableKey != null, "could not find ClassifyTable key in {}", id); + + final String cacheKey = CACHE_KEY + tableKey; + + ClassifySessionDetailsReplyDump classifySessionDump = + (ClassifySessionDetailsReplyDump) ctx.getModificationCache().get(cacheKey); + if (classifySessionDump != null) { + LOG.debug("Classify sessions is present in cache: {}", cacheKey); + return classifySessionDump; + } + + final String tableName = tableKey.getName(); + checkState(classifyTableContext.containsIndex(tableName, ctx.getMappingContext()), + "Reading classify sessions for table {}, but table index could not be found in the classify table context", + tableName); + final int tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext()); + LOG.debug("Dumping classify sessions for classify table id={}", tableId); + + try { + final ClassifySessionDump dumpRequest = new ClassifySessionDump(); + dumpRequest.tableId = tableId; + classifySessionDump = TranslateUtils + .getReplyForRead(getFutureJVpp().classifySessionDump(dumpRequest).toCompletableFuture(), id); + + // update the cache: + ctx.getModificationCache().put(cacheKey, classifySessionDump); + return classifySessionDump; + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } + + private static Optional findClassifySessionDetailsByMatch( + @Nullable final ClassifySessionDetailsReplyDump classifySessionDump, @Nonnull final byte[] match) { + if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) { + final List details = classifySessionDump.classifySessionDetails; + final List filteredSessions = details.stream() + .filter(singleDetail -> Arrays.equals(singleDetail.match, match)).collect(Collectors.toList()); + if (filteredSessions.isEmpty()) { + return Optional.absent(); + } else if (filteredSessions.size() == 1) { + return Optional.of(filteredSessions.get(0)); + } else { + throw new IllegalStateException(String.format( + "Found %d classify sessions witch given match. Single session expected.", + filteredSessions.size())); + } + } + return Optional.absent(); + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + LOG.debug("Reading list of keys for classify sessions: {}", id); + + final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx); + if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) { + return classifySessionDump.classifySessionDetails.stream() + .map(detail -> new ClassifySessionKey(new HexString(printHexBinary(detail.match)))) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.java new file mode 100644 index 000000000..5c00903ae --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriter.java @@ -0,0 +1,147 @@ +/* + * 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.translate.v3po.vppclassifier; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import javax.xml.bind.DatatypeConverter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyAddDelSession; +import org.openvpp.jvpp.dto.ClassifyAddDelSessionReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writer customizer responsible for classify session create/delete.
Sends {@code classify_add_del_session} message + * to VPP.
Equivalent to invoking {@code vppctl classify table} command. + */ +public class ClassifySessionWriter extends FutureJVppCustomizer + implements ListWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionWriter.class); + private final NamingContext classifyTableContext; + + public ClassifySessionWriter(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext classifyTableContext) { + super(futureJvpp); + this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final ClassifySession dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Creating classify session: iid={} dataAfter={}", id, dataAfter); + try { + classifyAddDelSession(true, id, dataAfter, writeContext); + LOG.debug("Successfully created classify session: iid={} dataAfter={}", id, dataAfter); + } catch (VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final ClassifySession dataBefore, + @Nonnull final ClassifySession dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + throw new UnsupportedOperationException("Classify session update is not supported"); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final ClassifySession dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Removing classify session: iid={} dataBefore={}", id, dataBefore); + try { + classifyAddDelSession(false, id, dataBefore, writeContext); + LOG.debug("Successfully removed classify session: iid={} dataBefore={}", id, dataBefore); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void classifyAddDelSession(final boolean isAdd, @Nonnull final InstanceIdentifier id, + @Nonnull final ClassifySession classifySession, + @Nonnull final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class); + checkArgument(tableKey != null, "could not find classify table key in {}", id); + + final String tableName = tableKey.getName(); + checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()), + "Could not find classify table index for {} in the classify table context", tableName); + final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext()); + + final CompletionStage createClassifyTableReplyCompletionStage = getFutureJVpp() + .classifyAddDelSession( + getClassifyAddDelSessionRequest(isAdd, tableIndex, classifySession)); + + TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id); + } + + private static ClassifyAddDelSession getClassifyAddDelSessionRequest(final boolean isAdd, final int tableIndex, + @Nonnull final ClassifySession classifySession) { + ClassifyAddDelSession request = new ClassifyAddDelSession(); + request.isAdd = booleanToByte(isAdd); + request.tableIndex = tableIndex; + + // mandatory: + // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed + request.hitNextIndex = classifySession.getHitNext().getPacketHandlingAction().getIntValue(); + + if (classifySession.getOpaqueIndex() != null) { + request.opaqueIndex = getOpaqueIndexValue(classifySession.getOpaqueIndex()); + } else { + request.opaqueIndex = ~0; // value not specified + } + + // default 0: + request.advance = classifySession.getAdvance(); + + request.match = DatatypeConverter.parseHexBinary(classifySession.getMatch().getValue().replace(":", "")); + return request; + } + + private static int getOpaqueIndexValue(@Nonnull final OpaqueIndex opaqueIndex) { + if (opaqueIndex.getUint32() != null) { + return opaqueIndex.getUint32().intValue(); + } else { + // TODO: implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed + return opaqueIndex.getVppNode().getPacketHandlingAction().getIntValue(); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.java new file mode 100644 index 000000000..6ad7b2151 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReader.java @@ -0,0 +1,147 @@ +/* + * 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.translate.v3po.vppclassifier; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary; + +import com.google.common.primitives.UnsignedInts; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyTableIds; +import org.openvpp.jvpp.dto.ClassifyTableIdsReply; +import org.openvpp.jvpp.dto.ClassifyTableInfo; +import org.openvpp.jvpp.dto.ClassifyTableInfoReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Reader customizer responsible for classify table read.
to VPP.
Equivalent to invoking {@code vppctl show + * class table} command. + */ +public class ClassifyTableReader extends FutureJVppCustomizer + implements ListReaderCustomizer, VppNodeReader { + + private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableReader.class); + private final NamingContext classifyTableContext; + + public ClassifyTableReader(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext classifyTableContext) { + super(futureJvpp); + this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); + } + + + @Override + public void merge(@Nonnull final Builder builder, + @Nonnull final List readData) { + ((VppClassifierStateBuilder) builder).setClassifyTable(readData); + } + + @Nonnull + @Override + public ClassifyTableBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new ClassifyTableBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final ClassifyTableBuilder builder, @Nonnull final ReadContext ctx) + throws ReadFailedException { + LOG.debug("Reading attributes for classify table: {}", id); + + final ClassifyTableKey key = id.firstKeyOf(ClassifyTable.class); + checkArgument(key != null, "could not find ClassifyTable key in {}", id); + final ClassifyTableInfo request = new ClassifyTableInfo(); + + final String tableName = key.getName(); + if (!classifyTableContext.containsIndex(tableName, ctx.getMappingContext())) { + LOG.debug("Could not find classify table {} in the naming context", tableName); + return; + } + request.tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext()); + + try { + final ClassifyTableInfoReply reply = + TranslateUtils.getReplyForRead(getFutureJVpp().classifyTableInfo(request).toCompletableFuture(), id); + + // mandatory values: + builder.setName(tableName); + builder.setKey(key); + builder.setNbuckets(UnsignedInts.toLong(reply.nbuckets)); + builder.setSkipNVectors(UnsignedInts.toLong(reply.skipNVectors)); + + + builder.setMissNext(readVppNode(reply.missNextIndex, LOG)); + builder.setMask(new HexString(printHexBinary(reply.mask))); + builder.setActiveSessions(UnsignedInts.toLong(reply.activeSessions)); + + if (reply.nextTableIndex != ~0) { + // next table index is present: + builder.setNextTable(classifyTableContext.getName(reply.nextTableIndex, ctx.getMappingContext())); + } + + if (LOG.isTraceEnabled()) { + LOG.trace("Attributes for classify table {} successfully read: {}", id, builder.build()); + } + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext context) throws ReadFailedException { + LOG.debug("Reading list of keys for classify tables: {}", id); + try { + final ClassifyTableIdsReply classifyTableIdsReply = TranslateUtils + .getReplyForRead(getFutureJVpp().classifyTableIds(new ClassifyTableIds()).toCompletableFuture(), id); + if (classifyTableIdsReply.ids != null) { + return Arrays.stream(classifyTableIdsReply.ids).mapToObj(i -> { + final String tableName = classifyTableContext.getName(i, context.getMappingContext()); + LOG.trace("Classify table with name: {} and index: {} found in VPP", tableName, i); + return new ClassifyTableKey(tableName); + }).collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java new file mode 100644 index 000000000..12680b9cf --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriter.java @@ -0,0 +1,146 @@ +/* + * 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.translate.v3po.vppclassifier; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte; + +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import javax.xml.bind.DatatypeConverter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyAddDelTable; +import org.openvpp.jvpp.dto.ClassifyAddDelTableReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writer customizer responsible for classify table create/delete.
Sends {@code classify_add_del_table} message to + * VPP.
Equivalent to invoking {@code vppctl classify table} command. + */ +public class ClassifyTableWriter extends FutureJVppCustomizer + implements ListWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableWriter.class); + private final NamingContext classifyTableContext; + + public ClassifyTableWriter(@Nonnull final FutureJVpp futureJvpp, + @Nonnull final NamingContext classifyTableContext) { + super(futureJvpp); + this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final ClassifyTable dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Creating classify table: iid={} dataAfter={}", id, dataAfter); + try { + final int newTableIndex = + classifyAddDelTable(true, id, dataAfter, ~0 /* value not present */, writeContext.getMappingContext()); + + // Add classify table name <-> vpp index mapping to the naming context: + classifyTableContext.addName(newTableIndex, dataAfter.getName(), writeContext.getMappingContext()); + LOG.debug("Successfully created classify table(id={]): iid={} dataAfter={}", newTableIndex, id, dataAfter); + } catch (VppBaseCallException e) { + throw new WriteFailedException.CreateFailedException(id, dataAfter, e); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final ClassifyTable dataBefore, @Nonnull final ClassifyTable dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + throw new UnsupportedOperationException("Classify table update is not supported"); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final ClassifyTable dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Removing classify table: iid={} dataBefore={}", id, dataBefore); + final String tableName = dataBefore.getName(); + checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()), + "Removing classify table {}, but index could not be found in the classify table context", tableName); + + final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext()); + try { + classifyAddDelTable(false, id, dataBefore, tableIndex, writeContext.getMappingContext()); + + // Remove deleted interface from interface context: + classifyTableContext.removeName(dataBefore.getName(), writeContext.getMappingContext()); + LOG.debug("Successfully removed classify table(id={]): iid={} dataAfter={}", tableIndex, id, dataBefore); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private int classifyAddDelTable(final boolean isAdd, @Nonnull final InstanceIdentifier id, + @Nonnull final ClassifyTable table, final int tableId, final MappingContext ctx) + throws VppBaseCallException, WriteTimeoutException { + final CompletionStage createClassifyTableReplyCompletionStage = + getFutureJVpp().classifyAddDelTable(getClassifyAddDelTableRequest(isAdd, tableId, table, ctx)); + + final ClassifyAddDelTableReply reply = + TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id); + return reply.newTableIndex; + + } + + private ClassifyAddDelTable getClassifyAddDelTableRequest(final boolean isAdd, final int tableIndex, + @Nonnull final ClassifyTable table, + @Nonnull final MappingContext ctx) { + final ClassifyAddDelTable request = new ClassifyAddDelTable(); + request.isAdd = booleanToByte(isAdd); + request.tableIndex = tableIndex; + + // mandatory, all u32 values are permitted: + request.nbuckets = table.getNbuckets().intValue(); + request.memorySize = table.getMemorySize().intValue(); + request.skipNVectors = table.getSkipNVectors().intValue(); + + // mandatory + // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed + request.missNextIndex = table.getMissNext().getPacketHandlingAction().getIntValue(); + + final String nextTable = table.getNextTable(); + if (isAdd && nextTable != null) { + request.nextTableIndex = classifyTableContext.getIndex(nextTable, ctx); + } else { + request.nextTableIndex = ~0; // value not specified + } + request.mask = DatatypeConverter.parseHexBinary(table.getMask().getValue().replace(":", "")); + checkArgument(request.mask.length % 16 == 0, "Number of mask bytes must be multiple of 16."); + request.matchNVectors = request.mask.length / 16; + + return request; + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java new file mode 100644 index 000000000..6061b8672 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppclassifier/VppNodeReader.java @@ -0,0 +1,41 @@ +/* + * 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.translate.v3po.vppclassifier; + +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; +import org.slf4j.Logger; + +interface VppNodeReader { + + /** + * Converts vpp node index to YANG representation of vpp node. + * + * @param nodeIndex index of vpp node treated as signed integer. + * @return vpp node representation + */ + default VppNode readVppNode(final int nodeIndex, @Nonnull final Logger log) { + final PacketHandlingAction action = PacketHandlingAction.forValue(nodeIndex); + if (action == null) { + // TODO: implement node index to name conversion after https://jira.fd.io/browse/VPP-203 is fixed + log.debug("VPP node index {} cannot be mapped to PacketHandlingAction", nodeIndex); + return null; + } + return new VppNode(action); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizer.java new file mode 100644 index 000000000..e8cfe3978 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizer.java @@ -0,0 +1,154 @@ +/* + * 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.translate.v3po.vppstate; + +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.byteToBoolean; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.BridgeDomainDetails; +import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump; +import org.openvpp.jvpp.dto.BridgeDomainDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class BridgeDomainCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class); + private final NamingContext bdContext; + + public BridgeDomainCustomizer(@Nonnull final FutureJVpp futureJVpp, @Nonnull final NamingContext bdContext) { + super(futureJVpp); + this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null"); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomainBuilder builder, @Nonnull final ReadContext context) + throws ReadFailedException { + LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: id={}, builderbuilder={}, context={}", + id, builder, context); + + final BridgeDomainKey key = id.firstKeyOf(id.getTargetType()); + LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: key={}", key); + + final int bdId = bdContext.getIndex(key.getName(), context.getMappingContext()); + LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: bdId={}", bdId); + + BridgeDomainDetailsReplyDump reply; + BridgeDomainDetails bridgeDomainDetails; + final BridgeDomainDump request = new BridgeDomainDump(); + request.bdId = bdContext.getIndex(key.getName(), context.getMappingContext()); + try { + reply = getFutureJVpp().bridgeDomainDump(request).toCompletableFuture().get(); + bridgeDomainDetails = Iterables.getOnlyElement(reply.bridgeDomainDetails); + } catch (Exception e) { + LOG.debug("Unable to read bridge domain: {}", key.getName(), e); + return; + } + + logBridgeDomainDetails(bridgeDomainDetails); + + builder.setName(key.getName()); + builder.setArpTermination(byteToBoolean(bridgeDomainDetails.arpTerm)); + builder.setFlood(byteToBoolean(bridgeDomainDetails.flood)); + builder.setForward(byteToBoolean(bridgeDomainDetails.forward)); + builder.setLearn(byteToBoolean(bridgeDomainDetails.learn)); + builder.setUnknownUnicastFlood(byteToBoolean(bridgeDomainDetails.uuFlood)); + } + + private void logBridgeDomainDetails(final BridgeDomainDetails bridgeDomainDetails) { + LOG.debug("bridgeDomainDetails={}", bridgeDomainDetails); + if (bridgeDomainDetails != null) { + LOG.debug("bridgeDomainDetails.arpTerm={}", bridgeDomainDetails.arpTerm); + LOG.debug("bridgeDomainDetails.bdId={}", bridgeDomainDetails.bdId); + LOG.debug("bridgeDomainDetails.bviSwIfIndex={}", bridgeDomainDetails.bviSwIfIndex); + LOG.debug("bridgeDomainDetails.flood={}", bridgeDomainDetails.flood); + LOG.debug("bridgeDomainDetails.forward={}", bridgeDomainDetails.forward); + LOG.debug("bridgeDomainDetails.learn={}", bridgeDomainDetails.learn); + LOG.debug("bridgeDomainDetails.nSwIfs={}", bridgeDomainDetails.nSwIfs); + LOG.debug("bridgeDomainDetails.uuFlood={}", bridgeDomainDetails.uuFlood); + } + } + + @Nonnull + @Override + public BridgeDomainBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new BridgeDomainBuilder(); + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext context) { + final BridgeDomainDump request = new BridgeDomainDump(); + request.bdId = -1; // dump call + + BridgeDomainDetailsReplyDump reply; + try { + reply = getFutureJVpp().bridgeDomainDump(request).toCompletableFuture().get(); + } catch (Exception e) { + throw new IllegalStateException("Bridge domain dump failed", e); // TODO ReadFailedException? + } + + if (reply == null || reply.bridgeDomainDetails == null) { + return Collections.emptyList(); + } + + final int bIdsLength = reply.bridgeDomainDetails.size(); + LOG.debug("vppstate.BridgeDomainCustomizer.getAllIds: bIds.length={}", bIdsLength); + if (bIdsLength == 0) { + // No bridge domains + return Collections.emptyList(); + } + + final List allIds = new ArrayList<>(bIdsLength); + for (BridgeDomainDetails detail : reply.bridgeDomainDetails) { + logBridgeDomainDetails(detail); + + final String bName = bdContext.getName(detail.bdId, context.getMappingContext()); + LOG.debug("vppstate.BridgeDomainCustomizer.getAllIds: bName={}", bName); + allIds.add(new BridgeDomainKey(bName)); + } + + return allIds; + } + + @Override + public void merge(@Nonnull final Builder builder, + @Nonnull final List readData) { + ((BridgeDomainsBuilder) builder).setBridgeDomain(readData); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizer.java new file mode 100644 index 000000000..a6ecafd72 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizer.java @@ -0,0 +1,154 @@ +/* + * 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.translate.v3po.vppstate; + +import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.vppPhysAddrToYang; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.byteToBoolean; + +import com.google.common.base.Preconditions; +import com.google.common.primitives.Longs; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.ReadTimeoutException; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibFilter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibForward; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.L2FibTableDump; +import org.openvpp.jvpp.dto.L2FibTableEntry; +import org.openvpp.jvpp.dto.L2FibTableEntryReplyDump; +import org.openvpp.jvpp.future.FutureJVpp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class L2FibEntryCustomizer extends FutureJVppCustomizer + implements ListReaderCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(L2FibEntryCustomizer.class); + + private static final Collector SINGLE_ITEM_COLLECTOR = + RWUtils.singleItemCollector(); + + private final NamingContext bdContext; + private final NamingContext interfaceContext; + + public L2FibEntryCustomizer(@Nonnull final FutureJVpp futureJVpp, @Nonnull final NamingContext bdContext, + @Nonnull final NamingContext interfaceContext) { + super(futureJVpp); + this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null"); + this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final L2FibEntryBuilder builder, @Nonnull final ReadContext ctx) + throws ReadFailedException { + + final L2FibEntryKey key = id.firstKeyOf(id.getTargetType()); + final BridgeDomainKey bridgeDomainKey = id.firstKeyOf(BridgeDomain.class); + final int bdId = bdContext.getIndex(bridgeDomainKey.getName(), ctx.getMappingContext()); + LOG.debug("Reading L2 FIB entry: key={}. bridgeDomainKey={}, bdId={}", key, bridgeDomainKey, bdId); + + try { + // TODO use cached l2FibTable + final L2FibTableEntry entry = dumpL2Fibs(id, bdId).stream().filter(e -> key.getPhysAddress() + .equals(new PhysAddress(vppPhysAddrToYang(Longs.toByteArray(e.mac), 2)))) + .collect(SINGLE_ITEM_COLLECTOR); + + builder.setAction(byteToBoolean(entry.filterMac) + ? L2FibFilter.class + : L2FibForward.class); + builder.setBridgedVirtualInterface(byteToBoolean(entry.bviMac)); + + if (entry.swIfIndex != -1) { + builder.setOutgoingInterface(interfaceContext.getName(entry.swIfIndex, ctx.getMappingContext())); + } + builder.setStaticConfig(byteToBoolean(entry.staticMac)); + builder.setPhysAddress(key.getPhysAddress()); + builder.setKey(key); + } catch (Exception e) { + throw new ReadFailedException(id, e); + } + } + + @Nonnull + private List dumpL2Fibs(final InstanceIdentifier id, final int bdId) + throws VppBaseCallException, ReadTimeoutException { + final L2FibTableDump l2FibRequest = new L2FibTableDump(); + l2FibRequest.bdId = bdId; + + final CompletableFuture l2FibTableDumpCompletableFuture = + getFutureJVpp().l2FibTableDump(l2FibRequest).toCompletableFuture(); + + final L2FibTableEntryReplyDump dump = TranslateUtils.getReplyForRead(l2FibTableDumpCompletableFuture, id); + + if (null == dump || null == dump.l2FibTableEntry) { + return Collections.emptyList(); + } else { + return dump.l2FibTableEntry; + } + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + final BridgeDomainKey bridgeDomainKey = id.firstKeyOf(BridgeDomain.class); + final int bdId = bdContext.getIndex(bridgeDomainKey.getName(), ctx.getMappingContext()); + + LOG.debug("Reading L2 FIB for bridge domain {} (bdId={})", bridgeDomainKey, bdId); + try { + return dumpL2Fibs(id, bdId).stream() + .map(entry -> new L2FibEntryKey( + new PhysAddress(vppPhysAddrToYang(Longs.toByteArray(entry.mac), 2)))) + .collect(Collectors.toList()); + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } + + @Override + public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { + ((L2FibTableBuilder) builder).setL2FibEntry(readData); + } + + @Nonnull + @Override + public L2FibEntryBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new L2FibEntryBuilder(); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizer.java new file mode 100644 index 000000000..7eaf2ec80 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizer.java @@ -0,0 +1,79 @@ +/* + * 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.translate.v3po.vppstate; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ShowVersion; +import org.openvpp.jvpp.dto.ShowVersionReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public final class VersionCustomizer + extends FutureJVppCustomizer + implements ReaderCustomizer { + + /** + * Default timeout for executing version read + */ + private static final int DEFAULT_TIMEOUT_IN_SECONDS = 30; + + public VersionCustomizer(@Nonnull final FutureJVpp futureJVpp) { + super(futureJVpp); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Version readValue) { + ((VppStateBuilder) parentBuilder).setVersion(readValue); + } + + @Nonnull + @Override + public VersionBuilder getBuilder(@Nonnull InstanceIdentifier id) { + return new VersionBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull final VersionBuilder builder, + @Nonnull final ReadContext context) throws ReadFailedException { + try { + // Execute with timeout + final CompletionStage showVersionFuture = getFutureJVpp().showVersion(new ShowVersion()); + final ShowVersionReply reply = TranslateUtils.getReplyForRead(showVersionFuture.toCompletableFuture(), id, + DEFAULT_TIMEOUT_IN_SECONDS); + + builder.setBranch(TranslateUtils.toString(reply.version)); + builder.setName(TranslateUtils.toString(reply.program)); + builder.setBuildDate(TranslateUtils.toString(reply.buildDate)); + builder.setBuildDirectory(TranslateUtils.toString(reply.buildDirectory)); + } catch (VppBaseCallException e) { + throw new ReadFailedException(id, e); + } + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/InterfacesInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/InterfacesInitializer.java deleted file mode 100644 index d4e41be76..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/InterfacesInitializer.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * 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.v3po.initializers; - -import static io.fd.honeycomb.v3po.translate.v3po.initializers.SubInterfaceInitializationUtils.initializeSubinterfaceStateAugmentation; - -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.vpp.data.init.AbstractDataTreeConverter; -import java.util.List; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Neighbor; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.NeighborBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeVni; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.AclBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.EthernetBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.TapBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Tap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUser; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBased; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBased; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBasedBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Initializes ietf-interfaces config data based on operational state - */ -public class InterfacesInitializer extends AbstractDataTreeConverter { - private static final Logger LOG = LoggerFactory.getLogger(InterfacesInitializer.class); - - public InterfacesInitializer(@Nonnull final DataBroker bindingDataBroker) { - super(bindingDataBroker, InstanceIdentifier.create(InterfacesState.class), - InstanceIdentifier.create(Interfaces.class)); - } - - @Override - protected Interfaces convert(final InterfacesState operationalData) { - LOG.debug("InterfacesInitializer.convert()"); - InterfacesBuilder interfacesBuilder = new InterfacesBuilder(); - interfacesBuilder - .setInterface(Lists.transform(operationalData.getInterface(), InterfacesInitializer::initialize)); - return interfacesBuilder.build(); - } - - // FIXME https://jira.fd.io/browse/HONEYCOMB-73 this kind of initialization/transformation is bad - // There is no relation to readers, it cannot be extended (readers can) and its hard to keep in sync with readers - - // TODO add IP v4/ v6 initializer - - private static Interface initialize( - final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input) { - InterfaceBuilder builder = new InterfaceBuilder(); - builder.setKey(new InterfaceKey(input.getKey().getName())); - builder.setName(input.getName()); - builder.setType(input.getType()); - builder.setEnabled(AdminStatus.Up.equals(input.getAdminStatus())); - // builder.setLinkUpDownTrapEnable(); TODO not present in interfaces-state - - initializeVppInterfaceStateAugmentation(input, builder); - initializeSubinterfaceStateAugmentation(input, builder); - initializeIetfIpAugmentation(input, builder); - - return builder.build(); - } - - private static void initializeVppInterfaceStateAugmentation( - final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, - final InterfaceBuilder builder) { - final VppInterfaceStateAugmentation vppIfcAugmentation = - input.getAugmentation(VppInterfaceStateAugmentation.class); - if (vppIfcAugmentation != null) { - final VppInterfaceAugmentationBuilder augmentBuilder = new VppInterfaceAugmentationBuilder(); - builder.setDescription(vppIfcAugmentation.getDescription()); - - final Vxlan vxlan = vppIfcAugmentation.getVxlan(); - if (vxlan != null) { - setVxlan(augmentBuilder, vxlan); - } - - final VxlanGpe vxlanGpe = vppIfcAugmentation.getVxlanGpe(); - if (vxlanGpe != null) { - setVxlanGpe(augmentBuilder, vxlanGpe); - } - - final Tap tap = vppIfcAugmentation.getTap(); - if (tap != null) { - setTap(input, augmentBuilder, tap); - } - - final VhostUser vhostUser = vppIfcAugmentation.getVhostUser(); - if (vhostUser != null) { - setVhostUser(augmentBuilder, vhostUser); - } - - final L2 l2 = vppIfcAugmentation.getL2(); - if (l2 != null) { - setL2(augmentBuilder, l2); - } - - final Ethernet ethernet = vppIfcAugmentation.getEthernet(); - if (ethernet != null) { - setEthernet(augmentBuilder, ethernet); - } - - final Acl acl = vppIfcAugmentation.getAcl(); - if (acl != null) { - setAcl(augmentBuilder, acl); - } - - // TODO set routing, not present in interface-state - - builder.addAugmentation(VppInterfaceAugmentation.class, augmentBuilder.build()); - } - } - - private static void initializeIetfIpAugmentation( - final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, - final InterfaceBuilder builder) { - final Interface2 ietfIpAugmentation = input.getAugmentation(Interface2.class); - if (ietfIpAugmentation != null) { - final Interface1Builder augmentBuilder = new Interface1Builder(); - - final Ipv4 ipv4 = ietfIpAugmentation.getIpv4(); - if (ipv4 != null) { - final List - collect = - ipv4.getAddress().stream() - .map( - address -> new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder() - .setIp(address.getIp()) - .setSubnet(getSubnet(address)) - .build()) - .collect(Collectors.toList()); - - final List neighbors = ipv4.getNeighbor().stream() - .map(neighbor -> new NeighborBuilder().setIp(neighbor.getIp()) - .setLinkLayerAddress(neighbor.getLinkLayerAddress()).build()) - .collect(Collectors.toList()); - - augmentBuilder.setIpv4(new Ipv4Builder().setAddress(collect).setNeighbor(neighbors).build()); - } - - // TODO ipv6 - - builder.addAugmentation(Interface1.class, augmentBuilder.build()); - } - } - - private static Subnet getSubnet(final Address address) { - final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.Subnet - subnet = address.getSubnet(); - - // TODO only prefix length supported - Preconditions.checkArgument( - subnet instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLength); - - return new PrefixLengthBuilder().setPrefixLength( - ((org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLength) subnet) - .getPrefixLength()).build(); - } - - private static void setEthernet(final VppInterfaceAugmentationBuilder augmentBuilder, final Ethernet ethernet) { - final EthernetBuilder ethernetBuilder = new EthernetBuilder(); - ethernetBuilder.setMtu(ethernet.getMtu()); - augmentBuilder.setEthernet(ethernetBuilder.build()); - } - - private static void setAcl(final VppInterfaceAugmentationBuilder augmentBuilder, final Acl acl) { - final AclBuilder aclBuilder = new AclBuilder(); - aclBuilder.setL2Acl(acl.getL2Acl()); - aclBuilder.setIp4Acl(acl.getIp4Acl()); - aclBuilder.setIp6Acl(acl.getIp6Acl()); - augmentBuilder.setAcl(aclBuilder.build()); - } - - private static void setL2(final VppInterfaceAugmentationBuilder augmentBuilder, final L2 l2) { - final L2Builder l2Builder = new L2Builder(); - - final Interconnection interconnection = l2.getInterconnection(); - if (interconnection != null) { - if (interconnection instanceof XconnectBased) { - final XconnectBasedBuilder xconnectBasedBuilder = new XconnectBasedBuilder(); - xconnectBasedBuilder.setXconnectOutgoingInterface( - ((XconnectBased) interconnection).getXconnectOutgoingInterface()); - l2Builder.setInterconnection(xconnectBasedBuilder.build()); - } else if (interconnection instanceof BridgeBased) { - final BridgeBasedBuilder bridgeBasedBuilder = new BridgeBasedBuilder(); - bridgeBasedBuilder.setBridgeDomain(((BridgeBased) interconnection).getBridgeDomain()); - bridgeBasedBuilder - .setBridgedVirtualInterface(((BridgeBased) interconnection).isBridgedVirtualInterface()); - bridgeBasedBuilder.setSplitHorizonGroup(((BridgeBased) interconnection).getSplitHorizonGroup()); - l2Builder.setInterconnection(bridgeBasedBuilder.build()); - } - } - - augmentBuilder.setL2(l2Builder.build()); - } - - private static void setVhostUser(final VppInterfaceAugmentationBuilder augmentBuilder, final VhostUser vhostUser) { - final VhostUserBuilder vhostUserBuilder = new VhostUserBuilder(); - vhostUserBuilder.setRole(vhostUser.getRole()); - vhostUserBuilder.setSocket(vhostUser.getSocket()); - augmentBuilder.setVhostUser(vhostUserBuilder.build()); - } - - private static void setTap( - final @Nonnull org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, - final VppInterfaceAugmentationBuilder augmentBuilder, - final Tap tap) { - final TapBuilder tapBuilder = new TapBuilder(); - tapBuilder.setMac(input.getPhysAddress()); - tapBuilder.setTapName(tap.getTapName()); -// tapBuilder.setDeviceInstance(); - augmentBuilder.setTap(tapBuilder.build()); - } - - private static void setVxlan(final VppInterfaceAugmentationBuilder augmentBuilder, final Vxlan vxlan) { - final VxlanBuilder vxlanBuilder = new VxlanBuilder(); - vxlanBuilder.setDst(vxlan.getDst()); - vxlanBuilder.setSrc(vxlan.getSrc()); - vxlanBuilder.setEncapVrfId(vxlan.getEncapVrfId()); - vxlanBuilder.setVni(new VxlanVni(vxlan.getVni())); - augmentBuilder.setVxlan(vxlanBuilder.build()); - } - - private static void setVxlanGpe(final VppInterfaceAugmentationBuilder augmentBuilder, final VxlanGpe vxlanGpe) { - final VxlanGpeBuilder vxlanGpeBuilder = new VxlanGpeBuilder(); - vxlanGpeBuilder.setLocal(vxlanGpe.getLocal()); - vxlanGpeBuilder.setRemote(vxlanGpe.getRemote()); - vxlanGpeBuilder.setVni(new VxlanGpeVni(vxlanGpe.getVni())); - vxlanGpeBuilder.setNextProtocol(vxlanGpe.getNextProtocol()); - vxlanGpeBuilder.setEncapVrfId(vxlanGpe.getEncapVrfId()); - vxlanGpeBuilder.setDecapVrfId(vxlanGpe.getDecapVrfId()); - augmentBuilder.setVxlanGpe(vxlanGpeBuilder.build()); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/SubInterfaceInitializationUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/SubInterfaceInitializationUtils.java deleted file mode 100644 index aa717cf98..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/SubInterfaceInitializationUtils.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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.v3po.initializers; - -import com.google.common.collect.Lists; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubInterfaceStatus; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfaces; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.AclBuilder; - -/** - * Utility class for sub interface initialization - */ -final class SubInterfaceInitializationUtils { - - private SubInterfaceInitializationUtils() { - throw new UnsupportedOperationException("Utility class cannot be instantiated"); - } - - static void initializeSubinterfaceStateAugmentation( - final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface input, - final InterfaceBuilder builder) { - final SubinterfaceStateAugmentation subIfcAugmentation = - input.getAugmentation(SubinterfaceStateAugmentation.class); - if (subIfcAugmentation != null) { - final SubinterfaceAugmentationBuilder augmentBuilder = new SubinterfaceAugmentationBuilder(); - - final SubInterfaces subInterfaces = subIfcAugmentation.getSubInterfaces(); - if (subInterfaces != null) { - setSubInterfaces(augmentBuilder, subInterfaces); - } - - builder.addAugmentation(SubinterfaceAugmentation.class, augmentBuilder.build()); - } - } - - private static void setSubInterfaces(final SubinterfaceAugmentationBuilder augmentBuilder, - final SubInterfaces operationalData) { - - final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfacesBuilder - subInterfacesCfgBuilder = - new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfacesBuilder(); - subInterfacesCfgBuilder.setSubInterface(Lists.transform(operationalData.getSubInterface(), - SubInterfaceInitializationUtils::convertSubInterface)); - augmentBuilder.setSubInterfaces(subInterfacesCfgBuilder.build()); - } - - private static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface convertSubInterface( - final SubInterface operationalData) { - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceBuilder subInterfaceCfgBuilder = - new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceBuilder(); - - subInterfaceCfgBuilder.setEnabled(SubInterfaceStatus.Up.equals(operationalData.getAdminStatus())); - subInterfaceCfgBuilder.setIdentifier(operationalData.getIdentifier()); - subInterfaceCfgBuilder.setKey(new SubInterfaceKey(operationalData.getIdentifier())); - subInterfaceCfgBuilder.setL2(operationalData.getL2()); - subInterfaceCfgBuilder.setMatch(operationalData.getMatch()); - subInterfaceCfgBuilder.setTags(operationalData.getTags()); - subInterfaceCfgBuilder.setVlanType(operationalData.getVlanType()); - subInterfaceCfgBuilder.setIpv4(operationalData.getIpv4()); - subInterfaceCfgBuilder.setIpv6(operationalData.getIpv6()); - - if (operationalData.getAcl() != null) { - final AclBuilder aclBuilder = new AclBuilder(); - aclBuilder.setL2Acl(operationalData.getAcl().getL2Acl()); - aclBuilder.setIp4Acl(operationalData.getAcl().getIp4Acl()); - aclBuilder.setIp6Acl(operationalData.getAcl().getIp6Acl()); - subInterfaceCfgBuilder.setAcl(aclBuilder.build()); - } - - return subInterfaceCfgBuilder.build(); - } - -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppClasifierInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppClasifierInitializer.java deleted file mode 100644 index 155f89479..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppClasifierInitializer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.v3po.initializers; - -import io.fd.honeycomb.v3po.vpp.data.init.AbstractDataTreeConverter; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Initializes vpp-classfier node in config data tree based on operational state. - */ -public class VppClasifierInitializer extends AbstractDataTreeConverter { - private static final InstanceIdentifier OPER_ID = - InstanceIdentifier.create(VppClassifierState.class); - private static final InstanceIdentifier CFG_ID = InstanceIdentifier.create(VppClassifier.class); - - public VppClasifierInitializer(@Nonnull final DataBroker bindingDataBroker) { - super(bindingDataBroker, OPER_ID, CFG_ID); - } - - @Override - protected VppClassifier convert(final VppClassifierState operationalData) { - final VppClassifierBuilder builder = new VppClassifierBuilder(); - builder.setClassifyTable(operationalData.getClassifyTable().stream() - .map(oper -> new ClassifyTableBuilder(oper).setName(oper.getName()).build()) - .collect(Collectors.toList())); - return builder.build(); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppInitializer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppInitializer.java deleted file mode 100644 index 8db903d8a..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppInitializer.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.v3po.initializers; - -import com.google.common.base.Function; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.vpp.data.init.AbstractDataTreeConverter; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTableBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Initializes vpp node in config data tree based on operational state. - */ -public class VppInitializer extends AbstractDataTreeConverter { - private static final Logger LOG = LoggerFactory.getLogger(VppInitializer.class); - - public VppInitializer(@Nonnull final DataBroker bindingDataBroker) { - 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()"); - - VppBuilder vppBuilder = new VppBuilder(); - BridgeDomainsBuilder bdsBuilder = new BridgeDomainsBuilder(); - bdsBuilder.setBridgeDomain(Lists.transform(operationalData.getBridgeDomains().getBridgeDomain(), CONVERT_BD)); - vppBuilder.setBridgeDomains(bdsBuilder.build()); - return vppBuilder.build(); - } - - private static final Function - CONVERT_BD = - new Function() { - @Nullable - @Override - public BridgeDomain apply( - @Nullable final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain input) { - final BridgeDomainBuilder builder = new BridgeDomainBuilder(); - builder.setLearn(input.isLearn()); - builder.setUnknownUnicastFlood(input.isUnknownUnicastFlood()); - builder.setArpTermination(input.isArpTermination()); - builder.setFlood(input.isFlood()); - builder.setForward(input.isForward()); - builder.setKey(new BridgeDomainKey(input.getKey().getName())); - builder.setName(input.getName()); - setL2FibTable(builder, input.getL2FibTable()); - return builder.build(); - } - }; - - private static void setL2FibTable(@Nonnull final BridgeDomainBuilder builder, - @Nullable final L2FibTable l2FibTable) { - if (l2FibTable == null) { - return; - } - final L2FibTableBuilder tableBuilder = new L2FibTableBuilder() - .setL2FibEntry( - l2FibTable.getL2FibEntry().stream() - // Convert operational object to config. VPP does not support setting BVI (see v3po.yang) - .map(oper -> new L2FibEntryBuilder(oper).setBridgedVirtualInterface(null).build()) - .collect(Collectors.toList())); - builder.setL2FibTable(tableBuilder.build()); - } - -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclCustomizer.java deleted file mode 100644 index cb8eed233..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclCustomizer.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Acl; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Customizer for enabling/disabling ACLs on given interface. - */ -public class AclCustomizer extends FutureJVppCustomizer implements WriterCustomizer, AclWriter { - - private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class); - private final NamingContext interfaceContext; - private final NamingContext classifyTableContext; - - public AclCustomizer(@Nonnull final FutureJVpp vppApi, @Nonnull final NamingContext interfaceContext, - @Nonnull final NamingContext classifyTableContext) { - super(vppApi); - this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); - this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataAfter, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - try { - setAcl(true, id, dataAfter, writeContext); - } catch (VppBaseCallException e) { - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, - @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - throw new UnsupportedOperationException("Acl update is not supported. Please delete Acl container first."); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - try { - setAcl(false, id, dataBefore, writeContext); - } catch (VppBaseCallException e) { - throw new WriteFailedException.DeleteFailedException(id, e); - } - } - - private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier id, @Nonnull final Acl acl, - @Nonnull final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - final String ifName = id.firstKeyOf(Interface.class).getName(); - final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext()); - - LOG.debug("Setting ACL(isAdd={}) on interface={}(id={}): {}", isAdd, ifName, ifIndex, acl); - - inputAclSetInterface(getFutureJVpp(), isAdd, id, acl, ifIndex, classifyTableContext, - writeContext.getMappingContext()); - LOG.debug("Successfully set ACL(isAdd={}) on interface={}(id={}): {}", isAdd, ifName, ifIndex, acl); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclWriter.java deleted file mode 100644 index 75b9121af..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclWriter.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static com.google.common.base.Preconditions.checkNotNull; -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.booleanToByte; - -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.AclBaseAttributes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2Acl; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.InputAclSetInterface; -import org.openvpp.jvpp.dto.InputAclSetInterfaceReply; -import org.openvpp.jvpp.future.FutureJVpp; - -interface AclWriter { - - default void inputAclSetInterface(@Nonnull final FutureJVpp futureJvpp, final boolean isAdd, - @Nonnull final InstanceIdentifier id, @Nonnull final AclBaseAttributes acl, - @Nonnegative final int ifIndex, @Nonnull final NamingContext classifyTableContext, - @Nonnull final MappingContext mappingContext) - throws VppBaseCallException, WriteTimeoutException { - final InputAclSetInterface request = new InputAclSetInterface(); - request.isAdd = booleanToByte(isAdd); - request.swIfIndex = ifIndex; - request.l2TableIndex = ~0; // skip - request.ip4TableIndex = ~0; // skip - request.ip6TableIndex = ~0; // skip - - final L2Acl l2Acl = acl.getL2Acl(); - if (l2Acl != null) { - final String tableName = checkNotNull(l2Acl.getClassifyTable(), "L2 classify table is null"); - request.l2TableIndex = classifyTableContext.getIndex(tableName, mappingContext); - } - final Ip4Acl ip4Acl = acl.getIp4Acl(); - if (ip4Acl != null) { - final String tableName = checkNotNull(ip4Acl.getClassifyTable(), "IPv4 classify table is null"); - request.ip4TableIndex = classifyTableContext.getIndex(tableName, mappingContext); - } - final Ip6Acl ip6Acl = acl.getIp6Acl(); - if (ip6Acl != null) { - final String tableName = checkNotNull(ip6Acl.getClassifyTable(), "IPv6 classify table is null"); - request.ip6TableIndex = classifyTableContext.getIndex(tableName, mappingContext); - } - - final CompletionStage inputAclSetInterfaceReplyCompletionStage = - futureJvpp.inputAclSetInterface(request); - - TranslateUtils.getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/EthernetCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/EthernetCustomizer.java deleted file mode 100644 index 94067fd6b..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/EthernetCustomizer.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.v3po.interfaces; - -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EthernetCustomizer extends FutureJVppCustomizer implements WriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(EthernetCustomizer.class); - - public EthernetCustomizer(final FutureJVpp vppApi) { - super(vppApi); - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Ethernet dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - // TODO - LOG.warn("Unsupported, ignoring configuration {}", dataAfter); - // VPP API does not support setting MTU - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Ethernet dataBefore, @Nonnull final Ethernet dataAfter, - @Nonnull final WriteContext writeContext) { - // TODO - LOG.warn("Unsupported, ignoring configuration {}", dataAfter); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Ethernet dataBefore, @Nonnull final WriteContext writeContext) { - // TODO - LOG.warn("Unsupported, ignoring configuration delete {}", id); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterconnectionWriteUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterconnectionWriteUtils.java deleted file mode 100644 index 8c550aaf5..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterconnectionWriteUtils.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Objects.requireNonNull; - -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBased; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.XconnectBased; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceSetL2Bridge; -import org.openvpp.jvpp.dto.SwInterfaceSetL2BridgeReply; -import org.openvpp.jvpp.dto.SwInterfaceSetL2Xconnect; -import org.openvpp.jvpp.dto.SwInterfaceSetL2XconnectReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility class providing Interconnection CUD support. - */ -final class InterconnectionWriteUtils { - - private static final Logger LOG = LoggerFactory.getLogger(InterconnectionWriteUtils.class); - - private final FutureJVpp futureJvpp; - private final NamingContext interfaceContext; - private final NamingContext bridgeDomainContext; - - InterconnectionWriteUtils(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext interfaceContext, - @Nonnull final NamingContext bridgeDomainContext) { - this.futureJvpp = requireNonNull(futureJvpp, "futureJvpp should not be null"); - this.interfaceContext = requireNonNull(interfaceContext, "interfaceContext should not be null"); - this.bridgeDomainContext = requireNonNull(bridgeDomainContext, "bridgeDomainContext should not be null"); - } - - void setInterconnection(final InstanceIdentifier id, final int swIfIndex, - final String ifcName, final Interconnection ic, final WriteContext writeContext) - throws WriteFailedException { - try { - if (ic == null) { // TODO in case of update we should delete interconnection - LOG.trace("Interconnection is not set. Skipping"); - } else if (ic instanceof XconnectBased) { - setXconnectBasedL2(id, swIfIndex, ifcName, (XconnectBased) ic, writeContext, (byte) 1 /*enable*/); - } else if (ic instanceof BridgeBased) { - setBridgeBasedL2(id, swIfIndex, ifcName, (BridgeBased) ic, writeContext, (byte) 1 /*enable*/); - } else { - // FIXME how does choice extensibility work - // FIXME it is not even possible to create a dedicated customizer for Interconnection, since it's not a DataObject - // FIXME we might need a choice customizer - // THis choice is already from augment, so its probably not possible to augment augmented choice - LOG.error("Unable to handle Interconnection of type {}", ic.getClass()); - throw new WriteFailedException(id, "Unable to handle Interconnection of type " + ic.getClass()); - } - } catch (VppBaseCallException e) { - LOG.warn("Failed to update bridge/xconnect based interconnection flags for: {}, interconnection: {}", - ifcName, ic); - throw new WriteFailedException(id, "Unable to handle Interconnection of type " + ic.getClass(), e); - } - } - - void deleteInterconnection(final InstanceIdentifier id, final int swIfIndex, - final String ifcName, final Interconnection ic, final WriteContext writeContext) - throws WriteFailedException { - try { - if (ic == null) { // TODO in case of update we should delete interconnection - LOG.trace("Interconnection is not set. Skipping"); - } else if (ic instanceof XconnectBased) { - setXconnectBasedL2(id, swIfIndex, ifcName, (XconnectBased) ic, writeContext, (byte) 0 /*disable*/); - } else if (ic instanceof BridgeBased) { - setBridgeBasedL2(id, swIfIndex, ifcName, (BridgeBased) ic, writeContext, (byte) 0 /*disable*/); - } else { - LOG.error("Unable to delete Interconnection of type {}", ic.getClass()); - throw new WriteFailedException(id, "Unable to delete Interconnection of type " + ic.getClass()); - } - } catch (VppBaseCallException e) { - LOG.warn("Failed to delete bridge/xconnect based interconnection flags for: {}, interconnection: {}", - ifcName, ic); - throw new WriteFailedException(id, "Unable to delete Interconnection of type " + ic.getClass(), e); - } - } - - private void setBridgeBasedL2(final InstanceIdentifier id, final int swIfIndex, - final String ifcName, final BridgeBased bb, - final WriteContext writeContext, final byte enabled) - throws VppBaseCallException, WriteTimeoutException { - LOG.debug("Setting bridge based interconnection(bridge-domain={}) for interface: {}", bb.getBridgeDomain(), - ifcName); - - String bdName = bb.getBridgeDomain(); - - int bdId = bridgeDomainContext.getIndex(bdName, writeContext.getMappingContext()); - checkArgument(bdId > 0, "Unable to set Interconnection for Interface: %s, bridge domain: %s does not exist", - ifcName, bdName); - - byte bvi = bb.isBridgedVirtualInterface() - ? (byte) 1 - : (byte) 0; - byte shg = 0; - if (bb.getSplitHorizonGroup() != null) { - shg = bb.getSplitHorizonGroup().byteValue(); - } - - final CompletionStage swInterfaceSetL2BridgeReplyCompletionStage = futureJvpp - .swInterfaceSetL2Bridge(getL2BridgeRequest(swIfIndex, bdId, shg, bvi, enabled)); - TranslateUtils.getReplyForWrite(swInterfaceSetL2BridgeReplyCompletionStage.toCompletableFuture(), id); - - LOG.debug("Bridge based interconnection updated successfully for: {}, interconnection: {}", ifcName, bb); - } - - private SwInterfaceSetL2Bridge getL2BridgeRequest(final int swIfIndex, final int bdId, final byte shg, - final byte bvi, final byte enabled) { - final SwInterfaceSetL2Bridge swInterfaceSetL2Bridge = new SwInterfaceSetL2Bridge(); - swInterfaceSetL2Bridge.rxSwIfIndex = swIfIndex; - swInterfaceSetL2Bridge.bdId = bdId; - swInterfaceSetL2Bridge.shg = shg; - swInterfaceSetL2Bridge.bvi = bvi; - swInterfaceSetL2Bridge.enable = enabled; - return swInterfaceSetL2Bridge; - } - - private void setXconnectBasedL2(final InstanceIdentifier id, final int swIfIndex, - final String ifcName, final XconnectBased ic, - final WriteContext writeContext, final byte enabled) - throws VppBaseCallException, WriteTimeoutException { - String outSwIfName = ic.getXconnectOutgoingInterface(); - LOG.debug("Setting xconnect based interconnection(outgoing ifc={}) for interface: {}", outSwIfName, ifcName); - - int outSwIfIndex = interfaceContext.getIndex(outSwIfName, writeContext.getMappingContext()); - checkArgument(outSwIfIndex > 0, - "Unable to set Interconnection for Interface: %s, outgoing interface: %s does not exist", - ifcName, outSwIfIndex); - - final CompletionStage swInterfaceSetL2XconnectReplyCompletionStage = - futureJvpp - .swInterfaceSetL2Xconnect(getL2XConnectRequest(swIfIndex, outSwIfIndex, enabled)); - TranslateUtils.getReplyForWrite(swInterfaceSetL2XconnectReplyCompletionStage.toCompletableFuture(), id); - LOG.debug("Xconnect based interconnection updated successfully for: {}, interconnection: {}", ifcName, ic); - } - - private SwInterfaceSetL2Xconnect getL2XConnectRequest(final int rxIfc, final int txIfc, - final byte enabled) { - - final SwInterfaceSetL2Xconnect swInterfaceSetL2Xconnect = new SwInterfaceSetL2Xconnect(); - swInterfaceSetL2Xconnect.enable = enabled; - swInterfaceSetL2Xconnect.rxSwIfIndex = rxIfc; - swInterfaceSetL2Xconnect.txSwIfIndex = txIfc; - return swInterfaceSetL2Xconnect; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceCustomizer.java deleted file mode 100644 index ac57ab4da..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceCustomizer.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.v3po.interfaces; - -import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceSetFlags; -import org.openvpp.jvpp.dto.SwInterfaceSetFlagsReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Ietf interface write customizer that only caches interface objects for child writers - */ -public class InterfaceCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class); - private final NamingContext interfaceContext; - - public InterfaceCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { - super(vppApi); - this.interfaceContext = interfaceContext; - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Interface dataAfter, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - - try { - setInterface(id, dataAfter, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Update of VppInterfaceAugment failed", 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 { - - try { - updateInterface(id, dataBefore, dataAfter, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Update of VppInterfaceAugment failed", e); - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); - } - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Interface dataBefore, - @Nonnull final WriteContext writeContext) { - - // TODO Handle deletes - } - - private void setInterface(final InstanceIdentifier id, final Interface swIf, - final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - LOG.debug("Setting interface: {} to: {}", id, swIf); - setInterfaceAttributes(id, swIf, swIf.getName(), writeContext); - } - - private void setInterfaceAttributes(final InstanceIdentifier id, final Interface swIf, - final String swIfName, final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - - setInterfaceFlags(id, swIfName, interfaceContext.getIndex(swIfName, writeContext.getMappingContext()), - swIf.isEnabled() ? (byte) 1 : (byte) 0); - } - - private void updateInterface(final InstanceIdentifier id, - final Interface dataBefore, - final Interface dataAfter, final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - LOG.debug("Updating interface:{} to: {}", id, dataAfter); - setInterfaceAttributes(id, dataAfter, dataAfter.getName(), writeContext); - } - - private void setInterfaceFlags(final InstanceIdentifier id, final String swIfName, final int swIfIndex, - final byte enabled) - throws VppBaseCallException, WriteTimeoutException { - final CompletionStage swInterfaceSetFlagsReplyFuture = getFutureJVpp().swInterfaceSetFlags( - getSwInterfaceSetFlagsInput(swIfIndex, enabled, (byte) 0 /* deleted */)); - - LOG.debug("Updating interface flags for: {}, index: {}, enabled: {}", swIfName, swIfIndex, enabled); - - TranslateUtils.getReplyForWrite(swInterfaceSetFlagsReplyFuture.toCompletableFuture(), id); - LOG.debug("Interface flags updated successfully for: {}, index: {}, enabled: {}", - swIfName, swIfIndex, enabled); - } - - private SwInterfaceSetFlags getSwInterfaceSetFlagsInput(final int swIfIndex, final byte enabled, final byte deleted) { - final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags(); - swInterfaceSetFlags.swIfIndex = swIfIndex; - swInterfaceSetFlags.adminUpDown = enabled; - swInterfaceSetFlags.linkUpDown = enabled; - swInterfaceSetFlags.deleted = deleted; - return swInterfaceSetFlags; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/L2Customizer.java deleted file mode 100644 index 83b522b63..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/L2Customizer.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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.v3po.interfaces; - -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class L2Customizer extends FutureJVppCustomizer implements WriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class); - private final NamingContext interfaceContext; - private final InterconnectionWriteUtils icWriteUtils; - - public L2Customizer(final FutureJVpp vppApi, final NamingContext interfaceContext, - final NamingContext bridgeDomainContext) { - super(vppApi); - this.interfaceContext = interfaceContext; - this.icWriteUtils = new InterconnectionWriteUtils(vppApi, interfaceContext, bridgeDomainContext); - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataAfter, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - - final String ifcName = id.firstKeyOf(Interface.class).getName(); - final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); - setL2(id, swIfc, ifcName, dataAfter, writeContext); - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, - @Nonnull final L2 dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - - final String ifcName = id.firstKeyOf(Interface.class).getName(); - final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); - // TODO handle update properly (if possible) - setL2(id, swIfc, ifcName, dataAfter, writeContext); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - final String ifcName = id.firstKeyOf(Interface.class).getName(); - final int swIfc = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); - deleteL2(id, swIfc, ifcName, dataBefore, writeContext); - } - - private void setL2(final InstanceIdentifier id, final int swIfIndex, final String ifcName, final L2 l2, - final WriteContext writeContext) - throws WriteFailedException { - LOG.debug("Setting L2 for interface: {}", ifcName); - // Nothing besides interconnection here - icWriteUtils.setInterconnection(id, swIfIndex, ifcName, l2.getInterconnection(), writeContext); - } - - private void deleteL2(final InstanceIdentifier id, final int swIfIndex, final String ifcName, final L2 l2Before, - final WriteContext writeContext) - throws WriteFailedException { - LOG.debug("Deleting L2 for interface: {}", ifcName); - // Nothing besides interconnection here - icWriteUtils.deleteInterconnection(id, swIfIndex, ifcName, l2Before.getInterconnection(), writeContext); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RewriteCustomizer.java deleted file mode 100644 index 54c6971a8..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RewriteCustomizer.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.booleanToByte; - -import com.google.common.base.Preconditions; -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.TagRewriteOperation; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.List; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.apache.commons.lang3.builder.ReflectionToStringBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1q; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTags; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewrite; -import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Writer Customizer responsible for vlan tag rewrite.
Sends {@code l2_interface_vlan_tag_rewrite} message to - * VPP.
Equivalent of invoking {@code vppctl set interface l2 tag-rewrite} command. - */ -public class RewriteCustomizer extends FutureJVppCustomizer implements WriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(RewriteCustomizer.class); - private final NamingContext interfaceContext; - - public RewriteCustomizer(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext interfaceContext) { - super(futureJvpp); - this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); - } - - @Override - public void writeCurrentAttributes(final InstanceIdentifier id, final Rewrite dataAfter, - final WriteContext writeContext) - throws WriteFailedException { - final String subifName = getSubInterfaceName(id); - try { - setTagRewrite(id, subifName, dataAfter, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Failed to write interface {}(id=): {}", subifName, writeContext, dataAfter); - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - private static String getSubInterfaceName(final InstanceIdentifier id) { - return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), - Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier())); - } - - private void setTagRewrite(final InstanceIdentifier id, final String ifname, final Rewrite rewrite, - final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - final int swIfIndex = interfaceContext.getIndex(ifname, writeContext.getMappingContext()); - LOG.debug("Setting tag rewrite for interface {}(id=): {}", ifname, swIfIndex, rewrite); - - final CompletionStage replyCompletionStage = - getFutureJVpp().l2InterfaceVlanTagRewrite(getTagRewriteRequest(swIfIndex, rewrite)); - - TranslateUtils.getReplyForWrite(replyCompletionStage.toCompletableFuture(), id); - LOG.debug("Tag rewrite for interface {}(id=) set successfully: {}", ifname, swIfIndex, rewrite); - } - - private L2InterfaceVlanTagRewrite getTagRewriteRequest(final int swIfIndex, final Rewrite rewrite) { - final L2InterfaceVlanTagRewrite request = new L2InterfaceVlanTagRewrite(); - request.swIfIndex = swIfIndex; - request.pushDot1Q = booleanToByte(_802dot1q.class == rewrite.getVlanType()); - - final List pushTags = rewrite.getPushTags(); - final Short popTags = rewrite.getPopTags(); - - final int numberOfTagsToPop = popTags == null - ? 0 - : popTags.intValue(); - final int numberOfTagsToPush = pushTags == null - ? 0 - : pushTags.size(); - - request.vtrOp = TagRewriteOperation.get(numberOfTagsToPop, numberOfTagsToPush).ordinal(); - - if (numberOfTagsToPush > 0) { - for (final PushTags tag : pushTags) { - if (tag.getIndex() == 0) { - request.tag1 = tag.getDot1qTag().getVlanId().getValue(); - } else { - request.tag2 = tag.getDot1qTag().getVlanId().getValue(); - } - } - } - - LOG.debug("Generated tag rewrite request: {}", ReflectionToStringBuilder.toString(request)); - return request; - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Rewrite dataBefore, - @Nonnull final Rewrite dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String subifName = getSubInterfaceName(id); - try { - setTagRewrite(id, subifName, dataAfter, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Failed to update interface {}(id=): {}", subifName, writeContext, dataAfter); - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); - } - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Rewrite dataBefore, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String subifName = getSubInterfaceName(id); - try { - LOG.debug("Disabling tag rewrite for interface {}", subifName); - final Rewrite rewrite = new RewriteBuilder().build(); // rewrite without push and pops will cause delete - setTagRewrite(id, subifName, rewrite, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Failed to delete interface {}(id=): {}", subifName, writeContext, dataBefore); - throw new WriteFailedException.DeleteFailedException(id, e); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RoutingCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RoutingCustomizer.java deleted file mode 100644 index 1e8102133..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RoutingCustomizer.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.v3po.interfaces; - -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Routing; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceSetTable; -import org.openvpp.jvpp.dto.SwInterfaceSetTableReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RoutingCustomizer extends FutureJVppCustomizer implements WriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(RoutingCustomizer.class); - private final NamingContext interfaceContext; - - public RoutingCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { - super(vppApi); - this.interfaceContext = interfaceContext; - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Routing dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - - final String ifName = id.firstKeyOf(Interface.class).getName(); - try { - setRouting(id, ifName, dataAfter, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Failed to set routing for interface: {}, {}, vxlan: {}", ifName, writeContext, dataAfter); - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Routing dataBefore, @Nonnull final Routing dataAfter, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - - final String ifName = id.firstKeyOf(Interface.class).getName(); - try { - // TODO handle updates properly - setRouting(id, ifName, dataAfter, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Failed to update routing for interface: {}, {}, vxlan: {}", ifName, writeContext, dataAfter); - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); - } - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Routing dataBefore, @Nonnull final WriteContext writeContext) { - // TODO implement delete - } - - private void setRouting(final InstanceIdentifier id, final String name, final Routing rt, - final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException { - final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext()); - LOG.debug("Setting routing for interface: {}, {}. Routing: {}", name, swIfc, rt); - - int vrfId = (rt != null) - ? rt.getVrfId().intValue() - : 0; - - if (vrfId != 0) { - final CompletionStage swInterfaceSetTableReplyCompletionStage = - getFutureJVpp().swInterfaceSetTable(getInterfaceSetTableRequest(swIfc, (byte) 0, /* isIpv6 */ vrfId)); - TranslateUtils.getReplyForWrite(swInterfaceSetTableReplyCompletionStage.toCompletableFuture(), id); - LOG.debug("Routing set successfully for interface: {}, {}, routing: {}", name, swIfc, rt); - } - } - - private SwInterfaceSetTable getInterfaceSetTableRequest(final int swIfc, final byte isIpv6, final int vrfId) { - final SwInterfaceSetTable swInterfaceSetTable = new SwInterfaceSetTable(); - swInterfaceSetTable.isIpv6 = isIpv6; - swInterfaceSetTable.swIfIndex = swIfc; - swInterfaceSetTable.vrfId = vrfId; - return swInterfaceSetTable; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceAclCustomizer.java deleted file mode 100644 index eb433dc37..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceAclCustomizer.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Acl; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Customizer for enabling/disabling ACLs on given sub-interface. - */ -public class SubInterfaceAclCustomizer extends FutureJVppCustomizer - implements WriterCustomizer, AclWriter { - - private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class); - private final NamingContext interfaceContext; - private final NamingContext classifyTableContext; - - public SubInterfaceAclCustomizer(@Nonnull final FutureJVpp vppApi, @Nonnull final NamingContext interfaceContext, - @Nonnull final NamingContext classifyTableContext) { - super(vppApi); - this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); - this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataAfter, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - try { - setAcl(true, id, dataAfter, writeContext); - } catch (VppBaseCallException e) { - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, - @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - throw new UnsupportedOperationException("Acl update is not supported. Please delete Acl container first."); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - try { - setAcl(false, id, dataBefore, writeContext); - } catch (VppBaseCallException e) { - throw new WriteFailedException.DeleteFailedException(id, e); - } - } - - private void setAcl(final boolean isAdd, @Nonnull final InstanceIdentifier id, @Nonnull final Acl acl, - @Nonnull final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); - final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); - final String subInterfaceName = SubInterfaceUtils - .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); - final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); - - LOG.debug("Setting ACL(isAdd={}) on sub-interface={}(id={}): {}", - isAdd, subInterfaceName, subInterfaceIndex, acl); - inputAclSetInterface(getFutureJVpp(), isAdd, id, acl, subInterfaceIndex, classifyTableContext, - writeContext.getMappingContext()); - LOG.debug("Successfully set ACL(isAdd={}) on sub-interface={}(id={}): {}", - isAdd, subInterfaceName, subInterfaceIndex, acl); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceCustomizer.java deleted file mode 100644 index c4971867c..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceCustomizer.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static com.google.common.base.Preconditions.checkState; -import static io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName; -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.booleanToByte; - -import com.google.common.base.Preconditions; -import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1ad; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.MatchType; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.Default; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.vlan.tagged.VlanTagged; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.CreateSubif; -import org.openvpp.jvpp.dto.CreateSubifReply; -import org.openvpp.jvpp.dto.SwInterfaceSetFlags; -import org.openvpp.jvpp.dto.SwInterfaceSetFlagsReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Writer Customizer responsible for sub interface creation.
Sends {@code create_subif} message to VPP.
- * Equivalent of invoking {@code vppclt create subif} command. - */ -public class SubInterfaceCustomizer extends FutureJVppCustomizer - implements ListWriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceCustomizer.class); - private final NamingContext interfaceContext; - - public SubInterfaceCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) { - super(futureJvpp); - this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final SubInterface dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String superIfName = id.firstKeyOf(Interface.class).getName(); - try { - createSubInterface(id, superIfName, dataAfter, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Failed to create sub interface for: {}, subInterface: {}", superIfName, dataAfter); - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - private void createSubInterface(final InstanceIdentifier id, @Nonnull final String superIfName, - @Nonnull final SubInterface subInterface, - final WriteContext writeContext) throws VppBaseCallException, - WriteTimeoutException { - final int superIfIndex = interfaceContext.getIndex(superIfName, writeContext.getMappingContext()); - final CompletionStage createSubifReplyCompletionStage = - getFutureJVpp().createSubif(getCreateSubifRequest(subInterface, superIfIndex)); - - final CreateSubifReply reply = - TranslateUtils.getReplyForWrite(createSubifReplyCompletionStage.toCompletableFuture(), id); - - setInterfaceState(id, reply.swIfIndex, booleanToByte(subInterface.isEnabled())); - interfaceContext.addName(reply.swIfIndex, - getSubInterfaceName(superIfName, Math.toIntExact(subInterface.getIdentifier())), - writeContext.getMappingContext()); - LOG.debug("Sub interface created successfully for: {}, subInterface: {}", superIfName, subInterface); - } - - private CreateSubif getCreateSubifRequest(@Nonnull final SubInterface subInterface, final int swIfIndex) { - // TODO add validation - CreateSubif request = new CreateSubif(); - request.subId = Math.toIntExact(subInterface.getIdentifier().intValue()); - request.swIfIndex = swIfIndex; - - final int numberOfTags = getNumberOfTags(subInterface); - switch (numberOfTags) { - case 0: - request.noTags = 1; - break; - case 1: - request.oneTag = 1; - break; - case 2: - request.twoTags = 1; - break; - } - request.dot1Ad = booleanToByte(_802dot1ad.class == subInterface.getVlanType()); - - final MatchType matchType = subInterface.getMatch().getMatchType(); // todo match should be mandatory - request.exactMatch = - booleanToByte(matchType instanceof VlanTagged && ((VlanTagged) matchType).isMatchExactTags()); - request.defaultSub = booleanToByte(matchType instanceof Default); - - if (numberOfTags > 0) { - for (final Tag tag : subInterface.getTags().getTag()) { - if (tag.getIndex() == 0) { - setOuterTag(request, tag); - } else if (tag.getIndex() == 1) { - setInnerTag(request, tag); - } - } - } - return request; - } - - private void setOuterTag(final CreateSubif request, final Tag outerTag) { - checkState(SVlan.class == outerTag.getDot1qTag().getTagType(), "Service Tag expected at index 0"); - final Dot1qTag.VlanId vlanId = outerTag.getDot1qTag().getVlanId(); - - request.outerVlanId = dot1qVlanIdToShort(vlanId.getDot1qVlanId()); - request.outerVlanIdAny = booleanToByte(Dot1qTag.VlanId.Enumeration.Any.equals(vlanId.getEnumeration())); - } - - private void setInnerTag(final CreateSubif request, final Tag innerTag) { - checkState(CVlan.class == innerTag.getDot1qTag().getTagType(), "Customer Tag expected at index 1"); - final Dot1qTag.VlanId vlanId = innerTag.getDot1qTag().getVlanId(); - - request.innerVlanId = dot1qVlanIdToShort(vlanId.getDot1qVlanId()); - request.innerVlanIdAny = booleanToByte(Dot1qTag.VlanId.Enumeration.Any.equals(vlanId.getEnumeration())); - } - - private static int getNumberOfTags(@Nonnull final SubInterface subInterface) { - final Tags tags = subInterface.getTags(); - if (tags == null) { - return 0; - } - final List tagList = tags.getTag(); - if (tagList == null) { - return 0; - } - return tagList.size(); - } - - private static short dot1qVlanIdToShort(@Nullable Dot1qVlanId dot1qVlanId) { - if (dot1qVlanId == null) { - return 0; // tell VPP that optional argument is missing - } else { - return dot1qVlanId.getValue().shortValue(); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final SubInterface dataBefore, @Nonnull final SubInterface dataAfter, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - if (Objects.equals(dataBefore.isEnabled(), dataAfter.isEnabled())) { - LOG.debug("No state update will be performed. Ignoring config"); - return; // TODO shouldn't we throw exception here (if there will be dedicated L2 customizer)? - } - final String subIfaceName = getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), - Math.toIntExact(dataAfter.getIdentifier())); - try { - setInterfaceState(id, interfaceContext.getIndex(subIfaceName, writeContext.getMappingContext()), - booleanToByte(dataAfter.isEnabled())); - } catch (VppBaseCallException e) { - LOG.warn("Failed to update interface state for: interface if={}, enabled: {}", - subIfaceName, booleanToByte(dataAfter.isEnabled())); - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); - } - } - - private void setInterfaceState(final InstanceIdentifier id, final int swIfIndex, final byte enabled) - throws VppBaseCallException, WriteTimeoutException { - final SwInterfaceSetFlags swInterfaceSetFlags = new SwInterfaceSetFlags(); - swInterfaceSetFlags.swIfIndex = swIfIndex; - swInterfaceSetFlags.adminUpDown = enabled; - - final CompletionStage swInterfaceSetFlagsReplyFuture = - getFutureJVpp().swInterfaceSetFlags(swInterfaceSetFlags); - - LOG.debug("Updating interface state for interface if={}, enabled: {}", swIfIndex, enabled); - - SwInterfaceSetFlagsReply reply = - TranslateUtils.getReplyForWrite(swInterfaceSetFlagsReplyFuture.toCompletableFuture(), id); - LOG.debug("Interface state updated successfully for interface index: {}, enabled: {}, ctxId: {}", - swIfIndex, enabled, reply.context); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final SubInterface dataBefore, - @Nonnull final WriteContext writeContext) - throws WriteFailedException.DeleteFailedException { - throw new UnsupportedOperationException("Sub interface delete is not supported"); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceL2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceL2Customizer.java deleted file mode 100644 index 567122d31..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceL2Customizer.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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.v3po.interfaces; - -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Customizer for writing vlan sub interface l2 configuration - */ -public class SubInterfaceL2Customizer extends FutureJVppCustomizer implements WriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceL2Customizer.class); - private final NamingContext interfaceContext; - private final InterconnectionWriteUtils icWriterUtils; - - public SubInterfaceL2Customizer(final FutureJVpp vppApi, final NamingContext interfaceContext, - final NamingContext bridgeDomainContext) { - super(vppApi); - this.interfaceContext = interfaceContext; - this.icWriterUtils = new InterconnectionWriteUtils(vppApi, interfaceContext, bridgeDomainContext); - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataAfter, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String subInterfaceName = getSubInterfaceName(id); - final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); - setL2(id, subInterfaceIndex, subInterfaceName, dataAfter, writeContext); - } - - private String getSubInterfaceName(@Nonnull final InstanceIdentifier id) { - final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); - final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); - return SubInterfaceUtils - .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, - @Nonnull final L2 dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - - final String subInterfaceName = getSubInterfaceName(id); - final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); - // TODO handle update properly (if possible) - setL2(id, subInterfaceIndex, subInterfaceName, dataAfter, writeContext); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2 dataBefore, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - final String subInterfaceName = getSubInterfaceName(id); - final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); - deleteL2(id, subInterfaceIndex, subInterfaceName, dataBefore, writeContext); - } - - private void setL2(final InstanceIdentifier id, final int swIfIndex, final String ifcName, final L2 l2, - final WriteContext writeContext) - throws WriteFailedException { - LOG.debug("Setting L2 for sub-interface: {}", ifcName); - icWriterUtils.setInterconnection(id, swIfIndex, ifcName, l2.getInterconnection(), writeContext); - } - - private void deleteL2(final InstanceIdentifier id, final int swIfIndex, final String ifcName, final L2 l2Before, - final WriteContext writeContext) - throws WriteFailedException { - LOG.debug("Deleting L2 for sub-interface: {}", ifcName); - icWriterUtils.deleteInterconnection(id, swIfIndex, ifcName, l2Before.getInterconnection(), writeContext); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizer.java deleted file mode 100644 index 6de3bc457..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizer.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * 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.v3po.interfaces; - -import io.fd.honeycomb.v3po.translate.v3po.util.AbstractInterfaceTypeCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Tap; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.TapConnect; -import org.openvpp.jvpp.dto.TapConnectReply; -import org.openvpp.jvpp.dto.TapDelete; -import org.openvpp.jvpp.dto.TapDeleteReply; -import org.openvpp.jvpp.dto.TapModify; -import org.openvpp.jvpp.dto.TapModifyReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TapCustomizer extends AbstractInterfaceTypeCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(TapCustomizer.class); - private final NamingContext interfaceContext; - - public TapCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { - super(vppApi); - this.interfaceContext = interfaceContext; - } - - @Override - protected Class getExpectedInterfaceType() { - return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap.class; - } - - @Override - protected final void writeInterface(@Nonnull final InstanceIdentifier id, @Nonnull final Tap dataAfter, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String ifcName = id.firstKeyOf(Interface.class).getName(); - try { - createTap(id, ifcName, dataAfter, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Failed to set tap interface: {}, tap: {}", ifcName, dataAfter, e); - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Tap dataBefore, - @Nonnull final Tap dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String ifcName = id.firstKeyOf(Interface.class).getName(); - - final int index; - try { - index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); - } catch (IllegalArgumentException e) { - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); - } - - try { - modifyTap(id, ifcName, index, dataAfter); - } catch (VppBaseCallException e) { - LOG.warn("Failed to set tap interface: {}, tap: {}", ifcName, dataAfter, e); - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); - } - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Tap dataBefore, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String ifcName = id.firstKeyOf(Interface.class).getName(); - - final int index; - try { - index = interfaceContext.getIndex(ifcName, writeContext.getMappingContext()); - } catch (IllegalArgumentException e) { - throw new WriteFailedException.DeleteFailedException(id, e); - } - - try { - deleteTap(id, ifcName, index, dataBefore, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Failed to delete tap interface: {}, tap: {}", ifcName, dataBefore.getTapName(), e); - throw new WriteFailedException.DeleteFailedException(id, e); - } - } - - private void createTap(final InstanceIdentifier id, final String swIfName, final Tap tap, - final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException { - LOG.debug("Setting tap interface: {}. Tap: {}", swIfName, tap); - final CompletionStage tapConnectFuture = - getFutureJVpp().tapConnect(getTapConnectRequest(tap.getTapName(), tap.getMac(), tap.getDeviceInstance())); - final TapConnectReply reply = - TranslateUtils.getReplyForWrite(tapConnectFuture.toCompletableFuture(), id); - LOG.debug("Tap set successfully for: {}, tap: {}", swIfName, tap); - // Add new interface to our interface context - interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); - } - - private void modifyTap(final InstanceIdentifier id, final String swIfName, final int index, final Tap tap) - throws VppBaseCallException, WriteTimeoutException { - LOG.debug("Modifying tap interface: {}. Tap: {}", swIfName, tap); - final CompletionStage vxlanAddDelTunnelReplyCompletionStage = - getFutureJVpp().tapModify(getTapModifyRequest(tap.getTapName(), index, tap.getMac(), tap.getDeviceInstance())); - TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); - LOG.debug("Tap modified successfully for: {}, tap: {}", swIfName, tap); - } - - private void deleteTap(final InstanceIdentifier id, final String swIfName, final int index, - final Tap dataBefore, - final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - LOG.debug("Deleting tap interface: {}. Tap: {}", swIfName, dataBefore); - final CompletionStage vxlanAddDelTunnelReplyCompletionStage = - getFutureJVpp().tapDelete(getTapDeleteRequest(index)); - TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); - LOG.debug("Tap deleted successfully for: {}, tap: {}", swIfName, dataBefore); - // Remove deleted interface from interface context - interfaceContext.removeName(swIfName, writeContext.getMappingContext()); - } - - private TapConnect getTapConnectRequest(final String tapName, final PhysAddress mac, final Long deviceInstance) { - final TapConnect tapConnect = new TapConnect(); - tapConnect.tapName = tapName.getBytes(); - - if(mac == null) { - tapConnect.useRandomMac = 1; - tapConnect.macAddress = new byte[6]; - } else { - tapConnect.useRandomMac = 0; - tapConnect.macAddress = TranslateUtils.parseMac(mac.getValue()); - } - - if(deviceInstance == null) { - tapConnect.renumber = 0; - } else { - tapConnect.renumber = 1; - tapConnect.customDevInstance = Math.toIntExact(deviceInstance); - } - - return tapConnect; - } - - private TapModify getTapModifyRequest(final String tapName, final int swIndex, final PhysAddress mac, final Long deviceInstance) { - final TapModify tapConnect = new TapModify(); - tapConnect.tapName = tapName.getBytes(); - tapConnect.swIfIndex = swIndex; - - if(mac == null) { - tapConnect.useRandomMac = 1; - tapConnect.macAddress = new byte[6]; - } else { - tapConnect.useRandomMac = 0; - tapConnect.macAddress = TranslateUtils.parseMac(mac.getValue()); - } - - if(deviceInstance == null) { - tapConnect.renumber = 0; - } else { - tapConnect.renumber = 1; - tapConnect.customDevInstance = Math.toIntExact(deviceInstance); - } - - return tapConnect; - } - - private TapDelete getTapDeleteRequest(final int swIndex) { - final TapDelete tapConnect = new TapDelete(); - tapConnect.swIfIndex = swIndex; - return tapConnect; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VhostUserCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VhostUserCustomizer.java deleted file mode 100644 index d087f30f5..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VhostUserCustomizer.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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.v3po.interfaces; - -import com.google.common.base.Preconditions; -import io.fd.honeycomb.v3po.translate.v3po.util.AbstractInterfaceTypeCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.CreateVhostUserIf; -import org.openvpp.jvpp.dto.CreateVhostUserIfReply; -import org.openvpp.jvpp.dto.DeleteVhostUserIf; -import org.openvpp.jvpp.dto.DeleteVhostUserIfReply; -import org.openvpp.jvpp.dto.ModifyVhostUserIf; -import org.openvpp.jvpp.dto.ModifyVhostUserIfReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Writer Customizer responsible for passing vhost user interface CRD operations to VPP - */ -public class VhostUserCustomizer extends AbstractInterfaceTypeCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(VhostUserCustomizer.class); - private final NamingContext interfaceContext; - - public VhostUserCustomizer(@Nonnull final FutureJVpp vppApi, @Nonnull final NamingContext interfaceContext) { - super(vppApi); - this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); - } - - @Override - protected Class getExpectedInterfaceType() { - return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class; - } - - @Override - protected final void writeInterface(@Nonnull final InstanceIdentifier id, - @Nonnull final VhostUser dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String swIfName = id.firstKeyOf(Interface.class).getName(); - try { - createVhostUserIf(id, swIfName, dataAfter, writeContext); - } catch (VppBaseCallException | IllegalInterfaceTypeException e) { - LOG.debug("Failed to create vhost user interface: {}, vhostUser: {}", swIfName, dataAfter); - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - private void createVhostUserIf(final InstanceIdentifier id, final String swIfName, - final VhostUser vhostUser, final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - LOG.debug("Creating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser); - - final CompletionStage createVhostUserIfReplyCompletionStage = - getFutureJVpp().createVhostUserIf(getCreateVhostUserIfRequest(vhostUser)); - final CreateVhostUserIfReply reply = - TranslateUtils.getReplyForWrite(createVhostUserIfReplyCompletionStage.toCompletableFuture(), id); - LOG.debug("Vhost user interface created successfully for: {}, vhostUser: {}", swIfName, vhostUser); - // Add new interface to our interface context - interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); - } - - private CreateVhostUserIf getCreateVhostUserIfRequest(final VhostUser vhostUser) { - CreateVhostUserIf request = new CreateVhostUserIf(); - request.isServer = TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())); - request.sockFilename = vhostUser.getSocket().getBytes(); - request.renumber = 0; // TODO - request.customDevInstance = 0; // TODO - request.useCustomMac = 0; - request.macAddress = new byte[]{}; - return request; - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final VhostUser dataBefore, @Nonnull final VhostUser dataAfter, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String swIfName = id.firstKeyOf(Interface.class).getName(); - try { - modifyVhostUserIf(id, swIfName, dataAfter, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Failed to update vhost user interface: {}, vhostUser: {}", swIfName, dataAfter); - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); - } - } - - private void modifyVhostUserIf(final InstanceIdentifier id, final String swIfName, - final VhostUser vhostUser, final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - LOG.debug("Updating vhost user interface: name={}, vhostUser={}", swIfName, vhostUser); - final CompletionStage modifyVhostUserIfReplyCompletionStage = - getFutureJVpp() - .modifyVhostUserIf(getModifyVhostUserIfRequest(vhostUser, interfaceContext.getIndex(swIfName, writeContext.getMappingContext()))); - - TranslateUtils.getReplyForWrite(modifyVhostUserIfReplyCompletionStage.toCompletableFuture(), id); - LOG.debug("Vhost user interface updated successfully for: {}, vhostUser: {}", swIfName, vhostUser); - } - - private ModifyVhostUserIf getModifyVhostUserIfRequest(final VhostUser vhostUser, final int swIfIndex) { - ModifyVhostUserIf request = new ModifyVhostUserIf(); - request.isServer = TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())); - request.sockFilename = vhostUser.getSocket().getBytes(); - request.renumber = 0; // TODO - request.customDevInstance = 0; // TODO - request.swIfIndex = swIfIndex; - return request; - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final VhostUser dataBefore, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String swIfName = id.firstKeyOf(Interface.class).getName(); - try { - deleteVhostUserIf(id, swIfName, dataBefore, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Failed to delete vhost user interface: {}, vhostUser: {}", swIfName, dataBefore); - throw new WriteFailedException.DeleteFailedException(id, e); - } - } - - private void deleteVhostUserIf(final InstanceIdentifier id, final String swIfName, - final VhostUser vhostUser, final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - LOG.debug("Deleting vhost user interface: name={}, vhostUser={}", swIfName, vhostUser); - final CompletionStage deleteVhostUserIfReplyCompletionStage = - getFutureJVpp().deleteVhostUserIf(getDeleteVhostUserIfRequest(interfaceContext.getIndex(swIfName, writeContext.getMappingContext()))); - - TranslateUtils.getReplyForWrite(deleteVhostUserIfReplyCompletionStage.toCompletableFuture(), id); - LOG.debug("Vhost user interface deleted successfully for: {}, vhostUser: {}", swIfName, vhostUser); - // Remove interface from our interface context - interfaceContext.removeName(swIfName, writeContext.getMappingContext()); - } - - private DeleteVhostUserIf getDeleteVhostUserIfRequest(final int swIfIndex) { - DeleteVhostUserIf request = new DeleteVhostUserIf(); - request.swIfIndex = swIfIndex; - return request; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanCustomizer.java deleted file mode 100644 index 82c572864..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanCustomizer.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.net.InetAddresses; -import io.fd.honeycomb.v3po.translate.v3po.util.AbstractInterfaceTypeCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.net.InetAddress; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.VxlanAddDelTunnel; -import org.openvpp.jvpp.dto.VxlanAddDelTunnelReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -// TODO extract common code from all Interface type specific writer customizers into a superclass -public class VxlanCustomizer extends AbstractInterfaceTypeCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class); - private final NamingContext interfaceContext; - - public VxlanCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { - super(vppApi); - this.interfaceContext = interfaceContext; - } - - @Override - protected Class getExpectedInterfaceType() { - return VxlanTunnel.class; - } - - @Override - protected final void writeInterface(@Nonnull final InstanceIdentifier id, @Nonnull final Vxlan dataAfter, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String swIfName = id.firstKeyOf(Interface.class).getName(); - try { - createVxlanTunnel(id, swIfName, dataAfter, writeContext); - } catch (VppBaseCallException | IllegalInterfaceTypeException e) { - LOG.debug("Failed to set vxlan tunnel for interface: {}, vxlan: {}", swIfName, dataAfter); - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Vxlan dataBefore, - @Nonnull final Vxlan dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException.UpdateFailedException { - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, - new UnsupportedOperationException("Vxlan tunnel update is not supported")); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Vxlan dataBefore, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String swIfName = id.firstKeyOf(Interface.class).getName(); - try { - deleteVxlanTunnel(id, swIfName, dataBefore, writeContext); - } catch (VppBaseCallException e) { - LOG.debug("Failed to delete vxlan tunnel for interface: {}, vxlan: {}", swIfName, dataBefore); - throw new WriteFailedException.DeleteFailedException(id, e); - } - } - - private void createVxlanTunnel(final InstanceIdentifier id, final String swIfName, final Vxlan vxlan, - final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException { - final byte isIpv6 = (byte) (isIpv6(vxlan) ? 1 : 0); - final InetAddress srcAddress = InetAddresses.forString(getAddressString(vxlan.getSrc())); - final InetAddress dstAddress = InetAddresses.forString(getAddressString(vxlan.getDst())); - - int encapVrfId = vxlan.getEncapVrfId().intValue(); - int vni = vxlan.getVni().getValue().intValue(); - - LOG.debug("Setting vxlan tunnel for interface: {}. Vxlan: {}", swIfName, vxlan); - final CompletionStage vxlanAddDelTunnelReplyCompletionStage = - getFutureJVpp().vxlanAddDelTunnel(getVxlanTunnelRequest((byte) 1 /* is add */, srcAddress.getAddress(), - dstAddress.getAddress(), encapVrfId, -1, vni, isIpv6)); - - final VxlanAddDelTunnelReply reply = - TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); - LOG.debug("Vxlan tunnel set successfully for: {}, vxlan: {}", swIfName, vxlan); - if(interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) { - // VPP keeps vxlan tunnels present even after they are delete(reserving ID for next tunnel) - // This may cause inconsistencies in mapping context when configuring tunnels like this: - // 1. Add tunnel 2. Delete tunnel 3. Read interfaces (reserved mapping e.g. vxlan_tunnel0 -> 6 - // will get into mapping context) 4. Add tunnel (this will add another mapping with the same - // reserved ID and context is invalid) - // That's why a check has to be performed here removing mapping vxlan_tunnel0 -> 6 mapping and storing - // new name for that ID - final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext()); - LOG.debug("Removing updated mapping of a vxlan tunnel, id: {}, former name: {}, new name: {}", - reply.swIfIndex, formerName, swIfName); - interfaceContext.removeName(formerName, writeContext.getMappingContext()); - } - // Add new interface to our interface context - interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); - } - - private boolean isIpv6(final Vxlan vxlan) { - if (vxlan.getSrc().getIpv4Address() == null) { - checkArgument(vxlan.getDst().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", vxlan.getSrc(), - vxlan.getDst()); - return true; - } else { - checkArgument(vxlan.getDst().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", vxlan.getSrc(), - vxlan.getDst()); - return false; - } - } - - private String getAddressString(final IpAddress addr) { - return addr.getIpv4Address() == null ? addr.getIpv6Address().getValue() : addr.getIpv4Address().getValue(); - } - - private void deleteVxlanTunnel(final InstanceIdentifier id, final String swIfName, final Vxlan vxlan, - final WriteContext writeContext) throws VppBaseCallException, WriteTimeoutException { - final byte isIpv6 = (byte) (isIpv6(vxlan) ? 1 : 0); - final InetAddress srcAddress = InetAddresses.forString(getAddressString(vxlan.getSrc())); - final InetAddress dstAddress = InetAddresses.forString(getAddressString(vxlan.getDst())); - - int encapVrfId = vxlan.getEncapVrfId().intValue(); - int vni = vxlan.getVni().getValue().intValue(); - - LOG.debug("Deleting vxlan tunnel for interface: {}. Vxlan: {}", swIfName, vxlan); - final CompletionStage vxlanAddDelTunnelReplyCompletionStage = - getFutureJVpp().vxlanAddDelTunnel(getVxlanTunnelRequest((byte) 0 /* is add */, srcAddress.getAddress(), - dstAddress.getAddress(), encapVrfId, -1, vni, isIpv6)); - - TranslateUtils.getReplyForWrite(vxlanAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); - LOG.debug("Vxlan tunnel deleted successfully for: {}, vxlan: {}", swIfName, vxlan); - // Remove interface from our interface context - interfaceContext.removeName(swIfName, writeContext.getMappingContext()); - } - - private static VxlanAddDelTunnel getVxlanTunnelRequest(final byte isAdd, final byte[] srcAddr, final byte[] dstAddr, - final int encapVrfId, - final int decapNextIndex, final int vni, final byte isIpv6) { - final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel(); - vxlanAddDelTunnel.isAdd = isAdd; - vxlanAddDelTunnel.srcAddress = srcAddr; - vxlanAddDelTunnel.dstAddress = dstAddr; - vxlanAddDelTunnel.encapVrfId = encapVrfId; - vxlanAddDelTunnel.vni = vni; - vxlanAddDelTunnel.decapNextIndex = decapNextIndex; - vxlanAddDelTunnel.isIpv6 = isIpv6; - return vxlanAddDelTunnel; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanGpeCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanGpeCustomizer.java deleted file mode 100644 index ebe7bfeab..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanGpeCustomizer.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.net.InetAddresses; -import io.fd.honeycomb.v3po.translate.v3po.util.AbstractInterfaceTypeCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.net.InetAddress; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpe; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnel; -import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnelReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class VxlanGpeCustomizer extends AbstractInterfaceTypeCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class); - private final NamingContext interfaceContext; - - public VxlanGpeCustomizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { - super(vppApi); - this.interfaceContext = interfaceContext; - } - - @Override - protected Class getExpectedInterfaceType() { - return VxlanGpeTunnel.class; - } - - @Override - protected final void writeInterface(@Nonnull final InstanceIdentifier id, @Nonnull final VxlanGpe dataAfter, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String swIfName = id.firstKeyOf(Interface.class).getName(); - try { - createVxlanGpeTunnel(id, swIfName, dataAfter, writeContext); - } catch (VppBaseCallException | IllegalInterfaceTypeException e) { - LOG.warn("Failed to set VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataAfter); - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final VxlanGpe dataBefore, - @Nonnull final VxlanGpe dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException.UpdateFailedException { - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, - new UnsupportedOperationException("VxlanGpe tunnel update is not supported")); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final VxlanGpe dataBefore, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String swIfName = id.firstKeyOf(Interface.class).getName(); - try { - deleteVxlanGpeTunnel(id, swIfName, dataBefore, writeContext); - } catch (VppBaseCallException e) { - LOG.warn("Failed to delete VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataBefore); - throw new WriteFailedException.DeleteFailedException(id, e); - } - } - - private void createVxlanGpeTunnel(final InstanceIdentifier id, final String swIfName, - final VxlanGpe vxlanGpe, final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - final byte isIpv6 = (byte) (isIpv6(vxlanGpe) ? 1 : 0); - final InetAddress Local = InetAddresses.forString(getAddressString(vxlanGpe.getLocal())); - final InetAddress Remote = InetAddresses.forString(getAddressString(vxlanGpe.getRemote())); - - int vni = vxlanGpe.getVni().getValue().intValue(); - byte protocol = (byte) vxlanGpe.getNextProtocol().getIntValue(); - int encapVrfId = vxlanGpe.getEncapVrfId().intValue(); - int decapVrfId = vxlanGpe.getDecapVrfId().intValue(); - - LOG.debug("Setting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, vxlanGpe); - final CompletionStage VxlanGpeAddDelTunnelReplyCompletionStage = - getFutureJVpp().vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 1 /* is add */, Local.getAddress(), - Remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6)); - - final VxlanGpeAddDelTunnelReply reply = - TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); - LOG.debug("VxlanGpe tunnel set successfully for: {}, VxlanGpe: {}", swIfName, vxlanGpe); - if(interfaceContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) { - final String formerName = interfaceContext.getName(reply.swIfIndex, writeContext.getMappingContext()); - LOG.debug("Removing updated mapping of a vxlan-gpe tunnel, id: {}, former name: {}, new name: {}", - reply.swIfIndex, formerName, swIfName); - interfaceContext.removeName(formerName, writeContext.getMappingContext()); - } - // Add new interface to our interface context - interfaceContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext()); - } - - private boolean isIpv6(final VxlanGpe VxlanGpe) { - if (VxlanGpe.getLocal().getIpv4Address() == null) { - checkArgument(VxlanGpe.getRemote().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", VxlanGpe.getLocal(), - VxlanGpe.getRemote()); - return true; - } else { - checkArgument(VxlanGpe.getRemote().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", VxlanGpe.getLocal(), - VxlanGpe.getRemote()); - return false; - } - } - - private String getAddressString(final IpAddress addr) { - return addr.getIpv4Address() == null ? addr.getIpv6Address().getValue() : addr.getIpv4Address().getValue(); - } - - private void deleteVxlanGpeTunnel(final InstanceIdentifier id, final String swIfName, - final VxlanGpe VxlanGpe, final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - final byte isIpv6 = (byte) (isIpv6(VxlanGpe) ? 1 : 0); - final InetAddress local = InetAddresses.forString(getAddressString(VxlanGpe.getLocal())); - final InetAddress remote = InetAddresses.forString(getAddressString(VxlanGpe.getRemote())); - - int vni = VxlanGpe.getVni().getValue().intValue(); - byte protocol = (byte) VxlanGpe.getNextProtocol().getIntValue(); - int encapVrfId = VxlanGpe.getEncapVrfId().intValue(); - int decapVrfId = VxlanGpe.getDecapVrfId().intValue(); - - LOG.debug("Deleting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, VxlanGpe); - final CompletionStage VxlanGpeAddDelTunnelReplyCompletionStage = - getFutureJVpp().vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 0 /* is delete */, local.getAddress(), - remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6)); - - TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id); - LOG.debug("VxlanGpe tunnel deleted successfully for: {}, VxlanGpe: {}", swIfName, VxlanGpe); - // Remove interface from our interface context - interfaceContext.removeName(swIfName, writeContext.getMappingContext()); - } - - private static VxlanGpeAddDelTunnel getVxlanGpeTunnelRequest(final byte isAdd, final byte[] local, final byte[] remote, - final int vni, final byte protocol, final int encapVrfId, final int decapVrfId, - final byte isIpv6) { - final VxlanGpeAddDelTunnel VxlanGpeAddDelTunnel = new VxlanGpeAddDelTunnel(); - VxlanGpeAddDelTunnel.isAdd = isAdd; - VxlanGpeAddDelTunnel.local = local; - VxlanGpeAddDelTunnel.remote = remote; - VxlanGpeAddDelTunnel.vni = vni; - VxlanGpeAddDelTunnel.protocol = protocol; - VxlanGpeAddDelTunnel.encapVrfId = encapVrfId; - VxlanGpeAddDelTunnel.decapVrfId = decapVrfId; - VxlanGpeAddDelTunnel.isIpv6 = isIpv6; - return VxlanGpeAddDelTunnel; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java deleted file mode 100644 index 26d05546b..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizer.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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.v3po.interfaces.ip; - -import static com.google.common.base.Preconditions.checkNotNull; -import static io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4WriteUtils.addDelAddress; -import static io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4WriteUtils.getSubnetMaskLength; - -import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Customizer for writing {@link Address} - */ -public class Ipv4AddressCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class); - private final NamingContext interfaceContext; - - public Ipv4AddressCustomizer(FutureJVpp futureJvpp, NamingContext interfaceContext) { - super(futureJvpp); - this.interfaceContext = interfaceContext; - } - - @Override - public void writeCurrentAttributes(InstanceIdentifier

id, Address dataAfter, WriteContext writeContext) - throws WriteFailedException { - setAddress(true, id, dataAfter, writeContext); - } - - @Override - public void updateCurrentAttributes(InstanceIdentifier
id, Address dataBefore, Address dataAfter, - WriteContext writeContext) throws WriteFailedException { - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, - new UnsupportedOperationException("Operation not supported")); - } - - @Override - public void deleteCurrentAttributes(InstanceIdentifier
id, Address dataBefore, WriteContext writeContext) - throws WriteFailedException { - setAddress(false, id, dataBefore, writeContext); - } - - private void setAddress(boolean add, final InstanceIdentifier
id, final Address address, - final WriteContext writeContext) throws WriteFailedException { - - final String interfaceName = id.firstKeyOf(Interface.class).getName(); - final int interfaceIndex = interfaceContext.getIndex(interfaceName, writeContext.getMappingContext()); - - Subnet subnet = address.getSubnet(); - - if (subnet instanceof PrefixLength) { - setPrefixLengthSubnet(add, id, interfaceName, interfaceIndex, address, (PrefixLength) subnet); - } else if (subnet instanceof Netmask) { - setNetmaskSubnet(add, id, interfaceName, interfaceIndex, address, (Netmask) subnet); - } else { - // FIXME how does choice extensibility work - // FIXME it is not even possible to create a dedicated - // customizer for Interconnection, since it's not a DataObject - // FIXME we might need a choice customizer - // THis choice is already from augment, so its probably not - // possible to augment augmented choice - LOG.error("Unable to handle subnet of type {}", subnet.getClass()); - throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass()); - } - } - - private void setNetmaskSubnet(final boolean add, @Nonnull final InstanceIdentifier
id, - @Nonnull final String interfaceName, final int interfaceIndex, - @Nonnull final Address address, @Nonnull final Netmask subnet) - throws WriteFailedException { - try { - LOG.debug("Setting Subnet(subnet-mask) for interface: {}(id={}). Subnet: {}, address: {}", - interfaceName, interfaceIndex, subnet, address); - - final DottedQuad netmask = subnet.getNetmask(); - checkNotNull(netmask, "netmask value should not be null"); - - final byte subnetLength = getSubnetMaskLength(netmask.getValue()); - addDelAddress(getFutureJVpp(), add, id, interfaceIndex, address.getIp(), subnetLength); - } catch (VppBaseCallException e) { - LOG.warn("Failed to set Subnet(subnet-mask) for interface: {}(id={}). Subnet: {}, address: {}", - interfaceName, interfaceIndex, subnet, address); - throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); - } - } - - private void setPrefixLengthSubnet(final boolean add, @Nonnull final InstanceIdentifier
id, - @Nonnull final String interfaceName, final int interfaceIndex, - @Nonnull final Address address, @Nonnull final PrefixLength subnet) - throws WriteFailedException { - try { - LOG.debug("Setting Subnet(prefix-length) for interface: {}(id={}). Subnet: {}, address: {}", - interfaceName, interfaceIndex, subnet, address); - - addDelAddress(getFutureJVpp(), add, id, interfaceIndex, address.getIp(), - subnet.getPrefixLength().byteValue()); - - LOG.debug("Subnet(prefix-length) set successfully for interface: {}(id={}). Subnet: {}, address: {}", - interfaceName, interfaceIndex, subnet, address); - } catch (VppBaseCallException e) { - LOG.warn("Failed to set Subnet(prefix-length) for interface: {}(id={}). Subnet: {}, address: {}", - interfaceName, interfaceIndex, subnet, address); - throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4Customizer.java deleted file mode 100644 index 7eb45b2e4..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4Customizer.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.v3po.interfaces.ip; - -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class Ipv4Customizer extends FutureJVppCustomizer implements WriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(Ipv4Customizer.class); - private final NamingContext interfaceContext; - - public Ipv4Customizer(final FutureJVpp vppApi, final NamingContext interfaceContext) { - super(vppApi); - this.interfaceContext = interfaceContext; - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Ipv4 dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String ifcName = id.firstKeyOf(Interface.class).getName(); - setIpv4(id, ifcName, dataAfter, writeContext); - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Ipv4 dataBefore, @Nonnull final Ipv4 dataAfter, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - final String ifcName = id.firstKeyOf(Interface.class).getName(); - - // TODO handle update in a better way - setIpv4(id, ifcName, dataAfter, writeContext); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Ipv4 dataBefore, @Nonnull final WriteContext writeContext) { - // TODO implement delete - } - - private void setIpv4(final InstanceIdentifier id, final String name, final Ipv4 ipv4, - final WriteContext writeContext) - throws WriteFailedException { - final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext()); - - LOG.warn("Ignoring Ipv4 leaf nodes (create/update is not supported)"); - // TODO add support for enabled leaf - // TODO add support for forwarding leaf - // TODO add support for mtu leaf - } - -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java deleted file mode 100644 index 426d81fbc..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizer.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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.v3po.interfaces.ip; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Neighbor; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.NeighborKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.IpNeighborAddDel; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Customizer for writing {@link Neighbor} for {@link Ipv4} - */ -public class Ipv4NeighbourCustomizer extends FutureJVppCustomizer - implements ListWriterCustomizer { - - - private static final Logger LOG = LoggerFactory.getLogger(Ipv4NeighbourCustomizer.class); - final NamingContext interfaceContext; - - public Ipv4NeighbourCustomizer(final FutureJVpp futureJvpp, final NamingContext interfaceContext) { - super(futureJvpp); - this.interfaceContext = interfaceContext; - } - - @Override - public void writeCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull Neighbor dataAfter, - @Nonnull WriteContext writeContext) - throws WriteFailedException { - - checkNotNull(dataAfter, "Cannot write null neighbour"); - checkArgument(id.firstKeyOf(Interface.class) != null, "No parent interface key found"); - - LOG.debug("Processing request for Neigbour write"); - String interfaceName = id.firstKeyOf(Interface.class).getName(); - MappingContext mappingContext = writeContext.getMappingContext(); - - checkState(interfaceContext.containsIndex(interfaceName, mappingContext), - "Mapping does not contains mapping for provider interface name ".concat(interfaceName)); - - LOG.debug("Parent interface index found"); - try { - addDelNeighbourAndReply(id, true, - interfaceContext.getIndex(interfaceName, mappingContext), dataAfter); - LOG.info("Neighbour successfully written"); - } catch (VppBaseCallException e) { - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull Neighbor dataBefore, - @Nonnull Neighbor dataAfter, - @Nonnull WriteContext writeContext) throws WriteFailedException { - throw new UnsupportedOperationException("Operation not supported"); - } - - @Override - public void deleteCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull Neighbor dataBefore, - @Nonnull WriteContext writeContext) - throws WriteFailedException { - - checkNotNull(dataBefore, "Cannot delete null neighbour"); - checkArgument(id.firstKeyOf(Interface.class) != null, "No parent interface key found"); - - LOG.debug("Processing request for Neigbour delete"); - String interfaceName = id.firstKeyOf(Interface.class).getName(); - MappingContext mappingContext = writeContext.getMappingContext(); - - checkState(interfaceContext.containsIndex(interfaceName, mappingContext), - "Mapping does not contains mapping for provider interface name %s", interfaceName); - - LOG.debug("Parent interface[{}] index found", interfaceName); - try { - addDelNeighbourAndReply(id, false, - interfaceContext.getIndex(interfaceName, mappingContext), dataBefore); - LOG.info("Neighbour {} successfully deleted", id); - } catch (VppBaseCallException e) { - throw new WriteFailedException.DeleteFailedException(id, e); - } - } - - private void addDelNeighbourAndReply(InstanceIdentifier id, boolean add, int parentInterfaceIndex, - Neighbor data) - throws VppBaseCallException, WriteTimeoutException { - - IpNeighborAddDel request = new IpNeighborAddDel(); - - request.isAdd = TranslateUtils.booleanToByte(add); - request.isIpv6 = 0; - request.isStatic = 1; - request.dstAddress = TranslateUtils.ipv4AddressNoZoneToArray(data.getIp()); - request.macAddress = TranslateUtils.parseMac(data.getLinkLayerAddress().getValue()); - request.swIfIndex = parentInterfaceIndex; - - //TODO if it is necessary for future use ,make adjustments to be able to set vrfid - //request.vrfId - TranslateUtils.getReplyForWrite(getFutureJVpp().ipNeighborAddDel(request).toCompletableFuture(), id); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4WriteUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4WriteUtils.java deleted file mode 100644 index c9fd2e692..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4WriteUtils.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.v3po.interfaces.ip; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress; -import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply; -import org.openvpp.jvpp.future.FutureJVpp; - -/** - * Utility class providing Ipv4 CUD support. - */ -// TODO replace with interface with default methods or abstract class -final class Ipv4WriteUtils { - - private static final int DOTTED_QUAD_MASK_LENGTH = 4; - private static final int IPV4_ADDRESS_PART_BITS_COUNT = 8; - private static final int NETMASK_PART_LIMIT = 256; // 2 power to 8 - - private Ipv4WriteUtils() { - throw new UnsupportedOperationException("This utility class cannot be instantiated"); - } - - static void addDelAddress(@Nonnull final FutureJVpp futureJvpp, final boolean add, final InstanceIdentifier id, - @Nonnegative final int ifaceId, - @Nonnull final Ipv4AddressNoZone address, @Nonnegative final byte prefixLength) - throws VppBaseCallException, WriteTimeoutException { - checkArgument(prefixLength > 0, "Invalid prefix length"); - checkNotNull(address, "address should not be null"); - - final byte[] addressBytes = TranslateUtils.ipv4AddressNoZoneToArray(address); - - final CompletionStage swInterfaceAddDelAddressReplyCompletionStage = - futureJvpp.swInterfaceAddDelAddress( - getSwInterfaceAddDelAddressRequest(ifaceId, TranslateUtils.booleanToByte(add) /* isAdd */, - (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, prefixLength, addressBytes)); - - TranslateUtils.getReplyForWrite(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture(), id); - } - - static SwInterfaceAddDelAddress getSwInterfaceAddDelAddressRequest(final int swIfc, final byte isAdd, - final byte ipv6, final byte deleteAll, - final byte length, final byte[] addr) { - final SwInterfaceAddDelAddress swInterfaceAddDelAddress = new SwInterfaceAddDelAddress(); - swInterfaceAddDelAddress.swIfIndex = swIfc; - swInterfaceAddDelAddress.isAdd = isAdd; - swInterfaceAddDelAddress.isIpv6 = ipv6; - swInterfaceAddDelAddress.delAll = deleteAll; - swInterfaceAddDelAddress.address = addr; - swInterfaceAddDelAddress.addressLength = length; - return swInterfaceAddDelAddress; - } - - /** - * Returns the prefix size in bits of the specified subnet mask. Example: For the subnet mask 255.255.255.128 it - * returns 25 while for 255.0.0.0 it returns 8. If the passed subnetMask array is not complete or contains not only - * leading ones, IllegalArgumentExpression is thrown - * - * @param mask the subnet mask in dot notation 255.255.255.255 - * @return the prefix length as number of bits - */ - static byte getSubnetMaskLength(final String mask) { - String[] maskParts = mask.split("\\."); - - checkArgument(maskParts.length == DOTTED_QUAD_MASK_LENGTH, - "Network mask %s is not in Quad Dotted Decimal notation!", mask); - - long maskAsNumber = 0; - for (int i = 0; i < DOTTED_QUAD_MASK_LENGTH; i++) { - maskAsNumber <<= IPV4_ADDRESS_PART_BITS_COUNT; - int value = Integer.parseInt(maskParts[i]); - checkArgument(value < NETMASK_PART_LIMIT, "Network mask %s contains invalid number(s) over 255!", mask); - checkArgument(value >= 0, "Network mask %s contains invalid negative number(s)!", mask); - maskAsNumber += value; - } - - String bits = Long.toBinaryString(maskAsNumber); - checkArgument(bits.length() == IPV4_ADDRESS_PART_BITS_COUNT * DOTTED_QUAD_MASK_LENGTH, - "Incorrect network mask %s", mask); - final int leadingOnes = bits.indexOf('0'); - checkArgument(leadingOnes != -1, "Broadcast address %s is not allowed!", mask); - checkArgument(bits.substring(leadingOnes).indexOf('1') == -1, - "Non-contiguous network mask %s is not allowed!", mask); - return (byte) leadingOnes; - } - -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv6Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv6Customizer.java deleted file mode 100644 index d43bc90d5..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv6Customizer.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.v3po.interfaces.ip; - -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv6; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class Ipv6Customizer extends FutureJVppCustomizer implements WriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(Ipv6Customizer.class); - - public Ipv6Customizer(final FutureJVpp vppApi) { - super(vppApi); - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Ipv6 dataAfter, @Nonnull final WriteContext writeContext) { - // TODO - LOG.warn("Unsupported, ignoring configuration {}", dataAfter); - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Ipv6 dataBefore, @Nonnull final Ipv6 dataAfter, - @Nonnull final WriteContext writeContext) { - LOG.warn("Unsupported, ignoring configuration {}", dataAfter); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final Ipv6 dataBefore, @Nonnull final WriteContext writeContext) { - LOG.warn("Unsupported, ignoring configuration delete {}", id); - // TODO - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java deleted file mode 100644 index 3d41b899f..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/SubInterfaceIpv4AddressCustomizer.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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.v3po.interfaces.ip; - -import static com.google.common.base.Preconditions.checkNotNull; -import static io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4WriteUtils.addDelAddress; -import static io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4WriteUtils.getSubnetMaskLength; - -import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.Subnet; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.Netmask; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLength; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Write customizer for sub-interface {@link Address} - */ -public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer - implements ListWriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class); - private final NamingContext interfaceContext; - - public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext interfaceContext) { - super(futureJvpp); - this.interfaceContext = checkNotNull(interfaceContext, "interface context should not be null"); - } - - @Override - public void writeCurrentAttributes(InstanceIdentifier
id, Address dataAfter, WriteContext writeContext) - throws WriteFailedException { - setAddress(true, id, dataAfter, writeContext); - } - - @Override - public void updateCurrentAttributes(InstanceIdentifier
id, Address dataBefore, Address dataAfter, - WriteContext writeContext) throws WriteFailedException { - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, - new UnsupportedOperationException("Operation not supported")); - } - - @Override - public void deleteCurrentAttributes(InstanceIdentifier
id, Address dataBefore, WriteContext writeContext) - throws WriteFailedException { - setAddress(false, id, dataBefore, writeContext); - } - - private void setAddress(boolean add, final InstanceIdentifier
id, final Address address, - final WriteContext writeContext) throws WriteFailedException { - - final String interfaceName = id.firstKeyOf(Interface.class).getName(); - final String subInterfaceName = getSubInterfaceName(id); - final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); - - Subnet subnet = address.getSubnet(); - - if (subnet instanceof PrefixLength) { - setPrefixLengthSubnet(add, id, interfaceName, subInterfaceIndex, address, (PrefixLength) subnet); - } else if (subnet instanceof Netmask) { - setNetmaskSubnet(add, id, interfaceName, subInterfaceIndex, address, (Netmask) subnet); - } else { - // FIXME how does choice extensibility work - // FIXME it is not even possible to create a dedicated - // customizer for Interconnection, since it's not a DataObject - // FIXME we might need a choice customizer - // THis choice is already from augment, so its probably not - // possible to augment augmented choice - LOG.error("Unable to handle subnet of type {}", subnet.getClass()); - throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass()); - } - } - - private String getSubInterfaceName(@Nonnull final InstanceIdentifier
id) { - final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); - final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); - return SubInterfaceUtils - .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); - } - - private void setNetmaskSubnet(final boolean add, @Nonnull final InstanceIdentifier
id, - @Nonnull final String subInterfaceName, final int subInterfaceIndex, - @Nonnull final Address address, @Nonnull final Netmask subnet) - throws WriteFailedException { - try { - LOG.debug("Setting Subnet(subnet-mask) for sub-interface: {}(id={}). Subnet: {}, address: {}", - subInterfaceName, subInterfaceIndex, subnet, address); - - final DottedQuad netmask = subnet.getNetmask(); - checkNotNull(netmask, "netmask value should not be null"); - - final byte subnetLength = getSubnetMaskLength(netmask.getValue()); - addDelAddress(getFutureJVpp(), add, id, subInterfaceIndex, address.getIp(), subnetLength); - - } catch (VppBaseCallException e) { - LOG.warn("Failed to set Subnet(subnet-mask) for sub-interface: {}(id={}). Subnet: {}, address: {}", - subInterfaceName, subInterfaceIndex, subnet, address); - throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); - } - } - - private void setPrefixLengthSubnet(final boolean add, @Nonnull final InstanceIdentifier
id, - @Nonnull final String subInterfaceName, final int subInterfaceIndex, - @Nonnull final Address address, @Nonnull final PrefixLength subnet) - throws WriteFailedException { - try { - LOG.debug("Setting Subnet(prefix-length) for sub-interface: {}(id={}). Subnet: {}, address: {}", - subInterfaceName, subInterfaceIndex, subnet, address); - - addDelAddress(getFutureJVpp(), add, id, subInterfaceIndex, address.getIp(), - subnet.getPrefixLength().byteValue()); - - LOG.debug("Subnet(prefix-length) set successfully for sub-interface: {}(id={}). Subnet: {}, address: {}", - subInterfaceName, subInterfaceIndex, subnet, address); - } catch (VppBaseCallException e) { - LOG.warn("Failed to set Subnet(prefix-length) for sub-interface: {}(id={}). Subnet: {}, address: {}", - subInterfaceName, subInterfaceIndex, subnet, address); - throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclCustomizer.java deleted file mode 100644 index c5b17e5b9..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclCustomizer.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.AclBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.ClassifyTableByInterface; -import org.openvpp.jvpp.dto.ClassifyTableByInterfaceReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Customizer for reading ACLs enabled on given interface. - */ -public class AclCustomizer extends FutureJVppCustomizer - implements ReaderCustomizer, AclReader { - - private static final Logger LOG = LoggerFactory.getLogger(AclCustomizer.class); - private final NamingContext interfaceContext; - private final NamingContext classifyTableContext; - - public AclCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext, - @Nonnull final NamingContext classifyTableContext) { - super(jvpp); - this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); - this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Acl readValue) { - ((VppInterfaceStateAugmentationBuilder) parentBuilder).setAcl(readValue); - } - - @Nonnull - @Override - public AclBuilder getBuilder(@Nonnull final InstanceIdentifier id) { - return new AclBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final AclBuilder builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - LOG.debug("Reading attributes for interface ACL: {}", id); - final InterfaceKey interfaceKey = id.firstKeyOf(Interface.class); - checkArgument(interfaceKey != null, "No parent interface key found"); - - final ClassifyTableByInterface request = new ClassifyTableByInterface(); - request.swIfIndex = interfaceContext.getIndex(interfaceKey.getName(), ctx.getMappingContext()); - try { - final ClassifyTableByInterfaceReply reply = TranslateUtils - .getReplyForRead(getFutureJVpp().classifyTableByInterface(request).toCompletableFuture(), id); - - builder.setL2Acl(readL2Acl(reply.l2TableId, classifyTableContext, ctx.getMappingContext())); - builder.setIp4Acl(readIp4Acl(reply.ip4TableId, classifyTableContext, ctx.getMappingContext())); - builder.setIp6Acl(readIp6Acl(reply.ip6TableId, classifyTableContext, ctx.getMappingContext())); - - if (LOG.isTraceEnabled()) { - LOG.trace("Attributes for ACL {} successfully read: {}", id, builder.build()); - } - } catch (VppBaseCallException e) { - throw new ReadFailedException(id, e); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclReader.java deleted file mode 100644 index 173269044..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclReader.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4AclBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6AclBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2AclBuilder; - -interface AclReader { - - @Nonnull - default L2Acl readL2Acl(final int l2TableId, @Nonnull final NamingContext classifyTableContext, - @Nonnull final MappingContext mappingContext) { - if (l2TableId == ~0) { - return null; - } - return new L2AclBuilder() - .setClassifyTable(classifyTableContext.getName(l2TableId, mappingContext)).build(); - } - - @Nonnull - default Ip4Acl readIp4Acl(final int ip4TableId, @Nonnull final NamingContext classifyTableContext, - @Nonnull final MappingContext mappingContext) { - if (ip4TableId == ~0) { - return null; - } - return new Ip4AclBuilder() - .setClassifyTable(classifyTableContext.getName(ip4TableId, mappingContext)).build(); - } - - @Nonnull - default Ip6Acl readIp6Acl(final int ip6TableId, @Nonnull final NamingContext classifyTableContext, - @Nonnull final MappingContext mappingContext) { - if (ip6TableId == ~0) { - return null; - } - return new Ip6AclBuilder() - .setClassifyTable(classifyTableContext.getName(ip6TableId, mappingContext)).build(); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/EthernetCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/EthernetCustomizer.java deleted file mode 100644 index a2643e408..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/EthernetCustomizer.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.EthernetBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.SwInterfaceDetails; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -public class EthernetCustomizer extends FutureJVppCustomizer - implements ReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(EthernetCustomizer.class); - private NamingContext interfaceContext; - - public EthernetCustomizer(@Nonnull final FutureJVpp jvpp, - @Nonnull final NamingContext interfaceContext) { - super(jvpp); - this.interfaceContext = interfaceContext; - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, - @Nonnull final Ethernet readValue) { - ((VppInterfaceStateAugmentationBuilder) parentBuilder).setEthernet(readValue); - } - - @Nonnull - @Override - public EthernetBuilder getBuilder(@Nonnull InstanceIdentifier id) { - return new EthernetBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final EthernetBuilder builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - - final InterfaceKey key = id.firstKeyOf(Interface.class); - final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, key.getName(), - interfaceContext.getIndex(key.getName(), ctx.getMappingContext()), ctx.getModificationCache()); - - if(iface.linkMtu != 0) { - builder.setMtu((int) iface.linkMtu); - } - - switch (iface.linkDuplex) { - case 1: - builder.setDuplex(Ethernet.Duplex.Half); - break; - case 2: - builder.setDuplex(Ethernet.Duplex.Full); - break; - default: - break; - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterconnectionReadUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterconnectionReadUtils.java deleted file mode 100644 index 4bd542b0c..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterconnectionReadUtils.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static com.google.common.base.Preconditions.checkState; -import static java.util.Objects.requireNonNull; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.BridgeDomainDetails; -import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump; -import org.openvpp.jvpp.dto.BridgeDomainDump; -import org.openvpp.jvpp.dto.BridgeDomainSwIfDetails; -import org.openvpp.jvpp.dto.SwInterfaceDetails; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility class providing Interconnection read support. - */ -// FIXME this should be customizer, but it is not possible because Interconnection is not a DataObject -final class InterconnectionReadUtils { - - private static final Logger LOG = LoggerFactory.getLogger(InterconnectionReadUtils.class); - - private final FutureJVpp futureJvpp; - private final NamingContext interfaceContext; - private final NamingContext bridgeDomainContext; - - InterconnectionReadUtils(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext interfaceContext, - @Nonnull final NamingContext bridgeDomainContext) { - this.futureJvpp = requireNonNull(futureJvpp, "futureJvpp should not be null"); - this.interfaceContext = requireNonNull(interfaceContext, "interfaceContext should not be null"); - this.bridgeDomainContext = requireNonNull(bridgeDomainContext, "bridgeDomainContext should not be null"); - } - - @Nullable - Interconnection readInterconnection(@Nonnull final InstanceIdentifier id, @Nonnull final String ifaceName, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - final int ifaceId = interfaceContext.getIndex(ifaceName, ctx.getMappingContext()); - - final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(futureJvpp, id, ifaceName, - ifaceId, ctx.getModificationCache()); - LOG.debug("Interface details for interface: {}, details: {}", ifaceName, iface); - - final BridgeDomainDetailsReplyDump dumpReply = getDumpReply(id); - final Optional bdForInterface = getBridgeDomainForInterface(ifaceId, dumpReply); - if (bdForInterface.isPresent()) { - final BridgeDomainSwIfDetails bdSwIfDetails = bdForInterface.get(); - final BridgeBasedBuilder bbBuilder = new BridgeBasedBuilder(); - bbBuilder.setBridgeDomain(bridgeDomainContext.getName(bdSwIfDetails.bdId, ctx.getMappingContext())); - - // Set BVI if the bridgeDomainDetails.bviSwIfIndex == current sw if index - final Optional bridgeDomainForInterface = - getBridgeDomainForInterface(dumpReply, bdForInterface.get().bdId); - // Since we already found an interface assigned to a bridge domain, the details for BD must be present - checkState(bridgeDomainForInterface.isPresent()); - if (bridgeDomainForInterface.get().bviSwIfIndex == ifaceId) { - bbBuilder.setBridgedVirtualInterface(true); - } else { - bbBuilder.setBridgedVirtualInterface(false); - } - - if (bdSwIfDetails.shg != 0) { - bbBuilder.setSplitHorizonGroup((short) bdSwIfDetails.shg); - } - return bbBuilder.build(); - } - // TODO is there a way to check if interconnection is XconnectBased? - - return null; - } - - private Optional getBridgeDomainForInterface(final int ifaceId, - final BridgeDomainDetailsReplyDump reply) { - if (null == reply || null == reply.bridgeDomainSwIfDetails || reply.bridgeDomainSwIfDetails.isEmpty()) { - return Optional.empty(); - } - // interface can be added to only one BD only - return reply.bridgeDomainSwIfDetails.stream().filter(a -> a.swIfIndex == ifaceId).findFirst(); - } - - private Optional getBridgeDomainForInterface(final BridgeDomainDetailsReplyDump reply, - int bdId) { - return reply.bridgeDomainDetails.stream().filter(a -> a.bdId == bdId).findFirst(); - } - - private BridgeDomainDetailsReplyDump getDumpReply(@Nonnull final InstanceIdentifier id) - throws ReadFailedException { - try { - // We need to perform full bd dump, because there is no way - // to ask VPP for BD details given interface id/name (TODO add it to vpp.api?) - // TODO cache dump result - final BridgeDomainDump request = new BridgeDomainDump(); - request.bdId = -1; - - final CompletableFuture bdCompletableFuture = - futureJvpp.bridgeDomainSwIfDump(request).toCompletableFuture(); - return TranslateUtils.getReplyForRead(bdCompletableFuture, id); - } catch (VppBaseCallException e) { - throw new ReadFailedException(id, e); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizer.java deleted file mode 100644 index 832b29c13..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizer.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceDetails; -import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump; -import org.openvpp.jvpp.dto.SwInterfaceDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Customizer for reading ietf-interfaces:interfaces-state/interface. - */ -public class InterfaceCustomizer extends FutureJVppCustomizer - implements ListReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(InterfaceCustomizer.class); - public static final String DUMPED_IFCS_CONTEXT_KEY = - InterfaceCustomizer.class.getName() + "dumpedInterfacesDuringGetAllIds"; - - private final NamingContext interfaceContext; - - public InterfaceCustomizer(@Nonnull final FutureJVpp jvpp, final NamingContext interfaceContext) { - super(jvpp); - this.interfaceContext = interfaceContext; - } - - @Nonnull - @Override - public InterfaceBuilder getBuilder(@Nonnull InstanceIdentifier id) { - return new InterfaceBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull InterfaceBuilder builder, - @Nonnull ReadContext ctx) throws ReadFailedException { - LOG.debug("Reading attributes for interface: {}", id); - final String ifaceName = id.firstKeyOf(id.getTargetType()).getName(); - - // Pass cached details from getAllIds to getDetails to avoid additional dumps - final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, ifaceName, - interfaceContext.getIndex(ifaceName, ctx.getMappingContext()), ctx.getModificationCache()); - LOG.debug("Interface details for interface: {}, details: {}", ifaceName, iface); - - if (!isRegularInterface(iface)) { - LOG.debug("Interface: {} is a sub-interface. Ignoring read request.", ifaceName); - return; - } - - builder.setName(ifaceName); - builder.setType(InterfaceUtils.getInterfaceType(new String(iface.interfaceName).intern())); - builder.setIfIndex(InterfaceUtils.vppIfIndexToYang(iface.swIfIndex)); - builder.setAdminStatus(1 == iface.adminUpDown - ? AdminStatus.Up - : AdminStatus.Down); - builder.setOperStatus(1 == iface.linkUpDown - ? OperStatus.Up - : OperStatus.Down); - if (0 != iface.linkSpeed) { - builder.setSpeed(InterfaceUtils.vppInterfaceSpeedToYang(iface.linkSpeed)); - } - if (iface.l2AddressLength == 6) { - builder.setPhysAddress(new PhysAddress(InterfaceUtils.vppPhysAddrToYang(iface.l2Address))); - } - LOG.trace("Base attributes read for interface: {} as: {}", ifaceName, builder); - } - - @Nonnull - @SuppressWarnings("unchecked") - public static Map getCachedInterfaceDump(@Nonnull final ModificationCache ctx) { - return ctx.get(DUMPED_IFCS_CONTEXT_KEY) == null - ? new HashMap<>() - // allow customizers to update the cache - : (Map) ctx.get(DUMPED_IFCS_CONTEXT_KEY); - } - - @Nonnull - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext context) throws ReadFailedException { - try { - final List interfacesKeys; - LOG.trace("Dumping all interfaces to get all IDs"); - - final SwInterfaceDump request = new SwInterfaceDump(); - request.nameFilter = "".getBytes(); - request.nameFilterValid = 0; - - final CompletableFuture swInterfaceDetailsReplyDumpCompletableFuture = - getFutureJVpp().swInterfaceDump(request).toCompletableFuture(); - final SwInterfaceDetailsReplyDump ifaces = - TranslateUtils.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, id); - - if (null == ifaces || null == ifaces.swInterfaceDetails) { - LOG.debug("No interfaces for :{} found in VPP", id); - return Collections.emptyList(); - } - - // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes - context.getModificationCache().put(DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream() - .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails))); - - interfacesKeys = ifaces.swInterfaceDetails.stream() - .filter(elt -> elt != null) - .map((elt) -> { - // Store interface name from VPP in context if not yet present - if (!interfaceContext.containsName(elt.swIfIndex, context.getMappingContext())) { - interfaceContext.addName(elt.swIfIndex, TranslateUtils.toString(elt.interfaceName), - context.getMappingContext()); - } - LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP", - interfaceContext.getName(elt.swIfIndex, context.getMappingContext()), elt.interfaceName, - elt.swIfIndex); - - return elt; - }) - .filter(InterfaceCustomizer::isRegularInterface) // filter out sub-interfaces - .map((elt) -> new InterfaceKey(interfaceContext.getName(elt.swIfIndex, context.getMappingContext()))) - .collect(Collectors.toList()); - - LOG.debug("Interfaces found in VPP: {}", interfacesKeys); - return interfacesKeys; - } catch (VppBaseCallException e) { - LOG.warn("getAllIds for id :{} failed with exception ", id, e); - throw new ReadFailedException(id, e); - } - } - - private static boolean isRegularInterface(final SwInterfaceDetails iface) { - return iface.subId == 0; - } - - @Override - public void merge(@Nonnull final org.opendaylight.yangtools.concepts.Builder builder, - @Nonnull final List readData) { - ((InterfacesStateBuilder) builder).setInterface(readData); - } - -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java deleted file mode 100644 index f902f8985..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static com.google.common.base.Preconditions.checkArgument; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceCustomizer.getCachedInterfaceDump; -import static java.util.Objects.requireNonNull; - -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.math.BigInteger; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.CompletionStage; -import java.util.stream.Collector; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Gauge64; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceDetails; -import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump; -import org.openvpp.jvpp.dto.SwInterfaceDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class InterfaceUtils { - private static final Logger LOG = LoggerFactory.getLogger(InterfaceUtils.class); - - private static final Gauge64 vppLinkSpeed0 = new Gauge64(BigInteger.ZERO); - private static final Gauge64 vppLinkSpeed1 = new Gauge64(BigInteger.valueOf(10L * 1000000)); - private static final Gauge64 vppLinkSpeed2 = new Gauge64(BigInteger.valueOf(100L * 1000000)); - private static final Gauge64 vppLinkSpeed4 = new Gauge64(BigInteger.valueOf(1000L * 1000000)); - private static final Gauge64 vppLinkSpeed8 = new Gauge64(BigInteger.valueOf(10000L * 1000000)); - private static final Gauge64 vppLinkSpeed16 = new Gauge64(BigInteger.valueOf(40000L * 1000000)); - private static final Gauge64 vppLinkSpeed32 = new Gauge64(BigInteger.valueOf(100000L * 1000000)); - - private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray(); - - private static final int PHYSICAL_ADDRESS_LENGTH = 6; - - private static final Collector SINGLE_ITEM_COLLECTOR = - RWUtils.singleItemCollector(); - - private InterfaceUtils() { - throw new UnsupportedOperationException("This utility class cannot be instantiated"); - } - - /** - * Convert VPP's link speed bitmask to Yang type. 1 = 10M, 2 = 100M, 4 = 1G, 8 = 10G, 16 = 40G, 32 = 100G - * - * @param vppLinkSpeed Link speed in bitmask format from VPP. - * @return Converted value from VPP link speed - */ - public static Gauge64 vppInterfaceSpeedToYang(byte vppLinkSpeed) { - switch (vppLinkSpeed) { - case 1: - return vppLinkSpeed1; - case 2: - return vppLinkSpeed2; - case 4: - return vppLinkSpeed4; - case 8: - return vppLinkSpeed8; - case 16: - return vppLinkSpeed16; - case 32: - return vppLinkSpeed32; - default: - return vppLinkSpeed0; - } - } - - private static final void appendHexByte(final StringBuilder sb, final byte b) { - final int v = b & 0xFF; - sb.append(HEX_CHARS[v >>> 4]); - sb.append(HEX_CHARS[v & 15]); - } - - // TODO rename and move to V3poUtils - - /** - * Reads first 6 bytes of supplied byte array and converts to string as Yang dictates

Replace later with - * https://git.opendaylight.org/gerrit/#/c/34869/10/model/ietf/ietf-type- util/src/main/ - * java/org/opendaylight/mdsal/model/ietf/util/AbstractIetfYangUtil.java - * - * @param vppPhysAddress byte array of bytes in big endian order, constructing the network IF physical address. - * @return String like "aa:bb:cc:dd:ee:ff" - * @throws NullPointerException if vppPhysAddress is null - * @throws IllegalArgumentException if vppPhysAddress.length < 6 - */ - public static String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress) { - return vppPhysAddrToYang(vppPhysAddress, 0); - } - - public static String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress, final int startIndex) { - Objects.requireNonNull(vppPhysAddress, "Empty physical address bytes"); - final int endIndex = startIndex + PHYSICAL_ADDRESS_LENGTH; - checkArgument(endIndex <= vppPhysAddress.length, - "Invalid physical address size (%s) for given startIndex (%s), expected >= %s", vppPhysAddress.length, - startIndex, endIndex); - return printHexBinary(vppPhysAddress, startIndex, endIndex); - } - - public static String printHexBinary(@Nonnull final byte[] bytes) { - Objects.requireNonNull(bytes, "bytes array should not be null"); - return printHexBinary(bytes, 0, bytes.length); - } - - private static String printHexBinary(@Nonnull final byte[] bytes, final int startIndex, final int endIndex) { - StringBuilder str = new StringBuilder(); - - appendHexByte(str, bytes[startIndex]); - for (int i = startIndex + 1; i < endIndex; i++) { - str.append(":"); - appendHexByte(str, bytes[i]); - } - - return str.toString(); - } - - /** - * VPP's interface index is counted from 0, whereas ietf-interface's if-index is from 1. This function converts from - * VPP's interface index to YANG's interface index. - * - * @param vppIfIndex the sw interface index VPP reported. - * @return VPP's interface index incremented by one - */ - public static int vppIfIndexToYang(int vppIfIndex) { - return vppIfIndex + 1; - } - - /** - * This function does the opposite of what {@link #vppIfIndexToYang(int)} does. - * - * @param yangIfIndex if-index from ietf-interfaces. - * @return VPP's representation of the if-index - */ - public static int yangIfIndexToVpp(int yangIfIndex) { - checkArgument(yangIfIndex >= 1, "YANG if-index has invalid value %s", yangIfIndex); - return yangIfIndex - 1; - } - - - /** - * Queries VPP for interface description given interface key. - * - * @param futureJvpp VPP Java Future API - * @param id InstanceIdentifier, which is passed in ReadFailedException - * @param name interface name - * @param index VPP index of the interface - * @param ctx per-tx scope context containing cached dump with all the interfaces. If the cache is not - * available or outdated, another dump will be performed. - * @return SwInterfaceDetails DTO or null if interface was not found - * @throws IllegalArgumentException If interface cannot be found - * @throws ReadFailedException If read operation had failed - */ - @Nonnull - public static SwInterfaceDetails getVppInterfaceDetails(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final InstanceIdentifier id, - @Nonnull final String name, final int index, - @Nonnull final ModificationCache ctx) - throws ReadFailedException { - requireNonNull(futureJvpp, "futureJvpp should not be null"); - requireNonNull(name, "name should not be null"); - requireNonNull(ctx, "ctx should not be null"); - - final SwInterfaceDump request = new SwInterfaceDump(); - request.nameFilter = name.getBytes(); - request.nameFilterValid = 1; - - final Map allInterfaces = getCachedInterfaceDump(ctx); - - // Returned cached if available - if (allInterfaces.containsKey(index)) { - return allInterfaces.get(index); - } - - SwInterfaceDetailsReplyDump ifaces; - try { - CompletionStage requestFuture = futureJvpp.swInterfaceDump(request); - ifaces = TranslateUtils.getReplyForRead(requestFuture.toCompletableFuture(), id); - if (null == ifaces || null == ifaces.swInterfaceDetails || ifaces.swInterfaceDetails.isEmpty()) { - request.nameFilterValid = 0; - - LOG.warn("VPP returned null instead of interface by key {} and its not cached", name); - LOG.warn("Iterating through all the interfaces to find interface: {}", name); - - // Or else just perform full dump and do inefficient filtering - requestFuture = futureJvpp.swInterfaceDump(request); - ifaces = TranslateUtils.getReplyForRead(requestFuture.toCompletableFuture(), id); - - // Update the cache - allInterfaces.clear(); - allInterfaces - .putAll(ifaces.swInterfaceDetails.stream().collect(Collectors.toMap(d -> d.swIfIndex, d -> d))); - - if (allInterfaces.containsKey(index)) { - return allInterfaces.get(index); - } - throw new IllegalArgumentException("Unable to find interface " + name); - } - } catch (VppBaseCallException e) { - LOG.warn("getVppInterfaceDetails for id :{} and name :{} failed with exception :", id, name, e); - throw new ReadFailedException(id, e); - } - - // SwInterfaceDump's name filter does prefix match, so we need additional filtering: - final SwInterfaceDetails iface = - ifaces.swInterfaceDetails.stream().filter(d -> d.swIfIndex == index).collect(SINGLE_ITEM_COLLECTOR); - allInterfaces.put(index, iface); // update the cache - return iface; - } - - /** - * Determine interface type based on its VPP name (relying on VPP's interface naming conventions) - * - * @param interfaceName VPP generated interface name - * @return Interface type - */ - @Nonnull - public static Class getInterfaceType(@Nonnull final String interfaceName) { - if (interfaceName.startsWith("tap")) { - return Tap.class; - } - - if (interfaceName.startsWith("vxlan_gpe")) { - return VxlanGpeTunnel.class; - } - - if (interfaceName.startsWith("vxlan")) { - return VxlanTunnel.class; - } - - if (interfaceName.startsWith("VirtualEthernet")) { - return VhostUser.class; - } - - return EthernetCsmacd.class; - } - - /** - * Check interface type. Uses interface details from VPP to determine. Uses {@link - * #getVppInterfaceDetails(FutureJVpp, InstanceIdentifier, String, int, ModificationCache)} internally so tries to - * utilize cache before asking VPP. - */ - static boolean isInterfaceOfType(@Nonnull final FutureJVpp jvpp, - @Nonnull final ModificationCache cache, - @Nonnull final InstanceIdentifier id, - final int index, - @Nonnull final Class ifcType) throws ReadFailedException { - final String name = id.firstKeyOf(Interface.class).getName(); - final SwInterfaceDetails vppInterfaceDetails = - getVppInterfaceDetails(jvpp, id, name, index, cache); - - return isInterfaceOfType(ifcType, vppInterfaceDetails); - } - - static boolean isInterfaceOfType(final Class ifcType, - final SwInterfaceDetails cachedDetails) { - return ifcType.equals(getInterfaceType(TranslateUtils.toString(cachedDetails.interfaceName))); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2Customizer.java deleted file mode 100644 index e7c6b2aa1..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2Customizer.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2Builder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nonnull; - -import static com.google.common.base.Preconditions.checkState; - -/** - * Customizer for reading ietf-interfaces:interfaces-state/interface/iface_name/v3po:l2 - */ -public class L2Customizer extends FutureJVppCustomizer implements ReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class); - private final InterconnectionReadUtils icReadUtils; - - public L2Customizer(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext interfaceContext, - @Nonnull final NamingContext bridgeDomainContext) { - super(futureJvpp); - this.icReadUtils = new InterconnectionReadUtils(futureJvpp, interfaceContext, bridgeDomainContext); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final L2 readValue) { - ((VppInterfaceStateAugmentationBuilder) parentBuilder).setL2(readValue); - } - - @Nonnull - @Override - public L2Builder getBuilder(@Nonnull final InstanceIdentifier id) { - return new L2Builder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2Builder builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - - LOG.debug("Reading attributes for L2: {}", id); - final InterfaceKey key = id.firstKeyOf(Interface.class); - final String ifaceName = key.getName(); - builder.setInterconnection(icReadUtils.readInterconnection(id, ifaceName, ctx)); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/RewriteCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/RewriteCustomizer.java deleted file mode 100644 index e76ed7662..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/RewriteCustomizer.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static com.google.common.base.Preconditions.checkState; - -import com.google.common.base.Preconditions; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.TagRewriteOperation; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import org.apache.commons.lang3.builder.ReflectionToStringBuilder; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qTagVlanType; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.Dot1qTagBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1ad; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1q; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2Builder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTags; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTagsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTagsKey; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.SwInterfaceDetails; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Customizer for reading vlan tag-rewrite configuration state form the VPP. - */ -public class RewriteCustomizer extends FutureJVppCustomizer - implements ReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(RewriteCustomizer.class); - private final NamingContext interfaceContext; - - public RewriteCustomizer(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext interfaceContext) { - super(futureJvpp); - this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, - @Nonnull final Rewrite readValue) { - ((L2Builder) parentBuilder).setRewrite(readValue); - } - - @Nonnull - @Override - public RewriteBuilder getBuilder(@Nonnull final InstanceIdentifier id) { - return new RewriteBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final RewriteBuilder builder, @Nonnull final ReadContext ctx) - throws ReadFailedException { - final String subInterfaceName = getSubInterfaceName(id); - LOG.debug("Reading attributes for sub interface: {}", subInterfaceName); - - final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, subInterfaceName, - interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()), ctx.getModificationCache()); - LOG.debug("VPP sub-interface details: {}", ReflectionToStringBuilder.toString(iface)); - - checkState(iface.subId != 0, "Interface returned by the VPP is not a sub-interface"); - - final TagRewriteOperation operation = TagRewriteOperation.get(iface.vtrOp); - if (TagRewriteOperation.disabled == operation) { - LOG.debug("Tag rewrite operation is disabled for "); - return; - } - - builder.setVlanType(iface.vtrPushDot1Q == 1 - ? _802dot1q.class - : _802dot1ad.class); - - setPushTags(builder, iface); - setPopTags(builder, operation); - } - - private static String getSubInterfaceName(final InstanceIdentifier id) { - return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), - Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier())); - } - - private void setPopTags(final RewriteBuilder builder, final TagRewriteOperation operation) { - final byte numberOfTagsToPop = operation.getPopTags(); - if (numberOfTagsToPop != 0) { - builder.setPopTags(Short.valueOf(numberOfTagsToPop)); - } - } - - private void setPushTags(final RewriteBuilder builder, final SwInterfaceDetails iface) { - final List tags = new ArrayList<>(); - if (iface.vtrTag1 != 0) { - tags.add(buildTag((short) 0, SVlan.class, iface.vtrTag1)); - } - if (iface.vtrTag2 != 0) { - tags.add(buildTag((short) 1, CVlan.class, iface.vtrTag2)); - } - if (tags.size() > 0) { - builder.setPushTags(tags); - } - } - - private PushTags buildTag(final short index, final Class tagType, final int vlanId) { - final PushTagsBuilder tag = new PushTagsBuilder(); - tag.setIndex(index); - tag.setKey(new PushTagsKey(index)); - final Dot1qTagBuilder dtag = new Dot1qTagBuilder(); - dtag.setTagType(tagType); - dtag.setVlanId(new Dot1qVlanId(vlanId)); - tag.setDot1qTag(dtag.build()); - return tag.build(); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java deleted file mode 100644 index 276849ba4..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceAclCustomizer.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.AclBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.ClassifyTableByInterface; -import org.openvpp.jvpp.dto.ClassifyTableByInterfaceReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Customizer for reading ACLs enabled on given sub-interface. - */ -public class SubInterfaceAclCustomizer extends FutureJVppCustomizer - implements ReaderCustomizer, AclReader { - - private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceAclCustomizer.class); - private final NamingContext interfaceContext; - private final NamingContext classifyTableContext; - - public SubInterfaceAclCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext, - @Nonnull final NamingContext classifyTableContext) { - super(jvpp); - this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); - this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Acl readValue) { - ((SubInterfaceBuilder) parentBuilder).setAcl(readValue); - } - - @Nonnull - @Override - public AclBuilder getBuilder(@Nonnull final InstanceIdentifier id) { - return new AclBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final AclBuilder builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - LOG.debug("Reading attributes for sub-interface ACL: {}", id); - final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); - checkArgument(parentInterfacekey != null, "No parent interface key found"); - final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); - checkArgument(subInterfacekey != null, "No sub-interface key found"); - final String subInterfaceName = - getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); - - final ClassifyTableByInterface request = new ClassifyTableByInterface(); - request.swIfIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()); - try { - final ClassifyTableByInterfaceReply reply = TranslateUtils - .getReplyForRead(getFutureJVpp().classifyTableByInterface(request).toCompletableFuture(), id); - - builder.setL2Acl(readL2Acl(reply.l2TableId, classifyTableContext, ctx.getMappingContext())); - builder.setIp4Acl(readIp4Acl(reply.ip4TableId, classifyTableContext, ctx.getMappingContext())); - builder.setIp6Acl(readIp6Acl(reply.ip6TableId, classifyTableContext, ctx.getMappingContext())); - - if (LOG.isTraceEnabled()) { - LOG.trace("Attributes for ACL {} successfully read: {}", id, builder.build()); - } - } catch (VppBaseCallException e) { - throw new ReadFailedException(id, e); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceCustomizer.java deleted file mode 100644 index fc44a54e5..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceCustomizer.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static com.google.common.base.Preconditions.checkState; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY; -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.byteToBoolean; - -import com.google.common.base.Preconditions; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.apache.commons.lang3.builder.ReflectionToStringBuilder; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qTagVlanType; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTagBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubInterfaceStatus; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfacesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.DefaultBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.UntaggedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.vlan.tagged.VlanTaggedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.TagsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.TagBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.TagKey; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceDetails; -import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump; -import org.openvpp.jvpp.dto.SwInterfaceDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Customizer for reading sub interfaces form the VPP. - */ -public class SubInterfaceCustomizer extends FutureJVppCustomizer - implements ListReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceCustomizer.class); - private NamingContext interfaceContext; - private static final Dot1qTag.VlanId ANY_VLAN_ID = new Dot1qTag.VlanId(Dot1qTag.VlanId.Enumeration.Any); - - public SubInterfaceCustomizer(@Nonnull final FutureJVpp jvpp, - @Nonnull final NamingContext interfaceContext) { - super(jvpp); - this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); - } - - @Nonnull - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext context) throws ReadFailedException { - try { - // Relying here that parent InterfaceCustomizer was invoked first (PREORDER) - // to fill in the context with initial ifc mapping - final InterfaceKey key = id.firstKeyOf(Interface.class); - final String ifaceName = key.getName(); - final int ifaceId = interfaceContext.getIndex(ifaceName, context.getMappingContext()); - - // TODO if we know that full dump was already performed we could use cache - // (checking if getCachedInterfaceDump() returns non empty map is not enough, because - // we could be part of particular iface state read - final SwInterfaceDump request = new SwInterfaceDump(); - request.nameFilter = "".getBytes(); - request.nameFilterValid = 0; - - final CompletableFuture swInterfaceDetailsReplyDumpCompletableFuture = - getFutureJVpp().swInterfaceDump(request).toCompletableFuture(); - final SwInterfaceDetailsReplyDump ifaces = - TranslateUtils.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, id); - - if (null == ifaces || null == ifaces.swInterfaceDetails) { - LOG.warn("Looking for sub-interfaces, but no interfaces found in VPP"); - return Collections.emptyList(); - } - - // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes - context.getModificationCache().put(DUMPED_IFCS_CONTEXT_KEY, ifaces.swInterfaceDetails.stream() - .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails))); - - final List interfacesKeys = ifaces.swInterfaceDetails.stream() - .filter(elt -> elt != null) - // accept only sub-interfaces for current iface: - .filter(elt -> elt.subId != 0 && elt.supSwIfIndex == ifaceId) - .map(details -> new SubInterfaceKey(new Long(details.subId))) - .collect(Collectors.toList()); - - LOG.debug("Sub-interfaces of {} found in VPP: {}", ifaceName, interfacesKeys); - return interfacesKeys; - } catch (VppBaseCallException e) { - throw new ReadFailedException(id,e); - } - } - - @Override - public void merge(@Nonnull final Builder builder, - @Nonnull final List readData) { - ((SubInterfacesBuilder) builder).setSubInterface(readData); - } - - @Nonnull - @Override - public SubInterfaceBuilder getBuilder(@Nonnull final InstanceIdentifier id) { - return new SubInterfaceBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final SubInterfaceBuilder builder, @Nonnull final ReadContext ctx) - throws ReadFailedException { - final String subInterfaceName = getSubInterfaceName(id); - LOG.debug("Reading attributes for sub interface: {}", subInterfaceName); - - final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), id, subInterfaceName, - interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()), ctx.getModificationCache()); - LOG.debug("VPP sub-interface details: {}", ReflectionToStringBuilder.toString(iface)); - - checkState(iface.subId != 0, "Interface returned by the VPP is not a sub-interface"); - - builder.setIdentifier(Long.valueOf(iface.subId)); - builder.setKey(new SubInterfaceKey(builder.getIdentifier())); - - // sub-interface-base-attributes: - builder.setTags(readTags(iface)); - builder.setMatch(readMatch(iface)); - - // sub-interface-operational-attributes: - builder.setAdminStatus(1 == iface.adminUpDown - ? SubInterfaceStatus.Up - : SubInterfaceStatus.Down); - builder.setOperStatus(1 == iface.linkUpDown - ? SubInterfaceStatus.Up - : SubInterfaceStatus.Down); - builder.setIfIndex(InterfaceUtils.vppIfIndexToYang(iface.swIfIndex)); - if (iface.l2AddressLength == 6) { - builder.setPhysAddress(new PhysAddress(InterfaceUtils.vppPhysAddrToYang(iface.l2Address))); - } - if (0 != iface.linkSpeed) { - builder.setSpeed(InterfaceUtils.vppInterfaceSpeedToYang(iface.linkSpeed)); - } - } - - private static String getSubInterfaceName(final InstanceIdentifier id) { - return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), - Math.toIntExact(id.firstKeyOf(id.getTargetType()).getIdentifier())); - } - - private Tags readTags(final SwInterfaceDetails iface) { - final TagsBuilder tags = new TagsBuilder(); - final List list = new ArrayList<>(); - if (iface.subNumberOfTags > 0) { - if (iface.subOuterVlanIdAny == 1) { - list.add(buildTag((short) 0, SVlan.class, ANY_VLAN_ID)); - } else { - list.add(buildTag((short) 0, SVlan.class, buildVlanId(iface.subOuterVlanId))); - } - // inner tag (customer tag): - if (iface.subNumberOfTags == 2) { - if (iface.subInnerVlanIdAny == 1) { - list.add(buildTag((short) 1, CVlan.class, ANY_VLAN_ID)); - } else { - list.add(buildTag((short) 1, CVlan.class, buildVlanId(iface.subInnerVlanId))); - } - } - } - tags.setTag(list); - return tags.build(); - } - - private static Tag buildTag(final short index, final Class tagType, - final Dot1qTag.VlanId vlanId) { - TagBuilder tag = new TagBuilder(); - tag.setIndex(index); - tag.setKey(new TagKey(index)); - final Dot1qTagBuilder dtag = new Dot1qTagBuilder(); - dtag.setTagType(tagType); - dtag.setVlanId(vlanId); - tag.setDot1qTag(dtag.build()); - return tag.build(); - } - - private static Dot1qTag.VlanId buildVlanId(final short vlanId) { - // treat vlanId as unsigned value: - return new Dot1qTag.VlanId(new Dot1qVlanId(0xffff & vlanId)); - } - - private Match readMatch(final SwInterfaceDetails iface) { - final MatchBuilder match = new MatchBuilder(); - if (iface.subDefault == 1) { - match.setMatchType(new DefaultBuilder().build()); - } else if (iface.subNumberOfTags == 0) { - match.setMatchType(new UntaggedBuilder().build()); - } else { - final VlanTaggedBuilder tagged = new VlanTaggedBuilder(); - tagged.setMatchExactTags(byteToBoolean(iface.subExactMatch)); - match.setMatchType( - new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.VlanTaggedBuilder() - .setVlanTagged(tagged.build()).build()); - } - return match.build(); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java deleted file mode 100644 index 6e9b16719..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceL2Customizer.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2Builder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Customizer for reading vlan sub interface L2 operational state - */ -public class SubInterfaceL2Customizer extends FutureJVppCustomizer implements ReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceL2Customizer.class); - private final InterconnectionReadUtils icReadUtils; - - public SubInterfaceL2Customizer(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext interfaceContext, - @Nonnull final NamingContext bridgeDomainContext) { - super(futureJvpp); - this.icReadUtils = new InterconnectionReadUtils(futureJvpp, interfaceContext, bridgeDomainContext); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final L2 readValue) { - ((SubInterfaceBuilder) parentBuilder).setL2(readValue); - } - - @Nonnull - @Override - public L2Builder getBuilder(@Nonnull final InstanceIdentifier id) { - return new L2Builder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final L2Builder builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - LOG.debug("Reading attributes for sub-interface L2: {}", id); - final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); - final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); - final String subInterfaceName = getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); - - builder.setInterconnection(icReadUtils.readInterconnection(id, subInterfaceName, ctx)); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/TapCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/TapCustomizer.java deleted file mode 100644 index c9a592e30..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/TapCustomizer.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletionStage; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Tap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.TapBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceTapDetails; -import org.openvpp.jvpp.dto.SwInterfaceTapDetailsReplyDump; -import org.openvpp.jvpp.dto.SwInterfaceTapDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -public class TapCustomizer extends FutureJVppCustomizer - implements ReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(TapCustomizer.class); - public static final String DUMPED_TAPS_CONTEXT_KEY = TapCustomizer.class.getName() + "dumpedTapsDuringGetAllIds"; - private NamingContext interfaceContext; - - public TapCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) { - super(jvpp); - this.interfaceContext = interfaceContext; - } - - @Override - public void merge(@Nonnull Builder parentBuilder, @Nonnull Tap readValue) { - ((VppInterfaceStateAugmentationBuilder) parentBuilder).setTap(readValue); - } - - @Nonnull - @Override - public TapBuilder getBuilder(@Nonnull InstanceIdentifier id) { - return new TapBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final TapBuilder builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - try { - final InterfaceKey key = id.firstKeyOf(Interface.class); - final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext()); - if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap.class)) { - return; - } - - LOG.debug("Reading attributes for tap interface: {}", key.getName()); - - @SuppressWarnings("unchecked") - Map mappedTaps = - (Map) ctx.getModificationCache().get(DUMPED_TAPS_CONTEXT_KEY); - - if(mappedTaps == null) { - // Full Tap dump has to be performed here, no filter or anything is here to help so at least we cache it - final SwInterfaceTapDump request = new SwInterfaceTapDump(); - final CompletionStage swInterfaceTapDetailsReplyDumpCompletionStage = - getFutureJVpp().swInterfaceTapDump(request); - final SwInterfaceTapDetailsReplyDump reply = - TranslateUtils.getReplyForRead(swInterfaceTapDetailsReplyDumpCompletionStage.toCompletableFuture(), id); - - if(null == reply || null == reply.swInterfaceTapDetails) { - mappedTaps = Collections.emptyMap(); - } else { - final List swInterfaceTapDetails = reply.swInterfaceTapDetails; - // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes - mappedTaps = swInterfaceTapDetails.stream() - .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails)); - } - - ctx.getModificationCache().put(DUMPED_TAPS_CONTEXT_KEY, mappedTaps); - } - - final SwInterfaceTapDetails swInterfaceTapDetails = mappedTaps.get(index); - LOG.trace("Tap interface: {} attributes returned from VPP: {}", key.getName(), swInterfaceTapDetails); - - builder.setTapName(TranslateUtils.toString(swInterfaceTapDetails.devName)); - LOG.debug("Tap interface: {}, id: {} attributes read as: {}", key.getName(), index, builder); - } catch (VppBaseCallException e) { - LOG.warn("Failed to readCurrentAttributes for: {}", id, e); - throw new ReadFailedException(id, e); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VhostUserCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VhostUserCustomizer.java deleted file mode 100644 index 878eb3179..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VhostUserCustomizer.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.math.BigInteger; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletionStage; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUser; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VhostUserBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceVhostUserDetails; -import org.openvpp.jvpp.dto.SwInterfaceVhostUserDetailsReplyDump; -import org.openvpp.jvpp.dto.SwInterfaceVhostUserDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -public class VhostUserCustomizer extends FutureJVppCustomizer - implements ReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(VhostUserCustomizer.class); - public static final String DUMPED_VHOST_USERS_CONTEXT_KEY = VhostUserCustomizer.class.getName() + "dumpedVhostUsersDuringGetAllIds"; - private NamingContext interfaceContext; - - public VhostUserCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) { - super(jvpp); - this.interfaceContext = interfaceContext; - } - - @Override - public void merge(@Nonnull Builder parentBuilder, @Nonnull VhostUser readValue) { - ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVhostUser(readValue); - } - - @Nonnull - @Override - public VhostUserBuilder getBuilder(@Nonnull InstanceIdentifier id) { - return new VhostUserBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final VhostUserBuilder builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - try { - final InterfaceKey key = id.firstKeyOf(Interface.class); - final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext()); - if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class)) { - return; - } - - LOG.debug("Reading attributes for vhpost user interface: {}", key.getName()); - - @SuppressWarnings("unchecked") - Map mappedVhostUsers = - (Map) ctx.getModificationCache().get(DUMPED_VHOST_USERS_CONTEXT_KEY); - - if(mappedVhostUsers == null) { - // Full VhostUser dump has to be performed here, no filter or anything is here to help so at least we cache it - final SwInterfaceVhostUserDump request = new SwInterfaceVhostUserDump(); - final CompletionStage swInterfaceVhostUserDetailsReplyDumpCompletionStage = - getFutureJVpp().swInterfaceVhostUserDump(request); - final SwInterfaceVhostUserDetailsReplyDump reply = - TranslateUtils.getReplyForRead(swInterfaceVhostUserDetailsReplyDumpCompletionStage.toCompletableFuture(), id); - - if(null == reply || null == reply.swInterfaceVhostUserDetails) { - mappedVhostUsers = Collections.emptyMap(); - } else { - final List swInterfaceVhostUserDetails = reply.swInterfaceVhostUserDetails; - // Cache interfaces dump in per-tx context to later be used in readCurrentAttributes - mappedVhostUsers = swInterfaceVhostUserDetails.stream() - .collect(Collectors.toMap(t -> t.swIfIndex, swInterfaceDetails -> swInterfaceDetails)); - } - - ctx.getModificationCache().put(DUMPED_VHOST_USERS_CONTEXT_KEY, mappedVhostUsers); - } - - // Relying here that parent InterfaceCustomizer was invoked first to fill in the context with initial ifc mapping - final SwInterfaceVhostUserDetails swInterfaceVhostUserDetails = mappedVhostUsers.get(index); - LOG.trace("Vhost user interface: {} attributes returned from VPP: {}", key.getName(), swInterfaceVhostUserDetails); - - builder.setRole(swInterfaceVhostUserDetails.isServer == 1 ? VhostUserRole.Server : VhostUserRole.Client); - builder.setFeatures(BigInteger.valueOf(swInterfaceVhostUserDetails.features)); - builder.setNumMemoryRegions((long) swInterfaceVhostUserDetails.numRegions); - builder.setSocket(TranslateUtils.toString(swInterfaceVhostUserDetails.sockFilename)); - builder.setVirtioNetHdrSize((long) swInterfaceVhostUserDetails.virtioNetHdrSz); - builder.setConnectError(Integer.toString(swInterfaceVhostUserDetails.sockErrno)); - - LOG.debug("Vhost user interface: {}, id: {} attributes read as: {}", key.getName(), index, builder); - } catch (VppBaseCallException e) { - LOG.warn("Failed to readCurrentAttributes for: {}", id, e); - throw new ReadFailedException(id, e); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanCustomizer.java deleted file mode 100644 index b57274a88..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanCustomizer.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static com.google.common.base.Preconditions.checkState; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.VxlanTunnelDetails; -import org.openvpp.jvpp.dto.VxlanTunnelDetailsReplyDump; -import org.openvpp.jvpp.dto.VxlanTunnelDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class VxlanCustomizer extends FutureJVppCustomizer - implements ReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class); - private final NamingContext interfaceContext; - - public VxlanCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) { - super(jvpp); - this.interfaceContext = interfaceContext; - } - - @Override - public void merge(@Nonnull Builder parentBuilder, - @Nonnull Vxlan readValue) { - ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVxlan(readValue); - } - - @Nonnull - @Override - public VxlanBuilder getBuilder(@Nonnull InstanceIdentifier id) { - return new VxlanBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final VxlanBuilder builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - try { - final InterfaceKey key = id.firstKeyOf(Interface.class); - final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext()); - if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, VxlanTunnel.class)) { - return; - } - - LOG.debug("Reading attributes for vxlan tunnel: {}", key.getName()); - // Dump just a single - final VxlanTunnelDump request = new VxlanTunnelDump(); - request.swIfIndex = index; - - final CompletionStage swInterfaceVxlanDetailsReplyDumpCompletionStage = - getFutureJVpp().vxlanTunnelDump(request); - final VxlanTunnelDetailsReplyDump reply = - TranslateUtils.getReplyForRead(swInterfaceVxlanDetailsReplyDumpCompletionStage.toCompletableFuture(), id); - - // VPP keeps vxlan tunnel interfaces even after they were deleted (optimization) - // However there ar no longer any vxlan tunnel specific fields assigned to it and this call - // returns nothing - if (reply == null || reply.vxlanTunnelDetails == null || reply.vxlanTunnelDetails.isEmpty()) { - LOG.debug( - "Vxlan tunnel {}, id {} has no attributes assigned in VPP. Probably is a leftover interface placeholder" + - "after delete", key.getName(), index); - return; - } - - checkState(reply.vxlanTunnelDetails.size() == 1, - "Unexpected number of returned vxlan tunnels: {} for tunnel: {}", reply.vxlanTunnelDetails, key.getName()); - LOG.trace("Vxlan tunnel: {} attributes returned from VPP: {}", key.getName(), reply); - - final VxlanTunnelDetails swInterfaceVxlanDetails = reply.vxlanTunnelDetails.get(0); - if (swInterfaceVxlanDetails.isIpv6 == 1) { - final Ipv6Address dstIpv6 = - new Ipv6Address(parseAddress(swInterfaceVxlanDetails.dstAddress).getHostAddress()); - builder.setDst(new IpAddress(dstIpv6)); - final Ipv6Address srcIpv6 = - new Ipv6Address(parseAddress(swInterfaceVxlanDetails.srcAddress).getHostAddress()); - builder.setSrc(new IpAddress(srcIpv6)); - } else { - final byte[] dstBytes = Arrays.copyOfRange(swInterfaceVxlanDetails.dstAddress, 0, 4); - final Ipv4Address dstIpv4 = new Ipv4Address(parseAddress(dstBytes).getHostAddress()); - builder.setDst(new IpAddress(dstIpv4)); - final byte[] srcBytes = Arrays.copyOfRange(swInterfaceVxlanDetails.srcAddress, 0, 4); - final Ipv4Address srcIpv4 = new Ipv4Address(parseAddress(srcBytes).getHostAddress()); - builder.setSrc(new IpAddress(srcIpv4)); - } - builder.setEncapVrfId((long) swInterfaceVxlanDetails.encapVrfId); - builder.setVni( new VxlanVni((long) swInterfaceVxlanDetails.vni)); - LOG.debug("Vxlan tunnel: {}, id: {} attributes read as: {}", key.getName(), index, builder); - } catch (VppBaseCallException e) { - LOG.warn("Failed to readCurrentAttributes for: {}", id); - throw new ReadFailedException( id, e ); - } - } - - @Nonnull - private static InetAddress parseAddress(@Nonnull final byte[] addr) { - try { - return InetAddress.getByAddress(addr); - } catch (UnknownHostException e) { - throw new IllegalArgumentException("Cannot create InetAddress from " + Arrays.toString(addr), e); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanGpeCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanGpeCustomizer.java deleted file mode 100644 index 2e45a2b64..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanGpeCustomizer.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static com.google.common.base.Preconditions.checkState; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.isInterfaceOfType; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeNextProtocol; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeVni; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpeBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.VxlanGpeTunnelDetails; -import org.openvpp.jvpp.dto.VxlanGpeTunnelDetailsReplyDump; -import org.openvpp.jvpp.dto.VxlanGpeTunnelDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class VxlanGpeCustomizer extends FutureJVppCustomizer - implements ReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class); - private NamingContext interfaceContext; - - public VxlanGpeCustomizer(@Nonnull final FutureJVpp jvpp, @Nonnull final NamingContext interfaceContext) { - super(jvpp); - this.interfaceContext = interfaceContext; - } - - @Override - public void merge(@Nonnull Builder parentBuilder, - @Nonnull VxlanGpe readValue) { - ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVxlanGpe(readValue); - } - - @Nonnull - @Override - public VxlanGpeBuilder getBuilder(@Nonnull InstanceIdentifier id) { - return new VxlanGpeBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final VxlanGpeBuilder builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - try { - final InterfaceKey key = id.firstKeyOf(Interface.class); - final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext()); - if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, VxlanGpeTunnel.class)) { - return; - } - - LOG.debug("Reading attributes for VxlanGpe tunnel: {}", key.getName()); - // Dump just a single - final VxlanGpeTunnelDump request = new VxlanGpeTunnelDump(); - request.swIfIndex = index; - - final CompletionStage swInterfaceVxlanGpeDetailsReplyDumpCompletionStage = - getFutureJVpp().vxlanGpeTunnelDump(request); - final VxlanGpeTunnelDetailsReplyDump reply = - TranslateUtils.getReplyForRead(swInterfaceVxlanGpeDetailsReplyDumpCompletionStage.toCompletableFuture(), id); - - // VPP keeps VxlanGpe tunnel interfaces even after they were deleted (optimization) - // However there are no longer any VxlanGpe tunnel specific fields assigned to it and this call - // returns nothing - if (reply == null || reply.vxlanGpeTunnelDetails == null || reply.vxlanGpeTunnelDetails.isEmpty()) { - LOG.debug( - "VxlanGpe tunnel {}, id {} has no attributes assigned in VPP. Probably is a leftover interface placeholder" + - "after delete", key.getName(), index); - return; - } - - checkState(reply.vxlanGpeTunnelDetails.size() == 1, - "Unexpected number of returned VxlanGpe tunnels: {} for tunnel: {}", reply.vxlanGpeTunnelDetails, key.getName()); - LOG.trace("VxlanGpe tunnel: {} attributes returned from VPP: {}", key.getName(), reply); - - final VxlanGpeTunnelDetails swInterfaceVxlanGpeDetails = reply.vxlanGpeTunnelDetails.get(0); - if (swInterfaceVxlanGpeDetails.isIpv6 == 1) { - final Ipv6Address remote6 = - new Ipv6Address(parseAddress(swInterfaceVxlanGpeDetails.remote).getHostAddress()); - builder.setRemote(new IpAddress(remote6)); - final Ipv6Address local6 = - new Ipv6Address(parseAddress(swInterfaceVxlanGpeDetails.local).getHostAddress()); - builder.setLocal(new IpAddress(local6)); - } else { - final byte[] dstBytes = Arrays.copyOfRange(swInterfaceVxlanGpeDetails.remote, 0, 4); - final Ipv4Address remote4 = new Ipv4Address(parseAddress(dstBytes).getHostAddress()); - builder.setRemote(new IpAddress(remote4)); - final byte[] srcBytes = Arrays.copyOfRange(swInterfaceVxlanGpeDetails.local, 0, 4); - final Ipv4Address local4 = new Ipv4Address(parseAddress(srcBytes).getHostAddress()); - builder.setLocal(new IpAddress(local4)); - } - builder.setVni(new VxlanGpeVni((long) swInterfaceVxlanGpeDetails.vni)); - builder.setNextProtocol(VxlanGpeNextProtocol.forValue(swInterfaceVxlanGpeDetails.protocol)); - builder.setEncapVrfId((long) swInterfaceVxlanGpeDetails.encapVrfId); - builder.setDecapVrfId((long) swInterfaceVxlanGpeDetails.decapVrfId); - LOG.debug("VxlanGpe tunnel: {}, id: {} attributes read as: {}", key.getName(), index, builder); - } catch (VppBaseCallException e) { - LOG.warn("Failed to readCurrentAttributes for: {}", id); - throw new ReadFailedException( id, e ); - } - } - - @Nonnull - private static InetAddress parseAddress(@Nonnull final byte[] addr) { - try { - return InetAddress.getByAddress(addr); - } catch (UnknownHostException e) { - throw new IllegalArgumentException("Cannot create InetAddress from " + Arrays.toString(addr), e); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java deleted file mode 100644 index 1d90d8cec..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.v3po.interfacesstate.ip; - -import static com.google.common.base.Preconditions.checkNotNull; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.dumpAddresses; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.findIpAddressDetailsByIp; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.getAllIpv4AddressIds; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLengthBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.IpAddressDetails; -import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Read customizer for interface Ipv4 addresses. - */ -public class Ipv4AddressCustomizer extends FutureJVppCustomizer - implements ListReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class); - - private final NamingContext interfaceContext; - - public Ipv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) { - super(futureJvpp); - this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); - } - - @Override - @Nonnull - public AddressBuilder getBuilder(@Nonnull InstanceIdentifier

id) { - return new AddressBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull InstanceIdentifier
id, @Nonnull AddressBuilder builder, - @Nonnull ReadContext ctx) - throws ReadFailedException { - LOG.debug("Reading attributes for interface address: {}", id); - - final String interfaceName = id.firstKeyOf(Interface.class).getName(); - final int interfaceIndex = interfaceContext.getIndex(interfaceName, ctx.getMappingContext()); - final Optional dumpOptional = - dumpAddresses(getFutureJVpp(), id, interfaceName, interfaceIndex, ctx); - - final Optional ipAddressDetails = - findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp()); - - if (ipAddressDetails.isPresent()) { - final IpAddressDetails detail = ipAddressDetails.get(); - builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)) - .setSubnet(new PrefixLengthBuilder().setPrefixLength(Short.valueOf(detail.prefixLength)).build()); - - if (LOG.isDebugEnabled()) { - LOG.debug("Attributes for {} interface (id={}) address {} successfully read: {}", - interfaceName, interfaceIndex, id, builder.build()); - } - } - } - - @Override - public List getAllIds(@Nonnull InstanceIdentifier
id, @Nonnull ReadContext ctx) - throws ReadFailedException { - LOG.debug("Reading list of keys for interface addresses: {}", id); - - final String interfaceName = id.firstKeyOf(Interface.class).getName(); - final int interfaceIndex = interfaceContext.getIndex(interfaceName, ctx.getMappingContext()); - final Optional dumpOptional = - dumpAddresses(getFutureJVpp(), id, interfaceName, interfaceIndex, ctx); - - return getAllIpv4AddressIds(dumpOptional, AddressKey::new); - } - - @Override - public void merge(@Nonnull Builder builder, @Nonnull List
readData) { - ((Ipv4Builder) builder).setAddress(readData); - } - -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4Customizer.java deleted file mode 100644 index fa912c05e..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4Customizer.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.v3po.interfacesstate.ip; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class Ipv4Customizer extends FutureJVppCustomizer implements ReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(Ipv4Customizer.class); - - public Ipv4Customizer(@Nonnull final FutureJVpp futureJvpp) { - super(futureJvpp); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Ipv4 readValue) { - ((Interface2Builder) parentBuilder).setIpv4(readValue); - } - - @Nonnull - @Override - public Ipv4Builder getBuilder(@Nonnull final InstanceIdentifier id) { - return new Ipv4Builder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Ipv4Builder builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - //TODO add reading of isForwarding flag when there is dump for it - LOG.warn("Operation not supported"); - } - -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java deleted file mode 100644 index 103fbb012..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4NeighbourCustomizer.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.v3po.interfacesstate.ip; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import java.util.Collections; -import java.util.List; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Neighbor; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.NeighborBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.NeighborKey; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Operational data read operation customizer for {@link Neighbor}
- * Currently not supported in jvpp, so this is only dummy implementation
- */ -public class Ipv4NeighbourCustomizer extends FutureJVppCustomizer - implements ListReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(Ipv4NeighbourCustomizer.class); - - public Ipv4NeighbourCustomizer(FutureJVpp futureJvpp) { - super(futureJvpp); - } - - @Override - public NeighborBuilder getBuilder(InstanceIdentifier id) { - return new NeighborBuilder(); - } - - @Override - public void readCurrentAttributes(InstanceIdentifier id, NeighborBuilder builder, ReadContext ctx) - throws ReadFailedException { - //TODO - not supported, implement https://jira.fd.io/browse/VPP-164 first - LOG.warn("Operation not supported"); - } - - @Override - public List getAllIds(InstanceIdentifier id, ReadContext context) - throws ReadFailedException { - //TODO - not supported, implement https://jira.fd.io/browse/VPP-164 first - LOG.warn("Operation not supported,returning empty List"); - return Collections.emptyList(); - } - - @Override - public void merge(Builder builder, List readData) { - ((Ipv4Builder) builder).setNeighbor(readData); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java deleted file mode 100644 index e7dfffd01..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4ReadUtils.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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.v3po.interfacesstate.ip; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.ReadTimeoutException; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.Collections; -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.IpAddressDetails; -import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; -import org.openvpp.jvpp.dto.IpAddressDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility class providing Ipv4 read support. - */ -final class Ipv4ReadUtils { - - static final String CACHE_KEY = Ipv4ReadUtils.class.getName(); - private static final Logger LOG = LoggerFactory.getLogger(Ipv4ReadUtils.class); - - private Ipv4ReadUtils() { - throw new UnsupportedOperationException("This utility class cannot be instantiated"); - } - - // Many VPP APIs do not provide get operation for single item. Dump requests for all items are used instead. - // To improve HC performance, caching dump requests is a common pattern. - // TODO: use more generic caching implementation, once provided - static Optional dumpAddresses(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final InstanceIdentifier id, - @Nonnull final String interfaceName, - final int interfaceIndex, @Nonnull final ReadContext ctx) - throws ReadFailedException { - - final String cacheKey = CACHE_KEY + interfaceName; - Optional dumpFromCache = dumpAddressFromCache(cacheKey, ctx.getModificationCache()); - - if (dumpFromCache.isPresent()) { - return dumpFromCache; - } - - Optional dumpFromOperational; - try { - dumpFromOperational = dumpAddressFromOperationalData(futureJvpp, id, interfaceIndex); - } catch (VppBaseCallException e) { - throw new ReadFailedException(id, e); - } - - if (dumpFromOperational.isPresent()) { - ctx.getModificationCache().put(cacheKey, dumpFromOperational.get()); - } - - return dumpFromOperational; - } - - private static Optional dumpAddressFromCache(@Nonnull final String cacheKey, - @Nonnull final ModificationCache cache) { - LOG.debug("Retrieving Ipv4 addresses from cache for {}", cacheKey); - return Optional.fromNullable((IpAddressDetailsReplyDump) cache.get(cacheKey)); - } - - private static Optional dumpAddressFromOperationalData( - @Nonnull final FutureJVpp futureJvpp, @Nonnull final InstanceIdentifier id, final int interfaceIndex) - throws VppBaseCallException, ReadTimeoutException { - LOG.debug("Dumping Ipv4 addresses for interface id={}", interfaceIndex); - final IpAddressDump dumpRequest = new IpAddressDump(); - dumpRequest.isIpv6 = 0; - dumpRequest.swIfIndex = interfaceIndex; - return Optional.fromNullable( - TranslateUtils.getReplyForRead(futureJvpp.ipAddressDump(dumpRequest).toCompletableFuture(), id)); - } - - @Nonnull static List getAllIpv4AddressIds( - final Optional dumpOptional, - @Nonnull final Function keyConstructor) { - if (dumpOptional.isPresent() && dumpOptional.get().ipAddressDetails != null) { - return dumpOptional.get().ipAddressDetails.stream() - .map(detail -> keyConstructor.apply(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip))) - .collect(Collectors.toList()); - } else { - return Collections.emptyList(); - } - } - - static Optional findIpAddressDetailsByIp( - final Optional dump, - @Nonnull final Ipv4AddressNoZone ip) { - checkNotNull(ip, "ip address should not be null"); - - if (dump.isPresent() && dump.get().ipAddressDetails != null) { - final List details = dump.get().ipAddressDetails; - - return Optional.of(details.stream() - .filter(singleDetail -> ip.equals(TranslateUtils.arrayToIpv4AddressNoZone(singleDetail.ip))) - .collect(RWUtils.singleItemCollector())); - } - return Optional.absent(); - } - -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv6Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv6Customizer.java deleted file mode 100644 index ada05b72f..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv6Customizer.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.v3po.interfacesstate.ip; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6Builder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; - -public class Ipv6Customizer extends FutureJVppCustomizer implements ReaderCustomizer { - - private final NamingContext interfaceContext; - - public Ipv6Customizer(@Nonnull final FutureJVpp futureJvpp, final NamingContext interfaceContext) { - super(futureJvpp); - this.interfaceContext = interfaceContext; - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Ipv6 readValue) { - ((Interface2Builder) parentBuilder).setIpv6(readValue); - } - - @Nonnull - @Override - public Ipv6Builder getBuilder(@Nonnull final InstanceIdentifier id) { - return new Ipv6Builder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Ipv6Builder builder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - // TODO implement -// final IpAddressDump dumpRequest = new IpAddressDump(); -// dumpRequest.isIpv6 = 1; -// dumpRequest.swIfIndex = interfaceContext.getIndex(id.firstKeyOf(Interface.class).getName(), ctx.getMappingContext()); -// final CompletionStage addressDumpFuture = getFutureJVpp().ipAddressDump(dumpRequest); - // TODO consider extracting customizer for address -// final IpAddressDetailsReplyDump reply = TranslateUtils.getReply(addressDumpFuture.toCompletableFuture()); - } - -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java deleted file mode 100644 index a8a47d71a..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/SubInterfaceIpv4AddressCustomizer.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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.v3po.interfacesstate.ip; - -import static com.google.common.base.Preconditions.checkNotNull; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.dumpAddresses; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.findIpAddressDetailsByIp; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4ReadUtils.getAllIpv4AddressIds; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.SubInterfaceUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.Ipv4Builder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.Address; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.AddressKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.ip4.attributes.ipv4.address.subnet.PrefixLengthBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.IpAddressDetails; -import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Read customizer for sub-interface Ipv4 addresses. - */ -public class SubInterfaceIpv4AddressCustomizer extends FutureJVppCustomizer - implements ListReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIpv4AddressCustomizer.class); - - private final NamingContext interfaceContext; - - public SubInterfaceIpv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext interfaceContext) { - super(futureJvpp); - this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); - } - - @Override - @Nonnull - public AddressBuilder getBuilder(@Nonnull InstanceIdentifier
id) { - return new AddressBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull InstanceIdentifier
id, @Nonnull AddressBuilder builder, - @Nonnull ReadContext ctx) - throws ReadFailedException { - LOG.debug("Reading attributes for sub-interface address: {}", id); - - final String subInterfaceName = getSubInterfaceName(id); - final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()); - final Optional dumpOptional = - dumpAddresses(getFutureJVpp(), id, subInterfaceName, subInterfaceIndex, ctx); - - final Optional ipAddressDetails = - findIpAddressDetailsByIp(dumpOptional, id.firstKeyOf(Address.class).getIp()); - - if (ipAddressDetails.isPresent()) { - final IpAddressDetails detail = ipAddressDetails.get(); - builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)) - .setSubnet(new PrefixLengthBuilder().setPrefixLength(Short.valueOf(detail.prefixLength)).build()); - - if (LOG.isDebugEnabled()) { - LOG.debug("Attributes for {} sub-interface (id={}) address {} successfully read: {}", - subInterfaceName, subInterfaceIndex, id, builder.build()); - } - } - } - - @Override - public List getAllIds(@Nonnull InstanceIdentifier
id, @Nonnull ReadContext ctx) - throws ReadFailedException { - LOG.debug("Reading list of keys for sub-interface addresses: {}", id); - - final String subInterfaceName = getSubInterfaceName(id); - final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, ctx.getMappingContext()); - final Optional dumpOptional = - dumpAddresses(getFutureJVpp(), id, subInterfaceName, subInterfaceIndex, ctx); - - return getAllIpv4AddressIds(dumpOptional, AddressKey::new); - } - - @Override - public void merge(@Nonnull Builder builder, @Nonnull List
readData) { - ((Ipv4Builder) builder).setAddress(readData); - } - - private static String getSubInterfaceName(@Nonnull final InstanceIdentifier
id) { - return SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(), - Math.toIntExact(id.firstKeyOf(SubInterface.class).getIdentifier())); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/notification/InterfaceChangeNotificationProducer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/notification/InterfaceChangeNotificationProducer.java deleted file mode 100644 index 002d58bdb..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/notification/InterfaceChangeNotificationProducer.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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.v3po.notification; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.notification.ManagedNotificationProducer; -import io.fd.honeycomb.v3po.notification.NotificationCollector; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.TimeoutException; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.annotation.concurrent.NotThreadSafe; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceDeleted; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceDeletedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceNameOrIndex; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStateChange; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStateChangeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStatus; -import org.opendaylight.yangtools.yang.binding.Notification; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceSetFlagsNotification; -import org.openvpp.jvpp.dto.WantInterfaceEvents; -import org.openvpp.jvpp.dto.WantInterfaceEventsReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Notification producer for interface events. It starts interface notification stream and for every - * received notification, it transforms it into its BA equivalent and pushes into HC's notification collector. - */ -@NotThreadSafe -public final class InterfaceChangeNotificationProducer implements ManagedNotificationProducer { - - private static final Logger LOG = LoggerFactory.getLogger(InterfaceChangeNotificationProducer.class); - - private final FutureJVpp jvpp; - private final NamingContext interfaceContext; - private final MappingContext mappingContext; - @Nullable - private AutoCloseable notificationListenerReg; - - public InterfaceChangeNotificationProducer(@Nonnull final FutureJVpp jvpp, - @Nonnull final NamingContext interfaceContext, - @Nonnull final MappingContext mappingContext) { - this.jvpp = jvpp; - this.interfaceContext = interfaceContext; - this.mappingContext = mappingContext; - } - - @Override - public void start(final NotificationCollector collector) { - LOG.trace("Starting interface notifications"); - enableDisableIfcNotifications(1); - LOG.debug("Interface notifications started successfully"); - notificationListenerReg = jvpp.getNotificationRegistry().registerSwInterfaceSetFlagsNotificationCallback( - swInterfaceSetFlagsNotification -> { - LOG.trace("Interface notification received: {}", swInterfaceSetFlagsNotification); - // TODO this should be lazy - collector.onNotification(transformNotification(swInterfaceSetFlagsNotification)); - } - ); - } - - private Notification transformNotification(final SwInterfaceSetFlagsNotification swInterfaceSetFlagsNotification) { - if (swInterfaceSetFlagsNotification.deleted == 1) { - return new InterfaceDeletedBuilder().setName(getIfcName(swInterfaceSetFlagsNotification)).build(); - } else { - return new InterfaceStateChangeBuilder() - .setName(getIfcName(swInterfaceSetFlagsNotification)) - .setAdminStatus(swInterfaceSetFlagsNotification.adminUpDown == 1 ? InterfaceStatus.Up : InterfaceStatus.Down) - .setOperStatus(swInterfaceSetFlagsNotification.linkUpDown == 1 ? InterfaceStatus.Up : InterfaceStatus.Down) - .build(); - } - } - - /** - * Get mapped name for the interface. Best effort only! The mapping might not yet be stored in context - * data tree (write transaction is still in progress and context changes have not been committed yet, or - * VPP sends the notification before it returns create request(that would store mapping)). - *

- * In case mapping is not available, index is used as name. TODO inconsistent behavior, maybe just use indices ? - */ - private InterfaceNameOrIndex getIfcName(final SwInterfaceSetFlagsNotification swInterfaceSetFlagsNotification) { - final Optional optionalName = - interfaceContext.getNameIfPresent(swInterfaceSetFlagsNotification.swIfIndex, mappingContext); - return optionalName.isPresent() - ? new InterfaceNameOrIndex(optionalName.get()) - : new InterfaceNameOrIndex((long) swInterfaceSetFlagsNotification.swIfIndex); - } - - @Override - public void stop() { - LOG.trace("Stopping interface notifications"); - enableDisableIfcNotifications(0); - LOG.debug("Interface notifications stopped successfully"); - try { - if (notificationListenerReg != null) { - notificationListenerReg.close(); - } - } catch (Exception e) { - LOG.warn("Unable to properly close notification registration: {}", notificationListenerReg, e); - } - } - - private void enableDisableIfcNotifications(int enableDisable) { - final WantInterfaceEvents wantInterfaceEvents = new WantInterfaceEvents(); - wantInterfaceEvents.pid = 1; - wantInterfaceEvents.enableDisable = enableDisable; - final CompletionStage wantInterfaceEventsReplyCompletionStage; - try { - wantInterfaceEventsReplyCompletionStage = jvpp.wantInterfaceEvents(wantInterfaceEvents); - TranslateUtils.getReply(wantInterfaceEventsReplyCompletionStage.toCompletableFuture()); - } catch (VppBaseCallException | TimeoutException e) { - LOG.warn("Unable to {} interface notifications", enableDisable == 1 ? "enable" : "disable", e); - throw new IllegalStateException("Unable to control interface notifications", e); - } - } - - @Nonnull - @Override - public Collection> getNotificationTypes() { - final ArrayList> classes = Lists.newArrayList(); - classes.add(InterfaceStateChange.class); - classes.add(InterfaceDeleted.class); - return classes; - } - - @Override - public void close() throws Exception { - LOG.trace("Closing interface notifications producer"); - stop(); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainCustomizer.java deleted file mode 100644 index 601a79eba..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainCustomizer.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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.v3po.vpp; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.booleanToByte; - -import com.google.common.base.Preconditions; -import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.BridgeDomainAddDel; -import org.openvpp.jvpp.dto.BridgeDomainAddDelReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class BridgeDomainCustomizer - extends FutureJVppCustomizer - implements ListWriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class); - - private static final byte ADD_OR_UPDATE_BD = (byte) 1; - private final NamingContext bdContext; - - public BridgeDomainCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext bdContext) { - super(futureJvpp); - this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null"); - } - - private BridgeDomainAddDelReply addOrUpdateBridgeDomain(@Nonnull final InstanceIdentifier id, - final int bdId, @Nonnull final BridgeDomain bd) - throws VppBaseCallException, WriteTimeoutException { - final BridgeDomainAddDelReply reply; - final BridgeDomainAddDel request = new BridgeDomainAddDel(); - request.bdId = bdId; - request.flood = booleanToByte(bd.isFlood()); - request.forward = booleanToByte(bd.isForward()); - request.learn = booleanToByte(bd.isLearn()); - request.uuFlood = booleanToByte(bd.isUnknownUnicastFlood()); - request.arpTerm = booleanToByte(bd.isArpTermination()); - request.isAdd = ADD_OR_UPDATE_BD; - - reply = TranslateUtils.getReplyForWrite(getFutureJVpp().bridgeDomainAddDel(request).toCompletableFuture(), id); - LOG.debug("Bridge domain {} (id={}) add/update successful", bd.getName(), bdId); - return reply; - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final BridgeDomain dataBefore, - @Nonnull final WriteContext ctx) - throws WriteFailedException { - LOG.debug("writeCurrentAttributes: id={}, current={}, ctx={}", id, dataBefore, ctx); - final String bdName = dataBefore.getName(); - - try { - int index; - if (bdContext.containsIndex(bdName, ctx.getMappingContext())) { - index = bdContext.getIndex(bdName, ctx.getMappingContext()); - } else { - // FIXME we need the bd index to be returned by VPP or we should have a counter field - // (maybe in context similar to artificial name) - // Here we assign the next available ID from bdContext's perspective - index = 1; - while (bdContext.containsName(index, ctx.getMappingContext())) { - index++; - } - } - addOrUpdateBridgeDomain(id, index, dataBefore); - bdContext.addName(index, bdName, ctx.getMappingContext()); - } catch (VppBaseCallException e) { - LOG.warn("Failed to create bridge domain", e); - throw new WriteFailedException.CreateFailedException(id, dataBefore, e); - } - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final BridgeDomain dataBefore, - @Nonnull final WriteContext ctx) - throws WriteFailedException { - LOG.debug("deleteCurrentAttributes: id={}, dataBefore={}, ctx={}", id, dataBefore, ctx); - final String bdName = id.firstKeyOf(BridgeDomain.class).getName(); - int bdId = bdContext.getIndex(bdName, ctx.getMappingContext()); - try { - - final BridgeDomainAddDel request = new BridgeDomainAddDel(); - request.bdId = bdId; - - TranslateUtils.getReplyForWrite(getFutureJVpp().bridgeDomainAddDel(request).toCompletableFuture(), id); - LOG.debug("Bridge domain {} (id={}) deleted successfully", bdName, bdId); - } catch (VppBaseCallException e) { - LOG.warn("Bridge domain {} (id={}) delete failed", bdName, bdId); - throw new WriteFailedException.DeleteFailedException(id, e); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final BridgeDomain dataBefore, @Nonnull final BridgeDomain dataAfter, - @Nonnull final WriteContext ctx) - throws WriteFailedException { - LOG.debug("updateCurrentAttributes: id={}, dataBefore={}, dataAfter={}, ctx={}", id, dataBefore, dataAfter, - ctx); - - final String bdName = checkNotNull(dataAfter.getName()); - checkArgument(bdName.equals(dataBefore.getName()), - "BridgeDomain name changed. It should be deleted and then created."); - - try { - addOrUpdateBridgeDomain(id, bdContext.getIndex(bdName, ctx.getMappingContext()), dataAfter); - } catch (VppBaseCallException e) { - LOG.warn("Failed to create bridge domain", e); - throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e); - } - } - -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vpp/L2FibEntryCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vpp/L2FibEntryCustomizer.java deleted file mode 100644 index 52bb1ad61..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vpp/L2FibEntryCustomizer.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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.v3po.vpp; - -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.booleanToByte; -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.parseMac; - -import com.google.common.base.Preconditions; -import com.google.common.primitives.Longs; -import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.apache.commons.lang3.builder.ReflectionToStringBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibFilter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.L2FibAddDel; -import org.openvpp.jvpp.dto.L2FibAddDelReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Writer Customizer responsible for L2 FIB create/delete operations.
Sends {@code l2_fib_add_del} message to - * VPP.
Equivalent of invoking {@code vppctl l2fib add/del} command. - */ -public class L2FibEntryCustomizer extends FutureJVppCustomizer - implements ListWriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(L2FibEntryCustomizer.class); - - private final NamingContext bdContext; - private final NamingContext interfaceContext; - - public L2FibEntryCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext bdContext, - @Nonnull final NamingContext interfaceContext) { - super(futureJvpp); - this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null"); - this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final L2FibEntry dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - try { - LOG.debug("Creating L2 FIB entry: {} {}", id, dataAfter); - l2FibAddDel(id, dataAfter, writeContext, true); - LOG.debug("L2 FIB entry created successfully: {} {}", id, dataAfter); - } catch (VppBaseCallException e) { - LOG.warn("Failed to create L2 FIB entry: {} {}", id, dataAfter); - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final L2FibEntry dataBefore, @Nonnull final L2FibEntry dataAfter, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - throw new UnsupportedOperationException( - "L2 FIB entry update is not supported. It has to be deleted and then created."); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final L2FibEntry dataBefore, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - try { - LOG.debug("Deleting L2 FIB entry: {} {}", id, dataBefore); - l2FibAddDel(id, dataBefore, writeContext, false); - LOG.debug("L2 FIB entry deleted successfully: {} {}", id, dataBefore); - } catch (VppBaseCallException e) { - LOG.warn("Failed to delete L2 FIB entry: {} {}", id, dataBefore); - throw new WriteFailedException.DeleteFailedException(id, e); - } - } - - private void l2FibAddDel(@Nonnull final InstanceIdentifier id, @Nonnull final L2FibEntry entry, - final WriteContext writeContext, boolean isAdd) - throws VppBaseCallException, WriteTimeoutException { - final String bdName = id.firstKeyOf(BridgeDomain.class).getName(); - final int bdId = bdContext.getIndex(bdName, writeContext.getMappingContext()); - - int swIfIndex = -1; - final String swIfName = entry.getOutgoingInterface(); - if (swIfName != null) { - swIfIndex = interfaceContext.getIndex(swIfName, writeContext.getMappingContext()); - } - - final L2FibAddDel l2FibRequest = createL2FibRequest(entry, bdId, swIfIndex, isAdd); - LOG.debug("Sending l2FibAddDel request: {}", ReflectionToStringBuilder.toString(l2FibRequest)); - final CompletionStage l2FibAddDelReplyCompletionStage = - getFutureJVpp().l2FibAddDel(l2FibRequest); - - TranslateUtils.getReplyForWrite(l2FibAddDelReplyCompletionStage.toCompletableFuture(), id); - } - - private L2FibAddDel createL2FibRequest(final L2FibEntry entry, final int bdId, final int swIfIndex, boolean isAdd) { - final L2FibAddDel request = new L2FibAddDel(); - request.mac = macToLong(entry.getPhysAddress().getValue()); - request.bdId = bdId; - request.swIfIndex = swIfIndex; - request.isAdd = booleanToByte(isAdd); - if (isAdd) { - request.staticMac = booleanToByte(entry.isStaticConfig()); - request.filterMac = booleanToByte(L2FibFilter.class == entry.getAction()); - } - return request; - } - - // mac address is string of the form: 11:22:33:44:55:66 - // but VPP expects long value in the format 11:22:33:44:55:66:XX:XX - private static long macToLong(final String macAddress) { - final byte[] mac = parseMac(macAddress); - return Longs.fromBytes(mac[0], mac[1], mac[2], mac[3], - mac[4], mac[5], (byte) 0, (byte) 0); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReader.java deleted file mode 100644 index 9bc2e9674..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReader.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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.v3po.vppclassifier; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary; - -import com.google.common.base.Optional; -import com.google.common.primitives.UnsignedInts; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.xml.bind.DatatypeConverter; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.ClassifySessionDetails; -import org.openvpp.jvpp.dto.ClassifySessionDetailsReplyDump; -import org.openvpp.jvpp.dto.ClassifySessionDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Reader customizer responsible for classify session read.
to VPP.
Equivalent to invoking {@code vppctl show - * class table verbose} command. - */ -public class ClassifySessionReader extends FutureJVppCustomizer - implements ListReaderCustomizer, VppNodeReader { - - private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionReader.class); - static final String CACHE_KEY = ClassifySessionReader.class.getName(); - - private final NamingContext classifyTableContext; - - public ClassifySessionReader(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext classifyTableContext) { - super(futureJvpp); - this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); - } - - @Override - public void merge(@Nonnull final Builder builder, - @Nonnull final List readData) { - ((ClassifyTableBuilder) builder).setClassifySession(readData); - } - - @Nonnull - @Override - public ClassifySessionBuilder getBuilder(@Nonnull final InstanceIdentifier id) { - return new ClassifySessionBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final ClassifySessionBuilder builder, @Nonnull final ReadContext ctx) - throws ReadFailedException { - LOG.debug("Reading attributes for classify session: {}", id); - - final ClassifySessionKey key = id.firstKeyOf(ClassifySession.class); - checkArgument(key != null, "could not find ClassifySession key in {}", id); - - final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx); - final byte[] match = DatatypeConverter.parseHexBinary(key.getMatch().getValue().replace(":", "")); - final Optional classifySession = - findClassifySessionDetailsByMatch(classifySessionDump, match); - - if (classifySession.isPresent()) { - final ClassifySessionDetails detail = classifySession.get(); - builder.setHitNext(readVppNode(detail.hitNextIndex, LOG)); - if (detail.opaqueIndex != ~0) { - // value is specified: - builder.setOpaqueIndex(readOpaqueIndex(detail.opaqueIndex)); - } - builder.setAdvance(detail.advance); - builder.setMatch(key.getMatch()); - - if (LOG.isTraceEnabled()) { - LOG.trace("Attributes for classify session {} successfully read: {}", id, builder.build()); - } - } - } - - private OpaqueIndex readOpaqueIndex(final int opaqueIndex) { - // We first try to map the value to a vpp node, if that fails, simply wrap the u32 value - // FIXME: the approach might fail if the opaqueIndex contains small value that collides - // with some of the adjacent nodes - final VppNode node = readVppNode(opaqueIndex, LOG); - if (node != null) { - return new OpaqueIndex(node); - } else { - return new OpaqueIndex(UnsignedInts.toLong(opaqueIndex)); - } - } - - @Nullable - private ClassifySessionDetailsReplyDump dumpClassifySessions(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class); - checkArgument(tableKey != null, "could not find ClassifyTable key in {}", id); - - final String cacheKey = CACHE_KEY + tableKey; - - ClassifySessionDetailsReplyDump classifySessionDump = - (ClassifySessionDetailsReplyDump) ctx.getModificationCache().get(cacheKey); - if (classifySessionDump != null) { - LOG.debug("Classify sessions is present in cache: {}", cacheKey); - return classifySessionDump; - } - - final String tableName = tableKey.getName(); - checkState(classifyTableContext.containsIndex(tableName, ctx.getMappingContext()), - "Reading classify sessions for table {}, but table index could not be found in the classify table context", - tableName); - final int tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext()); - LOG.debug("Dumping classify sessions for classify table id={}", tableId); - - try { - final ClassifySessionDump dumpRequest = new ClassifySessionDump(); - dumpRequest.tableId = tableId; - classifySessionDump = TranslateUtils - .getReplyForRead(getFutureJVpp().classifySessionDump(dumpRequest).toCompletableFuture(), id); - - // update the cache: - ctx.getModificationCache().put(cacheKey, classifySessionDump); - return classifySessionDump; - } catch (VppBaseCallException e) { - throw new ReadFailedException(id, e); - } - } - - private static Optional findClassifySessionDetailsByMatch( - @Nullable final ClassifySessionDetailsReplyDump classifySessionDump, @Nonnull final byte[] match) { - if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) { - final List details = classifySessionDump.classifySessionDetails; - final List filteredSessions = details.stream() - .filter(singleDetail -> Arrays.equals(singleDetail.match, match)).collect(Collectors.toList()); - if (filteredSessions.isEmpty()) { - return Optional.absent(); - } else if (filteredSessions.size() == 1) { - return Optional.of(filteredSessions.get(0)); - } else { - throw new IllegalStateException(String.format( - "Found %d classify sessions witch given match. Single session expected.", - filteredSessions.size())); - } - } - return Optional.absent(); - } - - @Nonnull - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - LOG.debug("Reading list of keys for classify sessions: {}", id); - - final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx); - if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) { - return classifySessionDump.classifySessionDetails.stream() - .map(detail -> new ClassifySessionKey(new HexString(printHexBinary(detail.match)))) - .collect(Collectors.toList()); - } else { - return Collections.emptyList(); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriter.java deleted file mode 100644 index ea183a839..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriter.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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.v3po.vppclassifier; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.booleanToByte; - -import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import javax.xml.bind.DatatypeConverter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.ClassifyAddDelSession; -import org.openvpp.jvpp.dto.ClassifyAddDelSessionReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Writer customizer responsible for classify session create/delete.
Sends {@code classify_add_del_session} message - * to VPP.
Equivalent to invoking {@code vppctl classify table} command. - */ -public class ClassifySessionWriter extends FutureJVppCustomizer - implements ListWriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionWriter.class); - private final NamingContext classifyTableContext; - - public ClassifySessionWriter(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext classifyTableContext) { - super(futureJvpp); - this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final ClassifySession dataAfter, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - LOG.debug("Creating classify session: iid={} dataAfter={}", id, dataAfter); - try { - classifyAddDelSession(true, id, dataAfter, writeContext); - LOG.debug("Successfully created classify session: iid={} dataAfter={}", id, dataAfter); - } catch (VppBaseCallException e) { - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final ClassifySession dataBefore, - @Nonnull final ClassifySession dataAfter, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - throw new UnsupportedOperationException("Classify session update is not supported"); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final ClassifySession dataBefore, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - LOG.debug("Removing classify session: iid={} dataBefore={}", id, dataBefore); - try { - classifyAddDelSession(false, id, dataBefore, writeContext); - LOG.debug("Successfully removed classify session: iid={} dataBefore={}", id, dataBefore); - } catch (VppBaseCallException e) { - throw new WriteFailedException.DeleteFailedException(id, e); - } - } - - private void classifyAddDelSession(final boolean isAdd, @Nonnull final InstanceIdentifier id, - @Nonnull final ClassifySession classifySession, - @Nonnull final WriteContext writeContext) - throws VppBaseCallException, WriteTimeoutException { - final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class); - checkArgument(tableKey != null, "could not find classify table key in {}", id); - - final String tableName = tableKey.getName(); - checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()), - "Could not find classify table index for {} in the classify table context", tableName); - final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext()); - - final CompletionStage createClassifyTableReplyCompletionStage = getFutureJVpp() - .classifyAddDelSession( - getClassifyAddDelSessionRequest(isAdd, tableIndex, classifySession)); - - TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id); - } - - private static ClassifyAddDelSession getClassifyAddDelSessionRequest(final boolean isAdd, final int tableIndex, - @Nonnull final ClassifySession classifySession) { - ClassifyAddDelSession request = new ClassifyAddDelSession(); - request.isAdd = booleanToByte(isAdd); - request.tableIndex = tableIndex; - - // mandatory: - // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed - request.hitNextIndex = classifySession.getHitNext().getPacketHandlingAction().getIntValue(); - - if (classifySession.getOpaqueIndex() != null) { - request.opaqueIndex = getOpaqueIndexValue(classifySession.getOpaqueIndex()); - } else { - request.opaqueIndex = ~0; // value not specified - } - - // default 0: - request.advance = classifySession.getAdvance(); - - request.match = DatatypeConverter.parseHexBinary(classifySession.getMatch().getValue().replace(":", "")); - return request; - } - - private static int getOpaqueIndexValue(@Nonnull final OpaqueIndex opaqueIndex) { - if (opaqueIndex.getUint32() != null) { - return opaqueIndex.getUint32().intValue(); - } else { - // TODO: implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed - return opaqueIndex.getVppNode().getPacketHandlingAction().getIntValue(); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReader.java deleted file mode 100644 index c8a39dd24..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReader.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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.v3po.vppclassifier; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary; - -import com.google.common.primitives.UnsignedInts; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierStateBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.ClassifyTableIds; -import org.openvpp.jvpp.dto.ClassifyTableIdsReply; -import org.openvpp.jvpp.dto.ClassifyTableInfo; -import org.openvpp.jvpp.dto.ClassifyTableInfoReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Reader customizer responsible for classify table read.
to VPP.
Equivalent to invoking {@code vppctl show - * class table} command. - */ -public class ClassifyTableReader extends FutureJVppCustomizer - implements ListReaderCustomizer, VppNodeReader { - - private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableReader.class); - private final NamingContext classifyTableContext; - - public ClassifyTableReader(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext classifyTableContext) { - super(futureJvpp); - this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); - } - - - @Override - public void merge(@Nonnull final Builder builder, - @Nonnull final List readData) { - ((VppClassifierStateBuilder) builder).setClassifyTable(readData); - } - - @Nonnull - @Override - public ClassifyTableBuilder getBuilder(@Nonnull final InstanceIdentifier id) { - return new ClassifyTableBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final ClassifyTableBuilder builder, @Nonnull final ReadContext ctx) - throws ReadFailedException { - LOG.debug("Reading attributes for classify table: {}", id); - - final ClassifyTableKey key = id.firstKeyOf(ClassifyTable.class); - checkArgument(key != null, "could not find ClassifyTable key in {}", id); - final ClassifyTableInfo request = new ClassifyTableInfo(); - - final String tableName = key.getName(); - if (!classifyTableContext.containsIndex(tableName, ctx.getMappingContext())) { - LOG.debug("Could not find classify table {} in the naming context", tableName); - return; - } - request.tableId = classifyTableContext.getIndex(tableName, ctx.getMappingContext()); - - try { - final ClassifyTableInfoReply reply = - TranslateUtils.getReplyForRead(getFutureJVpp().classifyTableInfo(request).toCompletableFuture(), id); - - // mandatory values: - builder.setName(tableName); - builder.setKey(key); - builder.setNbuckets(UnsignedInts.toLong(reply.nbuckets)); - builder.setSkipNVectors(UnsignedInts.toLong(reply.skipNVectors)); - - - builder.setMissNext(readVppNode(reply.missNextIndex, LOG)); - builder.setMask(new HexString(printHexBinary(reply.mask))); - builder.setActiveSessions(UnsignedInts.toLong(reply.activeSessions)); - - if (reply.nextTableIndex != ~0) { - // next table index is present: - builder.setNextTable(classifyTableContext.getName(reply.nextTableIndex, ctx.getMappingContext())); - } - - if (LOG.isTraceEnabled()) { - LOG.trace("Attributes for classify table {} successfully read: {}", id, builder.build()); - } - } catch (VppBaseCallException e) { - throw new ReadFailedException(id, e); - } - } - - @Nonnull - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext context) throws ReadFailedException { - LOG.debug("Reading list of keys for classify tables: {}", id); - try { - final ClassifyTableIdsReply classifyTableIdsReply = TranslateUtils - .getReplyForRead(getFutureJVpp().classifyTableIds(new ClassifyTableIds()).toCompletableFuture(), id); - if (classifyTableIdsReply.ids != null) { - return Arrays.stream(classifyTableIdsReply.ids).mapToObj(i -> { - final String tableName = classifyTableContext.getName(i, context.getMappingContext()); - LOG.trace("Classify table with name: {} and index: {} found in VPP", tableName, i); - return new ClassifyTableKey(tableName); - }).collect(Collectors.toList()); - } else { - return Collections.emptyList(); - } - } catch (VppBaseCallException e) { - throw new ReadFailedException(id, e); - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriter.java deleted file mode 100644 index c34468458..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriter.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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.v3po.vppclassifier; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.booleanToByte; - -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import javax.xml.bind.DatatypeConverter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.ClassifyAddDelTable; -import org.openvpp.jvpp.dto.ClassifyAddDelTableReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Writer customizer responsible for classify table create/delete.
Sends {@code classify_add_del_table} message to - * VPP.
Equivalent to invoking {@code vppctl classify table} command. - */ -public class ClassifyTableWriter extends FutureJVppCustomizer - implements ListWriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableWriter.class); - private final NamingContext classifyTableContext; - - public ClassifyTableWriter(@Nonnull final FutureJVpp futureJvpp, - @Nonnull final NamingContext classifyTableContext) { - super(futureJvpp); - this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null"); - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final ClassifyTable dataAfter, @Nonnull final WriteContext writeContext) - throws WriteFailedException { - LOG.debug("Creating classify table: iid={} dataAfter={}", id, dataAfter); - try { - final int newTableIndex = - classifyAddDelTable(true, id, dataAfter, ~0 /* value not present */, writeContext.getMappingContext()); - - // Add classify table name <-> vpp index mapping to the naming context: - classifyTableContext.addName(newTableIndex, dataAfter.getName(), writeContext.getMappingContext()); - LOG.debug("Successfully created classify table(id={]): iid={} dataAfter={}", newTableIndex, id, dataAfter); - } catch (VppBaseCallException e) { - throw new WriteFailedException.CreateFailedException(id, dataAfter, e); - } - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final ClassifyTable dataBefore, @Nonnull final ClassifyTable dataAfter, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - throw new UnsupportedOperationException("Classify table update is not supported"); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final ClassifyTable dataBefore, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - LOG.debug("Removing classify table: iid={} dataBefore={}", id, dataBefore); - final String tableName = dataBefore.getName(); - checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()), - "Removing classify table {}, but index could not be found in the classify table context", tableName); - - final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext()); - try { - classifyAddDelTable(false, id, dataBefore, tableIndex, writeContext.getMappingContext()); - - // Remove deleted interface from interface context: - classifyTableContext.removeName(dataBefore.getName(), writeContext.getMappingContext()); - LOG.debug("Successfully removed classify table(id={]): iid={} dataAfter={}", tableIndex, id, dataBefore); - } catch (VppBaseCallException e) { - throw new WriteFailedException.DeleteFailedException(id, e); - } - } - - private int classifyAddDelTable(final boolean isAdd, @Nonnull final InstanceIdentifier id, - @Nonnull final ClassifyTable table, final int tableId, final MappingContext ctx) - throws VppBaseCallException, WriteTimeoutException { - final CompletionStage createClassifyTableReplyCompletionStage = - getFutureJVpp().classifyAddDelTable(getClassifyAddDelTableRequest(isAdd, tableId, table, ctx)); - - final ClassifyAddDelTableReply reply = - TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id); - return reply.newTableIndex; - - } - - private ClassifyAddDelTable getClassifyAddDelTableRequest(final boolean isAdd, final int tableIndex, - @Nonnull final ClassifyTable table, - @Nonnull final MappingContext ctx) { - final ClassifyAddDelTable request = new ClassifyAddDelTable(); - request.isAdd = booleanToByte(isAdd); - request.tableIndex = tableIndex; - - // mandatory, all u32 values are permitted: - request.nbuckets = table.getNbuckets().intValue(); - request.memorySize = table.getMemorySize().intValue(); - request.skipNVectors = table.getSkipNVectors().intValue(); - - // mandatory - // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed - request.missNextIndex = table.getMissNext().getPacketHandlingAction().getIntValue(); - - final String nextTable = table.getNextTable(); - if (isAdd && nextTable != null) { - request.nextTableIndex = classifyTableContext.getIndex(nextTable, ctx); - } else { - request.nextTableIndex = ~0; // value not specified - } - request.mask = DatatypeConverter.parseHexBinary(table.getMask().getValue().replace(":", "")); - checkArgument(request.mask.length % 16 == 0, "Number of mask bytes must be multiple of 16."); - request.matchNVectors = request.mask.length / 16; - - return request; - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/VppNodeReader.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/VppNodeReader.java deleted file mode 100644 index aa8b4f9f3..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/VppNodeReader.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.v3po.vppclassifier; - -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; -import org.slf4j.Logger; - -interface VppNodeReader { - - /** - * Converts vpp node index to YANG representation of vpp node. - * - * @param nodeIndex index of vpp node treated as signed integer. - * @return vpp node representation - */ - default VppNode readVppNode(final int nodeIndex, @Nonnull final Logger log) { - final PacketHandlingAction action = PacketHandlingAction.forValue(nodeIndex); - if (action == null) { - // TODO: implement node index to name conversion after https://jira.fd.io/browse/VPP-203 is fixed - log.debug("VPP node index {} cannot be mapped to PacketHandlingAction", nodeIndex); - return null; - } - return new VppNode(action); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizer.java deleted file mode 100644 index 1ef6fcec3..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizer.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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.v3po.vppstate; - -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.byteToBoolean; - -import com.google.common.base.Preconditions; -import com.google.common.collect.Iterables; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.BridgeDomainDetails; -import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump; -import org.openvpp.jvpp.dto.BridgeDomainDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class BridgeDomainCustomizer extends FutureJVppCustomizer - implements ListReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class); - private final NamingContext bdContext; - - public BridgeDomainCustomizer(@Nonnull final FutureJVpp futureJVpp, @Nonnull final NamingContext bdContext) { - super(futureJVpp); - this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null"); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final BridgeDomainBuilder builder, @Nonnull final ReadContext context) - throws ReadFailedException { - LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: id={}, builderbuilder={}, context={}", - id, builder, context); - - final BridgeDomainKey key = id.firstKeyOf(id.getTargetType()); - LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: key={}", key); - - final int bdId = bdContext.getIndex(key.getName(), context.getMappingContext()); - LOG.debug("vppstate.BridgeDomainCustomizer.readCurrentAttributes: bdId={}", bdId); - - BridgeDomainDetailsReplyDump reply; - BridgeDomainDetails bridgeDomainDetails; - final BridgeDomainDump request = new BridgeDomainDump(); - request.bdId = bdContext.getIndex(key.getName(), context.getMappingContext()); - try { - reply = getFutureJVpp().bridgeDomainDump(request).toCompletableFuture().get(); - bridgeDomainDetails = Iterables.getOnlyElement(reply.bridgeDomainDetails); - } catch (Exception e) { - LOG.debug("Unable to read bridge domain: {}", key.getName(), e); - return; - } - - logBridgeDomainDetails(bridgeDomainDetails); - - builder.setName(key.getName()); - builder.setArpTermination(byteToBoolean(bridgeDomainDetails.arpTerm)); - builder.setFlood(byteToBoolean(bridgeDomainDetails.flood)); - builder.setForward(byteToBoolean(bridgeDomainDetails.forward)); - builder.setLearn(byteToBoolean(bridgeDomainDetails.learn)); - builder.setUnknownUnicastFlood(byteToBoolean(bridgeDomainDetails.uuFlood)); - } - - private void logBridgeDomainDetails(final BridgeDomainDetails bridgeDomainDetails) { - LOG.debug("bridgeDomainDetails={}", bridgeDomainDetails); - if (bridgeDomainDetails != null) { - LOG.debug("bridgeDomainDetails.arpTerm={}", bridgeDomainDetails.arpTerm); - LOG.debug("bridgeDomainDetails.bdId={}", bridgeDomainDetails.bdId); - LOG.debug("bridgeDomainDetails.bviSwIfIndex={}", bridgeDomainDetails.bviSwIfIndex); - LOG.debug("bridgeDomainDetails.flood={}", bridgeDomainDetails.flood); - LOG.debug("bridgeDomainDetails.forward={}", bridgeDomainDetails.forward); - LOG.debug("bridgeDomainDetails.learn={}", bridgeDomainDetails.learn); - LOG.debug("bridgeDomainDetails.nSwIfs={}", bridgeDomainDetails.nSwIfs); - LOG.debug("bridgeDomainDetails.uuFlood={}", bridgeDomainDetails.uuFlood); - } - } - - @Nonnull - @Override - public BridgeDomainBuilder getBuilder(@Nonnull final InstanceIdentifier id) { - return new BridgeDomainBuilder(); - } - - @Nonnull - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext context) { - final BridgeDomainDump request = new BridgeDomainDump(); - request.bdId = -1; // dump call - - BridgeDomainDetailsReplyDump reply; - try { - reply = getFutureJVpp().bridgeDomainDump(request).toCompletableFuture().get(); - } catch (Exception e) { - throw new IllegalStateException("Bridge domain dump failed", e); // TODO ReadFailedException? - } - - if (reply == null || reply.bridgeDomainDetails == null) { - return Collections.emptyList(); - } - - final int bIdsLength = reply.bridgeDomainDetails.size(); - LOG.debug("vppstate.BridgeDomainCustomizer.getAllIds: bIds.length={}", bIdsLength); - if (bIdsLength == 0) { - // No bridge domains - return Collections.emptyList(); - } - - final List allIds = new ArrayList<>(bIdsLength); - for (BridgeDomainDetails detail : reply.bridgeDomainDetails) { - logBridgeDomainDetails(detail); - - final String bName = bdContext.getName(detail.bdId, context.getMappingContext()); - LOG.debug("vppstate.BridgeDomainCustomizer.getAllIds: bName={}", bName); - allIds.add(new BridgeDomainKey(bName)); - } - - return allIds; - } - - @Override - public void merge(@Nonnull final Builder builder, - @Nonnull final List readData) { - ((BridgeDomainsBuilder) builder).setBridgeDomain(readData); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/L2FibEntryCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/L2FibEntryCustomizer.java deleted file mode 100644 index dcd9c7341..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/L2FibEntryCustomizer.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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.v3po.vppstate; - -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.vppPhysAddrToYang; -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.byteToBoolean; - -import com.google.common.base.Preconditions; -import com.google.common.primitives.Longs; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.ReadTimeoutException; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collector; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibFilter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibForward; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTableBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.L2FibTableDump; -import org.openvpp.jvpp.dto.L2FibTableEntry; -import org.openvpp.jvpp.dto.L2FibTableEntryReplyDump; -import org.openvpp.jvpp.future.FutureJVpp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class L2FibEntryCustomizer extends FutureJVppCustomizer - implements ListReaderCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(L2FibEntryCustomizer.class); - - private static final Collector SINGLE_ITEM_COLLECTOR = - RWUtils.singleItemCollector(); - - private final NamingContext bdContext; - private final NamingContext interfaceContext; - - public L2FibEntryCustomizer(@Nonnull final FutureJVpp futureJVpp, @Nonnull final NamingContext bdContext, - @Nonnull final NamingContext interfaceContext) { - super(futureJVpp); - this.bdContext = Preconditions.checkNotNull(bdContext, "bdContext should not be null"); - this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null"); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final L2FibEntryBuilder builder, @Nonnull final ReadContext ctx) - throws ReadFailedException { - - final L2FibEntryKey key = id.firstKeyOf(id.getTargetType()); - final BridgeDomainKey bridgeDomainKey = id.firstKeyOf(BridgeDomain.class); - final int bdId = bdContext.getIndex(bridgeDomainKey.getName(), ctx.getMappingContext()); - LOG.debug("Reading L2 FIB entry: key={}. bridgeDomainKey={}, bdId={}", key, bridgeDomainKey, bdId); - - try { - // TODO use cached l2FibTable - final L2FibTableEntry entry = dumpL2Fibs(id, bdId).stream().filter(e -> key.getPhysAddress() - .equals(new PhysAddress(vppPhysAddrToYang(Longs.toByteArray(e.mac), 2)))) - .collect(SINGLE_ITEM_COLLECTOR); - - builder.setAction(byteToBoolean(entry.filterMac) - ? L2FibFilter.class - : L2FibForward.class); - builder.setBridgedVirtualInterface(byteToBoolean(entry.bviMac)); - - if (entry.swIfIndex != -1) { - builder.setOutgoingInterface(interfaceContext.getName(entry.swIfIndex, ctx.getMappingContext())); - } - builder.setStaticConfig(byteToBoolean(entry.staticMac)); - builder.setPhysAddress(key.getPhysAddress()); - builder.setKey(key); - } catch (Exception e) { - throw new ReadFailedException(id, e); - } - } - - @Nonnull - private List dumpL2Fibs(final InstanceIdentifier id, final int bdId) - throws VppBaseCallException, ReadTimeoutException { - final L2FibTableDump l2FibRequest = new L2FibTableDump(); - l2FibRequest.bdId = bdId; - - final CompletableFuture l2FibTableDumpCompletableFuture = - getFutureJVpp().l2FibTableDump(l2FibRequest).toCompletableFuture(); - - final L2FibTableEntryReplyDump dump = TranslateUtils.getReplyForRead(l2FibTableDumpCompletableFuture, id); - - if (null == dump || null == dump.l2FibTableEntry) { - return Collections.emptyList(); - } else { - return dump.l2FibTableEntry; - } - } - - @Nonnull - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - final BridgeDomainKey bridgeDomainKey = id.firstKeyOf(BridgeDomain.class); - final int bdId = bdContext.getIndex(bridgeDomainKey.getName(), ctx.getMappingContext()); - - LOG.debug("Reading L2 FIB for bridge domain {} (bdId={})", bridgeDomainKey, bdId); - try { - return dumpL2Fibs(id, bdId).stream() - .map(entry -> new L2FibEntryKey( - new PhysAddress(vppPhysAddrToYang(Longs.toByteArray(entry.mac), 2)))) - .collect(Collectors.toList()); - } catch (VppBaseCallException e) { - throw new ReadFailedException(id, e); - } - } - - @Override - public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { - ((L2FibTableBuilder) builder).setL2FibEntry(readData); - } - - @Nonnull - @Override - public L2FibEntryBuilder getBuilder(@Nonnull final InstanceIdentifier id) { - return new L2FibEntryBuilder(); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VersionCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VersionCustomizer.java deleted file mode 100644 index 2032cd811..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VersionCustomizer.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.v3po.vppstate; - -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.concurrent.CompletionStage; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.ShowVersion; -import org.openvpp.jvpp.dto.ShowVersionReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public final class VersionCustomizer - extends FutureJVppCustomizer - implements ReaderCustomizer { - - /** - * Default timeout for executing version read - */ - private static final int DEFAULT_TIMEOUT_IN_SECONDS = 30; - - public VersionCustomizer(@Nonnull final FutureJVpp futureJVpp) { - super(futureJVpp); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Version readValue) { - ((VppStateBuilder) parentBuilder).setVersion(readValue); - } - - @Nonnull - @Override - public VersionBuilder getBuilder(@Nonnull InstanceIdentifier id) { - return new VersionBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull final VersionBuilder builder, - @Nonnull final ReadContext context) throws ReadFailedException { - try { - // Execute with timeout - final CompletionStage showVersionFuture = getFutureJVpp().showVersion(new ShowVersion()); - final ShowVersionReply reply = TranslateUtils.getReplyForRead(showVersionFuture.toCompletableFuture(), id, - DEFAULT_TIMEOUT_IN_SECONDS); - - builder.setBranch(TranslateUtils.toString(reply.version)); - builder.setName(TranslateUtils.toString(reply.program)); - builder.setBuildDate(TranslateUtils.toString(reply.buildDate)); - builder.setBuildDirectory(TranslateUtils.toString(reply.buildDirectory)); - } catch (VppBaseCallException e) { - throw new ReadFailedException(id, e); - } - } - -} diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesConfigurationInitializerModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesConfigurationInitializerModule.java index 0fa9f544a..606e27832 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesConfigurationInitializerModule.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesConfigurationInitializerModule.java @@ -1,6 +1,6 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406; -import io.fd.honeycomb.v3po.translate.v3po.initializers.InterfacesInitializer; +import io.fd.honeycomb.translate.v3po.initializers.InterfacesInitializer; public class InterfacesConfigurationInitializerModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.AbstractInterfacesConfigurationInitializerModule { public InterfacesConfigurationInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java index 7ac666b8a..c3e56ef80 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java @@ -4,24 +4,24 @@ import static org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po import static org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.VppClassifierHoneycombWriterModule.CLASSIFY_TABLE_ID; import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.impl.write.GenericListWriter; -import io.fd.honeycomb.v3po.translate.impl.write.GenericWriter; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.AclCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.EthernetCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.InterfaceCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.L2Customizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.RoutingCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.TapCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.VhostUserCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.VxlanCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.VxlanGpeCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4AddressCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4Customizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv4NeighbourCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.Ipv6Customizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.registry.ModifiableWriterRegistryBuilder; -import io.fd.honeycomb.v3po.translate.write.WriterFactory; +import io.fd.honeycomb.translate.impl.write.GenericListWriter; +import io.fd.honeycomb.translate.impl.write.GenericWriter; +import io.fd.honeycomb.translate.v3po.interfaces.AclCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.EthernetCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.InterfaceCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.L2Customizer; +import io.fd.honeycomb.translate.v3po.interfaces.RoutingCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.TapCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.VhostUserCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.VxlanCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.VxlanGpeCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv4AddressCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv4Customizer; +import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv4NeighbourCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv6Customizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import io.fd.honeycomb.translate.write.WriterFactory; import java.util.Set; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java index fb2f281f9..e2fd01cd2 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java @@ -1,23 +1,23 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406; import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader; -import io.fd.honeycomb.v3po.translate.impl.read.GenericReader; -import io.fd.honeycomb.v3po.translate.read.ReaderFactory; -import io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.AclCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.EthernetCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.L2Customizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.TapCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.VhostUserCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.VxlanCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.VxlanGpeCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4AddressCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4Customizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv4NeighbourCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.Ipv6Customizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; +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 io.fd.honeycomb.translate.v3po.interfacesstate.AclCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.EthernetCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.L2Customizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.TapCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.VhostUserCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.VxlanCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.VxlanGpeCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4AddressCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4Customizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv4NeighbourCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.ip.Ipv6Customizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceAugmentationWriterFactory.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceAugmentationWriterFactory.java index 034056425..d0d8f1bdc 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceAugmentationWriterFactory.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceAugmentationWriterFactory.java @@ -20,16 +20,16 @@ import static org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po import static org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.VppClassifierHoneycombWriterModule.CLASSIFY_TABLE_ID; import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.impl.write.GenericListWriter; -import io.fd.honeycomb.v3po.translate.impl.write.GenericWriter; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.RewriteCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.SubInterfaceAclCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.SubInterfaceCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.SubInterfaceL2Customizer; -import io.fd.honeycomb.v3po.translate.v3po.interfaces.ip.SubInterfaceIpv4AddressCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.registry.ModifiableWriterRegistryBuilder; -import io.fd.honeycomb.v3po.translate.write.WriterFactory; +import io.fd.honeycomb.translate.impl.write.GenericListWriter; +import io.fd.honeycomb.translate.impl.write.GenericWriter; +import io.fd.honeycomb.translate.v3po.interfaces.RewriteCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.SubInterfaceAclCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.SubInterfaceCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.SubInterfaceL2Customizer; +import io.fd.honeycomb.translate.v3po.interfaces.ip.SubInterfaceIpv4AddressCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import io.fd.honeycomb.translate.write.WriterFactory; import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl; diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceStateAugmentationReaderFactory.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceStateAugmentationReaderFactory.java index 42e8c5b34..0718d69d9 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceStateAugmentationReaderFactory.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/SubinterfaceStateAugmentationReaderFactory.java @@ -17,16 +17,16 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406; import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader; -import io.fd.honeycomb.v3po.translate.impl.read.GenericReader; -import io.fd.honeycomb.v3po.translate.read.ReaderFactory; -import io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.RewriteCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.SubInterfaceAclCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.SubInterfaceCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.SubInterfaceL2Customizer; -import io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip.SubInterfaceIpv4AddressCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; +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 io.fd.honeycomb.translate.v3po.interfacesstate.RewriteCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.SubInterfaceAclCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.SubInterfaceCustomizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.SubInterfaceL2Customizer; +import io.fd.honeycomb.translate.v3po.interfacesstate.ip.SubInterfaceIpv4AddressCustomizer; +import io.fd.honeycomb.translate.v3po.util.NamingContext; import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip4Acl; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.Ip6Acl; diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierConfigurationInitializerModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierConfigurationInitializerModule.java index ce29697cc..f83e54644 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierConfigurationInitializerModule.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierConfigurationInitializerModule.java @@ -1,6 +1,6 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406; -import io.fd.honeycomb.v3po.translate.v3po.initializers.VppClasifierInitializer; +import io.fd.honeycomb.translate.v3po.initializers.VppClasifierInitializer; public class VppClassifierConfigurationInitializerModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.AbstractVppClassifierConfigurationInitializerModule { public VppClassifierConfigurationInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModule.java index 7b78b6bc7..c321c2724 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModule.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModule.java @@ -2,12 +2,12 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.r import static org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.InterfacesHoneycombWriterModule.ACL_ID; -import io.fd.honeycomb.v3po.translate.impl.write.GenericListWriter; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.vppclassifier.ClassifySessionWriter; -import io.fd.honeycomb.v3po.translate.v3po.vppclassifier.ClassifyTableWriter; -import io.fd.honeycomb.v3po.translate.write.WriterFactory; -import io.fd.honeycomb.v3po.translate.write.registry.ModifiableWriterRegistryBuilder; +import io.fd.honeycomb.translate.impl.write.GenericListWriter; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.vppclassifier.ClassifySessionWriter; +import io.fd.honeycomb.translate.v3po.vppclassifier.ClassifyTableWriter; +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.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierStateHoneycombReaderModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierStateHoneycombReaderModule.java index 80370fe9d..de12bbeea 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierStateHoneycombReaderModule.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierStateHoneycombReaderModule.java @@ -1,11 +1,11 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406; -import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader; -import io.fd.honeycomb.v3po.translate.read.ReaderFactory; -import io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.vppclassifier.ClassifySessionReader; -import io.fd.honeycomb.v3po.translate.v3po.vppclassifier.ClassifyTableReader; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.vppclassifier.ClassifySessionReader; +import io.fd.honeycomb.translate.v3po.vppclassifier.ClassifyTableReader; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierStateBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppConfigurationInitializerModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppConfigurationInitializerModule.java index 48535ff64..266fc408c 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppConfigurationInitializerModule.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppConfigurationInitializerModule.java @@ -1,6 +1,6 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406; -import io.fd.honeycomb.v3po.translate.v3po.initializers.VppInitializer; +import io.fd.honeycomb.translate.v3po.initializers.VppInitializer; public class VppConfigurationInitializerModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.AbstractVppConfigurationInitializerModule { public VppConfigurationInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppHoneycombWriterModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppHoneycombWriterModule.java index 4b31e2ebe..625258b90 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppHoneycombWriterModule.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppHoneycombWriterModule.java @@ -1,12 +1,12 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406; import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.translate.impl.write.GenericListWriter; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.vpp.BridgeDomainCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.vpp.L2FibEntryCustomizer; -import io.fd.honeycomb.v3po.translate.write.registry.ModifiableWriterRegistryBuilder; -import io.fd.honeycomb.v3po.translate.write.WriterFactory; +import io.fd.honeycomb.translate.impl.write.GenericListWriter; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.vpp.BridgeDomainCustomizer; +import io.fd.honeycomb.translate.v3po.vpp.L2FibEntryCustomizer; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import io.fd.honeycomb.translate.write.WriterFactory; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTable; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppInterfaceNotificationProducerModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppInterfaceNotificationProducerModule.java index 4251fdab2..bb31760ad 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppInterfaceNotificationProducerModule.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppInterfaceNotificationProducerModule.java @@ -1,6 +1,6 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406; -import io.fd.honeycomb.v3po.translate.v3po.notification.InterfaceChangeNotificationProducer; +import io.fd.honeycomb.translate.v3po.notification.InterfaceChangeNotificationProducer; public class VppInterfaceNotificationProducerModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406.AbstractVppInterfaceNotificationProducerModule { diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppStateHoneycombReaderModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppStateHoneycombReaderModule.java index 98d38c5f8..5be949b13 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppStateHoneycombReaderModule.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppStateHoneycombReaderModule.java @@ -1,15 +1,15 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.v3po2vpp.rev160406; -import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader; -import io.fd.honeycomb.v3po.translate.impl.read.GenericReader; -import io.fd.honeycomb.v3po.translate.read.ReaderFactory; -import io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder; -import io.fd.honeycomb.v3po.translate.util.read.KeepaliveReaderWrapper; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.ReadTimeoutException; -import io.fd.honeycomb.v3po.translate.v3po.vppstate.BridgeDomainCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.vppstate.L2FibEntryCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.vppstate.VersionCustomizer; +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 io.fd.honeycomb.translate.util.read.KeepaliveReaderWrapper; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.ReadTimeoutException; +import io.fd.honeycomb.translate.v3po.vppstate.BridgeDomainCustomizer; +import io.fd.honeycomb.translate.v3po.vppstate.L2FibEntryCustomizer; +import io.fd.honeycomb.translate.v3po.vppstate.VersionCustomizer; import java.lang.management.ManagementFactory; import javax.management.Attribute; import javax.management.InstanceNotFoundException; diff --git a/v3po/v3po2vpp/src/main/yang/v3po2vpp.yang b/v3po/v3po2vpp/src/main/yang/v3po2vpp.yang index 6bc253e48..1e821f5c1 100644 --- a/v3po/v3po2vpp/src/main/yang/v3po2vpp.yang +++ b/v3po/v3po2vpp/src/main/yang/v3po2vpp.yang @@ -6,7 +6,7 @@ module v3po2vpp { import config { prefix config; revision-date 2013-04-05; } import translate-api { prefix tapi; revision-date 2016-04-06; } import vpp-jvpp-cfg { prefix vjvppc; revision-date 2016-04-06; } - import vpp-cfg-init { prefix init; revision-date "2016-04-07"; } + import cfg-init { prefix init; revision-date "2016-04-07"; } import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;} import vpp-util { prefix vpp-u; revision-date 2016-04-06; } import threadpool {prefix th;} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializerTest.java new file mode 100644 index 000000000..3dc74a3e5 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/initializers/InterfacesInitializerTest.java @@ -0,0 +1,106 @@ +/* + * 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.translate.v3po.initializers; + +import static org.junit.Assert.assertEquals; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; + +public class InterfacesInitializerTest { + + @Mock + private DataBroker bindingDataBroker; + + private InterfacesInitializer interfacesInitializer; + + @Before + public void setUp() { + initMocks(this); + interfacesInitializer = new InterfacesInitializer(bindingDataBroker); + } + + @Test + public void testConvert() throws Exception { + final InterfacesState operationalData = operationalData(); + final Interfaces expectedConfigData = expectedConfigData(); + + final Interfaces configData = interfacesInitializer.convert(operationalData); + assertEquals(expectedConfigData, configData); + } + + private org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface operInterface( + String name, Class inerfaceType, Interface.AdminStatus adminStatus) { + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder + iface = + new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder(); + iface.setKey( + new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey( + name)); + iface.setName(name); + iface.setType(inerfaceType); + iface.setAdminStatus(adminStatus); + return iface.build(); + } + + private InterfacesState operationalData() { + final InterfacesStateBuilder builder = new InterfacesStateBuilder(); + builder.setInterface( + Arrays.asList( + operInterface("eth1", EthernetCsmacd.class, Interface.AdminStatus.Up), + operInterface("eth2", EthernetCsmacd.class, Interface.AdminStatus.Down) + )); + return builder.build(); + } + + private org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface configInterface( + String name, Class inerfaceType, boolean isEnabled) { + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder + iface = + new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder(); + iface.setKey( + new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey( + name)); + iface.setName(name); + iface.setType(inerfaceType); + iface.setEnabled(isEnabled); + return iface.build(); + } + + private Interfaces expectedConfigData() { + final InterfacesBuilder builder = new InterfacesBuilder(); + + builder.setInterface( + Arrays.asList( + configInterface("eth1", EthernetCsmacd.class, true), + configInterface("eth2", EthernetCsmacd.class, false) + )); + return builder.build(); + } + +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializerTest.java new file mode 100644 index 000000000..48a35c371 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/initializers/VppInitializerTest.java @@ -0,0 +1,116 @@ +/* + * 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.translate.v3po.initializers; + +import static org.junit.Assert.assertEquals; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; + +public class VppInitializerTest { + + @Mock + private DataBroker bindingDataBroker; + + private VppInitializer vppInitializer; + + @Before + public void setUp() throws Exception { + initMocks(this); + vppInitializer = new VppInitializer(bindingDataBroker); + } + + @Test + public void testConvert() throws Exception { + final VppState operationalData = operationalData(); + final Vpp expectedConfigData = expectedConfigData(); + final Vpp configData = vppInitializer.convert(operationalData); + assertEquals(expectedConfigData, configData); + } + + private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain + operBd(String name, boolean learn, boolean unknownUnicastFlood, boolean arpTermination, boolean flood, + boolean forward) { + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder + bd = + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder(); + bd.setName(name); + bd.setKey( + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey( + name)); + bd.setLearn(learn); + bd.setUnknownUnicastFlood(unknownUnicastFlood); + bd.setArpTermination(arpTermination); + bd.setFlood(flood); + bd.setForward(forward); + return bd.build(); + } + + private VppState operationalData() { + final VppStateBuilder builder = new VppStateBuilder(); + + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder + bdBuilder = + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder(); + bdBuilder.setBridgeDomain(Arrays.asList( + operBd("b1", true, true, true, true, true), + operBd("b2", false, false, false, false, false) + )); + builder.setBridgeDomains(bdBuilder.build()); + return builder.build(); + } + + private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain + configBd(String name, boolean learn, boolean unknownUnicastFlood, boolean arpTermination, boolean flood, + boolean forward) { + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder + bd = + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder(); + bd.setName(name); + bd.setKey( + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey( + name)); + bd.setLearn(learn); + bd.setUnknownUnicastFlood(unknownUnicastFlood); + bd.setArpTermination(arpTermination); + bd.setFlood(flood); + bd.setForward(forward); + return bd.build(); + } + + private Vpp expectedConfigData() { + final VppBuilder builder = new VppBuilder(); + + final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder + bdBuilder = + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder(); + bdBuilder.setBridgeDomain(Arrays.asList( + configBd("b1", true, true, true, true, true), + configBd("b2", false, false, false, false, false) + )); + builder.setBridgeDomains(bdBuilder.build()); + return builder.build(); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizerTest.java new file mode 100644 index 000000000..af9799a99 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/AclCustomizerTest.java @@ -0,0 +1,221 @@ +/* + * 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.translate.v3po.interfaces; + +import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMapping; +import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMappingIid; +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.test.TestHelperUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2AclBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.AclBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.InputAclSetInterface; +import org.openvpp.jvpp.dto.InputAclSetInterfaceReply; +import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class AclCustomizerTest { + + @Mock + private FutureJVpp api; + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + + private NamingContext interfaceContext; + private NamingContext classifyTableContext; + private AclCustomizer customizer; + + private static final String IFC_TEST_INSTANCE = "ifc-test-instance"; + private static final String CT_TEST_INSTANCE = "ct-test-instance"; + private static final String IF_NAME = "local0"; + private static final int IF_INDEX = 1; + + private static final int ACL_TABLE_INDEX = 0; + private static final String ACL_TABLE_NAME = "table0"; + + @Before + public void setUp() throws Exception { + initMocks(this); + interfaceContext = new NamingContext("generatedInterfaceName", IFC_TEST_INSTANCE); + classifyTableContext = new NamingContext("generatedClassifyTable", CT_TEST_INSTANCE); + doReturn(mappingContext).when(writeContext).getMappingContext(); + customizer = new AclCustomizer(api, interfaceContext, classifyTableContext); + + final KeyedInstanceIdentifier ifcMappingKey = getMappingIid(IF_NAME, IFC_TEST_INSTANCE); + final Optional ifcMapping = getMapping(IF_NAME, IF_INDEX); + doReturn(ifcMapping).when(mappingContext).read(ifcMappingKey); + + final KeyedInstanceIdentifier ctMappingKey = + getMappingIid(ACL_TABLE_NAME, CT_TEST_INSTANCE); + final Optional ctMapping = getMapping(ACL_TABLE_NAME, ACL_TABLE_INDEX); + doReturn(ctMapping).when(mappingContext).read(ctMappingKey); + + final List allCtMappings = Lists.newArrayList(ctMapping.get()); + final Mappings allCtMappingsBaObject = new MappingsBuilder().setMapping(allCtMappings).build(); + doReturn(Optional.of(allCtMappingsBaObject)).when(mappingContext) + .read(ctMappingKey.firstIdentifierOf(Mappings.class)); + } + + + private InstanceIdentifier getAclId(final String name) { + return InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(name)).augmentation( + VppInterfaceAugmentation.class).child(Acl.class); + } + + private Acl generateAcl(final String tableName) { + final AclBuilder builder = new AclBuilder(); + final L2Acl l2Acl = new L2AclBuilder().setClassifyTable(tableName).build(); + builder.setL2Acl(l2Acl); + return builder.build(); + } + + private void whenInputAclSetInterfaceThenSuccess() throws ExecutionException, InterruptedException { + final CompletableFuture replyFuture = new CompletableFuture<>(); + final InputAclSetInterfaceReply reply = new InputAclSetInterfaceReply(); + replyFuture.complete(reply); + doReturn(replyFuture).when(api).inputAclSetInterface(any(InputAclSetInterface.class)); + } + + private void whenInputAclSetInterfaceThenFailure() throws ExecutionException, InterruptedException { + doReturn(TestHelperUtils.createFutureException()).when(api) + .inputAclSetInterface(any(InputAclSetInterface.class)); + } + + private void verifyInputAclSetInterfaceWasInvoked(final InputAclSetInterface expected) { + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(InputAclSetInterface.class); + verify(api).inputAclSetInterface(argumentCaptor.capture()); + final InputAclSetInterface actual = argumentCaptor.getValue(); + assertEquals(expected.swIfIndex, actual.swIfIndex); + assertEquals(expected.l2TableIndex, actual.l2TableIndex); + assertEquals(expected.ip4TableIndex, actual.ip4TableIndex); + assertEquals(expected.ip6TableIndex, actual.ip6TableIndex); + assertEquals(expected.isAdd, actual.isAdd); + } + + private void verifyInputAclSetInterfaceDisableWasInvoked(final InputAclSetInterface expected) { + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(InputAclSetInterface.class); + verify(api).inputAclSetInterface(argumentCaptor.capture()); + final InputAclSetInterface actual = argumentCaptor.getValue(); + assertEquals(expected.swIfIndex, actual.swIfIndex); + assertEquals(expected.l2TableIndex, actual.l2TableIndex); + assertEquals(0, actual.isAdd); + } + + private static InputAclSetInterface generateInputAclSetInterface(final byte isAdd, final int ifIndex, + final int l2TableIndex) { + final InputAclSetInterface request = new InputAclSetInterface(); + request.isAdd = isAdd; + request.l2TableIndex = l2TableIndex; + request.ip4TableIndex = ~0; + request.ip6TableIndex = ~0; + request.swIfIndex = ifIndex; + return request; + } + + @Test + public void testCreate() throws Exception { + final Acl acl = generateAcl(ACL_TABLE_NAME); + final InstanceIdentifier id = getAclId(IF_NAME); + + whenInputAclSetInterfaceThenSuccess(); + + customizer.writeCurrentAttributes(id, acl, writeContext); + + verifyInputAclSetInterfaceWasInvoked(generateInputAclSetInterface((byte) 1, IF_INDEX, ACL_TABLE_INDEX)); + } + + @Test + public void testCreateFailed() throws Exception { + final Acl acl = generateAcl(ACL_TABLE_NAME); + final InstanceIdentifier id = getAclId(IF_NAME); + + whenInputAclSetInterfaceThenFailure(); + + try { + customizer.writeCurrentAttributes(id, acl, writeContext); + } catch (WriteFailedException.CreateFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyInputAclSetInterfaceWasInvoked(generateInputAclSetInterface((byte) 1, IF_INDEX, ACL_TABLE_INDEX)); + return; + } + fail("WriteFailedException.CreateFailedException was expected"); + } + + @Test + public void testDelete() throws Exception { + final Acl acl = generateAcl(ACL_TABLE_NAME); + final InstanceIdentifier id = getAclId(IF_NAME); + + whenInputAclSetInterfaceThenSuccess(); + + customizer.deleteCurrentAttributes(id, acl, writeContext); + + verifyInputAclSetInterfaceDisableWasInvoked(generateInputAclSetInterface((byte) 0, IF_INDEX, ACL_TABLE_INDEX)); + } + + @Test + public void testDeleteFailed() throws Exception { + final Acl acl = generateAcl(ACL_TABLE_NAME); + final InstanceIdentifier id = getAclId(IF_NAME); + + whenInputAclSetInterfaceThenFailure(); + + try { + customizer.deleteCurrentAttributes(id, acl, writeContext); + } catch (WriteFailedException.DeleteFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyInputAclSetInterfaceDisableWasInvoked( + generateInputAclSetInterface((byte) 0, IF_INDEX, ACL_TABLE_INDEX)); + return; + } + fail("WriteFailedException.DeleteFailedException was expected"); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceTypeTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceTypeTestUtils.java new file mode 100644 index 000000000..0dabe1468 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/InterfaceTypeTestUtils.java @@ -0,0 +1,40 @@ +/* + * 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.translate.v3po.interfaces; + +import static org.mockito.Mockito.doReturn; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.ModificationCache; +import org.mockito.Matchers; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +final class InterfaceTypeTestUtils { + + private InterfaceTypeTestUtils() {} + + static void setupWriteContext(final WriteContext writeContext, final Class ifcType) { + doReturn(new ModificationCache()).when(writeContext).getModificationCache(); + doReturn(Optional.of(new InterfaceBuilder() + .setType(ifcType) + .build())).when(writeContext).readAfter(Matchers.any(InstanceIdentifier.class)); + } + +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizerTest.java new file mode 100644 index 000000000..1b35dfed2 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/RewriteCustomizerTest.java @@ -0,0 +1,245 @@ +/* + * 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.translate.v3po.interfaces; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.test.TestHelperUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TagRewriteOperation; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1q; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfaces; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.VppInvocationException; +import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewrite; +import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class RewriteCustomizerTest { + + @Mock + private FutureJVpp api; + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + + private NamingContext namingContext; + private RewriteCustomizer customizer; + + public static final String VLAN_IF_NAME = "local0.1"; + public static final int VLAN_IF_ID = 1; + public static final int VLAN_IF_INDEX = 11; + + @Before + public void setUp() throws Exception { + initMocks(this); + namingContext = new NamingContext("generatedSubInterfaceName", "test-instance"); + doReturn(mappingContext).when(writeContext).getMappingContext(); + customizer = new RewriteCustomizer(api, namingContext); + + final Optional ifcMapping = ContextTestUtils.getMapping(VLAN_IF_NAME, VLAN_IF_INDEX); + doReturn(ifcMapping).when(mappingContext).read(any()); + } + + private InstanceIdentifier getVlanTagRewriteId(final String name, final long index) { + final Class> child = (Class)Rewrite.class; + final InstanceIdentifier id = + InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(name)).augmentation( + SubinterfaceAugmentation.class).child(SubInterfaces.class) + .child(SubInterface.class, new SubInterfaceKey(index)) + .child(child); + return id; + } + + private Rewrite generateRewrite(final TagRewriteOperation op) { + final RewriteBuilder builder = new RewriteBuilder(); + builder.setPopTags((short) op.getPopTags()); + builder.setVlanType(_802dot1q.class); + return builder.build(); + } + + private L2InterfaceVlanTagRewrite generateL2InterfaceVlanTagRewrite(final int swIfIndex, + final TagRewriteOperation op) { + final L2InterfaceVlanTagRewrite request = new L2InterfaceVlanTagRewrite(); + request.swIfIndex = swIfIndex; + request.vtrOp = op.ordinal(); + request.pushDot1Q = 1; + return request; + } + + /** + * Positive response + */ + private void whenL2InterfaceVlanTagRewriteThenSuccess() + throws ExecutionException, InterruptedException, VppInvocationException { + final CompletableFuture replyFuture = new CompletableFuture<>(); + final L2InterfaceVlanTagRewriteReply reply = new L2InterfaceVlanTagRewriteReply(); + replyFuture.complete(reply); + doReturn(replyFuture).when(api).l2InterfaceVlanTagRewrite(any(L2InterfaceVlanTagRewrite.class)); + } + + /** + * Failure response send + */ + private void whenL2InterfaceVlanTagRewriteThenFailure() + throws ExecutionException, InterruptedException, VppInvocationException { + doReturn(TestHelperUtils.createFutureException()).when(api) + .l2InterfaceVlanTagRewrite(any(L2InterfaceVlanTagRewrite.class)); + } + + private void verifyL2InterfaceVlanTagRewriteWasInvoked(final L2InterfaceVlanTagRewrite expected) + throws VppInvocationException { + ArgumentCaptor argumentCaptor = + ArgumentCaptor.forClass(L2InterfaceVlanTagRewrite.class); + verify(api).l2InterfaceVlanTagRewrite(argumentCaptor.capture()); + final L2InterfaceVlanTagRewrite actual = argumentCaptor.getValue(); + assertEquals(expected.swIfIndex, actual.swIfIndex); + assertEquals(expected.vtrOp, actual.vtrOp); + assertEquals(expected.pushDot1Q, actual.pushDot1Q); + assertEquals(expected.tag1, actual.tag1); + assertEquals(expected.tag2, actual.tag2); + } + + private void verifyL2InterfaceVlanTagRewriteDeleteWasInvoked() throws VppInvocationException { + final L2InterfaceVlanTagRewrite request = new L2InterfaceVlanTagRewrite(); + request.swIfIndex = VLAN_IF_INDEX; + verifyL2InterfaceVlanTagRewriteWasInvoked(request); + } + + @Test + public void testCreate() throws Exception { + final TagRewriteOperation op = TagRewriteOperation.pop_2; + final Rewrite vlanTagRewrite = generateRewrite(op); + final InstanceIdentifier id = getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID); + + whenL2InterfaceVlanTagRewriteThenSuccess(); + + customizer.writeCurrentAttributes(id, vlanTagRewrite, writeContext); + + verifyL2InterfaceVlanTagRewriteWasInvoked(generateL2InterfaceVlanTagRewrite(VLAN_IF_INDEX, op)); + } + + @Test + public void testCreateFailed() throws Exception { + final TagRewriteOperation op = TagRewriteOperation.pop_2; + final Rewrite vlanTagRewrite = generateRewrite(op); + final String subIfaceName = "local0.11"; + final int subifIndex = 1; + final InstanceIdentifier id = getVlanTagRewriteId(subIfaceName, subifIndex); + + whenL2InterfaceVlanTagRewriteThenFailure(); + + try { + customizer.writeCurrentAttributes(id, vlanTagRewrite, writeContext); + } catch (WriteFailedException.CreateFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyL2InterfaceVlanTagRewriteWasInvoked(generateL2InterfaceVlanTagRewrite(VLAN_IF_INDEX, op)); + return; + } + fail("WriteFailedException.CreateFailedException was expected"); + } + + @Test + public void testUpdate() throws Exception { + final Rewrite before = generateRewrite(TagRewriteOperation.pop_2); + final Rewrite after = generateRewrite(TagRewriteOperation.pop_1); + final InstanceIdentifier id = getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID); + + whenL2InterfaceVlanTagRewriteThenSuccess(); + + customizer.updateCurrentAttributes(id, before, after, writeContext); + + verifyL2InterfaceVlanTagRewriteWasInvoked( + generateL2InterfaceVlanTagRewrite(VLAN_IF_INDEX, TagRewriteOperation.pop_1)); + } + + @Test + public void testUpdateFailed() throws Exception { + final Rewrite before = generateRewrite(TagRewriteOperation.pop_2); + final Rewrite after = generateRewrite(TagRewriteOperation.pop_1); + final InstanceIdentifier id = getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID); + + whenL2InterfaceVlanTagRewriteThenFailure(); + + try { + customizer.updateCurrentAttributes(id, before, after, writeContext); + } catch (WriteFailedException.UpdateFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyL2InterfaceVlanTagRewriteWasInvoked(generateL2InterfaceVlanTagRewrite(VLAN_IF_INDEX, + TagRewriteOperation.pop_1)); + return; + } + fail("WriteFailedException.UpdateFailedException was expected"); + } + + @Test + public void testDelete() throws Exception { + final InstanceIdentifier id = getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID); + + whenL2InterfaceVlanTagRewriteThenSuccess(); + + customizer.deleteCurrentAttributes(id, null, writeContext); + + verifyL2InterfaceVlanTagRewriteDeleteWasInvoked(); + } + + @Test + public void testDeleteFailed() throws Exception { + final InstanceIdentifier id = getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID); + + whenL2InterfaceVlanTagRewriteThenFailure(); + + try { + customizer.deleteCurrentAttributes(id, null, writeContext); + } catch (WriteFailedException.DeleteFailedException e) { + Assert.assertTrue(e.getCause() instanceof VppBaseCallException); + verifyL2InterfaceVlanTagRewriteDeleteWasInvoked(); + return; + } + fail("WriteFailedException.DeleteFailedException was expected"); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizerTest.java new file mode 100644 index 000000000..deecc6c83 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizerTest.java @@ -0,0 +1,320 @@ +/* + * 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.translate.v3po.interfaces; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.test.TestHelperUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qTagVlanType; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag; +import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTagBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1ad; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfaces; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.vlan.tagged.VlanTaggedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.TagsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.TagBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.TagKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.CreateSubif; +import org.openvpp.jvpp.dto.CreateSubifReply; +import org.openvpp.jvpp.dto.SwInterfaceSetFlags; +import org.openvpp.jvpp.dto.SwInterfaceSetFlagsReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class SubInterfaceCustomizerTest { + + @Mock + private FutureJVpp api; + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + + private NamingContext namingContext; + private SubInterfaceCustomizer customizer; + + public static final String SUPER_IF_NAME = "local0"; + public static final int SUPER_IF_ID = 1; + private static final String SUB_IFACE_NAME = "local0.11"; + private static final int SUBIF_INDEX = 11; + + private static final short STAG_ID = 100; + private static final short CTAG_ID = 200; + private static final short CTAG_ANY_ID = 0; // only the *IdAny flag is set + + private final Tag STAG_100; + private final Tag CTAG_200; + private final Tag CTAG_ANY; + + public SubInterfaceCustomizerTest() { + STAG_100 = generateTag((short) 0, SVlan.class, new Dot1qTag.VlanId(new Dot1qVlanId((int) STAG_ID))); + CTAG_200 = generateTag((short) 1, CVlan.class, new Dot1qTag.VlanId(new Dot1qVlanId(200))); + CTAG_ANY = generateTag((short) 1, CVlan.class, new Dot1qTag.VlanId(Dot1qTag.VlanId.Enumeration.Any)); + } + + @Before + public void setUp() throws Exception { + initMocks(this); + namingContext = new NamingContext("generatedSubInterfaceName", "test-instance"); + doReturn(mappingContext).when(writeContext).getMappingContext(); + // TODO create base class for tests using vppApi + customizer = new SubInterfaceCustomizer(api, namingContext); + doReturn(ContextTestUtils.getMapping(SUPER_IF_NAME, SUPER_IF_ID)).when(mappingContext) + .read(ContextTestUtils.getMappingIid(SUPER_IF_NAME, "test-instance")); + } + + private SubInterface generateSubInterface(final boolean enabled, final List tagList) { + SubInterfaceBuilder builder = new SubInterfaceBuilder(); + builder.setVlanType(_802dot1ad.class); + builder.setIdentifier(11L); + final TagsBuilder tags = new TagsBuilder(); + + tags.setTag(tagList); + + builder.setTags(tags.build()); + + builder.setMatch(generateMatch()); + builder.setEnabled(enabled); + return builder.build(); + } + + private static Tag generateTag(final short index, final Class tagType, + final Dot1qTag.VlanId vlanId) { + TagBuilder tag = new TagBuilder(); + tag.setIndex(index); + tag.setKey(new TagKey(index)); + final Dot1qTagBuilder dtag = new Dot1qTagBuilder(); + dtag.setTagType(tagType); + dtag.setVlanId(vlanId); + tag.setDot1qTag(dtag.build()); + return tag.build(); + } + + private static Match generateMatch() { + final MatchBuilder match = new MatchBuilder(); + final VlanTaggedBuilder tagged = new VlanTaggedBuilder(); + tagged.setMatchExactTags(true); + match.setMatchType( + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.VlanTaggedBuilder() + .setVlanTagged(tagged.build()).build()); + return match.build(); + } + + private CreateSubif generateSubInterfaceRequest(final int superIfId, final short innerVlanId, + final boolean isInnerAny) { + CreateSubif request = new CreateSubif(); + request.subId = 11; + request.swIfIndex = superIfId; + request.twoTags = 1; + request.innerVlanId = innerVlanId; + request.innerVlanIdAny = (byte) (isInnerAny + ? 1 + : 0); + request.dot1Ad = 1; + request.outerVlanId = STAG_ID; + return request; + } + + private SwInterfaceSetFlags generateSwInterfaceEnableRequest(final int swIfIndex) { + SwInterfaceSetFlags request = new SwInterfaceSetFlags(); + request.swIfIndex = swIfIndex; + request.adminUpDown = 1; + return request; + } + + private InstanceIdentifier getSubInterfaceId(final String name, final long index) { + return InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(name)).augmentation( + SubinterfaceAugmentation.class).child(SubInterfaces.class) + .child(SubInterface.class, new SubInterfaceKey(index)); + } + + private void whenCreateSubifThenSuccess() throws ExecutionException, InterruptedException, VppBaseCallException { + final CompletableFuture replyFuture = new CompletableFuture<>(); + final CreateSubifReply reply = new CreateSubifReply(); + replyFuture.complete(reply); + doReturn(replyFuture).when(api).createSubif(any(CreateSubif.class)); + } + + /** + * Failure response send + */ + private void whenCreateSubifThenFailure() throws ExecutionException, InterruptedException, VppBaseCallException { + doReturn(TestHelperUtils.createFutureException()).when(api) + .createSubif(any(CreateSubif.class)); + } + + private void whenSwInterfaceSetFlagsThenSuccess() + throws ExecutionException, InterruptedException, VppBaseCallException { + final CompletableFuture replyFuture = new CompletableFuture<>(); + final SwInterfaceSetFlagsReply reply = new SwInterfaceSetFlagsReply(); + replyFuture.complete(reply); + doReturn(replyFuture).when(api).swInterfaceSetFlags(any(SwInterfaceSetFlags.class)); + } + + private CreateSubif verifyCreateSubifWasInvoked(final CreateSubif expected) throws VppBaseCallException { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateSubif.class); + verify(api).createSubif(argumentCaptor.capture()); + final CreateSubif actual = argumentCaptor.getValue(); + + assertEquals(expected.swIfIndex, actual.swIfIndex); + assertEquals(expected.subId, actual.subId); + assertEquals(expected.noTags, actual.noTags); + assertEquals(expected.oneTag, actual.oneTag); + assertEquals(expected.twoTags, actual.twoTags); + assertEquals(expected.dot1Ad, actual.dot1Ad); + assertEquals(expected.exactMatch, actual.exactMatch); + assertEquals(expected.defaultSub, actual.defaultSub); + assertEquals(expected.outerVlanIdAny, actual.outerVlanIdAny); + assertEquals(expected.innerVlanIdAny, actual.innerVlanIdAny); + assertEquals(expected.outerVlanId, actual.outerVlanId); + assertEquals(expected.innerVlanId, actual.innerVlanId); + return actual; + } + + private SwInterfaceSetFlags verifySwInterfaceSetFlagsWasInvoked(final SwInterfaceSetFlags expected) + throws VppBaseCallException { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(SwInterfaceSetFlags.class); + verify(api).swInterfaceSetFlags(argumentCaptor.capture()); + final SwInterfaceSetFlags actual = argumentCaptor.getValue(); + + assertEquals(expected.swIfIndex, actual.swIfIndex); + assertEquals(expected.adminUpDown, actual.adminUpDown); + return actual; + } + + @Test + public void testCreateTwoTags() throws Exception { + final SubInterface subInterface = generateSubInterface(false, Arrays.asList(STAG_100, CTAG_200)); + final InstanceIdentifier id = getSubInterfaceId(SUPER_IF_NAME, SUBIF_INDEX); + + whenCreateSubifThenSuccess(); + whenSwInterfaceSetFlagsThenSuccess(); + + customizer.writeCurrentAttributes(id, subInterface, writeContext); + + verifyCreateSubifWasInvoked(generateSubInterfaceRequest(SUPER_IF_ID, CTAG_ID, false)); + verify(mappingContext) + .put(eq(ContextTestUtils.getMappingIid(SUB_IFACE_NAME, "test-instance")), eq( + ContextTestUtils.getMapping(SUB_IFACE_NAME, 0).get())); + } + + @Test + public void testCreateDot1qAnyTag() throws Exception { + final SubInterface subInterface = generateSubInterface(false, Arrays.asList(STAG_100, CTAG_ANY)); + final InstanceIdentifier id = getSubInterfaceId(SUPER_IF_NAME, SUBIF_INDEX); + + whenCreateSubifThenSuccess(); + whenSwInterfaceSetFlagsThenSuccess(); + + customizer.writeCurrentAttributes(id, subInterface, writeContext); + + verifyCreateSubifWasInvoked(generateSubInterfaceRequest(SUPER_IF_ID, CTAG_ANY_ID, true)); + verify(mappingContext) + .put(eq(ContextTestUtils.getMappingIid(SUB_IFACE_NAME, "test-instance")), eq( + ContextTestUtils.getMapping(SUB_IFACE_NAME, 0).get())); + } + + @Test + public void testCreateFailed() throws Exception { + final SubInterface subInterface = generateSubInterface(false, Arrays.asList(STAG_100, CTAG_200)); + final InstanceIdentifier id = getSubInterfaceId(SUPER_IF_NAME, SUBIF_INDEX); + + whenCreateSubifThenFailure(); + + try { + customizer.writeCurrentAttributes(id, subInterface, writeContext); + } catch (WriteFailedException.CreateFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyCreateSubifWasInvoked(generateSubInterfaceRequest(SUPER_IF_ID, CTAG_ID, false)); + verify(mappingContext, times(0)).put( + eq(ContextTestUtils.getMappingIid(SUPER_IF_NAME, "test-instance")), + eq(ContextTestUtils.getMapping(SUPER_IF_NAME, 0).get())); + return; + } + fail("WriteFailedException.CreateFailedException was expected"); + } + + @Test + public void testUpdate() throws Exception { + final List tags = Arrays.asList(STAG_100, CTAG_200); + final SubInterface before = generateSubInterface(false, tags); + final SubInterface after = generateSubInterface(true, tags); + final InstanceIdentifier id = getSubInterfaceId(SUPER_IF_NAME, SUBIF_INDEX); + + whenSwInterfaceSetFlagsThenSuccess(); + final Optional ifcMapping = ContextTestUtils.getMapping(SUPER_IF_NAME, SUBIF_INDEX); + doReturn(ifcMapping).when(mappingContext).read(any()); + + customizer.updateCurrentAttributes(id, before, after, writeContext); + + verifySwInterfaceSetFlagsWasInvoked(generateSwInterfaceEnableRequest(SUBIF_INDEX)); + } + + @Test + public void testUpdateNoStateChange() throws Exception { + final List tags = Arrays.asList(STAG_100, CTAG_200); + final SubInterface before = generateSubInterface(false, tags); + final SubInterface after = generateSubInterface(false, tags); + customizer.updateCurrentAttributes(null, before, after, writeContext); + + verify(api, never()).swInterfaceSetFlags(any()); + } + + @Test(expected = UnsupportedOperationException.class) + public void testDelete() throws Exception { + final SubInterface subInterface = generateSubInterface(false, Arrays.asList(STAG_100, CTAG_200)); + customizer.deleteCurrentAttributes(null, subInterface, writeContext); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizerTest.java new file mode 100644 index 000000000..43e210073 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/TapCustomizerTest.java @@ -0,0 +1,161 @@ +/* + * 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.translate.v3po.interfaces; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.util.concurrent.CompletableFuture; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Tap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.TapBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.TapConnect; +import org.openvpp.jvpp.dto.TapConnectReply; +import org.openvpp.jvpp.dto.TapDelete; +import org.openvpp.jvpp.dto.TapDeleteReply; +import org.openvpp.jvpp.dto.TapModify; +import org.openvpp.jvpp.dto.TapModifyReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class TapCustomizerTest { + + @Mock + private FutureJVpp vppApi; + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + + private TapCustomizer tapCustomizer; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + InterfaceTypeTestUtils.setupWriteContext(writeContext, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap.class); + final NamingContext ctx = new NamingContext("ifcintest", "test-instance"); + final ModificationCache toBeReturned = new ModificationCache(); + doReturn(toBeReturned).when(writeContext).getModificationCache(); + doReturn(mappingContext).when(writeContext).getMappingContext(); + + tapCustomizer = new TapCustomizer(vppApi, ctx); + } + + @Test + public void testCreate() throws Exception { + doAnswer(new Answer() { + + int idx = 0; + + @Override + public Object answer(final InvocationOnMock invocation) throws Throwable { + final CompletableFuture reply = new CompletableFuture<>(); + final TapConnectReply t = new TapConnectReply(); + t.swIfIndex = idx++; + reply.complete(t); + return reply; + } + }).when(vppApi).tapConnect(any(TapConnect.class)); + + tapCustomizer.writeCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), writeContext); + tapCustomizer.writeCurrentAttributes(getTapId("tap2"), getTapData("tap2", "ff:ff:ff:ff:ff:ff"), writeContext); + + verify(vppApi, times(2)).tapConnect(any(TapConnect.class)); + verify(mappingContext).put(eq(ContextTestUtils.getMappingIid("tap", "test-instance")), eq( + ContextTestUtils.getMapping("tap", 0).get())); + verify(mappingContext).put(eq(ContextTestUtils.getMappingIid("tap2", "test-instance")), eq( + ContextTestUtils.getMapping("tap2", 1).get())); + } + + @Test + public void testModify() throws Exception { + final CompletableFuture reply = new CompletableFuture<>(); + final TapConnectReply t = new TapConnectReply(); + t.swIfIndex = 0; + reply.complete(t); + doReturn(reply).when(vppApi).tapConnect(any(TapConnect.class)); + + final CompletableFuture replyModif = new CompletableFuture<>(); + final TapModifyReply tmodif = new TapModifyReply(); + tmodif.swIfIndex = 0; + replyModif.complete(tmodif); + doReturn(replyModif).when(vppApi).tapModify(any(TapModify.class)); + + tapCustomizer.writeCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), writeContext); + doReturn(ContextTestUtils.getMapping("tap", 1)).when(mappingContext).read( + ContextTestUtils.getMappingIid("tap", "test-instance")); + tapCustomizer.updateCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), getTapData("tap", "ff:ff:ff:ff:ff:f1"), writeContext); + + verify(vppApi).tapConnect(any(TapConnect.class)); + verify(vppApi).tapModify(any(TapModify.class)); + + verify(mappingContext).put(eq(ContextTestUtils.getMappingIid("tap", "test-instance")), eq( + ContextTestUtils.getMapping("tap", 0).get())); + } + + @Test + public void testDelete() throws Exception { + final CompletableFuture reply = new CompletableFuture<>(); + final TapConnectReply t = new TapConnectReply(); + t.swIfIndex = 0; + reply.complete(t); + doReturn(reply).when(vppApi).tapConnect(any(TapConnect.class)); + + final CompletableFuture replyDelete = new CompletableFuture<>(); + final TapDeleteReply tmodif = new TapDeleteReply(); + replyDelete.complete(tmodif); + doReturn(replyDelete).when(vppApi).tapDelete(any(TapDelete.class)); + + tapCustomizer.writeCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), writeContext); + doReturn(ContextTestUtils.getMapping("tap", 1)).when(mappingContext).read( + ContextTestUtils.getMappingIid("tap", "test-instance")); + tapCustomizer.deleteCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), writeContext); + + verify(vppApi).tapConnect(any(TapConnect.class)); + verify(vppApi).tapDelete(any(TapDelete.class)); + verify(mappingContext).delete(eq(ContextTestUtils.getMappingIid("tap", "test-instance"))); + } + + private InstanceIdentifier getTapId(final String tap) { + return InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(tap)).augmentation( + VppInterfaceAugmentation.class).child(Tap.class); + } + + private Tap getTapData(final String tap, final String mac) { + return new TapBuilder().setTapName(tap).setMac(new PhysAddress(mac)).build(); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizerTest.java new file mode 100644 index 000000000..f7165aa3c --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VhostUserCustomizerTest.java @@ -0,0 +1,294 @@ +/* + * 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.translate.v3po.interfaces; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.v3po.test.TestHelperUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.VppInvocationException; +import org.openvpp.jvpp.dto.CreateVhostUserIf; +import org.openvpp.jvpp.dto.CreateVhostUserIfReply; +import org.openvpp.jvpp.dto.DeleteVhostUserIf; +import org.openvpp.jvpp.dto.DeleteVhostUserIfReply; +import org.openvpp.jvpp.dto.ModifyVhostUserIf; +import org.openvpp.jvpp.dto.ModifyVhostUserIfReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class VhostUserCustomizerTest { + + @Mock + private FutureJVpp api; + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + + private VhostUserCustomizer customizer; + private static final int IFACE_ID = 1; + private static final String IFACE_NAME = "eth0"; + private static final InstanceIdentifier ID = + InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(IFACE_NAME)) + .augmentation(VppInterfaceAugmentation.class).child(VhostUser.class); + + @Before + public void setUp() throws Exception { + initMocks(this); + InterfaceTypeTestUtils.setupWriteContext(writeContext, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class); + final NamingContext namingContext = new NamingContext("generatedInterfaceName", "test-instance"); + final ModificationCache toBeReturned = new ModificationCache(); + doReturn(toBeReturned).when(writeContext).getModificationCache(); + doReturn(mappingContext).when(writeContext).getMappingContext(); + + // TODO create base class for tests using vppApi + customizer = new VhostUserCustomizer(api, namingContext); + } + + private void whenCreateVhostUserIfThenSuccess() + throws ExecutionException, InterruptedException, VppInvocationException, TimeoutException { + final CompletionStage replyCS = mock(CompletionStage.class); + final CompletableFuture replyFuture = mock(CompletableFuture.class); + when(replyCS.toCompletableFuture()).thenReturn(replyFuture); + final CreateVhostUserIfReply reply = new CreateVhostUserIfReply(); + when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); + when(api.createVhostUserIf(any(CreateVhostUserIf.class))).thenReturn(replyCS); + } + + /** + * Failure response send + */ + private void whenCreateVhostUserIfThenFailure() + throws ExecutionException, InterruptedException, VppInvocationException { + doReturn(TestHelperUtils.createFutureException()).when(api) + .createVhostUserIf(any(CreateVhostUserIf.class)); + } + + private void whenModifyVhostUserIfThenSuccess() + throws ExecutionException, InterruptedException, VppInvocationException, TimeoutException { + final CompletionStage replyCS = mock(CompletionStage.class); + final CompletableFuture replyFuture = mock(CompletableFuture.class); + when(replyCS.toCompletableFuture()).thenReturn(replyFuture); + final ModifyVhostUserIfReply reply = new ModifyVhostUserIfReply(); + when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); + when(api.modifyVhostUserIf(any(ModifyVhostUserIf.class))).thenReturn(replyCS); + } + + /** + * Failure response send + */ + private void whenModifyVhostUserIfThenFailure() + throws ExecutionException, InterruptedException, VppInvocationException { + doReturn(TestHelperUtils.createFutureException()).when(api) + .modifyVhostUserIf(any(ModifyVhostUserIf.class)); + } + + private void whenDeleteVhostUserIfThenSuccess() + throws ExecutionException, InterruptedException, VppInvocationException, TimeoutException { + final CompletionStage replyCS = mock(CompletionStage.class); + final CompletableFuture replyFuture = mock(CompletableFuture.class); + when(replyCS.toCompletableFuture()).thenReturn(replyFuture); + final DeleteVhostUserIfReply reply = new DeleteVhostUserIfReply(); + when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); + when(api.deleteVhostUserIf(any(DeleteVhostUserIf.class))).thenReturn(replyCS); + } + + /** + * Failure response send + */ + private void whenDeleteVhostUserIfThenFailure() + throws ExecutionException, InterruptedException, VppInvocationException { + doReturn(TestHelperUtils.createFutureException()).when(api) + .deleteVhostUserIf(any(DeleteVhostUserIf.class)); + } + + private CreateVhostUserIf verifyCreateVhostUserIfWasInvoked(final VhostUser vhostUser) throws VppInvocationException { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateVhostUserIf.class); + verify(api).createVhostUserIf(argumentCaptor.capture()); + final CreateVhostUserIf actual = argumentCaptor.getValue(); + assertEquals(0, actual.customDevInstance); + + assertEquals(TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())), actual.isServer); + assertEquals(0, actual.renumber); + assertEquals(0, actual.useCustomMac); + assertArrayEquals(vhostUser.getSocket().getBytes(), actual.sockFilename); + assertNotNull(actual.macAddress); + return actual; + } + + private ModifyVhostUserIf verifyModifyVhostUserIfWasInvoked(final VhostUser vhostUser, final int swIfIndex) + throws VppInvocationException { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(ModifyVhostUserIf.class); + verify(api).modifyVhostUserIf(argumentCaptor.capture()); + final ModifyVhostUserIf actual = argumentCaptor.getValue(); + assertEquals(0, actual.customDevInstance); + + assertEquals(TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())), actual.isServer); + assertEquals(0, actual.renumber); + assertEquals(swIfIndex, actual.swIfIndex); + assertArrayEquals(vhostUser.getSocket().getBytes(), actual.sockFilename); + return actual; + } + + private DeleteVhostUserIf verifyDeleteVhostUserIfWasInvoked(final int swIfIndex) throws VppInvocationException { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(DeleteVhostUserIf.class); + verify(api).deleteVhostUserIf(argumentCaptor.capture()); + final DeleteVhostUserIf actual = argumentCaptor.getValue(); + assertEquals(swIfIndex, actual.swIfIndex); + return actual; + } + + private static VhostUser generateVhostUser(final VhostUserRole role, final String socketName) { + VhostUserBuilder builder = new VhostUserBuilder(); + builder.setRole(role); + builder.setSocket(socketName); + return builder.build(); + } + + @Test + public void testWriteCurrentAttributes() throws Exception { + final VhostUser vhostUser = generateVhostUser(VhostUserRole.Server, "socketName"); + + whenCreateVhostUserIfThenSuccess(); + + customizer.writeCurrentAttributes(ID, vhostUser, writeContext); + verifyCreateVhostUserIfWasInvoked(vhostUser); + verify(mappingContext).put(eq(ContextTestUtils.getMappingIid(IFACE_NAME, "test-instance")), eq( + ContextTestUtils.getMapping(IFACE_NAME, 0).get())); + } + + @Test + public void testWriteCurrentAttributesFailed() throws Exception { + final VhostUser vhostUser = generateVhostUser(VhostUserRole.Client, "socketName"); + + whenCreateVhostUserIfThenFailure(); + + try { + customizer.writeCurrentAttributes(ID, vhostUser, writeContext); + } catch (WriteFailedException.CreateFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyCreateVhostUserIfWasInvoked(vhostUser); + verifyZeroInteractions(mappingContext); + return; + } + fail("WriteFailedException.CreateFailedException was expected"); + } + + @Test + public void testUpdateCurrentAttributes() throws Exception { + final VhostUser vhostUserBefore = generateVhostUser(VhostUserRole.Client, "socketName0"); + final VhostUser vhostUserAfter = generateVhostUser(VhostUserRole.Server, "socketName1"); + doReturn(ContextTestUtils.getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read( + ContextTestUtils.getMappingIid(IFACE_NAME, "test-instance")); + + whenModifyVhostUserIfThenSuccess(); + + customizer.updateCurrentAttributes(ID, vhostUserBefore, vhostUserAfter, writeContext); + verifyModifyVhostUserIfWasInvoked(vhostUserAfter, IFACE_ID); + } + + @Test + public void testUpdateCurrentAttributesFailed() throws Exception { + final VhostUser vhostUserBefore = generateVhostUser(VhostUserRole.Client, "socketName0"); + final VhostUser vhostUserAfter = generateVhostUser(VhostUserRole.Server, "socketName1"); + doReturn(ContextTestUtils.getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read( + ContextTestUtils.getMappingIid(IFACE_NAME, "test-instance")); + + whenModifyVhostUserIfThenFailure(); + + try { + customizer.updateCurrentAttributes(ID, vhostUserBefore, vhostUserAfter, writeContext); + } catch (WriteFailedException.UpdateFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyModifyVhostUserIfWasInvoked(vhostUserAfter, IFACE_ID); + return; + } + fail("WriteFailedException.UpdateFailedException was expected"); + } + + @Test + public void testDeleteCurrentAttributes() throws Exception { + final VhostUser vhostUser = generateVhostUser(VhostUserRole.Client, "socketName"); + doReturn(ContextTestUtils.getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read( + ContextTestUtils.getMappingIid(IFACE_NAME, "test-instance")); + + whenDeleteVhostUserIfThenSuccess(); + + customizer.deleteCurrentAttributes(ID, vhostUser, writeContext); + verifyDeleteVhostUserIfWasInvoked(IFACE_ID); + verify(mappingContext).delete(eq(ContextTestUtils.getMappingIid(IFACE_NAME, "test-instance"))); + } + + @Test + public void testDeleteCurrentAttributesFailed() throws Exception { + final VhostUser vhostUser = generateVhostUser(VhostUserRole.Client, "socketName"); + doReturn(ContextTestUtils.getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read( + ContextTestUtils.getMappingIid(IFACE_NAME, "test-instance")); + + whenDeleteVhostUserIfThenFailure(); + + try { + customizer.deleteCurrentAttributes(ID, vhostUser, writeContext); + } catch (WriteFailedException.DeleteFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyDeleteVhostUserIfWasInvoked(IFACE_ID); + // Delete from context not invoked if delete from VPP failed + verify(mappingContext, times(0)).delete(eq(ContextTestUtils.getMappingIid(IFACE_NAME, "test-instance"))); + verify(mappingContext).read(eq(ContextTestUtils.getMappingIid(IFACE_NAME, "test-instance"))); + return; + } + fail("WriteFailedException.DeleteFailedException was expected"); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizerTest.java new file mode 100644 index 000000000..b2b9aebba --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanCustomizerTest.java @@ -0,0 +1,253 @@ +/* + * 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.translate.v3po.interfaces; + +import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMapping; +import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMappingIid; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import com.google.common.net.InetAddresses; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.v3po.test.TestHelperUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.VppInvocationException; +import org.openvpp.jvpp.dto.VxlanAddDelTunnel; +import org.openvpp.jvpp.dto.VxlanAddDelTunnelReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class VxlanCustomizerTest { + + private static final byte ADD_VXLAN = 1; + private static final byte DEL_VXLAN = 0; + + @Mock + private FutureJVpp api; + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + + private VxlanCustomizer customizer; + private String ifaceName; + private InstanceIdentifier id; + + @Before + public void setUp() throws Exception { + initMocks(this); + InterfaceTypeTestUtils.setupWriteContext(writeContext, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel.class); + // TODO create base class for tests using vppApi + NamingContext namingContext = new NamingContext("generateInterfaceNAme", "test-instance"); + final ModificationCache toBeReturned = new ModificationCache(); + doReturn(toBeReturned).when(writeContext).getModificationCache(); + doReturn(mappingContext).when(writeContext).getMappingContext(); + + customizer = new VxlanCustomizer(api, namingContext); + + ifaceName = "eth0"; + id = InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(ifaceName)) + .augmentation(VppInterfaceAugmentation.class).child(Vxlan.class); + } + + private void whenVxlanAddDelTunnelThenSuccess() + throws ExecutionException, InterruptedException, VppInvocationException, TimeoutException { + final CompletionStage replyCS = mock(CompletionStage.class); + final CompletableFuture replyFuture = mock(CompletableFuture.class); + when(replyCS.toCompletableFuture()).thenReturn(replyFuture); + final VxlanAddDelTunnelReply reply = new VxlanAddDelTunnelReply(); + when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); + when(api.vxlanAddDelTunnel(any(VxlanAddDelTunnel.class))).thenReturn(replyCS); + } + + /** + * Failure response send + */ + private void whenVxlanAddDelTunnelThenFailure() + throws ExecutionException, InterruptedException, VppInvocationException { + doReturn(TestHelperUtils.createFutureException()).when(api) + .vxlanAddDelTunnel(any(VxlanAddDelTunnel.class)); + } + + private VxlanAddDelTunnel verifyVxlanAddDelTunnelWasInvoked(final Vxlan vxlan) throws VppInvocationException { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(VxlanAddDelTunnel.class); + verify(api).vxlanAddDelTunnel(argumentCaptor.capture()); + final VxlanAddDelTunnel actual = argumentCaptor.getValue(); + assertEquals(0, actual.isIpv6); + assertEquals(-1, actual.decapNextIndex); + assertArrayEquals(InetAddresses.forString(vxlan.getSrc().getIpv4Address().getValue()).getAddress(), + actual.srcAddress); + assertArrayEquals(InetAddresses.forString(vxlan.getDst().getIpv4Address().getValue()).getAddress(), + actual.dstAddress); + assertEquals(vxlan.getEncapVrfId().intValue(), actual.encapVrfId); + assertEquals(vxlan.getVni().getValue().intValue(), actual.vni); + return actual; + } + + private void verifyVxlanAddWasInvoked(final Vxlan vxlan) throws VppInvocationException { + final VxlanAddDelTunnel actual = verifyVxlanAddDelTunnelWasInvoked(vxlan); + assertEquals(ADD_VXLAN, actual.isAdd); + } + + private void verifyVxlanDeleteWasInvoked(final Vxlan vxlan) throws VppInvocationException { + final VxlanAddDelTunnel actual = verifyVxlanAddDelTunnelWasInvoked(vxlan); + assertEquals(DEL_VXLAN, actual.isAdd); + } + + private static Vxlan generateVxlan(long vni) { + final VxlanBuilder builder = new VxlanBuilder(); + builder.setSrc(new IpAddress(new Ipv4Address("192.168.20.10"))); + builder.setDst(new IpAddress(new Ipv4Address("192.168.20.11"))); + builder.setEncapVrfId(Long.valueOf(123)); + builder.setVni(new VxlanVni(Long.valueOf(vni))); + return builder.build(); + } + + private static Vxlan generateVxlan() { + return generateVxlan(Long.valueOf(11)); + } + + @Test + public void testWriteCurrentAttributes() throws Exception { + final Vxlan vxlan = generateVxlan(); + + whenVxlanAddDelTunnelThenSuccess(); + + doReturn(Optional.absent()) + .when(mappingContext).read(getMappingIid(ifaceName, "test-instance").firstIdentifierOf(Mappings.class)); + + customizer.writeCurrentAttributes(id, vxlan, writeContext); + verifyVxlanAddWasInvoked(vxlan); + verify(mappingContext).put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get())); + } + + @Test + public void testWriteCurrentAttributesMappingAlreadyPresent() throws Exception { + final Vxlan vxlan = generateVxlan(); + + whenVxlanAddDelTunnelThenSuccess(); + final Optional ifcMapping = getMapping(ifaceName, 0); + + doReturn(Optional.of(new MappingsBuilder().setMapping(singletonList(ifcMapping.get())).build())) + .when(mappingContext).read(getMappingIid(ifaceName, "test-instance").firstIdentifierOf(Mappings.class)); + + customizer.writeCurrentAttributes(id, vxlan, writeContext); + verifyVxlanAddWasInvoked(vxlan); + + // Remove the first mapping before putting in the new one + verify(mappingContext).delete(eq(getMappingIid(ifaceName, "test-instance"))); + verify(mappingContext).put(eq(getMappingIid(ifaceName, "test-instance")), eq(ifcMapping.get())); + } + + @Test + public void testWriteCurrentAttributesFailed() throws Exception { + final Vxlan vxlan = generateVxlan(); + + whenVxlanAddDelTunnelThenFailure(); + + try { + customizer.writeCurrentAttributes(id, vxlan, writeContext); + } catch (WriteFailedException.CreateFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyVxlanAddWasInvoked(vxlan); + // Mapping not stored due to failure + verify(mappingContext, times(0)).put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get())); + return; + } + fail("WriteFailedException.CreateFailedException was expected"); + } + + @Test + public void testUpdateCurrentAttributes() throws Exception { + try { + customizer.updateCurrentAttributes(id, generateVxlan(10), generateVxlan(11), writeContext); + } catch (WriteFailedException.UpdateFailedException e) { + assertEquals(UnsupportedOperationException.class, e.getCause().getClass()); + return; + } + fail("WriteFailedException.UpdateFailedException was expected"); + } + + @Test + public void testDeleteCurrentAttributes() throws Exception { + final Vxlan vxlan = generateVxlan(); + + whenVxlanAddDelTunnelThenSuccess(); + doReturn(getMapping(ifaceName, 1)).when(mappingContext).read(getMappingIid(ifaceName, "test-instance")); + + customizer.deleteCurrentAttributes(id, vxlan, writeContext); + verifyVxlanDeleteWasInvoked(vxlan); + verify(mappingContext).delete(eq(getMappingIid(ifaceName, "test-instance"))); + } + + @Test + public void testDeleteCurrentAttributesaFailed() throws Exception { + final Vxlan vxlan = generateVxlan(); + + whenVxlanAddDelTunnelThenFailure(); + doReturn(getMapping(ifaceName, 1)).when(mappingContext).read(getMappingIid(ifaceName, "test-instance")); + + try { + customizer.deleteCurrentAttributes(id, vxlan, writeContext); + } catch (WriteFailedException.DeleteFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyVxlanDeleteWasInvoked(vxlan); + verify(mappingContext, times(0)).delete(eq(getMappingIid(ifaceName, "test-instance"))); + return; + } + fail("WriteFailedException.DeleteFailedException was expected"); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizerTest.java new file mode 100644 index 000000000..bec33cbbd --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/VxlanGpeCustomizerTest.java @@ -0,0 +1,262 @@ +/* + * 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.translate.v3po.interfaces; + +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import com.google.common.net.InetAddresses; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.test.TestHelperUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.MappingContext; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeNextProtocol; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeVni; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpeBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.VxlanAddDelTunnelReply; +import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnel; +import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnelReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class VxlanGpeCustomizerTest { + + private static final byte ADD_VXLAN_GPE = 1; + private static final byte DEL_VXLAN_GPE = 0; + + @Mock + private FutureJVpp api; + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + + private VxlanGpeCustomizer customizer; + private String ifaceName; + private InstanceIdentifier id; + + @Before + public void setUp() throws Exception { + initMocks(this); + InterfaceTypeTestUtils.setupWriteContext(writeContext, + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel.class); + // TODO create base class for tests using vppApi + NamingContext namingContext = new NamingContext("generateInterfaceNAme", "test-instance"); + final ModificationCache toBeReturned = new ModificationCache(); + doReturn(toBeReturned).when(writeContext).getModificationCache(); + doReturn(mappingContext).when(writeContext).getMappingContext(); + + customizer = new VxlanGpeCustomizer(api, namingContext); + + ifaceName = "eth0"; + id = InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(ifaceName)) + .augmentation(VppInterfaceAugmentation.class).child(VxlanGpe.class); + } + + private void whenVxlanGpeAddDelTunnelThenSuccess() + throws ExecutionException, InterruptedException, VppBaseCallException, TimeoutException { + final CompletionStage replyCS = mock(CompletionStage.class); + final CompletableFuture replyFuture = mock(CompletableFuture.class); + when(replyCS.toCompletableFuture()).thenReturn(replyFuture); + final VxlanGpeAddDelTunnelReply reply = new VxlanGpeAddDelTunnelReply(); + when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); + when(api.vxlanGpeAddDelTunnel(any(VxlanGpeAddDelTunnel.class))).thenReturn(replyCS); + } + + /** + * Failure response send + */ + private void whenVxlanGpeAddDelTunnelThenFailure() + throws ExecutionException, InterruptedException, VppBaseCallException { + doReturn(TestHelperUtils.createFutureException()).when(api) + .vxlanGpeAddDelTunnel(any(VxlanGpeAddDelTunnel.class)); + } + + private VxlanGpeAddDelTunnel verifyVxlanGpeAddDelTunnelWasInvoked(final VxlanGpe vxlanGpe) + throws VppBaseCallException { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(VxlanGpeAddDelTunnel.class); + verify(api).vxlanGpeAddDelTunnel(argumentCaptor.capture()); + final VxlanGpeAddDelTunnel actual = argumentCaptor.getValue(); + assertEquals(0, actual.isIpv6); + assertArrayEquals(InetAddresses.forString(vxlanGpe.getLocal().getIpv4Address().getValue()).getAddress(), + actual.local); + assertArrayEquals(InetAddresses.forString(vxlanGpe.getRemote().getIpv4Address().getValue()).getAddress(), + actual.remote); + assertEquals(vxlanGpe.getVni().getValue().intValue(), actual.vni); + assertEquals(vxlanGpe.getNextProtocol().getIntValue(), actual.protocol); + assertEquals(vxlanGpe.getEncapVrfId().intValue(), actual.encapVrfId); + assertEquals(vxlanGpe.getDecapVrfId().intValue(), actual.decapVrfId); + return actual; + } + + private void verifyVxlanGpeAddWasInvoked(final VxlanGpe vxlanGpe) throws VppBaseCallException { + final VxlanGpeAddDelTunnel actual = verifyVxlanGpeAddDelTunnelWasInvoked(vxlanGpe); + assertEquals(ADD_VXLAN_GPE, actual.isAdd); + } + + private void verifyVxlanGpeDeleteWasInvoked(final VxlanGpe vxlanGpe) throws VppBaseCallException{ + final VxlanGpeAddDelTunnel actual = verifyVxlanGpeAddDelTunnelWasInvoked(vxlanGpe); + assertEquals(DEL_VXLAN_GPE, actual.isAdd); + } + + private static VxlanGpe generateVxlanGpe(long vni) { + final VxlanGpeBuilder builder = new VxlanGpeBuilder(); + builder.setLocal(new IpAddress(new Ipv4Address("192.168.20.10"))); + builder.setRemote(new IpAddress(new Ipv4Address("192.168.20.11"))); + builder.setVni(new VxlanGpeVni(Long.valueOf(vni))); + builder.setNextProtocol(VxlanGpeNextProtocol.forValue(1)); + builder.setEncapVrfId(Long.valueOf(123)); + builder.setDecapVrfId(Long.valueOf(456)); + return builder.build(); + } + + private static VxlanGpe generateVxlanGpe() { + return generateVxlanGpe(Long.valueOf(11)); + } + + @Test + public void testWriteCurrentAttributes() throws Exception { + final VxlanGpe vxlanGpe = generateVxlanGpe(); + + whenVxlanGpeAddDelTunnelThenSuccess(); + + doReturn(Optional.absent()) + .when(mappingContext).read(ContextTestUtils.getMappingIid(ifaceName, "test-instance").firstIdentifierOf(Mappings.class)); + + customizer.writeCurrentAttributes(id, vxlanGpe, writeContext); + verifyVxlanGpeAddWasInvoked(vxlanGpe); + verify(mappingContext).put(eq(ContextTestUtils.getMappingIid(ifaceName, "test-instance")), eq( + ContextTestUtils.getMapping(ifaceName, 0).get())); + } + + @Test + public void testWriteCurrentAttributesMappingAlreadyPresent() throws Exception { + final VxlanGpe vxlanGpe = generateVxlanGpe(); + + whenVxlanGpeAddDelTunnelThenSuccess(); + final Optional ifcMapping = ContextTestUtils.getMapping(ifaceName, 0); + + doReturn(Optional.of(new MappingsBuilder().setMapping(singletonList(ifcMapping.get())).build())) + .when(mappingContext).read(ContextTestUtils.getMappingIid(ifaceName, "test-instance").firstIdentifierOf(Mappings.class)); + + customizer.writeCurrentAttributes(id, vxlanGpe, writeContext); + verifyVxlanGpeAddWasInvoked(vxlanGpe); + + // Remove the first mapping before putting in the new one + verify(mappingContext).delete(eq(ContextTestUtils.getMappingIid(ifaceName, "test-instance"))); + verify(mappingContext).put(eq(ContextTestUtils.getMappingIid(ifaceName, "test-instance")), eq(ifcMapping.get())); + } + + @Test + public void testWriteCurrentAttributesFailed() throws Exception { + final VxlanGpe vxlanGpe = generateVxlanGpe(); + + whenVxlanGpeAddDelTunnelThenFailure(); + + try { + customizer.writeCurrentAttributes(id, vxlanGpe, writeContext); + } catch (WriteFailedException.CreateFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyVxlanGpeAddWasInvoked(vxlanGpe); + // Mapping not stored due to failure + verify(mappingContext, times(0)) + .put(eq(ContextTestUtils.getMappingIid(ifaceName, "test-instance")), eq( + ContextTestUtils.getMapping(ifaceName, 0).get())); + return; + } + fail("WriteFailedException.CreateFailedException was expected"); + } + + @Test + public void testUpdateCurrentAttributes() throws Exception { + try { + customizer.updateCurrentAttributes(id, generateVxlanGpe(10), generateVxlanGpe(11), writeContext); + } catch (WriteFailedException.UpdateFailedException e) { + assertEquals(UnsupportedOperationException.class, e.getCause().getClass()); + return; + } + fail("WriteFailedException.UpdateFailedException was expected"); + } + + @Test + public void testDeleteCurrentAttributes() throws Exception { + final VxlanGpe vxlanGpe = generateVxlanGpe(); + + whenVxlanGpeAddDelTunnelThenSuccess(); + doReturn(ContextTestUtils.getMapping(ifaceName, 1)).when(mappingContext).read( + ContextTestUtils.getMappingIid(ifaceName, "test-instance")); + + customizer.deleteCurrentAttributes(id, vxlanGpe, writeContext); + verifyVxlanGpeDeleteWasInvoked(vxlanGpe); + verify(mappingContext).delete(eq(ContextTestUtils.getMappingIid(ifaceName, "test-instance"))); + } + + @Test + public void testDeleteCurrentAttributesaFailed() throws Exception { + final VxlanGpe vxlanGpe = generateVxlanGpe(); + + whenVxlanGpeAddDelTunnelThenFailure(); + doReturn(ContextTestUtils.getMapping(ifaceName, 1)).when(mappingContext).read( + ContextTestUtils.getMappingIid(ifaceName, "test-instance")); + + try { + customizer.deleteCurrentAttributes(id, vxlanGpe, writeContext); + } catch (WriteFailedException.DeleteFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyVxlanGpeDeleteWasInvoked(vxlanGpe); + verify(mappingContext, times(0)).delete(eq(ContextTestUtils.getMappingIid(ifaceName, "test-instance"))); + return; + } + fail("WriteFailedException.DeleteFailedException was expected"); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizerTest.java new file mode 100644 index 000000000..8f3c9ad8d --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4AddressCustomizerTest.java @@ -0,0 +1,292 @@ +/* + * 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.translate.v3po.interfaces.ip; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +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.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.test.TestHelperUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletableFuture; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.NetmaskBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.VppInvocationException; +import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress; +import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class Ipv4AddressCustomizerTest { + + private static final String IFC_CTX_NAME = "ifc-test-instance"; + private static final String IFACE_NAME = "eth0"; + private static final int IFACE_ID = 123; + + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + @Mock + private FutureJVpp api; + + private NamingContext interfaceContext; + private Ipv4AddressCustomizer customizer; + + @Before + public void setUp() throws Exception { + initMocks(this); + doReturn(mappingContext).when(writeContext).getMappingContext(); + interfaceContext = new NamingContext("generatedlIfaceName", IFC_CTX_NAME); + + customizer = new Ipv4AddressCustomizer(api, interfaceContext); + } + + private static InstanceIdentifier
getAddressId(final String ifaceName) { + return InstanceIdentifier.builder(Interfaces.class) + .child(Interface.class, new InterfaceKey(ifaceName)) + .augmentation(Interface1.class) + .child(Ipv4.class) + .child(Address.class) + .build(); + } + + private void whenSwInterfaceAddDelAddressThenSuccess() { + final CompletableFuture replyFuture = new CompletableFuture<>(); + final SwInterfaceAddDelAddressReply reply = new SwInterfaceAddDelAddressReply(); + replyFuture.complete(reply); + doReturn(replyFuture).when(api).swInterfaceAddDelAddress(any(SwInterfaceAddDelAddress.class)); + } + + private void whenSwInterfaceAddDelAddressThenFailure() { + doReturn(TestHelperUtils.createFutureException()).when(api) + .swInterfaceAddDelAddress(any(SwInterfaceAddDelAddress.class)); + } + + private void verifySwInterfaceAddDelAddressWasInvoked(final SwInterfaceAddDelAddress expected) throws + VppInvocationException { + ArgumentCaptor argumentCaptor = + ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class); + verify(api).swInterfaceAddDelAddress(argumentCaptor.capture()); + verifySwInterfaceAddDelAddressWasInvoked(expected, argumentCaptor.getValue()); + } + + private void verifySwInterfaceAddDelAddressWasInvoked(final SwInterfaceAddDelAddress expected, + final SwInterfaceAddDelAddress actual) throws + VppInvocationException { + assertArrayEquals(expected.address, actual.address); + assertEquals(expected.addressLength, actual.addressLength); + assertEquals(expected.delAll, actual.delAll); + assertEquals(expected.isAdd, actual.isAdd); + assertEquals(expected.isIpv6, actual.isIpv6); + assertEquals(expected.swIfIndex, actual.swIfIndex); + } + + @Test + public void testAddPrefixLengthIpv4Address() throws Exception { + final InstanceIdentifier
id = getAddressId(IFACE_NAME); + + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); + Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); + + ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + whenSwInterfaceAddDelAddressThenSuccess(); + + customizer.writeCurrentAttributes(id, data, writeContext); + + verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, + (byte) 1, (byte) 24)); + } + + @Test + public void testAddPrefixLengthIpv4AddressFailed() throws Exception { + final InstanceIdentifier
id = getAddressId(IFACE_NAME); + + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); + Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); + + ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + whenSwInterfaceAddDelAddressThenFailure(); + + try { + customizer.writeCurrentAttributes(id, data, writeContext); + } catch (WriteFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifySwInterfaceAddDelAddressWasInvoked( + generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, + (byte) 1, (byte) 24)); + return; + } + fail("WriteFailedException was expected"); + } + + private SwInterfaceAddDelAddress generateSwInterfaceAddDelAddressRequest(final byte[] address, final byte isAdd, + final byte prefixLength) { + final SwInterfaceAddDelAddress request = new SwInterfaceAddDelAddress(); + request.swIfIndex = IFACE_ID; + request.isAdd = isAdd; + request.isIpv6 = 0; + request.delAll = 0; + request.addressLength = prefixLength; + request.address = address; + return request; + } + + @Test + public void testDeletePrefixLengthIpv4Address() throws Exception { + final InstanceIdentifier
id = getAddressId(IFACE_NAME); + + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); + Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); + + ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + whenSwInterfaceAddDelAddressThenSuccess(); + + customizer.deleteCurrentAttributes(id, data, writeContext); + + verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, + (byte) 0, (byte) 24)); + } + + @Test + public void testDeletePrefixLengthIpv4AddressFailed() throws Exception { + final InstanceIdentifier
id = getAddressId(IFACE_NAME); + + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); + Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); + + ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + whenSwInterfaceAddDelAddressThenFailure(); + + try { + customizer.deleteCurrentAttributes(id, data, writeContext); + } catch (WriteFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifySwInterfaceAddDelAddressWasInvoked( + generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, + (byte) 0, (byte) 24)); + return; + } + fail("WriteFailedException was expec16ted"); + } + + private void testSingleNetmask(final int expectedPrefixLength, final String stringMask) throws Exception { + final InstanceIdentifier
id = getAddressId(IFACE_NAME); + + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + Netmask subnet = new NetmaskBuilder().setNetmask(new DottedQuad(stringMask)).build(); + Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(subnet).build(); + + ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + + final CompletableFuture replyFuture = new CompletableFuture<>(); + replyFuture.complete(new SwInterfaceAddDelAddressReply()); + ArgumentCaptor argumentCaptor = + ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class); + doReturn(replyFuture).when(api).swInterfaceAddDelAddress(argumentCaptor.capture()); + + customizer.writeCurrentAttributes(id, data, writeContext); + + verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, + (byte) 1, (byte) expectedPrefixLength), argumentCaptor.getValue()); + } + + private void testSingleIllegalNetmask(final String stringMask) throws Exception { + try { + final InstanceIdentifier
id = getAddressId(IFACE_NAME); + + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + Netmask subnet = new NetmaskBuilder().setNetmask(new DottedQuad(stringMask)).build(); + Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(subnet).build(); + + ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + + final CompletableFuture replyFuture = new CompletableFuture<>(); + replyFuture.complete(new SwInterfaceAddDelAddressReply()); + ArgumentCaptor argumentCaptor = + ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class); + doReturn(replyFuture).when(api).swInterfaceAddDelAddress(argumentCaptor.capture()); + + customizer.writeCurrentAttributes(id, data, writeContext); + } catch (IllegalArgumentException e) { + return; + } + fail("IllegalArgumentException expected"); + + } + + /** + * Test contiguous netmask length from QuadDotted notation + */ + @Test + public void testNetmaskLength() throws Exception { + testSingleNetmask(1, "128.0.0.0"); + testSingleNetmask(2, "192.0.0.0"); + testSingleNetmask(8, "255.0.0.0"); + testSingleNetmask(9, "255.128.0.0"); + testSingleNetmask(16, "255.255.0.0"); + testSingleNetmask(24, "255.255.255.0"); + } + + @Test + public void testNetmaskIllegal() throws Exception { + testSingleIllegalNetmask(""); + testSingleIllegalNetmask("."); + testSingleIllegalNetmask(".255"); + testSingleIllegalNetmask("255"); + testSingleIllegalNetmask("255."); + testSingleIllegalNetmask("255.255"); + testSingleIllegalNetmask("255.255.0"); + testSingleIllegalNetmask("255.255.255."); + testSingleIllegalNetmask("255.255.255.256"); + testSingleIllegalNetmask("0.0.0.0"); + testSingleIllegalNetmask("10.10.10.10"); + testSingleIllegalNetmask("255.1.255.0"); + testSingleIllegalNetmask("255.255.255.255"); + } + +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizerTest.java new file mode 100644 index 000000000..27ab352cf --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizerTest.java @@ -0,0 +1,147 @@ +/* + * 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.translate.v3po.interfaces.ip; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.common.base.Optional; +import com.google.common.io.BaseEncoding; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletableFuture; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Neighbor; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.NeighborBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.IpNeighborAddDel; +import org.openvpp.jvpp.dto.IpNeighborAddDelReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class Ipv4NeighbourCustomizerTest { + + @Mock + private FutureJVpp jvpp; + + @Mock + private WriteContext context; + + @Mock + private MappingContext mappingContext; + + @Mock + private Mapping mapping; + + private ArgumentCaptor requestCaptor; + private Ipv4NeighbourCustomizer customizer; + private NamingContext namingContext; + + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + + namingContext = new NamingContext("prefix", "instance"); + namingContext.addName(5, "parent", mappingContext); + + customizer = new Ipv4NeighbourCustomizer(jvpp,namingContext); + + requestCaptor = ArgumentCaptor.forClass(IpNeighborAddDel.class); + + CompletableFuture future = new CompletableFuture<>(); + future.complete(new IpNeighborAddDelReply()); + + when(context.getMappingContext()).thenReturn(mappingContext); + when(mapping.getIndex()).thenReturn(5); + when(mapping.getName()).thenReturn("parent"); + when(mappingContext.read(Mockito.any())).thenReturn(Optional.fromNullable(mapping)); + when(jvpp.ipNeighborAddDel(Mockito.any(IpNeighborAddDel.class))).thenReturn(future); + } + + @Test + public void testWriteCurrentAttributes() throws WriteFailedException { + + InterfaceKey intfKey = new InterfaceKey("parent"); + + InstanceIdentifier id = InstanceIdentifier.builder(Interfaces.class).child(Interface.class, intfKey) + .augmentation(Interface1.class).child(Ipv4.class).child(Neighbor.class).build(); + + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + PhysAddress mac = new PhysAddress("aa:bb:cc:ee:11:22"); + + Neighbor data = new NeighborBuilder().setIp(noZoneIp).setLinkLayerAddress(mac).build(); + + customizer.writeCurrentAttributes(id, data, context); + + verify(jvpp, times(1)).ipNeighborAddDel(requestCaptor.capture()); + + IpNeighborAddDel request = requestCaptor.getValue(); + + assertEquals(0, request.isIpv6); + assertEquals(1, request.isAdd); + assertEquals(1, request.isStatic); + assertEquals("1.2.168.192", TranslateUtils.arrayToIpv4AddressNoZone(request.dstAddress).getValue()); + assertEquals("aabbccee1122", BaseEncoding.base16().lowerCase().encode(request.macAddress)); + assertEquals(5, request.swIfIndex); + } + + @Test + public void testDeleteCurrentAttributes() throws WriteFailedException { + InterfaceKey intfKey = new InterfaceKey("parent"); + + InstanceIdentifier id = InstanceIdentifier.builder(Interfaces.class).child(Interface.class, intfKey) + .augmentation(Interface1.class).child(Ipv4.class).child(Neighbor.class).build(); + + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + PhysAddress mac = new PhysAddress("aa:bb:cc:ee:11:22"); + + Neighbor data = new NeighborBuilder().setIp(noZoneIp).setLinkLayerAddress(mac).build(); + + customizer.deleteCurrentAttributes(id, data, context); + + verify(jvpp, times(1)).ipNeighborAddDel(requestCaptor.capture()); + + IpNeighborAddDel request = requestCaptor.getValue(); + + assertEquals(0, request.isIpv6); + assertEquals(0, request.isAdd); + assertEquals(1, request.isStatic); + assertEquals("1.2.168.192", TranslateUtils.arrayToIpv4AddressNoZone(request.dstAddress).getValue()); + assertEquals("aabbccee1122", BaseEncoding.base16().lowerCase().encode(request.macAddress)); + assertEquals(5, request.swIfIndex); + } + +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizerTest.java new file mode 100644 index 000000000..f36e49727 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/AclCustomizerTest.java @@ -0,0 +1,132 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.test.ReaderCustomizerTest; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2AclBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.AclBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.openvpp.jvpp.dto.ClassifyTableByInterface; +import org.openvpp.jvpp.dto.ClassifyTableByInterfaceReply; + +public class AclCustomizerTest extends ReaderCustomizerTest { + + private static final String IF_NAME = "local0"; + private static final int IF_INDEX = 1; + private static final int TABLE_INDEX = 123; + private static final String TABLE_NAME = "table123"; + + private static final String IFC_TEST_INSTANCE = "ifc-test-instance"; + private static final String CT_TEST_INSTANCE = "ct-test-instance"; + + private NamingContext interfaceContext; + private NamingContext classifyTableContext; + + public AclCustomizerTest() { + super(Acl.class); + } + + @Override + public void setUpBefore() { + interfaceContext = new NamingContext("generatedIfaceName", IFC_TEST_INSTANCE); + classifyTableContext = new NamingContext("generatedTableContext", CT_TEST_INSTANCE); + + final KeyedInstanceIdentifier ifcMappingKey = ContextTestUtils + .getMappingIid(IF_NAME, IFC_TEST_INSTANCE); + final Optional ifcMapping = ContextTestUtils.getMapping(IF_NAME, IF_INDEX); + doReturn(ifcMapping).when(mappingContext).read(ifcMappingKey); + + final KeyedInstanceIdentifier ctMappingKey = ContextTestUtils + .getMappingIid(TABLE_NAME, CT_TEST_INSTANCE); + final Optional ctMapping = ContextTestUtils.getMapping(TABLE_NAME, TABLE_INDEX); + doReturn(ctMapping).when(mappingContext).read(ctMappingKey); + + final List allCtMappings = Lists.newArrayList(ctMapping.get()); + final Mappings allCtMappingsBaObject = new MappingsBuilder().setMapping(allCtMappings).build(); + doReturn(Optional.of(allCtMappingsBaObject)).when(mappingContext) + .read(ctMappingKey.firstIdentifierOf(Mappings.class)); + + final List allIfcMappings = Lists.newArrayList(ifcMapping.get()); + final Mappings allIfcMappingsBaObject = new MappingsBuilder().setMapping(allIfcMappings).build(); + doReturn(Optional.of(allIfcMappingsBaObject)).when(mappingContext) + .read(ifcMappingKey.firstIdentifierOf(Mappings.class)); + } + + @Override + protected ReaderCustomizer initCustomizer() { + return new AclCustomizer(api, interfaceContext, classifyTableContext); + } + + @Test + public void testMerge() { + final VppInterfaceStateAugmentationBuilder builder = mock(VppInterfaceStateAugmentationBuilder.class); + final Acl value = mock(Acl.class); + getCustomizer().merge(builder, value); + verify(builder).setAcl(value); + } + + private InstanceIdentifier getAclId(final String name) { + return InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey(name)) + .augmentation( + VppInterfaceStateAugmentation.class).child(Acl.class); + } + + @Test + public void testRead() throws Exception { + final InstanceIdentifier id = getAclId(IF_NAME); + final AclBuilder builder = mock(AclBuilder.class); + + final CompletableFuture replyFuture = new CompletableFuture<>(); + final ClassifyTableByInterfaceReply reply = new ClassifyTableByInterfaceReply(); + reply.l2TableId = TABLE_INDEX; + reply.ip4TableId = ~0; + reply.ip6TableId = ~0; + replyFuture.complete(reply); + doReturn(replyFuture).when(api).classifyTableByInterface(any(ClassifyTableByInterface.class)); + + getCustomizer().readCurrentAttributes(id, builder, ctx); + + verify(builder).setL2Acl(new L2AclBuilder().setClassifyTable(TABLE_NAME).build()); + verify(builder).setIp4Acl(null); + verify(builder).setIp6Acl(null); + } + +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizerTest.java new file mode 100644 index 000000000..8bde1ac32 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceCustomizerTest.java @@ -0,0 +1,212 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.test.InterfaceTestUtils; +import io.fd.honeycomb.translate.v3po.test.ListReaderCustomizerTest; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.openvpp.jvpp.VppInvocationException; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.dto.SwInterfaceDump; + +public class InterfaceCustomizerTest extends + ListReaderCustomizerTest { + + private NamingContext interfacesContext; + + public InterfaceCustomizerTest() { + super(Interface.class); + } + + @Override + public void setUpBefore() { + interfacesContext = new NamingContext("generatedIfaceName", "test-instance"); + } + + @Override + protected ReaderCustomizer initCustomizer() { + final KeyedInstanceIdentifier eth0Id = ContextTestUtils + .getMappingIid("eth0", "test-instance"); + final KeyedInstanceIdentifier eth1Id = ContextTestUtils + .getMappingIid("eth1", "test-instance"); + final KeyedInstanceIdentifier subEth1Id = ContextTestUtils + .getMappingIid("eth1.1", "test-instance"); + final Optional eth0 = ContextTestUtils.getMapping("eth0", 0); + final Optional eth1 = ContextTestUtils.getMapping("eth1", 1); + final Optional subEth1 = ContextTestUtils.getMapping("eth1.1", 2); + + final List allMappings = + Lists.newArrayList(ContextTestUtils.getMapping("eth0", 0).get(), ContextTestUtils.getMapping("eth1", 1).get(), ContextTestUtils + .getMapping("eth1.1", 2).get()); + final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); + doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(eth0Id.firstIdentifierOf(Mappings.class)); + + doReturn(eth0).when(mappingContext).read(eth0Id); + doReturn(eth1).when(mappingContext).read(eth1Id); + doReturn(subEth1).when(mappingContext).read(subEth1Id); + + return new InterfaceCustomizer(api, interfacesContext); + } + + // TODO use reflexion and move to ListReaderCustomizerTest + @Test + public void testMerge() throws Exception { + final InterfacesStateBuilder builder = mock(InterfacesStateBuilder.class); + final List value = Collections.emptyList(); + getCustomizer().merge(builder, value); + verify(builder).setInterface(value); + } + + private void verifySwInterfaceDumpWasInvoked(final int nameFilterValid, final String ifaceName, + final int dumpIfcsInvocationCount) + throws VppInvocationException { + // TODO adding equals methods for jvpp DTOs would make ArgumentCaptor usage obsolete + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(SwInterfaceDump.class); + verify(api, times(dumpIfcsInvocationCount)).swInterfaceDump(argumentCaptor.capture()); + final SwInterfaceDump actual = argumentCaptor.getValue(); + assertEquals(nameFilterValid, actual.nameFilterValid); + assertArrayEquals(ifaceName.getBytes(), actual.nameFilter); + } + + private static void assertIfacesAreEqual(final Interface iface, final SwInterfaceDetails details) { + assertEquals(iface.getName(), new String(details.interfaceName)); + Assert.assertEquals(InterfaceUtils.yangIfIndexToVpp(iface.getIfIndex().intValue()), details.swIfIndex); + assertEquals(iface.getPhysAddress().getValue(), InterfaceUtils.vppPhysAddrToYang(details.l2Address)); + } + + @Test + public void testReadCurrentAttributes() throws Exception { + final String ifaceName = "eth0"; + final InstanceIdentifier id = InstanceIdentifier.create(InterfacesState.class) + .child(Interface.class, new InterfaceKey(ifaceName)); + final InterfaceBuilder builder = getCustomizer().getBuilder(id); + + final SwInterfaceDetails iface = new SwInterfaceDetails(); + iface.interfaceName = ifaceName.getBytes(); + iface.swIfIndex = 0; + iface.linkSpeed = 1; + iface.l2AddressLength = 6; + iface.l2Address = new byte[iface.l2AddressLength]; + final List interfaceList = Collections.singletonList(iface); + InterfaceTestUtils.whenSwInterfaceDumpThenReturn(api, interfaceList); + + getCustomizer().readCurrentAttributes(id, builder, ctx); + + verifySwInterfaceDumpWasInvoked(1, ifaceName, 1); + assertIfacesAreEqual(builder.build(), iface); + } + + @Test + public void testReadCurrentAttributesFailed() throws Exception { + final String ifaceName = "eth0"; + final InstanceIdentifier id = InstanceIdentifier.create(InterfacesState.class) + .child(Interface.class, new InterfaceKey(ifaceName)); + final InterfaceBuilder builder = getCustomizer().getBuilder(id); + + InterfaceTestUtils.whenSwInterfaceDumpThenReturn(api, Collections.emptyList()); + + try { + getCustomizer().readCurrentAttributes(id, builder, ctx); + } catch (IllegalArgumentException e) { + verifySwInterfaceDumpWasInvoked(0, ifaceName, 2); + return; + } + + fail("ReadFailedException was expected"); + } + + @Test + public void testReadSubInterface() throws Exception { + final String ifaceName = "eth1.1"; + final InstanceIdentifier id = InstanceIdentifier.create(InterfacesState.class) + .child(Interface.class, new InterfaceKey(ifaceName)); + final InterfaceBuilder builder = mock(InterfaceBuilder.class); + + final SwInterfaceDetails iface = new SwInterfaceDetails(); + iface.interfaceName = ifaceName.getBytes(); + iface.swIfIndex = 2; + iface.supSwIfIndex = 1; + iface.subId = 1; + final List interfaceList = Collections.singletonList(iface); + InterfaceTestUtils.whenSwInterfaceDumpThenReturn(api, interfaceList); + + getCustomizer().readCurrentAttributes(id, builder, ctx); + + verifySwInterfaceDumpWasInvoked(1, ifaceName, 1); + verifyZeroInteractions(builder); + } + + @Test + public void testGetAllIds() throws Exception { + final InstanceIdentifier id = InstanceIdentifier.create(InterfacesState.class) + .child(Interface.class); + + final String swIf0Name = "eth0"; + final SwInterfaceDetails swIf0 = new SwInterfaceDetails(); + swIf0.swIfIndex = 0; + swIf0.interfaceName = swIf0Name.getBytes(); + final String swIf1Name = "eth1"; + final SwInterfaceDetails swIf1 = new SwInterfaceDetails(); + swIf1.swIfIndex = 1; + swIf1.interfaceName = swIf1Name.getBytes(); + final String swSubIf1Name = "eth1.1"; + final SwInterfaceDetails swSubIf1 = new SwInterfaceDetails(); + swSubIf1.swIfIndex = 2; + swSubIf1.subId = 1; + swSubIf1.supSwIfIndex = 1; + swSubIf1.interfaceName = swSubIf1Name.getBytes(); + InterfaceTestUtils.whenSwInterfaceDumpThenReturn(api, Arrays.asList(swIf0, swIf1, swSubIf1)); + + final List expectedIds = Arrays.asList(new InterfaceKey(swIf0Name), new InterfaceKey(swIf1Name)); + final List actualIds = getCustomizer().getAllIds(id, ctx); + + verifySwInterfaceDumpWasInvoked(0, "", 1); + + // sub-interface should not be on the list + assertEquals(expectedIds, actualIds); + } +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtilsTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtilsTest.java new file mode 100644 index 000000000..c74e1ccfb --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/InterfaceUtilsTest.java @@ -0,0 +1,55 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; + +public class InterfaceUtilsTest { + + @Test + public void testVppPhysAddrToYang() throws Exception { + assertEquals("01:02:03:04:05:06", InterfaceUtils.vppPhysAddrToYang(new byte[]{1, 2, 3, 4, 5, 6})); + assertEquals("0a:0b:0c:0d:0e:0f", InterfaceUtils.vppPhysAddrToYang(new byte[]{0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0})); + } + + @Test(expected = NullPointerException.class) + public void testVppPhysAddrToYangFailNullArgument() throws Exception { + InterfaceUtils.vppPhysAddrToYang(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testVppPhysAddrToYangInvalidByteArrayLength() throws Exception { + InterfaceUtils.vppPhysAddrToYang(new byte[]{1, 2, 3, 4, 5}); + } + + @Test + public void testGetInterfaceType() { + assertEquals(Tap.class, InterfaceUtils.getInterfaceType("tap0")); + assertEquals(VxlanTunnel.class, InterfaceUtils.getInterfaceType("vxlan0")); + assertEquals(VxlanGpeTunnel.class, InterfaceUtils.getInterfaceType("vxlan_gpe0")); + assertEquals(VhostUser.class, InterfaceUtils.getInterfaceType("VirtualEthernet0/0/0")); + assertEquals(EthernetCsmacd.class, InterfaceUtils.getInterfaceType("eth0.0")); + assertEquals(EthernetCsmacd.class, InterfaceUtils.getInterfaceType("local0")); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2CustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2CustomizerTest.java new file mode 100644 index 000000000..ecd32c6d1 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/L2CustomizerTest.java @@ -0,0 +1,179 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.test.ReaderCustomizerTest; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.openvpp.jvpp.VppInvocationException; +import org.openvpp.jvpp.dto.BridgeDomainDetails; +import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump; +import org.openvpp.jvpp.dto.BridgeDomainDump; +import org.openvpp.jvpp.dto.BridgeDomainSwIfDetails; +import org.openvpp.jvpp.dto.SwInterfaceDetails; + +public class L2CustomizerTest extends ReaderCustomizerTest { + + private NamingContext interfaceContext; + private NamingContext bridgeDomainContext; + + public L2CustomizerTest() { + super(L2.class); + } + + @Override + public void setUpBefore() { + interfaceContext = new NamingContext("generatedIfaceName", "ifc-test-instance"); + bridgeDomainContext = new NamingContext("generatedBDName", "bd-test-instance"); + } + + @Override + protected ReaderCustomizer initCustomizer() { + return new L2Customizer(api, interfaceContext, bridgeDomainContext); + } + + @Test + public void testMerge() { + final VppInterfaceStateAugmentationBuilder builder = mock(VppInterfaceStateAugmentationBuilder.class); + final L2 value = mock(L2.class); + getCustomizer().merge(builder, value); + verify(builder).setL2(value); + } + + private InstanceIdentifier getL2Id(final String name) { + return InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey(name)) + .augmentation( + VppInterfaceStateAugmentation.class).child(L2.class); + } + + private void whenBridgeDomainSwIfDumpThenReturn(final List bdSwIfList, + final List bridgeDomainDetailses) + throws ExecutionException, InterruptedException, VppInvocationException { + final BridgeDomainDetailsReplyDump reply = new BridgeDomainDetailsReplyDump(); + reply.bridgeDomainSwIfDetails = bdSwIfList; + reply.bridgeDomainDetails = bridgeDomainDetailses; + + final CompletableFuture replyFuture = new CompletableFuture<>(); + replyFuture.complete(reply); + when(api.bridgeDomainSwIfDump(any(BridgeDomainDump.class))).thenReturn(replyFuture); + } + + + private BridgeDomainSwIfDetails generateBdSwIfDetails(final int ifId, final int bdId) { + final BridgeDomainSwIfDetails bdSwIfDetails = new BridgeDomainSwIfDetails(); + bdSwIfDetails.swIfIndex = ifId; + bdSwIfDetails.shg = 1; + bdSwIfDetails.bdId = bdId; + return bdSwIfDetails; + } + + private Interconnection generateInterconnection(final int ifId, final String bdName, final Boolean bvi) { + final BridgeBasedBuilder bbBuilder = new BridgeBasedBuilder(); + bbBuilder.setBridgeDomain(bdName); + bbBuilder.setSplitHorizonGroup((short) 1); + if (bvi != null) { + bbBuilder.setBridgedVirtualInterface(bvi); + } else { + bbBuilder.setBridgedVirtualInterface(false); // false is default + } + return bbBuilder.build(); + } + + @Test + public void testRead() throws Exception { + final Map cachedInterfaceDump = new HashMap<>(); + final int ifId = 1; + final int bdId = 1; + final String bdName = "bd001"; + final String ifName = "eth0.sub0"; + final KeyedInstanceIdentifier ifcIid = ContextTestUtils + .getMappingIid(ifName, "ifc-test-instance"); + doReturn(ContextTestUtils.getMapping(ifName, ifId)).when(mappingContext).read(ifcIid); + final KeyedInstanceIdentifier bdIid = ContextTestUtils + .getMappingIid(bdName, "bd-test-instance"); + doReturn(ContextTestUtils.getMapping(bdName, bdId)).when(mappingContext).read(bdIid); + + List allMappings = Lists.newArrayList(ContextTestUtils.getMapping(ifName, ifId).get()); + Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); + doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(ifcIid.firstIdentifierOf(Mappings.class)); + + allMappings = Lists.newArrayList(ContextTestUtils.getMapping(bdName, bdId).get()); + allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); + doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(bdIid.firstIdentifierOf(Mappings.class)); + + final SwInterfaceDetails ifaceDetails = new SwInterfaceDetails(); + ifaceDetails.subId = ifId; + cachedInterfaceDump.put(ifId, ifaceDetails); + cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump); + + // BVI + whenBridgeDomainSwIfDumpThenReturn(Collections.singletonList(generateBdSwIfDetails(ifId, bdId)), + Collections.singletonList(generateBdDetails(ifId, bdId))); + + L2Builder builder = mock(L2Builder.class); + getCustomizer().readCurrentAttributes(getL2Id(ifName), builder, ctx); + + verify(builder).setInterconnection(generateInterconnection(ifId, bdName, true)); + + // Not BVI + whenBridgeDomainSwIfDumpThenReturn(Collections.singletonList(generateBdSwIfDetails(ifId, bdId)), + Collections.singletonList(generateBdDetails(99 /* Different ifc is marked as BVI in bd details */, bdId))); + + builder = mock(L2Builder.class); + getCustomizer().readCurrentAttributes(getL2Id(ifName), builder, ctx); + + verify(builder).setInterconnection(generateInterconnection(ifId, bdName, null)); + } + + private BridgeDomainDetails generateBdDetails(final int ifId, final int bdId) { + final BridgeDomainDetails bridgeDomainDetails = new BridgeDomainDetails(); + bridgeDomainDetails.bviSwIfIndex = ifId; + bridgeDomainDetails.bdId = bdId; + return bridgeDomainDetails; + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizerTest.java new file mode 100644 index 000000000..ec0851d9c --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/RewriteCustomizerTest.java @@ -0,0 +1,127 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.test.ReaderCustomizerTest; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TagRewriteOperation; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1q; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfaces; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTags; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.SwInterfaceDetails; + +public class RewriteCustomizerTest extends ReaderCustomizerTest { + + public static final String VLAN_IF_NAME = "local0.1"; + public static final int VLAN_IF_ID = 1; + public static final int VLAN_IF_INDEX = 11; + + private NamingContext interfacesContext; + + @Captor + private ArgumentCaptor> captor; + + public RewriteCustomizerTest() { + super(Rewrite.class); + } + + @Override + public void setUpBefore() { + interfacesContext = new NamingContext("generatedIfaceName", "test-instance"); + + final Optional ifcMapping = ContextTestUtils.getMapping(VLAN_IF_NAME, VLAN_IF_INDEX); + doReturn(ifcMapping).when(mappingContext).read(any()); + } + + @Override + protected ReaderCustomizer initCustomizer() { + return new RewriteCustomizer(api, interfacesContext); + } + + @Test + public void testMerge() { + final L2Builder builder = mock(L2Builder.class); + final Rewrite value = mock(Rewrite.class); + getCustomizer().merge(builder, value); + verify(builder).setRewrite(value); + } + + private InstanceIdentifier getVlanTagRewriteId(final String name, final long index) { + final Class> child = (Class)Rewrite.class; + final InstanceIdentifier id = + InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey(name)).augmentation( + SubinterfaceStateAugmentation.class).child(SubInterfaces.class) + .child(SubInterface.class, new SubInterfaceKey(index)) + .child(child); + return id; + } + + @Test + public void testRead() throws ReadFailedException { + final Map cachedInterfaceDump = new HashMap<>(); + + final SwInterfaceDetails ifaceDetails = new SwInterfaceDetails(); + ifaceDetails.subId = VLAN_IF_ID; + ifaceDetails.interfaceName = VLAN_IF_NAME.getBytes(); + ifaceDetails.vtrOp = TagRewriteOperation.translate_2_to_2.ordinal(); + ifaceDetails.subNumberOfTags = 2; + ifaceDetails.vtrTag1 = 123; + ifaceDetails.vtrTag2 = 321; + ifaceDetails.vtrPushDot1Q = 1; + cachedInterfaceDump.put(VLAN_IF_INDEX, ifaceDetails); + cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump); + + final RewriteBuilder builder = mock(RewriteBuilder.class); + + getCustomizer().readCurrentAttributes(getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID), builder, ctx); + + verify(builder).setVlanType(_802dot1q.class); + verify(builder).setPopTags((short) 2); + + verify(builder).setPushTags(captor.capture()); + final List tags = captor.getValue(); + assertEquals(ifaceDetails.subNumberOfTags, tags.size()); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizerTest.java new file mode 100644 index 000000000..b93c9f42a --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/SubInterfaceCustomizerTest.java @@ -0,0 +1,146 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.test.InterfaceTestUtils; +import io.fd.honeycomb.translate.v3po.test.ListReaderCustomizerTest; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfaces; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfacesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.VlanTagged; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.SwInterfaceDetails; + +public class SubInterfaceCustomizerTest extends + ListReaderCustomizerTest { + + public static final String SUPER_IF_NAME = "local0"; + public static final int SUPER_IF_INDEX = 1; + public static final String VLAN_IF_NAME = "local0.1"; + public static final int VLAN_IF_ID = 1; + public static final int VLAN_IF_INDEX = 11; + + private NamingContext interfacesContext; + + public SubInterfaceCustomizerTest() { + super(SubInterface.class); + } + + @Override + public void setUpBefore() { + interfacesContext = new NamingContext("generatedIfaceName", "test-instance"); + } + + @Override + protected ReaderCustomizer initCustomizer() { + return new SubInterfaceCustomizer(api, interfacesContext); + } + + private InstanceIdentifier getSubInterfaceId(final String name, final long id) { + return InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey(name)).augmentation( + SubinterfaceStateAugmentation.class).child( + SubInterfaces.class).child(SubInterface.class, new SubInterfaceKey(id)); + } + + @Test + public void testMerge() { + final SubInterfacesBuilder builder = mock(SubInterfacesBuilder.class); + final List value = mock(List.class); + getCustomizer().merge(builder, value); + verify(builder).setSubInterface(value); + } + + @Test + public void testRead() throws ReadFailedException { + final Optional ifcMapping = ContextTestUtils.getMapping(VLAN_IF_NAME, VLAN_IF_INDEX); + doReturn(ifcMapping).when(mappingContext).read(any()); + + final Map cachedInterfaceDump = new HashMap<>(); + + final SwInterfaceDetails ifaceDetails = new SwInterfaceDetails(); + ifaceDetails.subId = VLAN_IF_ID; + ifaceDetails.interfaceName = VLAN_IF_NAME.getBytes(); + ifaceDetails.subDot1Ad = 1; + ifaceDetails.subNumberOfTags = 2; + ifaceDetails.subOuterVlanIdAny = 1; + ifaceDetails.subInnerVlanIdAny = 1; + ifaceDetails.subExactMatch = 1; + cachedInterfaceDump.put(VLAN_IF_INDEX, ifaceDetails); + cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump); + + final SubInterfaceBuilder builder = mock(SubInterfaceBuilder.class); + getCustomizer().readCurrentAttributes(getSubInterfaceId(VLAN_IF_NAME, VLAN_IF_ID), builder, ctx); + + verify(builder).setIdentifier((long) VLAN_IF_ID); + + ArgumentCaptor tagCaptor = ArgumentCaptor.forClass(Tags.class); + verify(builder).setTags(tagCaptor.capture()); + assertEquals(ifaceDetails.subNumberOfTags, tagCaptor.getValue().getTag().size()); + + ArgumentCaptor matchCaptor = ArgumentCaptor.forClass(Match.class); + verify(builder).setMatch(matchCaptor.capture()); + final VlanTagged matchType = (VlanTagged)matchCaptor.getValue().getMatchType(); + assertTrue(matchType.getVlanTagged().isMatchExactTags()); + } + + @Test + public void testGetAllIds() throws Exception { + final Optional ifcMapping = ContextTestUtils.getMapping(SUPER_IF_NAME, SUPER_IF_INDEX); + doReturn(ifcMapping).when(mappingContext).read(any()); + + final SwInterfaceDetails iface = new SwInterfaceDetails(); + iface.interfaceName = VLAN_IF_NAME.getBytes(); + iface.swIfIndex = VLAN_IF_INDEX; + iface.subId = VLAN_IF_ID; + iface.supSwIfIndex = SUPER_IF_INDEX; + final List ifaces = Collections.singletonList(iface); + InterfaceTestUtils.whenSwInterfaceDumpThenReturn(api, ifaces); + + final List allIds = + getCustomizer().getAllIds(getSubInterfaceId(VLAN_IF_NAME, VLAN_IF_ID), ctx); + + assertEquals(ifaces.size(), allIds.size()); + + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizerTest.java new file mode 100644 index 000000000..a5c1d3465 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanCustomizerTest.java @@ -0,0 +1,140 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import com.google.common.collect.Lists; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.test.ReaderCustomizerTest; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppInvocationException; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.dto.VxlanTunnelDetails; +import org.openvpp.jvpp.dto.VxlanTunnelDetailsReplyDump; +import org.openvpp.jvpp.dto.VxlanTunnelDump; + +public class VxlanCustomizerTest extends ReaderCustomizerTest { + + private NamingContext interfacesContext; + static final InstanceIdentifier IID = + InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey("ifc1")) + .augmentation(VppInterfaceStateAugmentation.class).child(Vxlan.class); + + public VxlanCustomizerTest() { + super(Vxlan.class); + } + + @Override + public void setUpBefore() { + interfacesContext = new NamingContext("vxlan-tunnel", "test-instance"); + doReturn(ContextTestUtils.getMapping("ifc1", 0)).when(mappingContext).read( + ContextTestUtils.getMappingIid("ifc1", "test-instance")); + + final SwInterfaceDetails v = new SwInterfaceDetails(); + v.interfaceName = "vxlan-tunnel4".getBytes(); + final Map map = new HashMap<>(); + map.put(0, v); + cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, map); + } + + @Override + protected void setUpAfter() throws UnknownHostException, VppInvocationException { + final CompletableFuture vxlanTunnelDetailsReplyDumpCompletionStage = + new CompletableFuture<>(); + + final VxlanTunnelDetailsReplyDump value = new VxlanTunnelDetailsReplyDump(); + final VxlanTunnelDetails vxlanTunnelDetails = new VxlanTunnelDetails(); + vxlanTunnelDetails.isIpv6 = 0; + vxlanTunnelDetails.decapNextIndex = 1; + vxlanTunnelDetails.dstAddress = InetAddress.getByName("1.2.3.4").getAddress(); + vxlanTunnelDetails.srcAddress = InetAddress.getByName("1.2.3.5").getAddress(); + vxlanTunnelDetails.encapVrfId = 55; + vxlanTunnelDetails.swIfIndex = 0; + vxlanTunnelDetails.vni = 9; + + value.vxlanTunnelDetails = Lists.newArrayList(vxlanTunnelDetails); + vxlanTunnelDetailsReplyDumpCompletionStage.complete(value); + + doReturn(vxlanTunnelDetailsReplyDumpCompletionStage).when(api).vxlanTunnelDump(any(VxlanTunnelDump.class)); + } + + @Test + public void testReadCurrentAttributes() throws Exception { + final VxlanBuilder builder = getCustomizer().getBuilder(IID); + getCustomizer().readCurrentAttributes(IID, builder, ctx); + + assertEquals(9, builder.getVni().getValue().intValue()); + assertEquals(55, builder.getEncapVrfId().intValue()); + + assertNull(builder.getSrc().getIpv6Address()); + assertNotNull(builder.getSrc().getIpv4Address()); + assertEquals("1.2.3.5", builder.getSrc().getIpv4Address().getValue()); + + assertNull(builder.getDst().getIpv6Address()); + assertNotNull(builder.getDst().getIpv4Address()); + assertEquals("1.2.3.4", builder.getDst().getIpv4Address().getValue()); + + verify(api).vxlanTunnelDump(any(VxlanTunnelDump.class)); + } + + @Test(expected = NullPointerException.class) + public void testReadCurrentAttributesVppNameNotCached() throws Exception { + InterfaceCustomizer.getCachedInterfaceDump(cache).remove(0); + + final VxlanBuilder builder = getCustomizer().getBuilder(IID); + getCustomizer().readCurrentAttributes(IID, builder, ctx); + } + + @Test + public void testReadCurrentAttributesWrongType() throws Exception { + final SwInterfaceDetails v = new SwInterfaceDetails(); + v.interfaceName = "tap-2".getBytes(); + InterfaceCustomizer.getCachedInterfaceDump(cache).put(0, v); + + final VxlanBuilder builder = getCustomizer().getBuilder(IID); + getCustomizer().readCurrentAttributes(IID, builder, ctx); + + // Should be ignored + verifyZeroInteractions(api); + } + + @Override + protected ReaderCustomizer initCustomizer() { + return new VxlanCustomizer(api, interfacesContext); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizerTest.java new file mode 100644 index 000000000..2569d8ae0 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/VxlanGpeCustomizerTest.java @@ -0,0 +1,285 @@ +/* + * 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.translate.v3po.interfacesstate; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import com.google.common.collect.Lists; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.test.ReaderCustomizerTest; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpeBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.dto.VxlanGpeTunnelDetails; +import org.openvpp.jvpp.dto.VxlanGpeTunnelDetailsReplyDump; +import org.openvpp.jvpp.dto.VxlanGpeTunnelDump; + +public class VxlanGpeCustomizerTest extends ReaderCustomizerTest { + + private NamingContext interfacesContext; + static final InstanceIdentifier VXLAN_GPE_ID = + InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey("ifc2")) + .augmentation(VppInterfaceStateAugmentation.class).child(VxlanGpe.class); + + public VxlanGpeCustomizerTest() { + super(VxlanGpe.class); + } + + @Override + public void setUpBefore() { + interfacesContext = new NamingContext("vxlan_gpe_inf", "test-instance"); + doReturn(ContextTestUtils.getMapping("ifc2", 0)).when(mappingContext).read( + ContextTestUtils.getMappingIid("ifc2", "test-instance")); + + final SwInterfaceDetails v = new SwInterfaceDetails(); + v.interfaceName = "vxlan_gpe_inf2".getBytes(); + final Map map = new HashMap<>(); + map.put(0, v); + cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, map); + } + + @Override + protected void setUpAfter() throws UnknownHostException, VppBaseCallException { + final CompletableFuture vxlanGpeTunnelDetailsReplyDumpCompletionStage = + new CompletableFuture<>(); + + final VxlanGpeTunnelDetailsReplyDump value = new VxlanGpeTunnelDetailsReplyDump(); + final VxlanGpeTunnelDetails vxlanGpeTunnelDetails = new VxlanGpeTunnelDetails(); + vxlanGpeTunnelDetails.isIpv6 = 0; + vxlanGpeTunnelDetails.local = InetAddress.getByName("1.2.3.4").getAddress(); + vxlanGpeTunnelDetails.remote = InetAddress.getByName("1.2.3.5").getAddress(); + vxlanGpeTunnelDetails.vni = 9; + vxlanGpeTunnelDetails.protocol = 1; + vxlanGpeTunnelDetails.encapVrfId = 55; + vxlanGpeTunnelDetails.decapVrfId = 66; + vxlanGpeTunnelDetails.swIfIndex = 0; + + value.vxlanGpeTunnelDetails = Lists.newArrayList(vxlanGpeTunnelDetails); + vxlanGpeTunnelDetailsReplyDumpCompletionStage.complete(value); + + doReturn(vxlanGpeTunnelDetailsReplyDumpCompletionStage).when(api).vxlanGpeTunnelDump(any(VxlanGpeTunnelDump.class)); + } + + @Test + public void testReadCurrentAttributes() throws Exception { + final VxlanGpeBuilder builder = getCustomizer().getBuilder(VXLAN_GPE_ID); + getCustomizer().readCurrentAttributes(VXLAN_GPE_ID, builder, ctx); + + assertNull(builder.getLocal().getIpv6Address()); + assertNotNull(builder.getLocal().getIpv4Address()); + assertEquals("1.2.3.4", builder.getLocal().getIpv4Address().getValue()); + + assertNull(builder.getRemote().getIpv6Address()); + assertNotNull(builder.getRemote().getIpv4Address()); + assertEquals("1.2.3.5", builder.getRemote().getIpv4Address().getValue()); + + assertEquals(9, builder.getVni().getValue().intValue()); + assertEquals(1, builder.getNextProtocol().getIntValue()); + assertEquals(55, builder.getEncapVrfId().intValue()); + assertEquals(66, builder.getDecapVrfId().intValue()); + + verify(api).vxlanGpeTunnelDump(any(VxlanGpeTunnelDump.class)); + } + + @Test(expected = NullPointerException.class) + public void testReadCurrentAttributesVppNameNotCached() throws Exception { + InterfaceCustomizer.getCachedInterfaceDump(cache).remove(0); + + final VxlanGpeBuilder builder = getCustomizer().getBuilder(VXLAN_GPE_ID); + getCustomizer().readCurrentAttributes(VXLAN_GPE_ID, builder, ctx); + } + + @Test + public void testReadCurrentAttributesWrongType() throws Exception { + final SwInterfaceDetails v = new SwInterfaceDetails(); + v.interfaceName = "tap-3".getBytes(); + InterfaceCustomizer.getCachedInterfaceDump(cache).put(0, v); + + final VxlanGpeBuilder builder = getCustomizer().getBuilder(VXLAN_GPE_ID); + getCustomizer().readCurrentAttributes(VXLAN_GPE_ID, builder, ctx); + + // Should be ignored + verifyZeroInteractions(api); + } + + @Override + protected ReaderCustomizer initCustomizer() { + return new VxlanGpeCustomizer(api, interfacesContext); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java new file mode 100644 index 000000000..e4814296d --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java @@ -0,0 +1,297 @@ +/* + * 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.translate.v3po.interfacesstate.ip; + +import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMapping; +import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMappingIid; +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.reverseBytes; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ListReaderCustomizerTest; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import org.hamcrest.CoreMatchers; +import org.junit.Test; +import org.mockito.Mockito; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.openvpp.jvpp.dto.IpAddressDetails; +import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; +import org.openvpp.jvpp.dto.IpAddressDump; + +public class Ipv4AddressCustomizerTest extends ListReaderCustomizerTest { + + private static final String IFACE_NAME = "eth0"; + private static final String IFACE_2_NAME = "eth1"; + private static final int IFACE_ID = 1; + private static final int IFACE_2_ID = 2; + + private NamingContext interfacesContext; + + public Ipv4AddressCustomizerTest() { + super(Address.class); + } + + @Override + public void setUpBefore() { + interfacesContext = new NamingContext("generatedIfaceName", "test-instance"); + } + + @Override + protected ReaderCustomizer initCustomizer() { + final KeyedInstanceIdentifier eth0Id = getMappingIid(IFACE_NAME, "test-instance"); + final KeyedInstanceIdentifier eth1Id = getMappingIid(IFACE_2_NAME, "test-instance"); + final Optional eth0 = getMapping(IFACE_NAME, IFACE_ID); + final Optional eth1 = getMapping(IFACE_2_NAME, IFACE_2_ID); + + final List allMappings = Lists.newArrayList(eth0.get(), eth1.get()); + final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); + doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(eth0Id.firstIdentifierOf(Mappings.class)); + + doReturn(eth0).when(mappingContext).read(eth0Id); + doReturn(eth1).when(mappingContext).read(eth1Id); + + return new Ipv4AddressCustomizer(api, interfacesContext); + } + + private static InstanceIdentifier
getId(final String address, final String ifaceName) { + return InstanceIdentifier.builder(InterfacesState.class) + .child(Interface.class, new InterfaceKey(ifaceName)) + .augmentation(Interface2.class) + .child(Ipv4.class) + .child(Address.class, new AddressKey(new Ipv4AddressNoZone(new Ipv4Address(address)))) + .build(); + } + + @Test + public void testReadCurrentAttributesFromCache() throws ReadFailedException { + ModificationCache cache = new ModificationCache(); + + IpAddressDetails detail1 = new IpAddressDetails(); + IpAddressDetails detail2 = new IpAddressDetails(); + IpAddressDetails detail3 = new IpAddressDetails(); + + detail1.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); + detail2.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); + detail3.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); + + IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); + reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); + + cache.put(Ipv4ReadUtils.CACHE_KEY + IFACE_NAME, reply); + when(ctx.getModificationCache()).thenReturn(cache); + + final AddressBuilder builder = new AddressBuilder(); + final InstanceIdentifier
id = getId("192.168.2.1", IFACE_NAME); + + getCustomizer().readCurrentAttributes(id, builder, ctx); + + assertEquals("192.168.2.1", builder.getIp().getValue()); + } + + @Test + public void testReadCurrentAttributesFor2Ifcs() throws ReadFailedException { + ModificationCache cache = new ModificationCache(); + + IpAddressDetails detail1 = new IpAddressDetails(); + IpAddressDetails detail2 = new IpAddressDetails(); + + detail1.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); + detail2.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); + + IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); + reply.ipAddressDetails = ImmutableList.of(detail1); + IpAddressDetailsReplyDump reply2 = new IpAddressDetailsReplyDump(); + reply2.ipAddressDetails = ImmutableList.of(detail2); + + CompletableFuture future = new CompletableFuture<>(); + future.complete(reply); + CompletableFuture future2 = new CompletableFuture<>(); + future2.complete(reply2); + + when(api.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future).thenReturn(future2); + when(ctx.getModificationCache()).thenReturn(cache); + + final InstanceIdentifier
id = getId("192.168.2.1", IFACE_NAME); + final InstanceIdentifier
id2 = getId("192.168.2.2", IFACE_2_NAME); + + final List ifc1Ids = getCustomizer().getAllIds(id, ctx); + assertThat(ifc1Ids.size(), is(1)); + assertThat(ifc1Ids, CoreMatchers.hasItem(new AddressKey(new Ipv4AddressNoZone("192.168.2.1")))); + final List ifc2Ids = getCustomizer().getAllIds(id2, ctx); + assertThat(ifc2Ids.size(), is(1)); + assertThat(ifc2Ids, CoreMatchers.hasItem(new AddressKey(new Ipv4AddressNoZone("192.168.2.2")))); + + AddressBuilder builder = new AddressBuilder(); + getCustomizer().readCurrentAttributes(id, builder, ctx); + assertEquals(builder.getIp().getValue(), "192.168.2.1"); + builder = new AddressBuilder(); + getCustomizer().readCurrentAttributes(id2, builder, ctx); + assertEquals(builder.getIp().getValue(), "192.168.2.2"); + } + + @Test + public void testReadCurrentAttributesFromOperationalData() throws ReadFailedException { + ModificationCache cache = new ModificationCache(); + + IpAddressDetails detail1 = new IpAddressDetails(); + IpAddressDetails detail2 = new IpAddressDetails(); + IpAddressDetails detail3 = new IpAddressDetails(); + + detail1.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); + detail2.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); + detail3.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); + + IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); + reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); + + CompletableFuture future = new CompletableFuture<>(); + future.complete(reply); + + when(api.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future); + when(ctx.getModificationCache()).thenReturn(cache); + + + final AddressBuilder builder = new AddressBuilder(); + final InstanceIdentifier
id = getId("192.168.2.1", IFACE_NAME); + + getCustomizer().readCurrentAttributes(id, builder, ctx); + + assertEquals("192.168.2.1", builder.getIp().getValue()); + } + + @Test + public void testGetAllIdsFromCache() throws ReadFailedException { + ModificationCache cache = new ModificationCache(); + + IpAddressDetails detail1 = new IpAddressDetails(); + IpAddressDetails detail2 = new IpAddressDetails(); + IpAddressDetails detail3 = new IpAddressDetails(); + + detail1.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); + detail2.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); + detail3.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); + + IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); + reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); + + cache.put(Ipv4ReadUtils.CACHE_KEY + IFACE_NAME, reply); + when(ctx.getModificationCache()).thenReturn(cache); + + final InstanceIdentifier
id = getId("192.168.2.1", IFACE_NAME); + + List ids = getCustomizer().getAllIds(id, ctx).stream() + .map(key -> key.getIp()) + .collect(Collectors.toList()); + + verify(api, times(0)).ipAddressDump(Mockito.any(IpAddressDump.class)); + assertEquals(3, ids.size()); + assertEquals(true, "192.168.2.1".equals(ids.get(0).getValue())); + assertEquals(true, "192.168.2.2".equals(ids.get(1).getValue())); + assertEquals(true, "192.168.2.3".equals(ids.get(2).getValue())); + } + + @Test + public void testGetAllIdsFromOperationalData() throws ReadFailedException { + ModificationCache cache = new ModificationCache(); + + IpAddressDetails detail1 = new IpAddressDetails(); + IpAddressDetails detail2 = new IpAddressDetails(); + IpAddressDetails detail3 = new IpAddressDetails(); + + detail1.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); + detail2.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); + detail3.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); + + IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); + reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); + + CompletableFuture future = new CompletableFuture<>(); + future.complete(reply); + + when(api.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future); + when(ctx.getModificationCache()).thenReturn(cache); + + final InstanceIdentifier
id = getId("192.168.2.1", IFACE_NAME); + + List ids = getCustomizer().getAllIds(id, ctx).stream() + .map(key -> key.getIp()) + .collect(Collectors.toList()); + + assertEquals(3, ids.size()); + assertEquals(true, "192.168.2.1".equals(ids.get(0).getValue())); + assertEquals(true, "192.168.2.2".equals(ids.get(1).getValue())); + assertEquals(true, "192.168.2.3".equals(ids.get(2).getValue())); + } + + @Test + public void testMerge() { + + Address address = new AddressBuilder().build(); + Ipv4Builder ipv4Builder = new Ipv4Builder(); + getCustomizer().merge(ipv4Builder, Arrays.asList(address)); + + assertEquals(1, ipv4Builder.getAddress().size()); + assertEquals(true, ipv4Builder.getAddress().contains(address)); + } + +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducerTest.java new file mode 100644 index 000000000..14b01193f --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/notification/InterfaceChangeNotificationProducerTest.java @@ -0,0 +1,130 @@ +/* + * 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.translate.v3po.notification; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import io.fd.honeycomb.notification.NotificationCollector; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.MappingContext; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStateChange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStatus; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.openvpp.jvpp.callback.SwInterfaceSetFlagsNotificationCallback; +import org.openvpp.jvpp.dto.SwInterfaceSetFlagsNotification; +import org.openvpp.jvpp.dto.WantInterfaceEvents; +import org.openvpp.jvpp.dto.WantInterfaceEventsReply; +import org.openvpp.jvpp.future.FutureJVpp; +import org.openvpp.jvpp.notification.NotificationRegistry; + +public class InterfaceChangeNotificationProducerTest { + + @Mock + private FutureJVpp jVpp; + private NamingContext namingContext = new NamingContext("test", "test-instance"); + @Mock + private MappingContext mappingContext; + @Mock + private NotificationCollector collector; + @Mock + private NotificationRegistry notificationRegistry; + @Mock + private AutoCloseable notificationListenerReg; + + private ArgumentCaptor callbackArgumentCaptor; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn(notificationRegistry).when(jVpp).getNotificationRegistry(); + callbackArgumentCaptor = ArgumentCaptor.forClass(SwInterfaceSetFlagsNotificationCallback.class); + doReturn(notificationListenerReg).when(notificationRegistry).registerSwInterfaceSetFlagsNotificationCallback( + callbackArgumentCaptor.capture()); + + final KeyedInstanceIdentifier eth0Id = ContextTestUtils + .getMappingIid("eth0", "test-instance"); + final Optional eth0 = ContextTestUtils.getMapping("eth0", 0); + + final List allMappings = Lists.newArrayList(ContextTestUtils.getMapping("eth0", 0).get()); + final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); + doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(eth0Id.firstIdentifierOf(Mappings.class)); + + doReturn(eth0).when(mappingContext).read(eth0Id); + } + + @Test + public void testStart() throws Exception { + final CompletableFuture response = new CompletableFuture<>(); + response.complete(new WantInterfaceEventsReply()); + doReturn(response).when(jVpp).wantInterfaceEvents(any(WantInterfaceEvents.class)); + final InterfaceChangeNotificationProducer interfaceChangeNotificationProducer = + new InterfaceChangeNotificationProducer(jVpp, namingContext, mappingContext); + + interfaceChangeNotificationProducer.start(collector); + verify(jVpp).wantInterfaceEvents(any(WantInterfaceEvents.class)); + verify(jVpp).getNotificationRegistry(); + verify(notificationRegistry).registerSwInterfaceSetFlagsNotificationCallback(any( + SwInterfaceSetFlagsNotificationCallback.class)); + + interfaceChangeNotificationProducer.stop(); + verify(jVpp, times(2)).wantInterfaceEvents(any(WantInterfaceEvents.class)); + verify(notificationListenerReg).close(); + } + + @Test + public void testNotification() throws Exception { + final CompletableFuture response = new CompletableFuture<>(); + response.complete(new WantInterfaceEventsReply()); + doReturn(response).when(jVpp).wantInterfaceEvents(any(WantInterfaceEvents.class)); + final InterfaceChangeNotificationProducer interfaceChangeNotificationProducer = + new InterfaceChangeNotificationProducer(jVpp, namingContext, mappingContext); + + interfaceChangeNotificationProducer.start(collector); + + final SwInterfaceSetFlagsNotification swInterfaceSetFlagsNotification = new SwInterfaceSetFlagsNotification(); + swInterfaceSetFlagsNotification.deleted = 0; + swInterfaceSetFlagsNotification.swIfIndex = 0; + swInterfaceSetFlagsNotification.adminUpDown = 1; + swInterfaceSetFlagsNotification.linkUpDown = 1; + + callbackArgumentCaptor.getValue().onSwInterfaceSetFlagsNotification(swInterfaceSetFlagsNotification); + final ArgumentCaptor notificationCaptor = + ArgumentCaptor.forClass(InterfaceStateChange.class); + verify(collector).onNotification(notificationCaptor.capture()); + + assertEquals("eth0", notificationCaptor.getValue().getName().getString()); + assertEquals(InterfaceStatus.Up, notificationCaptor.getValue().getAdminStatus()); + assertEquals(InterfaceStatus.Up, notificationCaptor.getValue().getOperStatus()); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ContextTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ContextTestUtils.java new file mode 100644 index 000000000..3b637a44c --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ContextTestUtils.java @@ -0,0 +1,70 @@ +/* + * 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.translate.v3po.test; + +import static org.mockito.Mockito.doReturn; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import io.fd.honeycomb.translate.MappingContext; +import java.util.List; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContextKey; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; + +public class ContextTestUtils { + + public static Optional getMapping(final String name, final int index) { + return Optional.of(new MappingBuilder().setName(name).setIndex(index).build()); + } + + public static KeyedInstanceIdentifier getMappingIid(final String name, + final String namingContextName) { + return InstanceIdentifier.create(Contexts.class).child( + org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.class, + new NamingContextKey(namingContextName)).child(Mappings.class).child(Mapping.class, new MappingKey(name)); + } + + public static void mockMapping(final MappingContext mappingContext, final String name, final int id, + final String namingContextName) { + final InstanceIdentifier mappingsIid = + getMappingIid(name, namingContextName).firstIdentifierOf(Mappings.class); + + final Optional singleMapping = getMapping(name, id); + final Optional previousMappings = mappingContext.read(mappingsIid); + + final MappingsBuilder mappingsBuilder; + if (previousMappings != null && previousMappings.isPresent()) { + mappingsBuilder = new MappingsBuilder(previousMappings.get()); + } else { + mappingsBuilder = new MappingsBuilder(); + mappingsBuilder.setMapping(Lists.newArrayList()); + } + + final List mappingList = mappingsBuilder.getMapping(); + mappingList.add(singleMapping.get()); + doReturn(Optional.of(mappingsBuilder.setMapping(mappingList).build())) + .when(mappingContext).read(mappingsIid); + doReturn(singleMapping).when(mappingContext).read(getMappingIid(name, namingContextName)); + } +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/InterfaceTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/InterfaceTestUtils.java new file mode 100644 index 000000000..08898bfed --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/InterfaceTestUtils.java @@ -0,0 +1,52 @@ +/* + * 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.translate.v3po.test; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.SwInterfaceDetails; +import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump; +import org.openvpp.jvpp.dto.SwInterfaceDump; +import org.openvpp.jvpp.future.FutureJVpp; + +public final class InterfaceTestUtils { + private InterfaceTestUtils() { + throw new UnsupportedOperationException("Utility class cannot be instantiated"); + } + + public static void whenSwInterfaceDumpThenReturn(final FutureJVpp api, final List interfaceList) + throws ExecutionException, InterruptedException, VppBaseCallException, TimeoutException { + final CompletionStage replyCS = mock(CompletionStage.class); + final CompletableFuture replyFuture = mock(CompletableFuture.class); + when(replyCS.toCompletableFuture()).thenReturn(replyFuture); + final SwInterfaceDetailsReplyDump reply = new SwInterfaceDetailsReplyDump(); + reply.swInterfaceDetails = interfaceList; + when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); + when(api.swInterfaceDump(any(SwInterfaceDump.class))).thenReturn(replyCS); + } +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ListReaderCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ListReaderCustomizerTest.java new file mode 100644 index 000000000..936e82c16 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ListReaderCustomizerTest.java @@ -0,0 +1,53 @@ +/* + * 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.translate.v3po.test; + +import static org.junit.Assert.assertNotNull; + +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import org.junit.Test; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifiable; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Generic test for classes implementing {@link ListReaderCustomizer} interface. + * + * @param Specific DataObject derived type (Identifiable), that is handled by this customizer + * @param Specific Identifier for handled type (D) + * @param Specific Builder for handled type (D) + */ +public abstract class ListReaderCustomizerTest, K extends Identifier, B extends Builder> extends + ReaderCustomizerTest { + + + protected ListReaderCustomizerTest(Class dataObjectClass) { + super(dataObjectClass); + } + + @Override + protected ListReaderCustomizer getCustomizer() { + return ListReaderCustomizer.class.cast(super.getCustomizer()); + } + + @Test + public void testGetBuilder() throws Exception { + assertNotNull(getCustomizer().getBuilder(InstanceIdentifier.create(dataObjectClass))); + } +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ReaderCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ReaderCustomizerTest.java new file mode 100644 index 000000000..170e53bfe --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/ReaderCustomizerTest.java @@ -0,0 +1,94 @@ +/* + * 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.translate.v3po.test; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.doReturn; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.ModificationCache; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; + +/** + * Generic test for classes implementing {@link ReaderCustomizer} interface. + * + * @param Specific DataObject derived type (Identifiable), that is handled by this customizer + * @param Specific Builder for handled type (D) + */ +public abstract class ReaderCustomizerTest> { + + @Mock + protected FutureJVpp api; + protected ModificationCache cache; + @Mock + protected ReadContext ctx; + @Mock + protected MappingContext mappingContext; + + protected final Class dataObjectClass; + private ReaderCustomizer customizer; + + protected ReaderCustomizerTest(Class dataObjectClass) { + this.dataObjectClass = dataObjectClass; + } + + @Before + public void setUpParent() throws Exception { + initMocks(this); + cache = new ModificationCache(); + doReturn(cache).when(ctx).getModificationCache(); + doReturn(mappingContext).when(ctx).getMappingContext(); + + setUpBefore(); + customizer = initCustomizer(); + setUpAfter(); + } + + /** + * Optional setup for subclasses. Invoked before customizer is initialized. + */ + protected void setUpBefore() { + + } + + /** + * Optional setup for subclasses. Invoked after customizer is initialized. + */ + protected void setUpAfter() throws Exception { + + } + + protected abstract ReaderCustomizer initCustomizer(); + + protected ReaderCustomizer getCustomizer() { + return customizer; + } + + @Test + public void testGetBuilder() throws Exception { + assertNotNull(customizer.getBuilder(InstanceIdentifier.create(dataObjectClass))); + } +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/TestHelperUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/TestHelperUtils.java new file mode 100644 index 000000000..4cf3a9b77 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/test/TestHelperUtils.java @@ -0,0 +1,37 @@ +/* + * 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.translate.v3po.test; + +import org.openvpp.jvpp.VppCallbackException; +import org.openvpp.jvpp.dto.JVppReply; + +import java.util.concurrent.CompletableFuture; + +public class TestHelperUtils { + private final static int ERROR_RETVAL = -1; + + /** + * Static helper method for creation of Exception failure state in CompletableFuture object + * with retval = -1 + * @return CompletableFuture with VppCallbackException as a cause + */ + public static CompletableFuture createFutureException() { + final CompletableFuture replyFuture = new CompletableFuture<>(); + replyFuture.completeExceptionally(new VppCallbackException("test-call", 1, ERROR_RETVAL)); + return replyFuture; + } +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizerTest.java new file mode 100644 index 000000000..e64a440ac --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainCustomizerTest.java @@ -0,0 +1,327 @@ +/* + * 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.translate.v3po.vpp; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.test.TestHelperUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.honeycomb.translate.MappingContext; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; +import org.openvpp.jvpp.VppInvocationException; +import org.openvpp.jvpp.dto.BridgeDomainAddDel; +import org.openvpp.jvpp.dto.BridgeDomainAddDelReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class BridgeDomainCustomizerTest { + + private static final byte ADD_OR_UPDATE_BD = (byte) 1; + private static final byte ZERO = 0; + + @Mock + private FutureJVpp api; + @Mock + private WriteContext ctx; + @Mock + private MappingContext mappingContext; + + private BridgeDomainCustomizer customizer; + + @Before + public void setUp() throws Exception { + initMocks(this); + // TODO create base class for tests using vppApi + NamingContext namingContext = new NamingContext("generatedBDName", "test-instance"); + final ModificationCache toBeReturned = new ModificationCache(); + doReturn(toBeReturned).when(ctx).getModificationCache(); + doReturn(mappingContext).when(ctx).getMappingContext(); + + customizer = new BridgeDomainCustomizer(api, namingContext); + } + + private BridgeDomain generateBridgeDomain(final String bdName) { + final byte arpTerm = 0; + final byte flood = 1; + final byte forward = 0; + final byte learn = 1; + final byte uuf = 0; + return generateBridgeDomain(bdName, arpTerm, flood, forward, learn, uuf); + } + + private BridgeDomain generateBridgeDomain(final String bdName, final int arpTerm, final int flood, + final int forward, final int learn, final int uuf) { + return new BridgeDomainBuilder() + .setName(bdName) + .setArpTermination(BridgeDomainTestUtils.intToBoolean(arpTerm)) + .setFlood(BridgeDomainTestUtils.intToBoolean(flood)) + .setForward(BridgeDomainTestUtils.intToBoolean(forward)) + .setLearn(BridgeDomainTestUtils.intToBoolean(learn)) + .setUnknownUnicastFlood(BridgeDomainTestUtils.intToBoolean(uuf)) + .build(); + } + + private void verifyBridgeDomainAddOrUpdateWasInvoked(final BridgeDomain bd, final int bdId) + throws VppInvocationException { + final byte arpTerm = BridgeDomainTestUtils.booleanToByte(bd.isArpTermination()); + final byte flood = BridgeDomainTestUtils.booleanToByte(bd.isFlood()); + final byte forward = BridgeDomainTestUtils.booleanToByte(bd.isForward()); + final byte learn = BridgeDomainTestUtils.booleanToByte(bd.isLearn()); + final byte uuf = BridgeDomainTestUtils.booleanToByte(bd.isUnknownUnicastFlood()); + + // TODO adding equals methods for jvpp DTOs would make ArgumentCaptor usage obsolete + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BridgeDomainAddDel.class); + verify(api).bridgeDomainAddDel(argumentCaptor.capture()); + final BridgeDomainAddDel actual = argumentCaptor.getValue(); + assertEquals(arpTerm, actual.arpTerm); + assertEquals(flood, actual.flood); + assertEquals(forward, actual.forward); + assertEquals(learn, actual.learn); + assertEquals(uuf, actual.uuFlood); + assertEquals(ADD_OR_UPDATE_BD, actual.isAdd); + assertEquals(bdId, actual.bdId); + } + + private void verifyBridgeDomainDeleteWasInvoked(final int bdId) throws VppInvocationException { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BridgeDomainAddDel.class); + verify(api).bridgeDomainAddDel(argumentCaptor.capture()); + final BridgeDomainAddDel actual = argumentCaptor.getValue(); + assertEquals(bdId, actual.bdId); + assertEquals(ZERO, actual.arpTerm); + assertEquals(ZERO, actual.flood); + assertEquals(ZERO, actual.forward); + assertEquals(ZERO, actual.learn); + assertEquals(ZERO, actual.uuFlood); + assertEquals(ZERO, actual.isAdd); + } + + private void whenBridgeDomainAddDelThenSuccess() + throws ExecutionException, InterruptedException, VppInvocationException { + final CompletionStage replyCS = mock(CompletionStage.class); + final CompletableFuture replyFuture = mock(CompletableFuture.class); + when(replyCS.toCompletableFuture()).thenReturn(replyFuture); + final BridgeDomainAddDelReply reply = new BridgeDomainAddDelReply(); + when(replyFuture.get()).thenReturn(reply); + when(api.bridgeDomainAddDel(any(BridgeDomainAddDel.class))).thenReturn(replyCS); + } + + private void whenBridgeDomainAddDelThenFailure() + throws ExecutionException, InterruptedException, VppInvocationException { + doReturn(TestHelperUtils.createFutureException()).when(api) + .bridgeDomainAddDel(any(BridgeDomainAddDel.class)); + } + + @Test + public void testAddBridgeDomain() throws Exception { + final int bdId = 1; + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain(bdName); + // Make bdContext.containsName() return false + doReturn(Optional.absent()).when(mappingContext) + .read(ContextTestUtils.getMappingIid(bdName, "test-instance").firstIdentifierOf(Mappings.class)); + // Make bdContext.containsIndex() return false + doReturn(Optional.absent()).when(mappingContext) + .read(ContextTestUtils.getMappingIid(bdName, "test-instance")); + + whenBridgeDomainAddDelThenSuccess(); + + customizer.writeCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); + + verifyBridgeDomainAddOrUpdateWasInvoked(bd, bdId); + verify(mappingContext).put( + ContextTestUtils.getMappingIid(bdName, "test-instance"), ContextTestUtils.getMapping(bdName, bdId).get()); + } + + @Test + public void testAddBridgeDomainPresentInBdContext() throws Exception { + final int bdId = 1; + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain(bdName); + // Make bdContext.containsIndex() return true + doReturn(Optional.of(new MappingBuilder().setIndex(bdId).build())).when(mappingContext) + .read(ContextTestUtils.getMappingIid(bdName, "test-instance")); + + whenBridgeDomainAddDelThenSuccess(); + + customizer.writeCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); + + verifyBridgeDomainAddOrUpdateWasInvoked(bd, bdId); + verify(mappingContext).put( + ContextTestUtils.getMappingIid(bdName, "test-instance"), ContextTestUtils.getMapping(bdName, bdId).get()); + } + + @Test + public void testAddBridgeDomainFailed() throws Exception { + final int bdId = 1; + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain(bdName); + + // Returning no Mappings for "test-instance" makes bdContext.containsName() return false + doReturn(Optional.absent()).when(mappingContext) + .read(ContextTestUtils.getMappingIid(bdName, "test-instance").firstIdentifierOf(Mappings.class)); + // Make bdContext.containsIndex() return false + doReturn(Optional.absent()).when(mappingContext) + .read(ContextTestUtils.getMappingIid(bdName, "test-instance")); + + whenBridgeDomainAddDelThenFailure(); + + try { + customizer.writeCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); + } catch (WriteFailedException.CreateFailedException e) { + verifyBridgeDomainAddOrUpdateWasInvoked(bd, bdId); + return; + } + fail("WriteFailedException.CreateFailedException was expected"); + } + + @Test + public void testDeleteBridgeDomain() throws Exception { + final int bdId = 1; + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain(bdName); + doReturn(ContextTestUtils.getMapping(bdName, bdId)).when(mappingContext).read( + ContextTestUtils.getMappingIid(bdName, "test-instance")); + + whenBridgeDomainAddDelThenSuccess(); + + customizer.deleteCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); + + verifyBridgeDomainDeleteWasInvoked(bdId); + } + + @Test + public void testDeleteUnknownBridgeDomain() throws Exception { + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain("bd1"); + doReturn(Optional.absent()).when(mappingContext).read(ContextTestUtils.getMappingIid(bdName, "test-instance")); + + try { + customizer.deleteCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); + } catch (IllegalArgumentException e) { + verify(api, never()).bridgeDomainAddDel(any(BridgeDomainAddDel.class)); + return; + } + fail("IllegalArgumentException was expected"); + } + + @Test + public void testDeleteBridgeDomainFailed() throws Exception { + final int bdId = 1; + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain(bdName); + doReturn(ContextTestUtils.getMapping(bdName, bdId)).when(mappingContext).read( + ContextTestUtils.getMappingIid(bdName, "test-instance")); + + whenBridgeDomainAddDelThenFailure(); + + try { + customizer.deleteCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); + } catch (WriteFailedException.DeleteFailedException e) { + verifyBridgeDomainDeleteWasInvoked(bdId); + return; + } + + fail("WriteFailedException.DeleteFailedException was expected"); + } + + @Test + public void testUpdateBridgeDomain() throws Exception { + final int bdId = 1; + final String bdName = "bd1"; + doReturn(ContextTestUtils.getMapping(bdName, bdId)).when(mappingContext).read( + ContextTestUtils.getMappingIid(bdName, "test-instance")); + + final byte arpTermBefore = 1; + final byte floodBefore = 1; + final byte forwardBefore = 0; + final byte learnBefore = 1; + final byte uufBefore = 0; + + final BridgeDomain dataBefore = + generateBridgeDomain(bdName, arpTermBefore, floodBefore, forwardBefore, learnBefore, uufBefore); + final BridgeDomain dataAfter = + generateBridgeDomain(bdName, arpTermBefore ^ 1, floodBefore ^ 1, forwardBefore ^ 1, learnBefore ^ 1, + uufBefore ^ 1); + + whenBridgeDomainAddDelThenSuccess(); + + customizer + .updateCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), dataBefore, dataAfter, ctx); + verifyBridgeDomainAddOrUpdateWasInvoked(dataAfter, bdId); + } + + @Test + public void testUpdateUnknownBridgeDomain() throws Exception { + final String bdName = "bd1"; + final BridgeDomain bdBefore = generateBridgeDomain(bdName, 0, 1, 0, 1, 0); + final BridgeDomain bdAfter = generateBridgeDomain(bdName, 1, 1, 0, 1, 0); + doReturn(Optional.absent()).when(mappingContext).read(ContextTestUtils.getMappingIid(bdName, "test-instance")); + + try { + customizer + .updateCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bdBefore, bdAfter, ctx); + } catch (IllegalArgumentException e) { + verify(api, never()).bridgeDomainAddDel(any(BridgeDomainAddDel.class)); + return; + } + fail("IllegalArgumentException was expected"); + } + + @Test + public void testUpdateBridgeDomainFailed() throws Exception { + final int bdId = 1; + final String bdName = "bd1"; + final BridgeDomain bdBefore = generateBridgeDomain(bdName, 0, 1, 0, 1, 0); + final BridgeDomain bdAfter = generateBridgeDomain(bdName, 1, 1, 0, 1, 0); + doReturn(ContextTestUtils.getMapping(bdName, bdId)).when(mappingContext).read( + ContextTestUtils.getMappingIid(bdName, "test-instance")); + + whenBridgeDomainAddDelThenFailure(); + + try { + customizer + .updateCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bdBefore, bdAfter, ctx); + } catch (WriteFailedException.UpdateFailedException e) { + verifyBridgeDomainAddOrUpdateWasInvoked(bdAfter, bdId); + return; + } + fail("IllegalStateException was expected"); + } + +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainTestUtils.java new file mode 100644 index 000000000..9ffc4edaa --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/BridgeDomainTestUtils.java @@ -0,0 +1,64 @@ +/* + * 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.translate.v3po.vpp; + +import javax.annotation.Nullable; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; + +final class BridgeDomainTestUtils { + + private BridgeDomainTestUtils() { + throw new UnsupportedOperationException("Utility class cannot be instantiated."); + } + + public static byte booleanToByte(@Nullable final Boolean value) { + return value != null && value ? (byte) 1 : (byte) 0; + } + + @Nullable + public static Boolean intToBoolean(final int value) { + if (value == 0) { + return Boolean.FALSE; + } + if (value == 1) { + return Boolean.TRUE; + } + return null; + } + + public static int bdNameToID(String bName) { + return Integer.parseInt(((Character)bName.charAt(bName.length() - 1)).toString()); + } + + public static KeyedInstanceIdentifier bdIdentifierForName( + final String bdName) { + return InstanceIdentifier.create(BridgeDomains.class).child(BridgeDomain.class, new BridgeDomainKey(bdName)); + } + + public static final Answer BD_NAME_TO_ID_ANSWER = new Answer() { + @Override + public Integer answer(final InvocationOnMock invocationOnMock) throws Throwable { + return bdNameToID((String) invocationOnMock.getArguments()[0]); + } + }; +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizerTest.java new file mode 100644 index 000000000..b351699c9 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vpp/L2FibEntryCustomizerTest.java @@ -0,0 +1,224 @@ +/* + * 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.translate.v3po.vpp; + +import static org.junit.Assert.assertEquals; +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.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.test.TestHelperUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletableFuture; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibFilter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.VppInvocationException; +import org.openvpp.jvpp.dto.L2FibAddDel; +import org.openvpp.jvpp.dto.L2FibAddDelReply; +import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class L2FibEntryCustomizerTest { + private static final String BD_CTX_NAME = "bd-test-instance"; + private static final String IFC_CTX_NAME = "ifc-test-instance"; + + private static final String BD_NAME = "testBD0"; + private static final int BD_ID = 111; + private static final String IFACE_NAME = "eth0"; + private static final int IFACE_ID = 123; + + @Mock + private FutureJVpp api; + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + + private NamingContext bdContext; + private NamingContext interfaceContext; + + private L2FibEntryCustomizer customizer; + + @Before + public void setUp() throws Exception { + initMocks(this); + doReturn(mappingContext).when(writeContext).getMappingContext(); + bdContext = new NamingContext("generatedBdName", BD_CTX_NAME); + interfaceContext = new NamingContext("generatedIfaceName", IFC_CTX_NAME); + + customizer = new L2FibEntryCustomizer(api, bdContext, interfaceContext); + } + + private static InstanceIdentifier getL2FibEntryId(final PhysAddress address) { + return InstanceIdentifier.create(BridgeDomains.class).child(BridgeDomain.class, new BridgeDomainKey(BD_NAME)) + .child(L2FibTable.class).child(L2FibEntry.class, new L2FibEntryKey(address)); + } + + private void whenL2FibAddDelThenSuccess() { + final CompletableFuture replyFuture = new CompletableFuture<>(); + final L2FibAddDelReply reply = new L2FibAddDelReply(); + replyFuture.complete(reply); + doReturn(replyFuture).when(api).l2FibAddDel(any(L2FibAddDel.class)); + } + + private void whenL2FibAddDelThenFailure() { + doReturn(TestHelperUtils.createFutureException()).when(api) + .l2FibAddDel(any(L2FibAddDel.class)); + } + + private L2FibAddDel generateL2FibAddDelRequest(final long mac, final byte isAdd) { + final L2FibAddDel request = new L2FibAddDel(); + request.mac = mac; + request.bdId = BD_ID; + request.swIfIndex = IFACE_ID; + request.isAdd = isAdd; + if (isAdd == 1) { + request.staticMac = 1; + request.filterMac = 1; + } + return request; + } + + private L2FibEntry generateL2FibEntry(final PhysAddress address) { + final L2FibEntryBuilder entry = new L2FibEntryBuilder(); + entry.setKey(new L2FibEntryKey(address)); + entry.setPhysAddress(address); + entry.setStaticConfig(true); + entry.setBridgedVirtualInterface(false); + entry.setAction(L2FibFilter.class); + entry.setOutgoingInterface(IFACE_NAME); + return entry.build(); + } + + private void verifyL2FibAddDelWasInvoked(final L2FibAddDel expected) throws + VppInvocationException { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(L2FibAddDel.class); + verify(api).l2FibAddDel(argumentCaptor.capture()); + final L2FibAddDel actual = argumentCaptor.getValue(); + assertEquals(expected.mac, actual.mac); + assertEquals(expected.bdId, actual.bdId); + assertEquals(expected.swIfIndex, actual.swIfIndex); + assertEquals(expected.isAdd, actual.isAdd); + assertEquals(expected.staticMac, actual.staticMac); + assertEquals(expected.filterMac, actual.filterMac); + } + + @Test + public void testCreate() throws Exception { + final long address_vpp = 0x0102030405060000L; + final PhysAddress address = new PhysAddress("01:02:03:04:05:06"); + final L2FibEntry entry = generateL2FibEntry(address); + final InstanceIdentifier id = getL2FibEntryId(address); + + ContextTestUtils.mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); + ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + + whenL2FibAddDelThenSuccess(); + + customizer.writeCurrentAttributes(id, entry, writeContext); + + verifyL2FibAddDelWasInvoked(generateL2FibAddDelRequest(address_vpp, (byte) 1)); + } + + @Test + public void testCreateFailed() throws Exception { + final long address_vpp = 0x1122334455660000L; + final PhysAddress address = new PhysAddress("11:22:33:44:55:66"); + final L2FibEntry entry = generateL2FibEntry(address); + final InstanceIdentifier id = getL2FibEntryId(address); + + ContextTestUtils.mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); + ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + + whenL2FibAddDelThenFailure(); + + try { + customizer.writeCurrentAttributes(id, entry, writeContext); + } catch (WriteFailedException.CreateFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyL2FibAddDelWasInvoked(generateL2FibAddDelRequest(address_vpp, (byte) 1)); + return; + } + fail("WriteFailedException.CreateFailedException was expected"); + } + + @Test(expected = UnsupportedOperationException.class) + public void testUpdate() throws Exception { + customizer.updateCurrentAttributes(InstanceIdentifier.create(L2FibEntry.class), mock(L2FibEntry.class), + mock(L2FibEntry.class), writeContext); + } + + @Test + public void testDelete() throws Exception { + final long address_vpp = 0x1122334455660000L; + final PhysAddress address = new PhysAddress("11:22:33:44:55:66"); + final L2FibEntry entry = generateL2FibEntry(address); + final InstanceIdentifier id = getL2FibEntryId(address); + + ContextTestUtils.mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); + ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + + whenL2FibAddDelThenSuccess(); + + customizer.deleteCurrentAttributes(id, entry, writeContext); + + verifyL2FibAddDelWasInvoked(generateL2FibAddDelRequest(address_vpp, (byte) 0)); + } + + @Test + public void testDeleteFailed() throws Exception { + final long address_vpp = 0x0102030405060000L; + final PhysAddress address = new PhysAddress("01:02:03:04:05:06"); + final L2FibEntry entry = generateL2FibEntry(address); + final InstanceIdentifier id = getL2FibEntryId(address); + + ContextTestUtils.mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); + ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + + whenL2FibAddDelThenFailure(); + + try { + customizer.deleteCurrentAttributes(id, entry, writeContext); + } catch (WriteFailedException.DeleteFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyL2FibAddDelWasInvoked(generateL2FibAddDelRequest(address_vpp, (byte) 0)); + return; + } + fail("WriteFailedException.DeleteFailedException was expected"); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReaderTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReaderTest.java new file mode 100644 index 000000000..895c20e87 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionReaderTest.java @@ -0,0 +1,136 @@ +/* + * 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.translate.v3po.vppclassifier; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.test.ListReaderCustomizerTest; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.ClassifySessionDetails; +import org.openvpp.jvpp.dto.ClassifySessionDetailsReplyDump; +import org.openvpp.jvpp.dto.ClassifySessionDump; + +public class ClassifySessionReaderTest extends + ListReaderCustomizerTest { + + private static final String MATCH_1 = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"; + private static final String MATCH_2 = "00:00:00:00:00:00:01:02:03:04:05:07:00:00:00:00"; + + private static final int TABLE_INDEX = 1; + private static final String TABLE_NAME = "table1"; + + private NamingContext classifyTableContext; + + public ClassifySessionReaderTest() { + super(ClassifySession.class); + } + + @Override + public void setUpBefore() { + classifyTableContext = new NamingContext("classifyTableContext", "test-instance"); + + final Optional ifcMapping = ContextTestUtils.getMapping(TABLE_NAME, TABLE_INDEX); + doReturn(ifcMapping).when(mappingContext).read(any()); + } + + @Override + protected ReaderCustomizer initCustomizer() { + return new ClassifySessionReader(api, classifyTableContext); + } + + private static InstanceIdentifier getClassifySessionId(final String tableName, + final String match) { + return InstanceIdentifier.create(VppClassifierState.class) + .child(ClassifyTable.class, new ClassifyTableKey(tableName)) + .child(ClassifySession.class, new ClassifySessionKey(new HexString(match))); + } + + @Test + public void testMerge() { + final ClassifyTableBuilder builder = mock(ClassifyTableBuilder.class); + final List value = mock(List.class); + getCustomizer().merge(builder, value); + verify(builder).setClassifySession(value); + } + + @Test + public void testReadWithCache() throws ReadFailedException { + final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, MATCH_1); + final ClassifySessionBuilder builder = mock(ClassifySessionBuilder.class); + final ModificationCache cache = new ModificationCache(); + final ClassifySessionDetailsReplyDump dump = new ClassifySessionDetailsReplyDump(); + final ClassifySessionDetails details = new ClassifySessionDetails(); + details.match = + new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, + (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; + dump.classifySessionDetails = Collections.singletonList(details); + cache.put(ClassifySessionReader.CACHE_KEY + id.firstKeyOf(ClassifyTable.class), dump); + when(ctx.getModificationCache()).thenReturn(cache); + + getCustomizer().readCurrentAttributes(id, builder, ctx); + } + + @Test + public void testGetAllIds() throws ReadFailedException { + final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, MATCH_1); + final ClassifySessionDetailsReplyDump dump = new ClassifySessionDetailsReplyDump(); + final ClassifySessionDetails details1 = new ClassifySessionDetails(); + details1.match = + new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, + (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; + final ClassifySessionDetails details2 = new ClassifySessionDetails(); + details2.match = + new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, + (byte) 0x05, (byte) 0x07, 0x00, 0x00, 0x00, 0x00}; + dump.classifySessionDetails = Arrays.asList(details1, details2); + + final CompletableFuture replyFuture = new CompletableFuture<>(); + replyFuture.complete(dump); + doReturn(replyFuture).when(api).classifySessionDump(any(ClassifySessionDump.class)); + + final List allIds = getCustomizer().getAllIds(id, ctx); + assertEquals(2, allIds.size()); + assertEquals(MATCH_1, allIds.get(0).getMatch().getValue()); + assertEquals(MATCH_2, allIds.get(1).getMatch().getValue()); + } + +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriterTest.java new file mode 100644 index 000000000..25c7ffbb0 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifySessionWriterTest.java @@ -0,0 +1,218 @@ +/* + * 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.translate.v3po.vppclassifier; + +import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMapping; +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.test.TestHelperUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyAddDelSession; +import org.openvpp.jvpp.dto.ClassifyAddDelSessionReply; +import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class ClassifySessionWriterTest { + + private static final int TABLE_INDEX = 123; + private static final String TABLE_NAME = "table123"; + + @Mock + private FutureJVpp api; + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + + private NamingContext classifyTableContext; + private ClassifySessionWriter customizer; + private static final int SESSION_INDEX = 456; + + @Before + public void setUp() throws Exception { + initMocks(this); + classifyTableContext = new NamingContext("generatedClassifyTableName", "test-instance"); + doReturn(mappingContext).when(writeContext).getMappingContext(); + customizer = new ClassifySessionWriter(api, classifyTableContext); + + final Optional ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX); + doReturn(ifcMapping).when(mappingContext).read(any()); + } + + private static ClassifySession generateClassifySession(final long opaqueIndex, final String match) { + final ClassifySessionBuilder builder = new ClassifySessionBuilder(); + builder.setOpaqueIndex(new OpaqueIndex(opaqueIndex)); + builder.setHitNext(new VppNode(PacketHandlingAction.Deny)); + builder.setAdvance(123); + builder.setMatch(new HexString(match)); + return builder.build(); + } + + private static InstanceIdentifier getClassifySessionId(final String tableName, + final String match) { + return InstanceIdentifier.create(VppClassifier.class) + .child(ClassifyTable.class, new ClassifyTableKey(tableName)) + .child(ClassifySession.class, new ClassifySessionKey(new HexString(match))); + } + + private void whenClassifyAddDelSessionThenSuccess() throws ExecutionException, InterruptedException { + final CompletableFuture replyFuture = new CompletableFuture<>(); + replyFuture.complete(new ClassifyAddDelSessionReply()); + doReturn(replyFuture).when(api).classifyAddDelSession(any(ClassifyAddDelSession.class)); + } + + private void whenClassifyAddDelSessionThenFailure() throws ExecutionException, InterruptedException { + doReturn(TestHelperUtils.createFutureException()).when(api) + .classifyAddDelSession(any(ClassifyAddDelSession.class)); + } + + private void verifyClassifyAddDelSessionWasInvoked(final ClassifyAddDelSession expected) { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelSession.class); + verify(api).classifyAddDelSession(argumentCaptor.capture()); + final ClassifyAddDelSession actual = argumentCaptor.getValue(); + assertEquals(expected.opaqueIndex, actual.opaqueIndex); + assertEquals(expected.isAdd, actual.isAdd); + assertEquals(expected.tableIndex, actual.tableIndex); + assertEquals(expected.hitNextIndex, actual.hitNextIndex); + assertArrayEquals(expected.match, actual.match); + assertEquals(expected.advance, actual.advance); + } + + private void verifyClassifyAddDelSessionDeleteWasInvoked(final ClassifyAddDelSession expected) { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelSession.class); + verify(api).classifyAddDelSession(argumentCaptor.capture()); + final ClassifyAddDelSession actual = argumentCaptor.getValue(); + assertEquals(expected.opaqueIndex, actual.opaqueIndex); + assertEquals(expected.isAdd, actual.isAdd); + assertEquals(expected.tableIndex, actual.tableIndex); + } + + private static ClassifyAddDelSession generateClassifyAddDelSession(final byte isAdd, final int tableIndex, + final int sessionIndex) { + final ClassifyAddDelSession request = new ClassifyAddDelSession(); + request.isAdd = isAdd; + request.tableIndex = tableIndex; + request.opaqueIndex = sessionIndex; + request.hitNextIndex = 0; + request.advance = 123; + request.match = + new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, + (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; + return request; + } + + @Test + public void testCreate() throws Exception { + final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"; + final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match); + final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, match); + + whenClassifyAddDelSessionThenSuccess(); + + customizer.writeCurrentAttributes(id, classifySession, writeContext); + + verifyClassifyAddDelSessionWasInvoked(generateClassifyAddDelSession((byte) 1, TABLE_INDEX, SESSION_INDEX)); + } + + @Test + public void testCreateFailed() throws Exception { + final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"; + final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match); + final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, match); + + whenClassifyAddDelSessionThenFailure(); + + try { + customizer.writeCurrentAttributes(id, classifySession, writeContext); + } catch (WriteFailedException.CreateFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyClassifyAddDelSessionWasInvoked(generateClassifyAddDelSession((byte) 1, TABLE_INDEX, SESSION_INDEX)); + return; + } + fail("WriteFailedException.CreateFailedException was expected"); + } + + @Test(expected = UnsupportedOperationException.class) + public void testUpdate() throws Exception { + customizer.updateCurrentAttributes(null, null, null, writeContext); + } + + @Test + public void testDelete() throws Exception { + final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"; + final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match); + final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, match); + + whenClassifyAddDelSessionThenSuccess(); + + customizer.deleteCurrentAttributes(id, classifySession, writeContext); + + verifyClassifyAddDelSessionDeleteWasInvoked( + generateClassifyAddDelSession((byte) 0, TABLE_INDEX, SESSION_INDEX)); + } + + @Test + public void testDeleteFailed() throws Exception { + final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"; + final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match); + final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, match); + + whenClassifyAddDelSessionThenFailure(); + + try { + customizer.deleteCurrentAttributes(id, classifySession, writeContext); + } catch (WriteFailedException.DeleteFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyClassifyAddDelSessionDeleteWasInvoked( + generateClassifyAddDelSession((byte) 0, TABLE_INDEX, SESSION_INDEX)); + return; + } + fail("WriteFailedException.DeleteFailedException was expected"); + + customizer.deleteCurrentAttributes(id, classifySession, writeContext); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReaderTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReaderTest.java new file mode 100644 index 000000000..e334da3b4 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableReaderTest.java @@ -0,0 +1,154 @@ +/* + * 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.translate.v3po.vppclassifier; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.test.ListReaderCustomizerTest; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.openvpp.jvpp.dto.ClassifyTableIds; +import org.openvpp.jvpp.dto.ClassifyTableIdsReply; +import org.openvpp.jvpp.dto.ClassifyTableInfo; +import org.openvpp.jvpp.dto.ClassifyTableInfoReply; + +public class ClassifyTableReaderTest extends + ListReaderCustomizerTest { + + private static final int TABLE_INDEX_1 = 1; + private static final String TABLE_NAME_1 = "table1"; + private static final int TABLE_INDEX_2 = 2; + private static final String TABLE_NAME_2 = "table2"; + + private NamingContext classifyTableContext; + + public ClassifyTableReaderTest() { + super(ClassifyTable.class); + } + + @Override + public void setUpBefore() { + classifyTableContext = new NamingContext("classifyTableContext", "test-instance"); + + final KeyedInstanceIdentifier t0Id = ContextTestUtils + .getMappingIid(TABLE_NAME_1, "test-instance"); + final KeyedInstanceIdentifier t1Id = ContextTestUtils + .getMappingIid(TABLE_NAME_2, "test-instance"); + final Optional t0 = ContextTestUtils.getMapping(TABLE_NAME_1, TABLE_INDEX_1); + final Optional t1 = ContextTestUtils.getMapping(TABLE_NAME_2, TABLE_INDEX_2); + final List allMappings = Lists.newArrayList(t0.get(), t1.get()); + final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); + doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(t0Id.firstIdentifierOf(Mappings.class)); + doReturn(t0).when(mappingContext).read(t0Id); + doReturn(t1).when(mappingContext).read(t1Id); + } + + @Override + protected ReaderCustomizer initCustomizer() { + return new ClassifyTableReader(api, classifyTableContext); + } + + private static InstanceIdentifier getClassifyTableId(final String name) { + return InstanceIdentifier.create(VppClassifierState.class) + .child(ClassifyTable.class, new ClassifyTableKey(name)); + } + + private static ClassifyTableInfoReply generateClassifyTableInfoReply() { + final ClassifyTableInfoReply reply = new ClassifyTableInfoReply(); + reply.tableId = TABLE_INDEX_1; + reply.nbuckets = 2; + reply.skipNVectors = 0; + reply.matchNVectors = 1; + reply.nextTableIndex = ~0; + reply.missNextIndex = ~0; + reply.mask = + new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, + (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; + return reply; + } + + private void verifyClasifyTableRead(final ClassifyTableBuilder builder) { + verify(builder).setName(TABLE_NAME_1); + verify(builder).setNbuckets(2L); + verify(builder, times(0)).setNextTable(anyString()); + verify(builder).setMissNext(new VppNode(PacketHandlingAction.Permit)); + verify(builder).setMask(new HexString("00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00")); + verify(builder).setActiveSessions(0L); + } + + @Test + public void testMerge() { + final VppClassifierStateBuilder builder = mock(VppClassifierStateBuilder.class); + final List value = mock(List.class); + getCustomizer().merge(builder, value); + verify(builder).setClassifyTable(value); + } + + @Test + public void testRead() throws ReadFailedException { + final CompletableFuture replyFuture = new CompletableFuture<>(); + replyFuture.complete(generateClassifyTableInfoReply()); + doReturn(replyFuture).when(api).classifyTableInfo(any(ClassifyTableInfo.class)); + + final ClassifyTableBuilder builder = mock(ClassifyTableBuilder.class); + getCustomizer().readCurrentAttributes(getClassifyTableId(TABLE_NAME_1), builder, ctx); + + verifyClasifyTableRead(builder); + } + + @Test + public void testGetAllIds() throws ReadFailedException { + final CompletableFuture replyFuture = new CompletableFuture<>(); + final ClassifyTableIdsReply reply = new ClassifyTableIdsReply(); + reply.ids = new int[] {1, 2}; + replyFuture.complete(reply); + doReturn(replyFuture).when(api).classifyTableIds(any(ClassifyTableIds.class)); + + final List allIds = getCustomizer().getAllIds(getClassifyTableId(TABLE_NAME_1), ctx); + + assertEquals(reply.ids.length, allIds.size()); + assertEquals(TABLE_NAME_1, allIds.get(0).getName()); + assertEquals(TABLE_NAME_2, allIds.get(1).getName()); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriterTest.java new file mode 100644 index 000000000..7724116fd --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppclassifier/ClassifyTableWriterTest.java @@ -0,0 +1,228 @@ +/* + * 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.translate.v3po.vppclassifier; + +import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMapping; +import static io.fd.honeycomb.translate.v3po.test.ContextTestUtils.getMappingIid; +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.v3po.test.TestHelperUtils; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.ClassifyAddDelTable; +import org.openvpp.jvpp.dto.ClassifyAddDelTableReply; +import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class ClassifyTableWriterTest { + + private static final int TABLE_INDEX = 123; + private static final String TABLE_NAME = "table123"; + + @Mock + private FutureJVpp api; + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + + private NamingContext classifyTableContext; + private ClassifyTableWriter customizer; + + @Before + public void setUp() throws Exception { + initMocks(this); + classifyTableContext = new NamingContext("generatedClassifyTableName", "test-instance"); + doReturn(mappingContext).when(writeContext).getMappingContext(); + customizer = new ClassifyTableWriter(api, classifyTableContext); + } + + private static ClassifyTable generateClassifyTable(final String name) { + final ClassifyTableBuilder builder = new ClassifyTableBuilder(); + builder.setName(name); + builder.setKey(new ClassifyTableKey(name)); + builder.setSkipNVectors(0L); + builder.setNbuckets(2L); + builder.setMemorySize(2L << 20); + builder.setMissNext(new VppNode(PacketHandlingAction.Permit)); + builder.setMask(new HexString("00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00")); + return builder.build(); + } + + private static InstanceIdentifier getClassifyTableId(final String name) { + return InstanceIdentifier.create(VppClassifier.class) + .child(ClassifyTable.class, new ClassifyTableKey(name)); + } + + private void whenClassifyAddDelTableThenSuccess() throws ExecutionException, InterruptedException { + final CompletableFuture replyFuture = new CompletableFuture<>(); + final ClassifyAddDelTableReply reply = new ClassifyAddDelTableReply(); + reply.newTableIndex = TABLE_INDEX; + replyFuture.complete(reply); + doReturn(replyFuture).when(api).classifyAddDelTable(any(ClassifyAddDelTable.class)); + } + + private void whenClassifyAddDelTableThenFailure() throws ExecutionException, InterruptedException { + doReturn(TestHelperUtils.createFutureException()).when(api) + .classifyAddDelTable(any(ClassifyAddDelTable.class)); + } + + private void verifyClassifyAddDelTableAddWasInvoked(final ClassifyAddDelTable expected) { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelTable.class); + verify(api).classifyAddDelTable(argumentCaptor.capture()); + final ClassifyAddDelTable actual = argumentCaptor.getValue(); + assertEquals(expected.isAdd, actual.isAdd); + assertEquals(~0, actual.tableIndex); + assertEquals(expected.nbuckets, actual.nbuckets); + assertEquals(expected.memorySize, actual.memorySize); + assertEquals(expected.skipNVectors, actual.skipNVectors); + assertEquals(expected.matchNVectors, actual.matchNVectors); + assertEquals(expected.nextTableIndex, actual.nextTableIndex); + assertEquals(expected.missNextIndex, actual.missNextIndex); + assertArrayEquals(expected.mask, actual.mask); + } + + private void verifyClassifyAddDelTableDeleteWasInvoked(final ClassifyAddDelTable expected) { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelTable.class); + verify(api).classifyAddDelTable(argumentCaptor.capture()); + final ClassifyAddDelTable actual = argumentCaptor.getValue(); + assertEquals(expected.isAdd, actual.isAdd); + assertEquals(expected.tableIndex, actual.tableIndex); + } + + private static ClassifyAddDelTable generateClassifyAddDelTable(final byte isAdd, final int tableIndex) { + final ClassifyAddDelTable request = new ClassifyAddDelTable(); + request.isAdd = isAdd; + request.tableIndex = tableIndex; + request.nbuckets = 2; + request.memorySize = 2 << 20; + request.skipNVectors = 0; + request.matchNVectors = 1; + request.nextTableIndex = ~0; + request.missNextIndex = ~0; + request.mask = + new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, + (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; + return request; + } + + @Test + public void testCreate() throws Exception { + final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME); + final InstanceIdentifier id = getClassifyTableId(TABLE_NAME); + + whenClassifyAddDelTableThenSuccess(); + + customizer.writeCurrentAttributes(id, classifyTable, writeContext); + + verifyClassifyAddDelTableAddWasInvoked(generateClassifyAddDelTable((byte) 1, TABLE_INDEX)); + verify(mappingContext) + .put(eq(getMappingIid(TABLE_NAME, "test-instance")), eq(getMapping(TABLE_NAME, TABLE_INDEX).get())); + } + + @Test + public void testCreateFailed() throws Exception { + final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME); + final InstanceIdentifier id = getClassifyTableId(TABLE_NAME); + + whenClassifyAddDelTableThenFailure(); + + try { + customizer.writeCurrentAttributes(id, classifyTable, writeContext); + } catch (WriteFailedException.CreateFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyClassifyAddDelTableAddWasInvoked(generateClassifyAddDelTable((byte) 1, TABLE_INDEX)); + verify(mappingContext, times(0)).put( + eq(getMappingIid(TABLE_NAME, "test-instance")), + eq(getMapping(TABLE_NAME, TABLE_INDEX).get())); + return; + } + fail("WriteFailedException.CreateFailedException was expected"); + } + + @Test + public void testDelete() throws Exception { + final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME); + final InstanceIdentifier id = getClassifyTableId(TABLE_NAME); + + final Optional ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX); + doReturn(ifcMapping).when(mappingContext).read(any()); + + whenClassifyAddDelTableThenSuccess(); + + customizer.deleteCurrentAttributes(id, classifyTable, writeContext); + + verifyClassifyAddDelTableDeleteWasInvoked(generateClassifyAddDelTable((byte) 0, TABLE_INDEX)); + } + + @Test + public void testDeleteFailed() throws Exception { + final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME); + final InstanceIdentifier id = getClassifyTableId(TABLE_NAME); + + final Optional ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX); + doReturn(ifcMapping).when(mappingContext).read(any()); + + whenClassifyAddDelTableThenFailure(); + + try { + customizer.deleteCurrentAttributes(id, classifyTable, writeContext); + } catch (WriteFailedException.DeleteFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifyClassifyAddDelTableDeleteWasInvoked(generateClassifyAddDelTable((byte) 0, TABLE_INDEX)); + return; + } + fail("WriteFailedException.DeleteFailedException was expected"); + + customizer.deleteCurrentAttributes(id, classifyTable, writeContext); + } + + @Test(expected = UnsupportedOperationException.class) + public void testUpdate() throws Exception { + final ClassifyTable classifyTableBefore = generateClassifyTable(TABLE_NAME); + final InstanceIdentifier id = getClassifyTableId(TABLE_NAME); + customizer.updateCurrentAttributes(id, classifyTableBefore, new ClassifyTableBuilder().build(), writeContext); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizerTest.java new file mode 100644 index 000000000..bcd6a36f6 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/BridgeDomainCustomizerTest.java @@ -0,0 +1,61 @@ +/* + * 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.translate.v3po.vppstate; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ListReaderCustomizerTest; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.util.Collections; +import java.util.List; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; + +public class BridgeDomainCustomizerTest + extends ListReaderCustomizerTest { + + private NamingContext bdContext; + private NamingContext interfacesContext; + + public BridgeDomainCustomizerTest() { + super(BridgeDomain.class); + } + + @Override + public void setUpBefore() { + bdContext = new NamingContext("generatedBdName", "bd-test-instance"); + interfacesContext = new NamingContext("generatedIfaceName", "ifc-test-instance"); + } + + @Test + public void testMerge() throws Exception { + final BridgeDomainsBuilder builder = mock(BridgeDomainsBuilder.class); + final List value = Collections.emptyList(); + getCustomizer().merge(builder, value); + verify(builder).setBridgeDomain(value); + } + + @Override + protected ReaderCustomizer initCustomizer() { + return new BridgeDomainCustomizer(api, bdContext); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizerTest.java new file mode 100644 index 000000000..f9eb2d6c6 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/L2FibEntryCustomizerTest.java @@ -0,0 +1,139 @@ +/* + * 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.translate.v3po.vppstate; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.v3po.test.ListReaderCustomizerTest; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibForward; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppInvocationException; +import org.openvpp.jvpp.dto.L2FibTableDump; +import org.openvpp.jvpp.dto.L2FibTableEntry; +import org.openvpp.jvpp.dto.L2FibTableEntryReplyDump; + +public class L2FibEntryCustomizerTest extends ListReaderCustomizerTest { + + private static final String BD_NAME = "testBD0"; + private static final int BD_ID = 111; + private static final String IFACE_NAME = "eth0"; + private static final int IFACE_ID = 123; + private static final String BD_CTX_NAME = "bd-test-instance"; + private static final String IFC_CTX_NAME = "ifc-test-instance"; + private NamingContext bdContext; + private NamingContext interfacesContext; + + public L2FibEntryCustomizerTest() { + super(L2FibEntry.class); + } + + @Override + public void setUpBefore() { + bdContext = new NamingContext("generatedBdName", BD_CTX_NAME); + interfacesContext = new NamingContext("generatedIfaceName", IFC_CTX_NAME); + } + + @Override + protected ReaderCustomizer initCustomizer() { + return new L2FibEntryCustomizer(api, bdContext, interfacesContext); + } + + @Test + public void testMerge() throws Exception { + final L2FibTableBuilder builder = mock(L2FibTableBuilder.class); + final List value = Collections.emptyList(); + getCustomizer().merge(builder, value); + verify(builder).setL2FibEntry(value); + } + + private static InstanceIdentifier getL2FibEntryId(final String bdName, final PhysAddress address) { + return InstanceIdentifier.create(BridgeDomains.class).child(BridgeDomain.class, new BridgeDomainKey(bdName)) + .child(L2FibTable.class).child(L2FibEntry.class, new L2FibEntryKey(address)); + } + + private void whenL2FibTableDumpThenReturn(final List l2FibTableEntryList) + throws ExecutionException, InterruptedException, VppInvocationException { + final L2FibTableEntryReplyDump reply = new L2FibTableEntryReplyDump(); + reply.l2FibTableEntry = l2FibTableEntryList; + + final CompletableFuture replyFuture = new CompletableFuture<>(); + replyFuture.complete(reply); + when(api.l2FibTableDump(any(L2FibTableDump.class))).thenReturn(replyFuture); + } + + @Test + public void testRead() throws Exception { + final long address_vpp = 0x0000010203040506L; + final PhysAddress address = new PhysAddress("01:02:03:04:05:06"); + + ContextTestUtils.mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); + ContextTestUtils.mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + + whenL2FibTableDumpThenReturn(Collections.singletonList(generateL2FibEntry(address_vpp))); + + final L2FibEntryBuilder builder = mock(L2FibEntryBuilder.class); + getCustomizer().readCurrentAttributes(getL2FibEntryId(BD_NAME, address), builder, ctx); + + verify(builder).setAction(L2FibForward.class); + verify(builder).setBridgedVirtualInterface(false); + verify(builder).setOutgoingInterface(IFACE_NAME); + verify(builder).setStaticConfig(false); + verify(builder).setPhysAddress(address); + verify(builder).setKey(new L2FibEntryKey(address)); + } + + private L2FibTableEntry generateL2FibEntry(final long mac) { + final L2FibTableEntry entry = new L2FibTableEntry(); + entry.mac = mac; + entry.swIfIndex = IFACE_ID; + return entry; + } + + @Test + public void testGetAllIds() throws Exception { + final long address_vpp = 0x0000112233445566L; + final PhysAddress address = new PhysAddress("11:22:33:44:55:66"); + ContextTestUtils.mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); + + whenL2FibTableDumpThenReturn(Collections.singletonList(generateL2FibEntry(address_vpp))); + + final List ids = getCustomizer().getAllIds(getL2FibEntryId(BD_NAME, address), ctx); + assertEquals(1, ids.size()); + assertEquals(address, ids.get(0).getPhysAddress()); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizerTest.java new file mode 100644 index 000000000..b220b32da --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VersionCustomizerTest.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.translate.v3po.vppstate; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.v3po.test.ReaderCustomizerTest; +import java.util.concurrent.CompletableFuture; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.ShowVersion; +import org.openvpp.jvpp.dto.ShowVersionReply; + +public class VersionCustomizerTest extends ReaderCustomizerTest { + + public VersionCustomizerTest() { + super(Version.class); + } + + @Override + protected ReaderCustomizer initCustomizer() { + return new VersionCustomizer(api); + } + + @Test + public void testMerge() { + final VppStateBuilder builder = mock(VppStateBuilder.class); + final Version value = mock(Version.class); + getCustomizer().merge(builder, value); + verify(builder).setVersion(value); + } + + @Test + public void testReadCurrentAttributes() throws Exception { + final CompletableFuture replyFuture = new CompletableFuture<>(); + final ShowVersionReply reply = new ShowVersionReply(); + reply.version = new byte[]{}; + reply.program = new byte[]{}; + reply.buildDate = new byte[]{}; + reply.buildDirectory = new byte[]{}; + replyFuture.complete(reply); + + when(api.showVersion(any(ShowVersion.class))).thenReturn(replyFuture); + getCustomizer().readCurrentAttributes(InstanceIdentifier.create(Version.class), new VersionBuilder(), ctx); + verify(api).showVersion(any(ShowVersion.class)); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VppStateTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VppStateTest.java new file mode 100644 index 000000000..7287c2859 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VppStateTest.java @@ -0,0 +1,308 @@ +/* + * 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.translate.v3po.vppstate; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import com.google.common.collect.Iterables; +import com.google.common.collect.Multimap; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.v3po.test.ContextTestUtils; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppInvocationException; +import org.openvpp.jvpp.dto.BridgeDomainDetails; +import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump; +import org.openvpp.jvpp.dto.BridgeDomainDump; +import org.openvpp.jvpp.dto.L2FibTableDump; +import org.openvpp.jvpp.dto.L2FibTableEntry; +import org.openvpp.jvpp.dto.L2FibTableEntryReplyDump; +import org.openvpp.jvpp.dto.ShowVersion; +import org.openvpp.jvpp.dto.ShowVersionReply; +import org.openvpp.jvpp.future.FutureJVpp; + +public class VppStateTest { + + @Mock + private FutureJVpp api; + @Mock + private ReadContext ctx; + @Mock + private MappingContext mappingContext; + + private NamingContext bdContext; + private NamingContext interfaceContext; + + private ReaderRegistry readerRegistry; + + @Before + public void setUp() throws Exception { + initMocks(this); + final ModificationCache cache = new ModificationCache(); + doReturn(cache).when(ctx).getModificationCache(); + doReturn(mappingContext).when(ctx).getMappingContext(); + + bdContext = new NamingContext("generatedBdName", "bd-test-instance"); + interfaceContext = new NamingContext("generatedIfaceName", "ifc-test-instance"); + readerRegistry = VppStateTestUtils.getVppStateReader(api, bdContext); + } + + private static Version getVersion() { + return new VersionBuilder() + .setName("test") + .setBuildDirectory("1") + .setBranch("2") + .setBuildDate("3") + .build(); + } + + private void whenShowVersionThenReturn(int retval, Version version) + throws ExecutionException, InterruptedException, VppInvocationException { + final CompletableFuture replyFuture = new CompletableFuture<>(); + final ShowVersionReply reply = new ShowVersionReply(); + reply.buildDate = version.getBuildDate().getBytes(); + reply.program = version.getName().getBytes(); + reply.version = version.getBranch().getBytes(); + reply.buildDirectory = version.getBuildDirectory().getBytes(); + + replyFuture.complete(reply); + when(api.showVersion(any(ShowVersion.class))).thenReturn(replyFuture); + } + + private void whenL2FibTableDumpThenReturn(final List entryList) + throws ExecutionException, InterruptedException, VppInvocationException { + final CompletionStage replyCS = mock(CompletionStage.class); + final CompletableFuture replyFuture = mock(CompletableFuture.class); + when(replyCS.toCompletableFuture()).thenReturn(replyFuture); + final L2FibTableEntryReplyDump reply = new L2FibTableEntryReplyDump(); + reply.l2FibTableEntry = entryList; + when(replyFuture.get()).thenReturn(reply); + when(api.l2FibTableDump(any(L2FibTableDump.class))).thenReturn(replyCS); + } + + private void whenBridgeDomainDumpThenReturn(final List bdList) + throws ExecutionException, InterruptedException, VppInvocationException { + final CompletionStage replyCS = mock(CompletionStage.class); + final CompletableFuture replyFuture = mock(CompletableFuture.class); + when(replyCS.toCompletableFuture()).thenReturn(replyFuture); + final BridgeDomainDetailsReplyDump reply = new BridgeDomainDetailsReplyDump(); + reply.bridgeDomainDetails = bdList; + when(replyFuture.get()).thenReturn(reply); + + doAnswer(invocation -> { + BridgeDomainDump request = (BridgeDomainDump) invocation.getArguments()[0]; + if (request.bdId == -1) { + reply.bridgeDomainDetails = bdList; + } else { + reply.bridgeDomainDetails = Collections.singletonList(bdList.get(request.bdId)); + } + return replyCS; + }).when(api).bridgeDomainDump(any(BridgeDomainDump.class)); + } + + @Test + public void testReadAll() throws Exception { + final Version version = getVersion(); + whenShowVersionThenReturn(0, version); + + final BridgeDomainDetails bridgeDomainDetails = new BridgeDomainDetails(); + final BridgeDomainDetails bridgeDomainDetails2 = new BridgeDomainDetails(); + bridgeDomainDetails2.bdId = 1; + + final List bdList = Arrays.asList(bridgeDomainDetails, bridgeDomainDetails2); + mockBdMapping(bridgeDomainDetails, "bd1"); + mockBdMapping(bridgeDomainDetails2, "bd2"); + + whenBridgeDomainDumpThenReturn(bdList); + + final Multimap, ? extends DataObject> dataObjects = + readerRegistry.readAll(ctx); + assertEquals(dataObjects.size(), 1); + final VppState dataObject = + (VppState) Iterables.getOnlyElement(dataObjects.get(Iterables.getOnlyElement(dataObjects.keySet()))); + assertEquals(version, dataObject.getVersion()); + assertEquals(2, dataObject.getBridgeDomains().getBridgeDomain().size()); + } + + @Test + public void testReadSpecific() throws Exception { + final Version version = getVersion(); + whenShowVersionThenReturn(0, version); + whenBridgeDomainDumpThenReturn(Collections.emptyList()); + + final Optional read = readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx); + assertTrue(read.isPresent()); + assertEquals(version, ((VppState) read.get()).getVersion()); + } + + @Test + public void testReadBridgeDomains() throws Exception { + final Version version = getVersion(); + whenShowVersionThenReturn(0, version); + final BridgeDomainDetails details = new BridgeDomainDetails(); + whenBridgeDomainDumpThenReturn(Collections.singletonList(details)); + + mockBdMapping(details, "bdn1"); + VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); + + Optional read = + readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class), ctx); + assertTrue(read.isPresent()); + assertEquals(readRoot.getBridgeDomains(), read.get()); + } + + /** + * L2fib does not have a dedicated reader, relying on auto filtering + */ + @Test + @Ignore("L2 FIB was moved to dedicated customizer. TODO: add infra test that covers such case") + @SuppressWarnings("unchecked") + public void testReadL2Fib() throws Exception { + final BridgeDomainDetails bd = new BridgeDomainDetails(); + bd.bdId = 0; + final String bdName = "bdn1"; + mockBdMapping(bd, bdName); + ContextTestUtils.mockMapping(mappingContext, "eth1", 0, "ifc-test-instance"); + + whenBridgeDomainDumpThenReturn(Collections.singletonList(bd)); + final L2FibTableEntry l2FibEntry = new L2FibTableEntry(); + l2FibEntry.bdId = 0; + l2FibEntry.mac = 0x0605040302010000L; + whenL2FibTableDumpThenReturn(Collections.singletonList(l2FibEntry)); + + // Deep child without a dedicated reader with specific l2fib key + final InstanceIdentifier idExisting = + InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( + BridgeDomain.class, new BridgeDomainKey("bdn1")).child(L2FibTable.class) + .child(L2FibEntry.class, new L2FibEntryKey(new PhysAddress("01:02:03:04:05:06"))); + Optional read = + readerRegistry.read(idExisting, ctx); + assertTrue(read.isPresent()); + + // non existing l2fib + final InstanceIdentifier idNonExisting = + InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( + BridgeDomain.class, new BridgeDomainKey("bdn1")).child(L2FibTable.class) + .child(L2FibEntry.class, new L2FibEntryKey(new PhysAddress("FF:FF:FF:04:05:06"))); + read = readerRegistry.read(idNonExisting, ctx); + assertFalse(read.isPresent()); + } + + private void mockBdMapping(final BridgeDomainDetails bd, final String bdName) { + ContextTestUtils.mockMapping(mappingContext, bdName, bd.bdId, "bd-test-instance"); + } + + @Test + public void testReadBridgeDomainAll() throws Exception { + final Version version = getVersion(); + whenShowVersionThenReturn(0, version); + final BridgeDomainDetails details = new BridgeDomainDetails(); + whenBridgeDomainDumpThenReturn(Collections.singletonList(details)); + mockBdMapping(details, "bd2"); + + VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); + + final GenericListReader bridgeDomainReader = + VppStateTestUtils.getBridgeDomainReader(api, bdContext); + + final List read = + bridgeDomainReader.readList(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( + BridgeDomain.class), ctx); + + assertEquals(readRoot.getBridgeDomains().getBridgeDomain(), read); + } + + @Test + public void testReadBridgeDomain() throws Exception { + final BridgeDomainDetails bd = new BridgeDomainDetails(); + bd.bdId = 0; + final String bdName = "bdn1"; + mockBdMapping(bd, bdName); + + whenBridgeDomainDumpThenReturn(Collections.singletonList(bd)); + whenShowVersionThenReturn(0, getVersion()); + + VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); + + final Optional read = + readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( + BridgeDomain.class, new BridgeDomainKey(bdName)), ctx); + + assertTrue(read.isPresent()); + assertEquals(readRoot.getBridgeDomains().getBridgeDomain().stream().filter( + input -> input.getKey().getName().equals(bdName)).findFirst().get(), + read.get()); + } + + @Test(expected = IllegalArgumentException.class) + public void testReadBridgeDomainNotExisting() throws Exception { + doReturn(Optional.absent()).when(mappingContext).read( + ContextTestUtils.getMappingIid("NOT EXISTING", "bd-test-instance")); + + final Optional read = + readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( + BridgeDomain.class, new BridgeDomainKey("NOT EXISTING")), ctx); + assertFalse(read.isPresent()); + } + + @Test + public void testReadVersion() throws Exception { + whenShowVersionThenReturn(0, getVersion()); + whenBridgeDomainDumpThenReturn(Collections.emptyList()); + VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); + + Optional read = + readerRegistry.read(InstanceIdentifier.create(VppState.class).child(Version.class), ctx); + assertTrue(read.isPresent()); + assertEquals(readRoot.getVersion(), read.get()); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VppStateTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VppStateTestUtils.java new file mode 100644 index 000000000..b0f8e78d3 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/vppstate/VppStateTestUtils.java @@ -0,0 +1,72 @@ +/* + * 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.translate.v3po.vppstate; + +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.impl.read.GenericReader; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import io.fd.honeycomb.translate.util.read.registry.CompositeReaderRegistryBuilder; +import io.fd.honeycomb.translate.v3po.util.NamingContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; + +final class VppStateTestUtils { + + private static InstanceIdentifier bridgeDomainsId; + + public VppStateTestUtils() { + } + + /** + * Create root VppState reader with all its children wired. + */ + static ReaderRegistry getVppStateReader(@Nonnull final FutureJVpp jVpp, + @Nonnull final NamingContext bdContext) { + final CompositeReaderRegistryBuilder registry = new CompositeReaderRegistryBuilder(); + + // VppState(Structural) + final InstanceIdentifier vppStateId = InstanceIdentifier.create(VppState.class); + registry.addStructuralReader(vppStateId, VppStateBuilder.class); + // Version + // Wrap with keepalive reader to detect connection issues + // TODO keepalive reader wrapper relies on VersionReaderCustomizer (to perform timeout on reads) + // Once readers+customizers are asynchronous, pull the timeout to keepalive executor so that keepalive wrapper + // is truly generic + registry.add(new GenericReader<>(vppStateId.child(Version.class), new VersionCustomizer(jVpp))); + // BridgeDomains(Structural) + bridgeDomainsId = vppStateId.child(BridgeDomains.class); + registry.addStructuralReader(bridgeDomainsId, BridgeDomainsBuilder.class); + // BridgeDomain + registry.add(getBridgeDomainReader(jVpp, bdContext)); + return registry.build(); + } + + static GenericListReader getBridgeDomainReader( + final @Nonnull FutureJVpp jVpp, final @Nonnull NamingContext bdContext) { + final InstanceIdentifier bridgeDomainId = bridgeDomainsId.child(BridgeDomain.class); + return new GenericListReader<>(bridgeDomainId, new BridgeDomainCustomizer(jVpp, bdContext)); + } +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/initializers/InterfacesInitializerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/initializers/InterfacesInitializerTest.java deleted file mode 100644 index c7f71b977..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/initializers/InterfacesInitializerTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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.v3po.initializers; - -import static org.junit.Assert.assertEquals; -import static org.mockito.MockitoAnnotations.initMocks; - -import java.util.Arrays; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; - -public class InterfacesInitializerTest { - - @Mock - private DataBroker bindingDataBroker; - - private InterfacesInitializer interfacesInitializer; - - @Before - public void setUp() { - initMocks(this); - interfacesInitializer = new InterfacesInitializer(bindingDataBroker); - } - - @Test - public void testConvert() throws Exception { - final InterfacesState operationalData = operationalData(); - final Interfaces expectedConfigData = expectedConfigData(); - - final Interfaces configData = interfacesInitializer.convert(operationalData); - assertEquals(expectedConfigData, configData); - } - - private org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface operInterface( - String name, Class inerfaceType, Interface.AdminStatus adminStatus) { - final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder - iface = - new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder(); - iface.setKey( - new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey( - name)); - iface.setName(name); - iface.setType(inerfaceType); - iface.setAdminStatus(adminStatus); - return iface.build(); - } - - private InterfacesState operationalData() { - final InterfacesStateBuilder builder = new InterfacesStateBuilder(); - builder.setInterface( - Arrays.asList( - operInterface("eth1", EthernetCsmacd.class, Interface.AdminStatus.Up), - operInterface("eth2", EthernetCsmacd.class, Interface.AdminStatus.Down) - )); - return builder.build(); - } - - private org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface configInterface( - String name, Class inerfaceType, boolean isEnabled) { - final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder - iface = - new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder(); - iface.setKey( - new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey( - name)); - iface.setName(name); - iface.setType(inerfaceType); - iface.setEnabled(isEnabled); - return iface.build(); - } - - private Interfaces expectedConfigData() { - final InterfacesBuilder builder = new InterfacesBuilder(); - - builder.setInterface( - Arrays.asList( - configInterface("eth1", EthernetCsmacd.class, true), - configInterface("eth2", EthernetCsmacd.class, false) - )); - return builder.build(); - } - -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppInitializerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppInitializerTest.java deleted file mode 100644 index 4669ac83b..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/initializers/VppInitializerTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.v3po.initializers; - -import static org.junit.Assert.assertEquals; -import static org.mockito.MockitoAnnotations.initMocks; - -import java.util.Arrays; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; - -public class VppInitializerTest { - - @Mock - private DataBroker bindingDataBroker; - - private VppInitializer vppInitializer; - - @Before - public void setUp() throws Exception { - initMocks(this); - vppInitializer = new VppInitializer(bindingDataBroker); - } - - @Test - public void testConvert() throws Exception { - final VppState operationalData = operationalData(); - final Vpp expectedConfigData = expectedConfigData(); - final Vpp configData = vppInitializer.convert(operationalData); - assertEquals(expectedConfigData, configData); - } - - private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain - operBd(String name, boolean learn, boolean unknownUnicastFlood, boolean arpTermination, boolean flood, - boolean forward) { - final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder - bd = - new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder(); - bd.setName(name); - bd.setKey( - new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey( - name)); - bd.setLearn(learn); - bd.setUnknownUnicastFlood(unknownUnicastFlood); - bd.setArpTermination(arpTermination); - bd.setFlood(flood); - bd.setForward(forward); - return bd.build(); - } - - private VppState operationalData() { - final VppStateBuilder builder = new VppStateBuilder(); - - final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder - bdBuilder = - new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder(); - bdBuilder.setBridgeDomain(Arrays.asList( - operBd("b1", true, true, true, true, true), - operBd("b2", false, false, false, false, false) - )); - builder.setBridgeDomains(bdBuilder.build()); - return builder.build(); - } - - private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain - configBd(String name, boolean learn, boolean unknownUnicastFlood, boolean arpTermination, boolean flood, - boolean forward) { - final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder - bd = - new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder(); - bd.setName(name); - bd.setKey( - new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey( - name)); - bd.setLearn(learn); - bd.setUnknownUnicastFlood(unknownUnicastFlood); - bd.setArpTermination(arpTermination); - bd.setFlood(flood); - bd.setForward(forward); - return bd.build(); - } - - private Vpp expectedConfigData() { - final VppBuilder builder = new VppBuilder(); - - final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder - bdBuilder = - new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder(); - bdBuilder.setBridgeDomain(Arrays.asList( - configBd("b1", true, true, true, true, true), - configBd("b2", false, false, false, false, false) - )); - builder.setBridgeDomains(bdBuilder.build()); - return builder.build(); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclCustomizerTest.java deleted file mode 100644 index f08ffd46f..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/AclCustomizerTest.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2AclBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.AclBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.InputAclSetInterface; -import org.openvpp.jvpp.dto.InputAclSetInterfaceReply; -import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class AclCustomizerTest { - - @Mock - private FutureJVpp api; - @Mock - private WriteContext writeContext; - @Mock - private MappingContext mappingContext; - - private NamingContext interfaceContext; - private NamingContext classifyTableContext; - private AclCustomizer customizer; - - private static final String IFC_TEST_INSTANCE = "ifc-test-instance"; - private static final String CT_TEST_INSTANCE = "ct-test-instance"; - private static final String IF_NAME = "local0"; - private static final int IF_INDEX = 1; - - private static final int ACL_TABLE_INDEX = 0; - private static final String ACL_TABLE_NAME = "table0"; - - @Before - public void setUp() throws Exception { - initMocks(this); - interfaceContext = new NamingContext("generatedInterfaceName", IFC_TEST_INSTANCE); - classifyTableContext = new NamingContext("generatedClassifyTable", CT_TEST_INSTANCE); - doReturn(mappingContext).when(writeContext).getMappingContext(); - customizer = new AclCustomizer(api, interfaceContext, classifyTableContext); - - final KeyedInstanceIdentifier ifcMappingKey = getMappingIid(IF_NAME, IFC_TEST_INSTANCE); - final Optional ifcMapping = getMapping(IF_NAME, IF_INDEX); - doReturn(ifcMapping).when(mappingContext).read(ifcMappingKey); - - final KeyedInstanceIdentifier ctMappingKey = - getMappingIid(ACL_TABLE_NAME, CT_TEST_INSTANCE); - final Optional ctMapping = getMapping(ACL_TABLE_NAME, ACL_TABLE_INDEX); - doReturn(ctMapping).when(mappingContext).read(ctMappingKey); - - final List allCtMappings = Lists.newArrayList(ctMapping.get()); - final Mappings allCtMappingsBaObject = new MappingsBuilder().setMapping(allCtMappings).build(); - doReturn(Optional.of(allCtMappingsBaObject)).when(mappingContext) - .read(ctMappingKey.firstIdentifierOf(Mappings.class)); - } - - - private InstanceIdentifier getAclId(final String name) { - return InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(name)).augmentation( - VppInterfaceAugmentation.class).child(Acl.class); - } - - private Acl generateAcl(final String tableName) { - final AclBuilder builder = new AclBuilder(); - final L2Acl l2Acl = new L2AclBuilder().setClassifyTable(tableName).build(); - builder.setL2Acl(l2Acl); - return builder.build(); - } - - private void whenInputAclSetInterfaceThenSuccess() throws ExecutionException, InterruptedException { - final CompletableFuture replyFuture = new CompletableFuture<>(); - final InputAclSetInterfaceReply reply = new InputAclSetInterfaceReply(); - replyFuture.complete(reply); - doReturn(replyFuture).when(api).inputAclSetInterface(any(InputAclSetInterface.class)); - } - - private void whenInputAclSetInterfaceThenFailure() throws ExecutionException, InterruptedException { - doReturn(TestHelperUtils.createFutureException()).when(api) - .inputAclSetInterface(any(InputAclSetInterface.class)); - } - - private void verifyInputAclSetInterfaceWasInvoked(final InputAclSetInterface expected) { - final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(InputAclSetInterface.class); - verify(api).inputAclSetInterface(argumentCaptor.capture()); - final InputAclSetInterface actual = argumentCaptor.getValue(); - assertEquals(expected.swIfIndex, actual.swIfIndex); - assertEquals(expected.l2TableIndex, actual.l2TableIndex); - assertEquals(expected.ip4TableIndex, actual.ip4TableIndex); - assertEquals(expected.ip6TableIndex, actual.ip6TableIndex); - assertEquals(expected.isAdd, actual.isAdd); - } - - private void verifyInputAclSetInterfaceDisableWasInvoked(final InputAclSetInterface expected) { - final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(InputAclSetInterface.class); - verify(api).inputAclSetInterface(argumentCaptor.capture()); - final InputAclSetInterface actual = argumentCaptor.getValue(); - assertEquals(expected.swIfIndex, actual.swIfIndex); - assertEquals(expected.l2TableIndex, actual.l2TableIndex); - assertEquals(0, actual.isAdd); - } - - private static InputAclSetInterface generateInputAclSetInterface(final byte isAdd, final int ifIndex, - final int l2TableIndex) { - final InputAclSetInterface request = new InputAclSetInterface(); - request.isAdd = isAdd; - request.l2TableIndex = l2TableIndex; - request.ip4TableIndex = ~0; - request.ip6TableIndex = ~0; - request.swIfIndex = ifIndex; - return request; - } - - @Test - public void testCreate() throws Exception { - final Acl acl = generateAcl(ACL_TABLE_NAME); - final InstanceIdentifier id = getAclId(IF_NAME); - - whenInputAclSetInterfaceThenSuccess(); - - customizer.writeCurrentAttributes(id, acl, writeContext); - - verifyInputAclSetInterfaceWasInvoked(generateInputAclSetInterface((byte) 1, IF_INDEX, ACL_TABLE_INDEX)); - } - - @Test - public void testCreateFailed() throws Exception { - final Acl acl = generateAcl(ACL_TABLE_NAME); - final InstanceIdentifier id = getAclId(IF_NAME); - - whenInputAclSetInterfaceThenFailure(); - - try { - customizer.writeCurrentAttributes(id, acl, writeContext); - } catch (WriteFailedException.CreateFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyInputAclSetInterfaceWasInvoked(generateInputAclSetInterface((byte) 1, IF_INDEX, ACL_TABLE_INDEX)); - return; - } - fail("WriteFailedException.CreateFailedException was expected"); - } - - @Test - public void testDelete() throws Exception { - final Acl acl = generateAcl(ACL_TABLE_NAME); - final InstanceIdentifier id = getAclId(IF_NAME); - - whenInputAclSetInterfaceThenSuccess(); - - customizer.deleteCurrentAttributes(id, acl, writeContext); - - verifyInputAclSetInterfaceDisableWasInvoked(generateInputAclSetInterface((byte) 0, IF_INDEX, ACL_TABLE_INDEX)); - } - - @Test - public void testDeleteFailed() throws Exception { - final Acl acl = generateAcl(ACL_TABLE_NAME); - final InstanceIdentifier id = getAclId(IF_NAME); - - whenInputAclSetInterfaceThenFailure(); - - try { - customizer.deleteCurrentAttributes(id, acl, writeContext); - } catch (WriteFailedException.DeleteFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyInputAclSetInterfaceDisableWasInvoked( - generateInputAclSetInterface((byte) 0, IF_INDEX, ACL_TABLE_INDEX)); - return; - } - fail("WriteFailedException.DeleteFailedException was expected"); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceTypeTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceTypeTestUtils.java deleted file mode 100644 index fbb47b5d4..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/InterfaceTypeTestUtils.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static org.mockito.Mockito.doReturn; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import org.mockito.Matchers; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContextKey; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; - -final class InterfaceTypeTestUtils { - - private InterfaceTypeTestUtils() {} - - static void setupWriteContext(final WriteContext writeContext, final Class ifcType) { - doReturn(new ModificationCache()).when(writeContext).getModificationCache(); - doReturn(Optional.of(new InterfaceBuilder() - .setType(ifcType) - .build())).when(writeContext).readAfter(Matchers.any(InstanceIdentifier.class)); - } - -} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RewriteCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RewriteCustomizerTest.java deleted file mode 100644 index 45eaf9ec9..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/RewriteCustomizerTest.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TagRewriteOperation; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1q; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfaces; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.VppInvocationException; -import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewrite; -import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class RewriteCustomizerTest { - - @Mock - private FutureJVpp api; - @Mock - private WriteContext writeContext; - @Mock - private MappingContext mappingContext; - - private NamingContext namingContext; - private RewriteCustomizer customizer; - - public static final String VLAN_IF_NAME = "local0.1"; - public static final int VLAN_IF_ID = 1; - public static final int VLAN_IF_INDEX = 11; - - @Before - public void setUp() throws Exception { - initMocks(this); - namingContext = new NamingContext("generatedSubInterfaceName", "test-instance"); - doReturn(mappingContext).when(writeContext).getMappingContext(); - customizer = new RewriteCustomizer(api, namingContext); - - final Optional ifcMapping = getMapping(VLAN_IF_NAME, VLAN_IF_INDEX); - doReturn(ifcMapping).when(mappingContext).read(any()); - } - - private InstanceIdentifier getVlanTagRewriteId(final String name, final long index) { - final Class> child = (Class)Rewrite.class; - final InstanceIdentifier id = - InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(name)).augmentation( - SubinterfaceAugmentation.class).child(SubInterfaces.class) - .child(SubInterface.class, new SubInterfaceKey(index)) - .child(child); - return id; - } - - private Rewrite generateRewrite(final TagRewriteOperation op) { - final RewriteBuilder builder = new RewriteBuilder(); - builder.setPopTags((short) op.getPopTags()); - builder.setVlanType(_802dot1q.class); - return builder.build(); - } - - private L2InterfaceVlanTagRewrite generateL2InterfaceVlanTagRewrite(final int swIfIndex, - final TagRewriteOperation op) { - final L2InterfaceVlanTagRewrite request = new L2InterfaceVlanTagRewrite(); - request.swIfIndex = swIfIndex; - request.vtrOp = op.ordinal(); - request.pushDot1Q = 1; - return request; - } - - /** - * Positive response - */ - private void whenL2InterfaceVlanTagRewriteThenSuccess() - throws ExecutionException, InterruptedException, VppInvocationException { - final CompletableFuture replyFuture = new CompletableFuture<>(); - final L2InterfaceVlanTagRewriteReply reply = new L2InterfaceVlanTagRewriteReply(); - replyFuture.complete(reply); - doReturn(replyFuture).when(api).l2InterfaceVlanTagRewrite(any(L2InterfaceVlanTagRewrite.class)); - } - - /** - * Failure response send - */ - private void whenL2InterfaceVlanTagRewriteThenFailure() - throws ExecutionException, InterruptedException, VppInvocationException { - doReturn(TestHelperUtils.createFutureException()).when(api) - .l2InterfaceVlanTagRewrite(any(L2InterfaceVlanTagRewrite.class)); - } - - private void verifyL2InterfaceVlanTagRewriteWasInvoked(final L2InterfaceVlanTagRewrite expected) - throws VppInvocationException { - ArgumentCaptor argumentCaptor = - ArgumentCaptor.forClass(L2InterfaceVlanTagRewrite.class); - verify(api).l2InterfaceVlanTagRewrite(argumentCaptor.capture()); - final L2InterfaceVlanTagRewrite actual = argumentCaptor.getValue(); - assertEquals(expected.swIfIndex, actual.swIfIndex); - assertEquals(expected.vtrOp, actual.vtrOp); - assertEquals(expected.pushDot1Q, actual.pushDot1Q); - assertEquals(expected.tag1, actual.tag1); - assertEquals(expected.tag2, actual.tag2); - } - - private void verifyL2InterfaceVlanTagRewriteDeleteWasInvoked() throws VppInvocationException { - final L2InterfaceVlanTagRewrite request = new L2InterfaceVlanTagRewrite(); - request.swIfIndex = VLAN_IF_INDEX; - verifyL2InterfaceVlanTagRewriteWasInvoked(request); - } - - @Test - public void testCreate() throws Exception { - final TagRewriteOperation op = TagRewriteOperation.pop_2; - final Rewrite vlanTagRewrite = generateRewrite(op); - final InstanceIdentifier id = getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID); - - whenL2InterfaceVlanTagRewriteThenSuccess(); - - customizer.writeCurrentAttributes(id, vlanTagRewrite, writeContext); - - verifyL2InterfaceVlanTagRewriteWasInvoked(generateL2InterfaceVlanTagRewrite(VLAN_IF_INDEX, op)); - } - - @Test - public void testCreateFailed() throws Exception { - final TagRewriteOperation op = TagRewriteOperation.pop_2; - final Rewrite vlanTagRewrite = generateRewrite(op); - final String subIfaceName = "local0.11"; - final int subifIndex = 1; - final InstanceIdentifier id = getVlanTagRewriteId(subIfaceName, subifIndex); - - whenL2InterfaceVlanTagRewriteThenFailure(); - - try { - customizer.writeCurrentAttributes(id, vlanTagRewrite, writeContext); - } catch (WriteFailedException.CreateFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyL2InterfaceVlanTagRewriteWasInvoked(generateL2InterfaceVlanTagRewrite(VLAN_IF_INDEX, op)); - return; - } - fail("WriteFailedException.CreateFailedException was expected"); - } - - @Test - public void testUpdate() throws Exception { - final Rewrite before = generateRewrite(TagRewriteOperation.pop_2); - final Rewrite after = generateRewrite(TagRewriteOperation.pop_1); - final InstanceIdentifier id = getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID); - - whenL2InterfaceVlanTagRewriteThenSuccess(); - - customizer.updateCurrentAttributes(id, before, after, writeContext); - - verifyL2InterfaceVlanTagRewriteWasInvoked( - generateL2InterfaceVlanTagRewrite(VLAN_IF_INDEX, TagRewriteOperation.pop_1)); - } - - @Test - public void testUpdateFailed() throws Exception { - final Rewrite before = generateRewrite(TagRewriteOperation.pop_2); - final Rewrite after = generateRewrite(TagRewriteOperation.pop_1); - final InstanceIdentifier id = getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID); - - whenL2InterfaceVlanTagRewriteThenFailure(); - - try { - customizer.updateCurrentAttributes(id, before, after, writeContext); - } catch (WriteFailedException.UpdateFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyL2InterfaceVlanTagRewriteWasInvoked(generateL2InterfaceVlanTagRewrite(VLAN_IF_INDEX, - TagRewriteOperation.pop_1)); - return; - } - fail("WriteFailedException.UpdateFailedException was expected"); - } - - @Test - public void testDelete() throws Exception { - final InstanceIdentifier id = getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID); - - whenL2InterfaceVlanTagRewriteThenSuccess(); - - customizer.deleteCurrentAttributes(id, null, writeContext); - - verifyL2InterfaceVlanTagRewriteDeleteWasInvoked(); - } - - @Test - public void testDeleteFailed() throws Exception { - final InstanceIdentifier id = getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID); - - whenL2InterfaceVlanTagRewriteThenFailure(); - - try { - customizer.deleteCurrentAttributes(id, null, writeContext); - } catch (WriteFailedException.DeleteFailedException e) { - Assert.assertTrue(e.getCause() instanceof VppBaseCallException); - verifyL2InterfaceVlanTagRewriteDeleteWasInvoked(); - return; - } - fail("WriteFailedException.DeleteFailedException was expected"); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceCustomizerTest.java deleted file mode 100644 index 3e15acb0c..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/SubInterfaceCustomizerTest.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.CVlan; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qTagVlanType; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.Dot1qVlanId; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.SVlan; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag; -import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTagBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1ad; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.SubInterfaces; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.vlan.tagged.VlanTaggedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.MatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.TagsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.TagBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.TagKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.CreateSubif; -import org.openvpp.jvpp.dto.CreateSubifReply; -import org.openvpp.jvpp.dto.SwInterfaceSetFlags; -import org.openvpp.jvpp.dto.SwInterfaceSetFlagsReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class SubInterfaceCustomizerTest { - - @Mock - private FutureJVpp api; - @Mock - private WriteContext writeContext; - @Mock - private MappingContext mappingContext; - - private NamingContext namingContext; - private SubInterfaceCustomizer customizer; - - public static final String SUPER_IF_NAME = "local0"; - public static final int SUPER_IF_ID = 1; - private static final String SUB_IFACE_NAME = "local0.11"; - private static final int SUBIF_INDEX = 11; - - private static final short STAG_ID = 100; - private static final short CTAG_ID = 200; - private static final short CTAG_ANY_ID = 0; // only the *IdAny flag is set - - private final Tag STAG_100; - private final Tag CTAG_200; - private final Tag CTAG_ANY; - - public SubInterfaceCustomizerTest() { - STAG_100 = generateTag((short) 0, SVlan.class, new Dot1qTag.VlanId(new Dot1qVlanId((int) STAG_ID))); - CTAG_200 = generateTag((short) 1, CVlan.class, new Dot1qTag.VlanId(new Dot1qVlanId(200))); - CTAG_ANY = generateTag((short) 1, CVlan.class, new Dot1qTag.VlanId(Dot1qTag.VlanId.Enumeration.Any)); - } - - @Before - public void setUp() throws Exception { - initMocks(this); - namingContext = new NamingContext("generatedSubInterfaceName", "test-instance"); - doReturn(mappingContext).when(writeContext).getMappingContext(); - // TODO create base class for tests using vppApi - customizer = new SubInterfaceCustomizer(api, namingContext); - doReturn(getMapping(SUPER_IF_NAME, SUPER_IF_ID)).when(mappingContext) - .read(getMappingIid(SUPER_IF_NAME, "test-instance")); - } - - private SubInterface generateSubInterface(final boolean enabled, final List tagList) { - SubInterfaceBuilder builder = new SubInterfaceBuilder(); - builder.setVlanType(_802dot1ad.class); - builder.setIdentifier(11L); - final TagsBuilder tags = new TagsBuilder(); - - tags.setTag(tagList); - - builder.setTags(tags.build()); - - builder.setMatch(generateMatch()); - builder.setEnabled(enabled); - return builder.build(); - } - - private static Tag generateTag(final short index, final Class tagType, - final Dot1qTag.VlanId vlanId) { - TagBuilder tag = new TagBuilder(); - tag.setIndex(index); - tag.setKey(new TagKey(index)); - final Dot1qTagBuilder dtag = new Dot1qTagBuilder(); - dtag.setTagType(tagType); - dtag.setVlanId(vlanId); - tag.setDot1qTag(dtag.build()); - return tag.build(); - } - - private static Match generateMatch() { - final MatchBuilder match = new MatchBuilder(); - final VlanTaggedBuilder tagged = new VlanTaggedBuilder(); - tagged.setMatchExactTags(true); - match.setMatchType( - new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.VlanTaggedBuilder() - .setVlanTagged(tagged.build()).build()); - return match.build(); - } - - private CreateSubif generateSubInterfaceRequest(final int superIfId, final short innerVlanId, - final boolean isInnerAny) { - CreateSubif request = new CreateSubif(); - request.subId = 11; - request.swIfIndex = superIfId; - request.twoTags = 1; - request.innerVlanId = innerVlanId; - request.innerVlanIdAny = (byte) (isInnerAny - ? 1 - : 0); - request.dot1Ad = 1; - request.outerVlanId = STAG_ID; - return request; - } - - private SwInterfaceSetFlags generateSwInterfaceEnableRequest(final int swIfIndex) { - SwInterfaceSetFlags request = new SwInterfaceSetFlags(); - request.swIfIndex = swIfIndex; - request.adminUpDown = 1; - return request; - } - - private InstanceIdentifier getSubInterfaceId(final String name, final long index) { - return InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(name)).augmentation( - SubinterfaceAugmentation.class).child(SubInterfaces.class) - .child(SubInterface.class, new SubInterfaceKey(index)); - } - - private void whenCreateSubifThenSuccess() throws ExecutionException, InterruptedException, VppBaseCallException { - final CompletableFuture replyFuture = new CompletableFuture<>(); - final CreateSubifReply reply = new CreateSubifReply(); - replyFuture.complete(reply); - doReturn(replyFuture).when(api).createSubif(any(CreateSubif.class)); - } - - /** - * Failure response send - */ - private void whenCreateSubifThenFailure() throws ExecutionException, InterruptedException, VppBaseCallException { - doReturn(TestHelperUtils.createFutureException()).when(api) - .createSubif(any(CreateSubif.class)); - } - - private void whenSwInterfaceSetFlagsThenSuccess() - throws ExecutionException, InterruptedException, VppBaseCallException { - final CompletableFuture replyFuture = new CompletableFuture<>(); - final SwInterfaceSetFlagsReply reply = new SwInterfaceSetFlagsReply(); - replyFuture.complete(reply); - doReturn(replyFuture).when(api).swInterfaceSetFlags(any(SwInterfaceSetFlags.class)); - } - - private CreateSubif verifyCreateSubifWasInvoked(final CreateSubif expected) throws VppBaseCallException { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateSubif.class); - verify(api).createSubif(argumentCaptor.capture()); - final CreateSubif actual = argumentCaptor.getValue(); - - assertEquals(expected.swIfIndex, actual.swIfIndex); - assertEquals(expected.subId, actual.subId); - assertEquals(expected.noTags, actual.noTags); - assertEquals(expected.oneTag, actual.oneTag); - assertEquals(expected.twoTags, actual.twoTags); - assertEquals(expected.dot1Ad, actual.dot1Ad); - assertEquals(expected.exactMatch, actual.exactMatch); - assertEquals(expected.defaultSub, actual.defaultSub); - assertEquals(expected.outerVlanIdAny, actual.outerVlanIdAny); - assertEquals(expected.innerVlanIdAny, actual.innerVlanIdAny); - assertEquals(expected.outerVlanId, actual.outerVlanId); - assertEquals(expected.innerVlanId, actual.innerVlanId); - return actual; - } - - private SwInterfaceSetFlags verifySwInterfaceSetFlagsWasInvoked(final SwInterfaceSetFlags expected) - throws VppBaseCallException { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(SwInterfaceSetFlags.class); - verify(api).swInterfaceSetFlags(argumentCaptor.capture()); - final SwInterfaceSetFlags actual = argumentCaptor.getValue(); - - assertEquals(expected.swIfIndex, actual.swIfIndex); - assertEquals(expected.adminUpDown, actual.adminUpDown); - return actual; - } - - @Test - public void testCreateTwoTags() throws Exception { - final SubInterface subInterface = generateSubInterface(false, Arrays.asList(STAG_100, CTAG_200)); - final InstanceIdentifier id = getSubInterfaceId(SUPER_IF_NAME, SUBIF_INDEX); - - whenCreateSubifThenSuccess(); - whenSwInterfaceSetFlagsThenSuccess(); - - customizer.writeCurrentAttributes(id, subInterface, writeContext); - - verifyCreateSubifWasInvoked(generateSubInterfaceRequest(SUPER_IF_ID, CTAG_ID, false)); - verify(mappingContext) - .put(eq(getMappingIid(SUB_IFACE_NAME, "test-instance")), eq(getMapping(SUB_IFACE_NAME, 0).get())); - } - - @Test - public void testCreateDot1qAnyTag() throws Exception { - final SubInterface subInterface = generateSubInterface(false, Arrays.asList(STAG_100, CTAG_ANY)); - final InstanceIdentifier id = getSubInterfaceId(SUPER_IF_NAME, SUBIF_INDEX); - - whenCreateSubifThenSuccess(); - whenSwInterfaceSetFlagsThenSuccess(); - - customizer.writeCurrentAttributes(id, subInterface, writeContext); - - verifyCreateSubifWasInvoked(generateSubInterfaceRequest(SUPER_IF_ID, CTAG_ANY_ID, true)); - verify(mappingContext) - .put(eq(getMappingIid(SUB_IFACE_NAME, "test-instance")), eq(getMapping(SUB_IFACE_NAME, 0).get())); - } - - @Test - public void testCreateFailed() throws Exception { - final SubInterface subInterface = generateSubInterface(false, Arrays.asList(STAG_100, CTAG_200)); - final InstanceIdentifier id = getSubInterfaceId(SUPER_IF_NAME, SUBIF_INDEX); - - whenCreateSubifThenFailure(); - - try { - customizer.writeCurrentAttributes(id, subInterface, writeContext); - } catch (WriteFailedException.CreateFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyCreateSubifWasInvoked(generateSubInterfaceRequest(SUPER_IF_ID, CTAG_ID, false)); - verify(mappingContext, times(0)).put( - eq(getMappingIid(SUPER_IF_NAME, "test-instance")), - eq(getMapping(SUPER_IF_NAME, 0).get())); - return; - } - fail("WriteFailedException.CreateFailedException was expected"); - } - - @Test - public void testUpdate() throws Exception { - final List tags = Arrays.asList(STAG_100, CTAG_200); - final SubInterface before = generateSubInterface(false, tags); - final SubInterface after = generateSubInterface(true, tags); - final InstanceIdentifier id = getSubInterfaceId(SUPER_IF_NAME, SUBIF_INDEX); - - whenSwInterfaceSetFlagsThenSuccess(); - final Optional ifcMapping = getMapping(SUPER_IF_NAME, SUBIF_INDEX); - doReturn(ifcMapping).when(mappingContext).read(any()); - - customizer.updateCurrentAttributes(id, before, after, writeContext); - - verifySwInterfaceSetFlagsWasInvoked(generateSwInterfaceEnableRequest(SUBIF_INDEX)); - } - - @Test - public void testUpdateNoStateChange() throws Exception { - final List tags = Arrays.asList(STAG_100, CTAG_200); - final SubInterface before = generateSubInterface(false, tags); - final SubInterface after = generateSubInterface(false, tags); - customizer.updateCurrentAttributes(null, before, after, writeContext); - - verify(api, never()).swInterfaceSetFlags(any()); - } - - @Test(expected = UnsupportedOperationException.class) - public void testDelete() throws Exception { - final SubInterface subInterface = generateSubInterface(false, Arrays.asList(STAG_100, CTAG_200)); - customizer.deleteCurrentAttributes(null, subInterface, writeContext); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizerTest.java deleted file mode 100644 index ea6990f60..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/TapCustomizerTest.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import java.util.concurrent.CompletableFuture; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Tap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.TapBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.TapConnect; -import org.openvpp.jvpp.dto.TapConnectReply; -import org.openvpp.jvpp.dto.TapDelete; -import org.openvpp.jvpp.dto.TapDeleteReply; -import org.openvpp.jvpp.dto.TapModify; -import org.openvpp.jvpp.dto.TapModifyReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class TapCustomizerTest { - - @Mock - private FutureJVpp vppApi; - @Mock - private WriteContext writeContext; - @Mock - private MappingContext mappingContext; - - private TapCustomizer tapCustomizer; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - InterfaceTypeTestUtils.setupWriteContext(writeContext, - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap.class); - final NamingContext ctx = new NamingContext("ifcintest", "test-instance"); - final ModificationCache toBeReturned = new ModificationCache(); - doReturn(toBeReturned).when(writeContext).getModificationCache(); - doReturn(mappingContext).when(writeContext).getMappingContext(); - - tapCustomizer = new TapCustomizer(vppApi, ctx); - } - - @Test - public void testCreate() throws Exception { - doAnswer(new Answer() { - - int idx = 0; - - @Override - public Object answer(final InvocationOnMock invocation) throws Throwable { - final CompletableFuture reply = new CompletableFuture<>(); - final TapConnectReply t = new TapConnectReply(); - t.swIfIndex = idx++; - reply.complete(t); - return reply; - } - }).when(vppApi).tapConnect(any(TapConnect.class)); - - tapCustomizer.writeCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), writeContext); - tapCustomizer.writeCurrentAttributes(getTapId("tap2"), getTapData("tap2", "ff:ff:ff:ff:ff:ff"), writeContext); - - verify(vppApi, times(2)).tapConnect(any(TapConnect.class)); - verify(mappingContext).put(eq(getMappingIid("tap", "test-instance")), eq(getMapping("tap", 0).get())); - verify(mappingContext).put(eq(getMappingIid("tap2", "test-instance")), eq(getMapping("tap2", 1).get())); - } - - @Test - public void testModify() throws Exception { - final CompletableFuture reply = new CompletableFuture<>(); - final TapConnectReply t = new TapConnectReply(); - t.swIfIndex = 0; - reply.complete(t); - doReturn(reply).when(vppApi).tapConnect(any(TapConnect.class)); - - final CompletableFuture replyModif = new CompletableFuture<>(); - final TapModifyReply tmodif = new TapModifyReply(); - tmodif.swIfIndex = 0; - replyModif.complete(tmodif); - doReturn(replyModif).when(vppApi).tapModify(any(TapModify.class)); - - tapCustomizer.writeCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), writeContext); - doReturn(getMapping("tap", 1)).when(mappingContext).read(getMappingIid("tap", "test-instance")); - tapCustomizer.updateCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), getTapData("tap", "ff:ff:ff:ff:ff:f1"), writeContext); - - verify(vppApi).tapConnect(any(TapConnect.class)); - verify(vppApi).tapModify(any(TapModify.class)); - - verify(mappingContext).put(eq(getMappingIid("tap", "test-instance")), eq(getMapping("tap", 0).get())); - } - - @Test - public void testDelete() throws Exception { - final CompletableFuture reply = new CompletableFuture<>(); - final TapConnectReply t = new TapConnectReply(); - t.swIfIndex = 0; - reply.complete(t); - doReturn(reply).when(vppApi).tapConnect(any(TapConnect.class)); - - final CompletableFuture replyDelete = new CompletableFuture<>(); - final TapDeleteReply tmodif = new TapDeleteReply(); - replyDelete.complete(tmodif); - doReturn(replyDelete).when(vppApi).tapDelete(any(TapDelete.class)); - - tapCustomizer.writeCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), writeContext); - doReturn(getMapping("tap", 1)).when(mappingContext).read(getMappingIid("tap", "test-instance")); - tapCustomizer.deleteCurrentAttributes(getTapId("tap"), getTapData("tap", "ff:ff:ff:ff:ff:ff"), writeContext); - - verify(vppApi).tapConnect(any(TapConnect.class)); - verify(vppApi).tapDelete(any(TapDelete.class)); - verify(mappingContext).delete(eq(getMappingIid("tap", "test-instance"))); - } - - private InstanceIdentifier getTapId(final String tap) { - return InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(tap)).augmentation( - VppInterfaceAugmentation.class).child(Tap.class); - } - - private Tap getTapData(final String tap, final String mac) { - return new TapBuilder().setTapName(tap).setMac(new PhysAddress(mac)).build(); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VhostUserCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VhostUserCustomizerTest.java deleted file mode 100644 index 959d6eb4a..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VhostUserCustomizerTest.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUserRole; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUser; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VhostUserBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.VppInvocationException; -import org.openvpp.jvpp.dto.CreateVhostUserIf; -import org.openvpp.jvpp.dto.CreateVhostUserIfReply; -import org.openvpp.jvpp.dto.DeleteVhostUserIf; -import org.openvpp.jvpp.dto.DeleteVhostUserIfReply; -import org.openvpp.jvpp.dto.ModifyVhostUserIf; -import org.openvpp.jvpp.dto.ModifyVhostUserIfReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class VhostUserCustomizerTest { - - @Mock - private FutureJVpp api; - @Mock - private WriteContext writeContext; - @Mock - private MappingContext mappingContext; - - private VhostUserCustomizer customizer; - private static final int IFACE_ID = 1; - private static final String IFACE_NAME = "eth0"; - private static final InstanceIdentifier ID = - InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(IFACE_NAME)) - .augmentation(VppInterfaceAugmentation.class).child(VhostUser.class); - - @Before - public void setUp() throws Exception { - initMocks(this); - InterfaceTypeTestUtils.setupWriteContext(writeContext, - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser.class); - final NamingContext namingContext = new NamingContext("generatedInterfaceName", "test-instance"); - final ModificationCache toBeReturned = new ModificationCache(); - doReturn(toBeReturned).when(writeContext).getModificationCache(); - doReturn(mappingContext).when(writeContext).getMappingContext(); - - // TODO create base class for tests using vppApi - customizer = new VhostUserCustomizer(api, namingContext); - } - - private void whenCreateVhostUserIfThenSuccess() - throws ExecutionException, InterruptedException, VppInvocationException, TimeoutException { - final CompletionStage replyCS = mock(CompletionStage.class); - final CompletableFuture replyFuture = mock(CompletableFuture.class); - when(replyCS.toCompletableFuture()).thenReturn(replyFuture); - final CreateVhostUserIfReply reply = new CreateVhostUserIfReply(); - when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); - when(api.createVhostUserIf(any(CreateVhostUserIf.class))).thenReturn(replyCS); - } - - /** - * Failure response send - */ - private void whenCreateVhostUserIfThenFailure() - throws ExecutionException, InterruptedException, VppInvocationException { - doReturn(TestHelperUtils.createFutureException()).when(api) - .createVhostUserIf(any(CreateVhostUserIf.class)); - } - - private void whenModifyVhostUserIfThenSuccess() - throws ExecutionException, InterruptedException, VppInvocationException, TimeoutException { - final CompletionStage replyCS = mock(CompletionStage.class); - final CompletableFuture replyFuture = mock(CompletableFuture.class); - when(replyCS.toCompletableFuture()).thenReturn(replyFuture); - final ModifyVhostUserIfReply reply = new ModifyVhostUserIfReply(); - when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); - when(api.modifyVhostUserIf(any(ModifyVhostUserIf.class))).thenReturn(replyCS); - } - - /** - * Failure response send - */ - private void whenModifyVhostUserIfThenFailure() - throws ExecutionException, InterruptedException, VppInvocationException { - doReturn(TestHelperUtils.createFutureException()).when(api) - .modifyVhostUserIf(any(ModifyVhostUserIf.class)); - } - - private void whenDeleteVhostUserIfThenSuccess() - throws ExecutionException, InterruptedException, VppInvocationException, TimeoutException { - final CompletionStage replyCS = mock(CompletionStage.class); - final CompletableFuture replyFuture = mock(CompletableFuture.class); - when(replyCS.toCompletableFuture()).thenReturn(replyFuture); - final DeleteVhostUserIfReply reply = new DeleteVhostUserIfReply(); - when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); - when(api.deleteVhostUserIf(any(DeleteVhostUserIf.class))).thenReturn(replyCS); - } - - /** - * Failure response send - */ - private void whenDeleteVhostUserIfThenFailure() - throws ExecutionException, InterruptedException, VppInvocationException { - doReturn(TestHelperUtils.createFutureException()).when(api) - .deleteVhostUserIf(any(DeleteVhostUserIf.class)); - } - - private CreateVhostUserIf verifyCreateVhostUserIfWasInvoked(final VhostUser vhostUser) throws VppInvocationException { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(CreateVhostUserIf.class); - verify(api).createVhostUserIf(argumentCaptor.capture()); - final CreateVhostUserIf actual = argumentCaptor.getValue(); - assertEquals(0, actual.customDevInstance); - - assertEquals(TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())), actual.isServer); - assertEquals(0, actual.renumber); - assertEquals(0, actual.useCustomMac); - assertArrayEquals(vhostUser.getSocket().getBytes(), actual.sockFilename); - assertNotNull(actual.macAddress); - return actual; - } - - private ModifyVhostUserIf verifyModifyVhostUserIfWasInvoked(final VhostUser vhostUser, final int swIfIndex) - throws VppInvocationException { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(ModifyVhostUserIf.class); - verify(api).modifyVhostUserIf(argumentCaptor.capture()); - final ModifyVhostUserIf actual = argumentCaptor.getValue(); - assertEquals(0, actual.customDevInstance); - - assertEquals(TranslateUtils.booleanToByte(VhostUserRole.Server.equals(vhostUser.getRole())), actual.isServer); - assertEquals(0, actual.renumber); - assertEquals(swIfIndex, actual.swIfIndex); - assertArrayEquals(vhostUser.getSocket().getBytes(), actual.sockFilename); - return actual; - } - - private DeleteVhostUserIf verifyDeleteVhostUserIfWasInvoked(final int swIfIndex) throws VppInvocationException { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(DeleteVhostUserIf.class); - verify(api).deleteVhostUserIf(argumentCaptor.capture()); - final DeleteVhostUserIf actual = argumentCaptor.getValue(); - assertEquals(swIfIndex, actual.swIfIndex); - return actual; - } - - private static VhostUser generateVhostUser(final VhostUserRole role, final String socketName) { - VhostUserBuilder builder = new VhostUserBuilder(); - builder.setRole(role); - builder.setSocket(socketName); - return builder.build(); - } - - @Test - public void testWriteCurrentAttributes() throws Exception { - final VhostUser vhostUser = generateVhostUser(VhostUserRole.Server, "socketName"); - - whenCreateVhostUserIfThenSuccess(); - - customizer.writeCurrentAttributes(ID, vhostUser, writeContext); - verifyCreateVhostUserIfWasInvoked(vhostUser); - verify(mappingContext).put(eq(getMappingIid(IFACE_NAME, "test-instance")), eq(getMapping(IFACE_NAME, 0).get())); - } - - @Test - public void testWriteCurrentAttributesFailed() throws Exception { - final VhostUser vhostUser = generateVhostUser(VhostUserRole.Client, "socketName"); - - whenCreateVhostUserIfThenFailure(); - - try { - customizer.writeCurrentAttributes(ID, vhostUser, writeContext); - } catch (WriteFailedException.CreateFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyCreateVhostUserIfWasInvoked(vhostUser); - verifyZeroInteractions(mappingContext); - return; - } - fail("WriteFailedException.CreateFailedException was expected"); - } - - @Test - public void testUpdateCurrentAttributes() throws Exception { - final VhostUser vhostUserBefore = generateVhostUser(VhostUserRole.Client, "socketName0"); - final VhostUser vhostUserAfter = generateVhostUser(VhostUserRole.Server, "socketName1"); - doReturn(getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read(getMappingIid(IFACE_NAME, "test-instance")); - - whenModifyVhostUserIfThenSuccess(); - - customizer.updateCurrentAttributes(ID, vhostUserBefore, vhostUserAfter, writeContext); - verifyModifyVhostUserIfWasInvoked(vhostUserAfter, IFACE_ID); - } - - @Test - public void testUpdateCurrentAttributesFailed() throws Exception { - final VhostUser vhostUserBefore = generateVhostUser(VhostUserRole.Client, "socketName0"); - final VhostUser vhostUserAfter = generateVhostUser(VhostUserRole.Server, "socketName1"); - doReturn(getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read(getMappingIid(IFACE_NAME, "test-instance")); - - whenModifyVhostUserIfThenFailure(); - - try { - customizer.updateCurrentAttributes(ID, vhostUserBefore, vhostUserAfter, writeContext); - } catch (WriteFailedException.UpdateFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyModifyVhostUserIfWasInvoked(vhostUserAfter, IFACE_ID); - return; - } - fail("WriteFailedException.UpdateFailedException was expected"); - } - - @Test - public void testDeleteCurrentAttributes() throws Exception { - final VhostUser vhostUser = generateVhostUser(VhostUserRole.Client, "socketName"); - doReturn(getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read(getMappingIid(IFACE_NAME, "test-instance")); - - whenDeleteVhostUserIfThenSuccess(); - - customizer.deleteCurrentAttributes(ID, vhostUser, writeContext); - verifyDeleteVhostUserIfWasInvoked(IFACE_ID); - verify(mappingContext).delete(eq(getMappingIid(IFACE_NAME, "test-instance"))); - } - - @Test - public void testDeleteCurrentAttributesFailed() throws Exception { - final VhostUser vhostUser = generateVhostUser(VhostUserRole.Client, "socketName"); - doReturn(getMapping(IFACE_NAME, IFACE_ID)).when(mappingContext).read(getMappingIid(IFACE_NAME, "test-instance")); - - whenDeleteVhostUserIfThenFailure(); - - try { - customizer.deleteCurrentAttributes(ID, vhostUser, writeContext); - } catch (WriteFailedException.DeleteFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyDeleteVhostUserIfWasInvoked(IFACE_ID); - // Delete from context not invoked if delete from VPP failed - verify(mappingContext, times(0)).delete(eq(getMappingIid(IFACE_NAME, "test-instance"))); - verify(mappingContext).read(eq(getMappingIid(IFACE_NAME, "test-instance"))); - return; - } - fail("WriteFailedException.DeleteFailedException was expected"); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanCustomizerTest.java deleted file mode 100644 index 1d00e2f11..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanCustomizerTest.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static java.util.Collections.singletonList; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import com.google.common.net.InetAddresses; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.VppInvocationException; -import org.openvpp.jvpp.dto.VxlanAddDelTunnel; -import org.openvpp.jvpp.dto.VxlanAddDelTunnelReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class VxlanCustomizerTest { - - private static final byte ADD_VXLAN = 1; - private static final byte DEL_VXLAN = 0; - - @Mock - private FutureJVpp api; - @Mock - private WriteContext writeContext; - @Mock - private MappingContext mappingContext; - - private VxlanCustomizer customizer; - private String ifaceName; - private InstanceIdentifier id; - - @Before - public void setUp() throws Exception { - initMocks(this); - InterfaceTypeTestUtils.setupWriteContext(writeContext, - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel.class); - // TODO create base class for tests using vppApi - NamingContext namingContext = new NamingContext("generateInterfaceNAme", "test-instance"); - final ModificationCache toBeReturned = new ModificationCache(); - doReturn(toBeReturned).when(writeContext).getModificationCache(); - doReturn(mappingContext).when(writeContext).getMappingContext(); - - customizer = new VxlanCustomizer(api, namingContext); - - ifaceName = "eth0"; - id = InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(ifaceName)) - .augmentation(VppInterfaceAugmentation.class).child(Vxlan.class); - } - - private void whenVxlanAddDelTunnelThenSuccess() - throws ExecutionException, InterruptedException, VppInvocationException, TimeoutException { - final CompletionStage replyCS = mock(CompletionStage.class); - final CompletableFuture replyFuture = mock(CompletableFuture.class); - when(replyCS.toCompletableFuture()).thenReturn(replyFuture); - final VxlanAddDelTunnelReply reply = new VxlanAddDelTunnelReply(); - when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); - when(api.vxlanAddDelTunnel(any(VxlanAddDelTunnel.class))).thenReturn(replyCS); - } - - /** - * Failure response send - */ - private void whenVxlanAddDelTunnelThenFailure() - throws ExecutionException, InterruptedException, VppInvocationException { - doReturn(TestHelperUtils.createFutureException()).when(api) - .vxlanAddDelTunnel(any(VxlanAddDelTunnel.class)); - } - - private VxlanAddDelTunnel verifyVxlanAddDelTunnelWasInvoked(final Vxlan vxlan) throws VppInvocationException { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(VxlanAddDelTunnel.class); - verify(api).vxlanAddDelTunnel(argumentCaptor.capture()); - final VxlanAddDelTunnel actual = argumentCaptor.getValue(); - assertEquals(0, actual.isIpv6); - assertEquals(-1, actual.decapNextIndex); - assertArrayEquals(InetAddresses.forString(vxlan.getSrc().getIpv4Address().getValue()).getAddress(), - actual.srcAddress); - assertArrayEquals(InetAddresses.forString(vxlan.getDst().getIpv4Address().getValue()).getAddress(), - actual.dstAddress); - assertEquals(vxlan.getEncapVrfId().intValue(), actual.encapVrfId); - assertEquals(vxlan.getVni().getValue().intValue(), actual.vni); - return actual; - } - - private void verifyVxlanAddWasInvoked(final Vxlan vxlan) throws VppInvocationException { - final VxlanAddDelTunnel actual = verifyVxlanAddDelTunnelWasInvoked(vxlan); - assertEquals(ADD_VXLAN, actual.isAdd); - } - - private void verifyVxlanDeleteWasInvoked(final Vxlan vxlan) throws VppInvocationException { - final VxlanAddDelTunnel actual = verifyVxlanAddDelTunnelWasInvoked(vxlan); - assertEquals(DEL_VXLAN, actual.isAdd); - } - - private static Vxlan generateVxlan(long vni) { - final VxlanBuilder builder = new VxlanBuilder(); - builder.setSrc(new IpAddress(new Ipv4Address("192.168.20.10"))); - builder.setDst(new IpAddress(new Ipv4Address("192.168.20.11"))); - builder.setEncapVrfId(Long.valueOf(123)); - builder.setVni(new VxlanVni(Long.valueOf(vni))); - return builder.build(); - } - - private static Vxlan generateVxlan() { - return generateVxlan(Long.valueOf(11)); - } - - @Test - public void testWriteCurrentAttributes() throws Exception { - final Vxlan vxlan = generateVxlan(); - - whenVxlanAddDelTunnelThenSuccess(); - - doReturn(Optional.absent()) - .when(mappingContext).read(getMappingIid(ifaceName, "test-instance").firstIdentifierOf(Mappings.class)); - - customizer.writeCurrentAttributes(id, vxlan, writeContext); - verifyVxlanAddWasInvoked(vxlan); - verify(mappingContext).put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get())); - } - - @Test - public void testWriteCurrentAttributesMappingAlreadyPresent() throws Exception { - final Vxlan vxlan = generateVxlan(); - - whenVxlanAddDelTunnelThenSuccess(); - final Optional ifcMapping = getMapping(ifaceName, 0); - - doReturn(Optional.of(new MappingsBuilder().setMapping(singletonList(ifcMapping.get())).build())) - .when(mappingContext).read(getMappingIid(ifaceName, "test-instance").firstIdentifierOf(Mappings.class)); - - customizer.writeCurrentAttributes(id, vxlan, writeContext); - verifyVxlanAddWasInvoked(vxlan); - - // Remove the first mapping before putting in the new one - verify(mappingContext).delete(eq(getMappingIid(ifaceName, "test-instance"))); - verify(mappingContext).put(eq(getMappingIid(ifaceName, "test-instance")), eq(ifcMapping.get())); - } - - @Test - public void testWriteCurrentAttributesFailed() throws Exception { - final Vxlan vxlan = generateVxlan(); - - whenVxlanAddDelTunnelThenFailure(); - - try { - customizer.writeCurrentAttributes(id, vxlan, writeContext); - } catch (WriteFailedException.CreateFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyVxlanAddWasInvoked(vxlan); - // Mapping not stored due to failure - verify(mappingContext, times(0)).put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get())); - return; - } - fail("WriteFailedException.CreateFailedException was expected"); - } - - @Test - public void testUpdateCurrentAttributes() throws Exception { - try { - customizer.updateCurrentAttributes(id, generateVxlan(10), generateVxlan(11), writeContext); - } catch (WriteFailedException.UpdateFailedException e) { - assertEquals(UnsupportedOperationException.class, e.getCause().getClass()); - return; - } - fail("WriteFailedException.UpdateFailedException was expected"); - } - - @Test - public void testDeleteCurrentAttributes() throws Exception { - final Vxlan vxlan = generateVxlan(); - - whenVxlanAddDelTunnelThenSuccess(); - doReturn(getMapping(ifaceName, 1)).when(mappingContext).read(getMappingIid(ifaceName, "test-instance")); - - customizer.deleteCurrentAttributes(id, vxlan, writeContext); - verifyVxlanDeleteWasInvoked(vxlan); - verify(mappingContext).delete(eq(getMappingIid(ifaceName, "test-instance"))); - } - - @Test - public void testDeleteCurrentAttributesaFailed() throws Exception { - final Vxlan vxlan = generateVxlan(); - - whenVxlanAddDelTunnelThenFailure(); - doReturn(getMapping(ifaceName, 1)).when(mappingContext).read(getMappingIid(ifaceName, "test-instance")); - - try { - customizer.deleteCurrentAttributes(id, vxlan, writeContext); - } catch (WriteFailedException.DeleteFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyVxlanDeleteWasInvoked(vxlan); - verify(mappingContext, times(0)).delete(eq(getMappingIid(ifaceName, "test-instance"))); - return; - } - fail("WriteFailedException.DeleteFailedException was expected"); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanGpeCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanGpeCustomizerTest.java deleted file mode 100644 index 12424999f..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/VxlanGpeCustomizerTest.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * 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.v3po.interfaces; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static java.util.Collections.singletonList; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import com.google.common.net.InetAddresses; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeNextProtocol; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeVni; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpe; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpeBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.VxlanAddDelTunnelReply; -import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnel; -import org.openvpp.jvpp.dto.VxlanGpeAddDelTunnelReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class VxlanGpeCustomizerTest { - - private static final byte ADD_VXLAN_GPE = 1; - private static final byte DEL_VXLAN_GPE = 0; - - @Mock - private FutureJVpp api; - @Mock - private WriteContext writeContext; - @Mock - private MappingContext mappingContext; - - private VxlanGpeCustomizer customizer; - private String ifaceName; - private InstanceIdentifier id; - - @Before - public void setUp() throws Exception { - initMocks(this); - InterfaceTypeTestUtils.setupWriteContext(writeContext, - org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel.class); - // TODO create base class for tests using vppApi - NamingContext namingContext = new NamingContext("generateInterfaceNAme", "test-instance"); - final ModificationCache toBeReturned = new ModificationCache(); - doReturn(toBeReturned).when(writeContext).getModificationCache(); - doReturn(mappingContext).when(writeContext).getMappingContext(); - - customizer = new VxlanGpeCustomizer(api, namingContext); - - ifaceName = "eth0"; - id = InstanceIdentifier.create(Interfaces.class).child(Interface.class, new InterfaceKey(ifaceName)) - .augmentation(VppInterfaceAugmentation.class).child(VxlanGpe.class); - } - - private void whenVxlanGpeAddDelTunnelThenSuccess() - throws ExecutionException, InterruptedException, VppBaseCallException, TimeoutException { - final CompletionStage replyCS = mock(CompletionStage.class); - final CompletableFuture replyFuture = mock(CompletableFuture.class); - when(replyCS.toCompletableFuture()).thenReturn(replyFuture); - final VxlanGpeAddDelTunnelReply reply = new VxlanGpeAddDelTunnelReply(); - when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); - when(api.vxlanGpeAddDelTunnel(any(VxlanGpeAddDelTunnel.class))).thenReturn(replyCS); - } - - /** - * Failure response send - */ - private void whenVxlanGpeAddDelTunnelThenFailure() - throws ExecutionException, InterruptedException, VppBaseCallException { - doReturn(TestHelperUtils.createFutureException()).when(api) - .vxlanGpeAddDelTunnel(any(VxlanGpeAddDelTunnel.class)); - } - - private VxlanGpeAddDelTunnel verifyVxlanGpeAddDelTunnelWasInvoked(final VxlanGpe vxlanGpe) - throws VppBaseCallException { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(VxlanGpeAddDelTunnel.class); - verify(api).vxlanGpeAddDelTunnel(argumentCaptor.capture()); - final VxlanGpeAddDelTunnel actual = argumentCaptor.getValue(); - assertEquals(0, actual.isIpv6); - assertArrayEquals(InetAddresses.forString(vxlanGpe.getLocal().getIpv4Address().getValue()).getAddress(), - actual.local); - assertArrayEquals(InetAddresses.forString(vxlanGpe.getRemote().getIpv4Address().getValue()).getAddress(), - actual.remote); - assertEquals(vxlanGpe.getVni().getValue().intValue(), actual.vni); - assertEquals(vxlanGpe.getNextProtocol().getIntValue(), actual.protocol); - assertEquals(vxlanGpe.getEncapVrfId().intValue(), actual.encapVrfId); - assertEquals(vxlanGpe.getDecapVrfId().intValue(), actual.decapVrfId); - return actual; - } - - private void verifyVxlanGpeAddWasInvoked(final VxlanGpe vxlanGpe) throws VppBaseCallException { - final VxlanGpeAddDelTunnel actual = verifyVxlanGpeAddDelTunnelWasInvoked(vxlanGpe); - assertEquals(ADD_VXLAN_GPE, actual.isAdd); - } - - private void verifyVxlanGpeDeleteWasInvoked(final VxlanGpe vxlanGpe) throws VppBaseCallException{ - final VxlanGpeAddDelTunnel actual = verifyVxlanGpeAddDelTunnelWasInvoked(vxlanGpe); - assertEquals(DEL_VXLAN_GPE, actual.isAdd); - } - - private static VxlanGpe generateVxlanGpe(long vni) { - final VxlanGpeBuilder builder = new VxlanGpeBuilder(); - builder.setLocal(new IpAddress(new Ipv4Address("192.168.20.10"))); - builder.setRemote(new IpAddress(new Ipv4Address("192.168.20.11"))); - builder.setVni(new VxlanGpeVni(Long.valueOf(vni))); - builder.setNextProtocol(VxlanGpeNextProtocol.forValue(1)); - builder.setEncapVrfId(Long.valueOf(123)); - builder.setDecapVrfId(Long.valueOf(456)); - return builder.build(); - } - - private static VxlanGpe generateVxlanGpe() { - return generateVxlanGpe(Long.valueOf(11)); - } - - @Test - public void testWriteCurrentAttributes() throws Exception { - final VxlanGpe vxlanGpe = generateVxlanGpe(); - - whenVxlanGpeAddDelTunnelThenSuccess(); - - doReturn(Optional.absent()) - .when(mappingContext).read(getMappingIid(ifaceName, "test-instance").firstIdentifierOf(Mappings.class)); - - customizer.writeCurrentAttributes(id, vxlanGpe, writeContext); - verifyVxlanGpeAddWasInvoked(vxlanGpe); - verify(mappingContext).put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get())); - } - - @Test - public void testWriteCurrentAttributesMappingAlreadyPresent() throws Exception { - final VxlanGpe vxlanGpe = generateVxlanGpe(); - - whenVxlanGpeAddDelTunnelThenSuccess(); - final Optional ifcMapping = getMapping(ifaceName, 0); - - doReturn(Optional.of(new MappingsBuilder().setMapping(singletonList(ifcMapping.get())).build())) - .when(mappingContext).read(getMappingIid(ifaceName, "test-instance").firstIdentifierOf(Mappings.class)); - - customizer.writeCurrentAttributes(id, vxlanGpe, writeContext); - verifyVxlanGpeAddWasInvoked(vxlanGpe); - - // Remove the first mapping before putting in the new one - verify(mappingContext).delete(eq(getMappingIid(ifaceName, "test-instance"))); - verify(mappingContext).put(eq(getMappingIid(ifaceName, "test-instance")), eq(ifcMapping.get())); - } - - @Test - public void testWriteCurrentAttributesFailed() throws Exception { - final VxlanGpe vxlanGpe = generateVxlanGpe(); - - whenVxlanGpeAddDelTunnelThenFailure(); - - try { - customizer.writeCurrentAttributes(id, vxlanGpe, writeContext); - } catch (WriteFailedException.CreateFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyVxlanGpeAddWasInvoked(vxlanGpe); - // Mapping not stored due to failure - verify(mappingContext, times(0)) - .put(eq(getMappingIid(ifaceName, "test-instance")), eq(getMapping(ifaceName, 0).get())); - return; - } - fail("WriteFailedException.CreateFailedException was expected"); - } - - @Test - public void testUpdateCurrentAttributes() throws Exception { - try { - customizer.updateCurrentAttributes(id, generateVxlanGpe(10), generateVxlanGpe(11), writeContext); - } catch (WriteFailedException.UpdateFailedException e) { - assertEquals(UnsupportedOperationException.class, e.getCause().getClass()); - return; - } - fail("WriteFailedException.UpdateFailedException was expected"); - } - - @Test - public void testDeleteCurrentAttributes() throws Exception { - final VxlanGpe vxlanGpe = generateVxlanGpe(); - - whenVxlanGpeAddDelTunnelThenSuccess(); - doReturn(getMapping(ifaceName, 1)).when(mappingContext).read(getMappingIid(ifaceName, "test-instance")); - - customizer.deleteCurrentAttributes(id, vxlanGpe, writeContext); - verifyVxlanGpeDeleteWasInvoked(vxlanGpe); - verify(mappingContext).delete(eq(getMappingIid(ifaceName, "test-instance"))); - } - - @Test - public void testDeleteCurrentAttributesaFailed() throws Exception { - final VxlanGpe vxlanGpe = generateVxlanGpe(); - - whenVxlanGpeAddDelTunnelThenFailure(); - doReturn(getMapping(ifaceName, 1)).when(mappingContext).read(getMappingIid(ifaceName, "test-instance")); - - try { - customizer.deleteCurrentAttributes(id, vxlanGpe, writeContext); - } catch (WriteFailedException.DeleteFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyVxlanGpeDeleteWasInvoked(vxlanGpe); - verify(mappingContext, times(0)).delete(eq(getMappingIid(ifaceName, "test-instance"))); - return; - } - fail("WriteFailedException.DeleteFailedException was expected"); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizerTest.java deleted file mode 100644 index 21deb9135..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4AddressCustomizerTest.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * 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.v3po.interfaces.ip; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.mockMapping; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -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.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletableFuture; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.NetmaskBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.VppInvocationException; -import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress; -import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class Ipv4AddressCustomizerTest { - - private static final String IFC_CTX_NAME = "ifc-test-instance"; - private static final String IFACE_NAME = "eth0"; - private static final int IFACE_ID = 123; - - @Mock - private WriteContext writeContext; - @Mock - private MappingContext mappingContext; - @Mock - private FutureJVpp api; - - private NamingContext interfaceContext; - private Ipv4AddressCustomizer customizer; - - @Before - public void setUp() throws Exception { - initMocks(this); - doReturn(mappingContext).when(writeContext).getMappingContext(); - interfaceContext = new NamingContext("generatedlIfaceName", IFC_CTX_NAME); - - customizer = new Ipv4AddressCustomizer(api, interfaceContext); - } - - private static InstanceIdentifier
getAddressId(final String ifaceName) { - return InstanceIdentifier.builder(Interfaces.class) - .child(Interface.class, new InterfaceKey(ifaceName)) - .augmentation(Interface1.class) - .child(Ipv4.class) - .child(Address.class) - .build(); - } - - private void whenSwInterfaceAddDelAddressThenSuccess() { - final CompletableFuture replyFuture = new CompletableFuture<>(); - final SwInterfaceAddDelAddressReply reply = new SwInterfaceAddDelAddressReply(); - replyFuture.complete(reply); - doReturn(replyFuture).when(api).swInterfaceAddDelAddress(any(SwInterfaceAddDelAddress.class)); - } - - private void whenSwInterfaceAddDelAddressThenFailure() { - doReturn(TestHelperUtils.createFutureException()).when(api) - .swInterfaceAddDelAddress(any(SwInterfaceAddDelAddress.class)); - } - - private void verifySwInterfaceAddDelAddressWasInvoked(final SwInterfaceAddDelAddress expected) throws - VppInvocationException { - ArgumentCaptor argumentCaptor = - ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class); - verify(api).swInterfaceAddDelAddress(argumentCaptor.capture()); - verifySwInterfaceAddDelAddressWasInvoked(expected, argumentCaptor.getValue()); - } - - private void verifySwInterfaceAddDelAddressWasInvoked(final SwInterfaceAddDelAddress expected, - final SwInterfaceAddDelAddress actual) throws - VppInvocationException { - assertArrayEquals(expected.address, actual.address); - assertEquals(expected.addressLength, actual.addressLength); - assertEquals(expected.delAll, actual.delAll); - assertEquals(expected.isAdd, actual.isAdd); - assertEquals(expected.isIpv6, actual.isIpv6); - assertEquals(expected.swIfIndex, actual.swIfIndex); - } - - @Test - public void testAddPrefixLengthIpv4Address() throws Exception { - final InstanceIdentifier
id = getAddressId(IFACE_NAME); - - Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); - PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); - Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); - - mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); - whenSwInterfaceAddDelAddressThenSuccess(); - - customizer.writeCurrentAttributes(id, data, writeContext); - - verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, - (byte) 1, (byte) 24)); - } - - @Test - public void testAddPrefixLengthIpv4AddressFailed() throws Exception { - final InstanceIdentifier
id = getAddressId(IFACE_NAME); - - Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); - PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); - Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); - - mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); - whenSwInterfaceAddDelAddressThenFailure(); - - try { - customizer.writeCurrentAttributes(id, data, writeContext); - } catch (WriteFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifySwInterfaceAddDelAddressWasInvoked( - generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, - (byte) 1, (byte) 24)); - return; - } - fail("WriteFailedException was expected"); - } - - private SwInterfaceAddDelAddress generateSwInterfaceAddDelAddressRequest(final byte[] address, final byte isAdd, - final byte prefixLength) { - final SwInterfaceAddDelAddress request = new SwInterfaceAddDelAddress(); - request.swIfIndex = IFACE_ID; - request.isAdd = isAdd; - request.isIpv6 = 0; - request.delAll = 0; - request.addressLength = prefixLength; - request.address = address; - return request; - } - - @Test - public void testDeletePrefixLengthIpv4Address() throws Exception { - final InstanceIdentifier
id = getAddressId(IFACE_NAME); - - Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); - PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); - Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); - - mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); - whenSwInterfaceAddDelAddressThenSuccess(); - - customizer.deleteCurrentAttributes(id, data, writeContext); - - verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, - (byte) 0, (byte) 24)); - } - - @Test - public void testDeletePrefixLengthIpv4AddressFailed() throws Exception { - final InstanceIdentifier
id = getAddressId(IFACE_NAME); - - Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); - PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); - Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); - - mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); - whenSwInterfaceAddDelAddressThenFailure(); - - try { - customizer.deleteCurrentAttributes(id, data, writeContext); - } catch (WriteFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifySwInterfaceAddDelAddressWasInvoked( - generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, - (byte) 0, (byte) 24)); - return; - } - fail("WriteFailedException was expec16ted"); - } - - private void testSingleNetmask(final int expectedPrefixLength, final String stringMask) throws Exception { - final InstanceIdentifier
id = getAddressId(IFACE_NAME); - - Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); - Netmask subnet = new NetmaskBuilder().setNetmask(new DottedQuad(stringMask)).build(); - Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(subnet).build(); - - mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); - - final CompletableFuture replyFuture = new CompletableFuture<>(); - replyFuture.complete(new SwInterfaceAddDelAddressReply()); - ArgumentCaptor argumentCaptor = - ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class); - doReturn(replyFuture).when(api).swInterfaceAddDelAddress(argumentCaptor.capture()); - - customizer.writeCurrentAttributes(id, data, writeContext); - - verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, - (byte) 1, (byte) expectedPrefixLength), argumentCaptor.getValue()); - } - - private void testSingleIllegalNetmask(final String stringMask) throws Exception { - try { - final InstanceIdentifier
id = getAddressId(IFACE_NAME); - - Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); - Netmask subnet = new NetmaskBuilder().setNetmask(new DottedQuad(stringMask)).build(); - Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(subnet).build(); - - mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); - - final CompletableFuture replyFuture = new CompletableFuture<>(); - replyFuture.complete(new SwInterfaceAddDelAddressReply()); - ArgumentCaptor argumentCaptor = - ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class); - doReturn(replyFuture).when(api).swInterfaceAddDelAddress(argumentCaptor.capture()); - - customizer.writeCurrentAttributes(id, data, writeContext); - } catch (IllegalArgumentException e) { - return; - } - fail("IllegalArgumentException expected"); - - } - - /** - * Test contiguous netmask length from QuadDotted notation - */ - @Test - public void testNetmaskLength() throws Exception { - testSingleNetmask(1, "128.0.0.0"); - testSingleNetmask(2, "192.0.0.0"); - testSingleNetmask(8, "255.0.0.0"); - testSingleNetmask(9, "255.128.0.0"); - testSingleNetmask(16, "255.255.0.0"); - testSingleNetmask(24, "255.255.255.0"); - } - - @Test - public void testNetmaskIllegal() throws Exception { - testSingleIllegalNetmask(""); - testSingleIllegalNetmask("."); - testSingleIllegalNetmask(".255"); - testSingleIllegalNetmask("255"); - testSingleIllegalNetmask("255."); - testSingleIllegalNetmask("255.255"); - testSingleIllegalNetmask("255.255.0"); - testSingleIllegalNetmask("255.255.255."); - testSingleIllegalNetmask("255.255.255.256"); - testSingleIllegalNetmask("0.0.0.0"); - testSingleIllegalNetmask("10.10.10.10"); - testSingleIllegalNetmask("255.1.255.0"); - testSingleIllegalNetmask("255.255.255.255"); - } - -} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizerTest.java deleted file mode 100644 index 7026ee2a4..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/Ipv4NeighbourCustomizerTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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.v3po.interfaces.ip; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.base.Optional; -import com.google.common.io.BaseEncoding; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletableFuture; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Neighbor; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.NeighborBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.IpNeighborAddDel; -import org.openvpp.jvpp.dto.IpNeighborAddDelReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class Ipv4NeighbourCustomizerTest { - - @Mock - private FutureJVpp jvpp; - - @Mock - private WriteContext context; - - @Mock - private MappingContext mappingContext; - - @Mock - private Mapping mapping; - - private ArgumentCaptor requestCaptor; - private Ipv4NeighbourCustomizer customizer; - private NamingContext namingContext; - - - @Before - public void init() { - MockitoAnnotations.initMocks(this); - - namingContext = new NamingContext("prefix", "instance"); - namingContext.addName(5, "parent", mappingContext); - - customizer = new Ipv4NeighbourCustomizer(jvpp,namingContext); - - requestCaptor = ArgumentCaptor.forClass(IpNeighborAddDel.class); - - CompletableFuture future = new CompletableFuture<>(); - future.complete(new IpNeighborAddDelReply()); - - when(context.getMappingContext()).thenReturn(mappingContext); - when(mapping.getIndex()).thenReturn(5); - when(mapping.getName()).thenReturn("parent"); - when(mappingContext.read(Mockito.any())).thenReturn(Optional.fromNullable(mapping)); - when(jvpp.ipNeighborAddDel(Mockito.any(IpNeighborAddDel.class))).thenReturn(future); - } - - @Test - public void testWriteCurrentAttributes() throws WriteFailedException { - - InterfaceKey intfKey = new InterfaceKey("parent"); - - InstanceIdentifier id = InstanceIdentifier.builder(Interfaces.class).child(Interface.class, intfKey) - .augmentation(Interface1.class).child(Ipv4.class).child(Neighbor.class).build(); - - Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); - PhysAddress mac = new PhysAddress("aa:bb:cc:ee:11:22"); - - Neighbor data = new NeighborBuilder().setIp(noZoneIp).setLinkLayerAddress(mac).build(); - - customizer.writeCurrentAttributes(id, data, context); - - verify(jvpp, times(1)).ipNeighborAddDel(requestCaptor.capture()); - - IpNeighborAddDel request = requestCaptor.getValue(); - - assertEquals(0, request.isIpv6); - assertEquals(1, request.isAdd); - assertEquals(1, request.isStatic); - assertEquals("1.2.168.192", TranslateUtils.arrayToIpv4AddressNoZone(request.dstAddress).getValue()); - assertEquals("aabbccee1122", BaseEncoding.base16().lowerCase().encode(request.macAddress)); - assertEquals(5, request.swIfIndex); - } - - @Test - public void testDeleteCurrentAttributes() throws WriteFailedException { - InterfaceKey intfKey = new InterfaceKey("parent"); - - InstanceIdentifier id = InstanceIdentifier.builder(Interfaces.class).child(Interface.class, intfKey) - .augmentation(Interface1.class).child(Ipv4.class).child(Neighbor.class).build(); - - Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); - PhysAddress mac = new PhysAddress("aa:bb:cc:ee:11:22"); - - Neighbor data = new NeighborBuilder().setIp(noZoneIp).setLinkLayerAddress(mac).build(); - - customizer.deleteCurrentAttributes(id, data, context); - - verify(jvpp, times(1)).ipNeighborAddDel(requestCaptor.capture()); - - IpNeighborAddDel request = requestCaptor.getValue(); - - assertEquals(0, request.isIpv6); - assertEquals(0, request.isAdd); - assertEquals(1, request.isStatic); - assertEquals("1.2.168.192", TranslateUtils.arrayToIpv4AddressNoZone(request.dstAddress).getValue()); - assertEquals("aabbccee1122", BaseEncoding.base16().lowerCase().encode(request.macAddress)); - assertEquals(5, request.swIfIndex); - } - -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclCustomizerTest.java deleted file mode 100644 index 09c0e8815..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/AclCustomizerTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.acl.base.attributes.L2AclBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.AclBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.openvpp.jvpp.dto.ClassifyTableByInterface; -import org.openvpp.jvpp.dto.ClassifyTableByInterfaceReply; - -public class AclCustomizerTest extends ReaderCustomizerTest { - - private static final String IF_NAME = "local0"; - private static final int IF_INDEX = 1; - private static final int TABLE_INDEX = 123; - private static final String TABLE_NAME = "table123"; - - private static final String IFC_TEST_INSTANCE = "ifc-test-instance"; - private static final String CT_TEST_INSTANCE = "ct-test-instance"; - - private NamingContext interfaceContext; - private NamingContext classifyTableContext; - - public AclCustomizerTest() { - super(Acl.class); - } - - @Override - public void setUpBefore() { - interfaceContext = new NamingContext("generatedIfaceName", IFC_TEST_INSTANCE); - classifyTableContext = new NamingContext("generatedTableContext", CT_TEST_INSTANCE); - - final KeyedInstanceIdentifier ifcMappingKey = getMappingIid(IF_NAME, IFC_TEST_INSTANCE); - final Optional ifcMapping = getMapping(IF_NAME, IF_INDEX); - doReturn(ifcMapping).when(mappingContext).read(ifcMappingKey); - - final KeyedInstanceIdentifier ctMappingKey = getMappingIid(TABLE_NAME, CT_TEST_INSTANCE); - final Optional ctMapping = getMapping(TABLE_NAME, TABLE_INDEX); - doReturn(ctMapping).when(mappingContext).read(ctMappingKey); - - final List allCtMappings = Lists.newArrayList(ctMapping.get()); - final Mappings allCtMappingsBaObject = new MappingsBuilder().setMapping(allCtMappings).build(); - doReturn(Optional.of(allCtMappingsBaObject)).when(mappingContext) - .read(ctMappingKey.firstIdentifierOf(Mappings.class)); - - final List allIfcMappings = Lists.newArrayList(ifcMapping.get()); - final Mappings allIfcMappingsBaObject = new MappingsBuilder().setMapping(allIfcMappings).build(); - doReturn(Optional.of(allIfcMappingsBaObject)).when(mappingContext) - .read(ifcMappingKey.firstIdentifierOf(Mappings.class)); - } - - @Override - protected ReaderCustomizer initCustomizer() { - return new AclCustomizer(api, interfaceContext, classifyTableContext); - } - - @Test - public void testMerge() { - final VppInterfaceStateAugmentationBuilder builder = mock(VppInterfaceStateAugmentationBuilder.class); - final Acl value = mock(Acl.class); - getCustomizer().merge(builder, value); - verify(builder).setAcl(value); - } - - private InstanceIdentifier getAclId(final String name) { - return InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey(name)) - .augmentation( - VppInterfaceStateAugmentation.class).child(Acl.class); - } - - @Test - public void testRead() throws Exception { - final InstanceIdentifier id = getAclId(IF_NAME); - final AclBuilder builder = mock(AclBuilder.class); - - final CompletableFuture replyFuture = new CompletableFuture<>(); - final ClassifyTableByInterfaceReply reply = new ClassifyTableByInterfaceReply(); - reply.l2TableId = TABLE_INDEX; - reply.ip4TableId = ~0; - reply.ip6TableId = ~0; - replyFuture.complete(reply); - doReturn(replyFuture).when(api).classifyTableByInterface(any(ClassifyTableByInterface.class)); - - getCustomizer().readCurrentAttributes(id, builder, ctx); - - verify(builder).setL2Acl(new L2AclBuilder().setClassifyTable(TABLE_NAME).build()); - verify(builder).setIp4Acl(null); - verify(builder).setIp6Acl(null); - } - -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizerTest.java deleted file mode 100644 index 61df50e4b..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceCustomizerTest.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceUtils.yangIfIndexToVpp; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static io.fd.honeycomb.v3po.translate.v3po.test.InterfaceTestUtils.whenSwInterfaceDumpThenReturn; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.openvpp.jvpp.VppInvocationException; -import org.openvpp.jvpp.dto.SwInterfaceDetails; -import org.openvpp.jvpp.dto.SwInterfaceDump; - -public class InterfaceCustomizerTest extends - ListReaderCustomizerTest { - - private NamingContext interfacesContext; - - public InterfaceCustomizerTest() { - super(Interface.class); - } - - @Override - public void setUpBefore() { - interfacesContext = new NamingContext("generatedIfaceName", "test-instance"); - } - - @Override - protected ReaderCustomizer initCustomizer() { - final KeyedInstanceIdentifier eth0Id = getMappingIid("eth0", "test-instance"); - final KeyedInstanceIdentifier eth1Id = getMappingIid("eth1", "test-instance"); - final KeyedInstanceIdentifier subEth1Id = getMappingIid("eth1.1", "test-instance"); - final Optional eth0 = getMapping("eth0", 0); - final Optional eth1 = getMapping("eth1", 1); - final Optional subEth1 = getMapping("eth1.1", 2); - - final List allMappings = - Lists.newArrayList(getMapping("eth0", 0).get(), getMapping("eth1", 1).get(), getMapping("eth1.1", 2).get()); - final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); - doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(eth0Id.firstIdentifierOf(Mappings.class)); - - doReturn(eth0).when(mappingContext).read(eth0Id); - doReturn(eth1).when(mappingContext).read(eth1Id); - doReturn(subEth1).when(mappingContext).read(subEth1Id); - - return new InterfaceCustomizer(api, interfacesContext); - } - - // TODO use reflexion and move to ListReaderCustomizerTest - @Test - public void testMerge() throws Exception { - final InterfacesStateBuilder builder = mock(InterfacesStateBuilder.class); - final List value = Collections.emptyList(); - getCustomizer().merge(builder, value); - verify(builder).setInterface(value); - } - - private void verifySwInterfaceDumpWasInvoked(final int nameFilterValid, final String ifaceName, - final int dumpIfcsInvocationCount) - throws VppInvocationException { - // TODO adding equals methods for jvpp DTOs would make ArgumentCaptor usage obsolete - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(SwInterfaceDump.class); - verify(api, times(dumpIfcsInvocationCount)).swInterfaceDump(argumentCaptor.capture()); - final SwInterfaceDump actual = argumentCaptor.getValue(); - assertEquals(nameFilterValid, actual.nameFilterValid); - assertArrayEquals(ifaceName.getBytes(), actual.nameFilter); - } - - private static void assertIfacesAreEqual(final Interface iface, final SwInterfaceDetails details) { - assertEquals(iface.getName(), new String(details.interfaceName)); - assertEquals(yangIfIndexToVpp(iface.getIfIndex().intValue()), details.swIfIndex); - assertEquals(iface.getPhysAddress().getValue(), InterfaceUtils.vppPhysAddrToYang(details.l2Address)); - } - - @Test - public void testReadCurrentAttributes() throws Exception { - final String ifaceName = "eth0"; - final InstanceIdentifier id = InstanceIdentifier.create(InterfacesState.class) - .child(Interface.class, new InterfaceKey(ifaceName)); - final InterfaceBuilder builder = getCustomizer().getBuilder(id); - - final SwInterfaceDetails iface = new SwInterfaceDetails(); - iface.interfaceName = ifaceName.getBytes(); - iface.swIfIndex = 0; - iface.linkSpeed = 1; - iface.l2AddressLength = 6; - iface.l2Address = new byte[iface.l2AddressLength]; - final List interfaceList = Collections.singletonList(iface); - whenSwInterfaceDumpThenReturn(api, interfaceList); - - getCustomizer().readCurrentAttributes(id, builder, ctx); - - verifySwInterfaceDumpWasInvoked(1, ifaceName, 1); - assertIfacesAreEqual(builder.build(), iface); - } - - @Test - public void testReadCurrentAttributesFailed() throws Exception { - final String ifaceName = "eth0"; - final InstanceIdentifier id = InstanceIdentifier.create(InterfacesState.class) - .child(Interface.class, new InterfaceKey(ifaceName)); - final InterfaceBuilder builder = getCustomizer().getBuilder(id); - - whenSwInterfaceDumpThenReturn(api, Collections.emptyList()); - - try { - getCustomizer().readCurrentAttributes(id, builder, ctx); - } catch (IllegalArgumentException e) { - verifySwInterfaceDumpWasInvoked(0, ifaceName, 2); - return; - } - - fail("ReadFailedException was expected"); - } - - @Test - public void testReadSubInterface() throws Exception { - final String ifaceName = "eth1.1"; - final InstanceIdentifier id = InstanceIdentifier.create(InterfacesState.class) - .child(Interface.class, new InterfaceKey(ifaceName)); - final InterfaceBuilder builder = mock(InterfaceBuilder.class); - - final SwInterfaceDetails iface = new SwInterfaceDetails(); - iface.interfaceName = ifaceName.getBytes(); - iface.swIfIndex = 2; - iface.supSwIfIndex = 1; - iface.subId = 1; - final List interfaceList = Collections.singletonList(iface); - whenSwInterfaceDumpThenReturn(api, interfaceList); - - getCustomizer().readCurrentAttributes(id, builder, ctx); - - verifySwInterfaceDumpWasInvoked(1, ifaceName, 1); - verifyZeroInteractions(builder); - } - - @Test - public void testGetAllIds() throws Exception { - final InstanceIdentifier id = InstanceIdentifier.create(InterfacesState.class) - .child(Interface.class); - - final String swIf0Name = "eth0"; - final SwInterfaceDetails swIf0 = new SwInterfaceDetails(); - swIf0.swIfIndex = 0; - swIf0.interfaceName = swIf0Name.getBytes(); - final String swIf1Name = "eth1"; - final SwInterfaceDetails swIf1 = new SwInterfaceDetails(); - swIf1.swIfIndex = 1; - swIf1.interfaceName = swIf1Name.getBytes(); - final String swSubIf1Name = "eth1.1"; - final SwInterfaceDetails swSubIf1 = new SwInterfaceDetails(); - swSubIf1.swIfIndex = 2; - swSubIf1.subId = 1; - swSubIf1.supSwIfIndex = 1; - swSubIf1.interfaceName = swSubIf1Name.getBytes(); - whenSwInterfaceDumpThenReturn(api, Arrays.asList(swIf0, swIf1, swSubIf1)); - - final List expectedIds = Arrays.asList(new InterfaceKey(swIf0Name), new InterfaceKey(swIf1Name)); - final List actualIds = getCustomizer().getAllIds(id, ctx); - - verifySwInterfaceDumpWasInvoked(0, "", 1); - - // sub-interface should not be on the list - assertEquals(expectedIds, actualIds); - } -} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtilsTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtilsTest.java deleted file mode 100644 index c5781624a..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtilsTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; - -public class InterfaceUtilsTest { - - @Test - public void testVppPhysAddrToYang() throws Exception { - assertEquals("01:02:03:04:05:06", InterfaceUtils.vppPhysAddrToYang(new byte[]{1, 2, 3, 4, 5, 6})); - assertEquals("0a:0b:0c:0d:0e:0f", InterfaceUtils.vppPhysAddrToYang(new byte[]{0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0})); - } - - @Test(expected = NullPointerException.class) - public void testVppPhysAddrToYangFailNullArgument() throws Exception { - InterfaceUtils.vppPhysAddrToYang(null); - } - - @Test(expected = IllegalArgumentException.class) - public void testVppPhysAddrToYangInvalidByteArrayLength() throws Exception { - InterfaceUtils.vppPhysAddrToYang(new byte[]{1, 2, 3, 4, 5}); - } - - @Test - public void testGetInterfaceType() { - assertEquals(Tap.class, InterfaceUtils.getInterfaceType("tap0")); - assertEquals(VxlanTunnel.class, InterfaceUtils.getInterfaceType("vxlan0")); - assertEquals(VxlanGpeTunnel.class, InterfaceUtils.getInterfaceType("vxlan_gpe0")); - assertEquals(VhostUser.class, InterfaceUtils.getInterfaceType("VirtualEthernet0/0/0")); - assertEquals(EthernetCsmacd.class, InterfaceUtils.getInterfaceType("eth0.0")); - assertEquals(EthernetCsmacd.class, InterfaceUtils.getInterfaceType("local0")); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2CustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2CustomizerTest.java deleted file mode 100644 index c07583857..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/L2CustomizerTest.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2Builder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.Interconnection; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.base.attributes.interconnection.BridgeBasedBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.openvpp.jvpp.VppInvocationException; -import org.openvpp.jvpp.dto.BridgeDomainDetails; -import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump; -import org.openvpp.jvpp.dto.BridgeDomainDump; -import org.openvpp.jvpp.dto.BridgeDomainSwIfDetails; -import org.openvpp.jvpp.dto.SwInterfaceDetails; - -public class L2CustomizerTest extends ReaderCustomizerTest { - - private NamingContext interfaceContext; - private NamingContext bridgeDomainContext; - - public L2CustomizerTest() { - super(L2.class); - } - - @Override - public void setUpBefore() { - interfaceContext = new NamingContext("generatedIfaceName", "ifc-test-instance"); - bridgeDomainContext = new NamingContext("generatedBDName", "bd-test-instance"); - } - - @Override - protected ReaderCustomizer initCustomizer() { - return new L2Customizer(api, interfaceContext, bridgeDomainContext); - } - - @Test - public void testMerge() { - final VppInterfaceStateAugmentationBuilder builder = mock(VppInterfaceStateAugmentationBuilder.class); - final L2 value = mock(L2.class); - getCustomizer().merge(builder, value); - verify(builder).setL2(value); - } - - private InstanceIdentifier getL2Id(final String name) { - return InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey(name)) - .augmentation( - VppInterfaceStateAugmentation.class).child(L2.class); - } - - private void whenBridgeDomainSwIfDumpThenReturn(final List bdSwIfList, - final List bridgeDomainDetailses) - throws ExecutionException, InterruptedException, VppInvocationException { - final BridgeDomainDetailsReplyDump reply = new BridgeDomainDetailsReplyDump(); - reply.bridgeDomainSwIfDetails = bdSwIfList; - reply.bridgeDomainDetails = bridgeDomainDetailses; - - final CompletableFuture replyFuture = new CompletableFuture<>(); - replyFuture.complete(reply); - when(api.bridgeDomainSwIfDump(any(BridgeDomainDump.class))).thenReturn(replyFuture); - } - - - private BridgeDomainSwIfDetails generateBdSwIfDetails(final int ifId, final int bdId) { - final BridgeDomainSwIfDetails bdSwIfDetails = new BridgeDomainSwIfDetails(); - bdSwIfDetails.swIfIndex = ifId; - bdSwIfDetails.shg = 1; - bdSwIfDetails.bdId = bdId; - return bdSwIfDetails; - } - - private Interconnection generateInterconnection(final int ifId, final String bdName, final Boolean bvi) { - final BridgeBasedBuilder bbBuilder = new BridgeBasedBuilder(); - bbBuilder.setBridgeDomain(bdName); - bbBuilder.setSplitHorizonGroup((short) 1); - if (bvi != null) { - bbBuilder.setBridgedVirtualInterface(bvi); - } else { - bbBuilder.setBridgedVirtualInterface(false); // false is default - } - return bbBuilder.build(); - } - - @Test - public void testRead() throws Exception { - final Map cachedInterfaceDump = new HashMap<>(); - final int ifId = 1; - final int bdId = 1; - final String bdName = "bd001"; - final String ifName = "eth0.sub0"; - final KeyedInstanceIdentifier ifcIid = getMappingIid(ifName, "ifc-test-instance"); - doReturn(getMapping(ifName, ifId)).when(mappingContext).read(ifcIid); - final KeyedInstanceIdentifier bdIid = getMappingIid(bdName, "bd-test-instance"); - doReturn(getMapping(bdName, bdId)).when(mappingContext).read(bdIid); - - List allMappings = Lists.newArrayList(getMapping(ifName, ifId).get()); - Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); - doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(ifcIid.firstIdentifierOf(Mappings.class)); - - allMappings = Lists.newArrayList(getMapping(bdName, bdId).get()); - allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); - doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(bdIid.firstIdentifierOf(Mappings.class)); - - final SwInterfaceDetails ifaceDetails = new SwInterfaceDetails(); - ifaceDetails.subId = ifId; - cachedInterfaceDump.put(ifId, ifaceDetails); - cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump); - - // BVI - whenBridgeDomainSwIfDumpThenReturn(Collections.singletonList(generateBdSwIfDetails(ifId, bdId)), - Collections.singletonList(generateBdDetails(ifId, bdId))); - - L2Builder builder = mock(L2Builder.class); - getCustomizer().readCurrentAttributes(getL2Id(ifName), builder, ctx); - - verify(builder).setInterconnection(generateInterconnection(ifId, bdName, true)); - - // Not BVI - whenBridgeDomainSwIfDumpThenReturn(Collections.singletonList(generateBdSwIfDetails(ifId, bdId)), - Collections.singletonList(generateBdDetails(99 /* Different ifc is marked as BVI in bd details */, bdId))); - - builder = mock(L2Builder.class); - getCustomizer().readCurrentAttributes(getL2Id(ifName), builder, ctx); - - verify(builder).setInterconnection(generateInterconnection(ifId, bdName, null)); - } - - private BridgeDomainDetails generateBdDetails(final int ifId, final int bdId) { - final BridgeDomainDetails bridgeDomainDetails = new BridgeDomainDetails(); - bridgeDomainDetails.bviSwIfIndex = ifId; - bridgeDomainDetails.bdId = bdId; - return bridgeDomainDetails; - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/RewriteCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/RewriteCustomizerTest.java deleted file mode 100644 index 3255826d1..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/RewriteCustomizerTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TagRewriteOperation; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527._802dot1q; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfaces; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.L2Builder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.Rewrite; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.l2.RewriteBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.tag.rewrite.PushTags; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.SwInterfaceDetails; - -public class RewriteCustomizerTest extends ReaderCustomizerTest { - - public static final String VLAN_IF_NAME = "local0.1"; - public static final int VLAN_IF_ID = 1; - public static final int VLAN_IF_INDEX = 11; - - private NamingContext interfacesContext; - - @Captor - private ArgumentCaptor> captor; - - public RewriteCustomizerTest() { - super(Rewrite.class); - } - - @Override - public void setUpBefore() { - interfacesContext = new NamingContext("generatedIfaceName", "test-instance"); - - final Optional ifcMapping = getMapping(VLAN_IF_NAME, VLAN_IF_INDEX); - doReturn(ifcMapping).when(mappingContext).read(any()); - } - - @Override - protected ReaderCustomizer initCustomizer() { - return new RewriteCustomizer(api, interfacesContext); - } - - @Test - public void testMerge() { - final L2Builder builder = mock(L2Builder.class); - final Rewrite value = mock(Rewrite.class); - getCustomizer().merge(builder, value); - verify(builder).setRewrite(value); - } - - private InstanceIdentifier getVlanTagRewriteId(final String name, final long index) { - final Class> child = (Class)Rewrite.class; - final InstanceIdentifier id = - InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey(name)).augmentation( - SubinterfaceStateAugmentation.class).child(SubInterfaces.class) - .child(SubInterface.class, new SubInterfaceKey(index)) - .child(child); - return id; - } - - @Test - public void testRead() throws ReadFailedException { - final Map cachedInterfaceDump = new HashMap<>(); - - final SwInterfaceDetails ifaceDetails = new SwInterfaceDetails(); - ifaceDetails.subId = VLAN_IF_ID; - ifaceDetails.interfaceName = VLAN_IF_NAME.getBytes(); - ifaceDetails.vtrOp = TagRewriteOperation.translate_2_to_2.ordinal(); - ifaceDetails.subNumberOfTags = 2; - ifaceDetails.vtrTag1 = 123; - ifaceDetails.vtrTag2 = 321; - ifaceDetails.vtrPushDot1Q = 1; - cachedInterfaceDump.put(VLAN_IF_INDEX, ifaceDetails); - cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump); - - final RewriteBuilder builder = mock(RewriteBuilder.class); - - getCustomizer().readCurrentAttributes(getVlanTagRewriteId(VLAN_IF_NAME, VLAN_IF_ID), builder, ctx); - - verify(builder).setVlanType(_802dot1q.class); - verify(builder).setPopTags((short) 2); - - verify(builder).setPushTags(captor.capture()); - final List tags = captor.getValue(); - assertEquals(ifaceDetails.subNumberOfTags, tags.size()); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceCustomizerTest.java deleted file mode 100644 index 641995991..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/SubInterfaceCustomizerTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.InterfaceTestUtils.whenSwInterfaceDumpThenReturn; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.SubinterfaceStateAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfaces; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.SubInterfacesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.interfaces.state._interface.sub.interfaces.SubInterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.VlanTagged; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.SwInterfaceDetails; - -public class SubInterfaceCustomizerTest extends ListReaderCustomizerTest { - - public static final String SUPER_IF_NAME = "local0"; - public static final int SUPER_IF_INDEX = 1; - public static final String VLAN_IF_NAME = "local0.1"; - public static final int VLAN_IF_ID = 1; - public static final int VLAN_IF_INDEX = 11; - - private NamingContext interfacesContext; - - public SubInterfaceCustomizerTest() { - super(SubInterface.class); - } - - @Override - public void setUpBefore() { - interfacesContext = new NamingContext("generatedIfaceName", "test-instance"); - } - - @Override - protected ReaderCustomizer initCustomizer() { - return new SubInterfaceCustomizer(api, interfacesContext); - } - - private InstanceIdentifier getSubInterfaceId(final String name, final long id) { - return InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey(name)).augmentation( - SubinterfaceStateAugmentation.class).child( - SubInterfaces.class).child(SubInterface.class, new SubInterfaceKey(id)); - } - - @Test - public void testMerge() { - final SubInterfacesBuilder builder = mock(SubInterfacesBuilder.class); - final List value = mock(List.class); - getCustomizer().merge(builder, value); - verify(builder).setSubInterface(value); - } - - @Test - public void testRead() throws ReadFailedException { - final Optional ifcMapping = getMapping(VLAN_IF_NAME, VLAN_IF_INDEX); - doReturn(ifcMapping).when(mappingContext).read(any()); - - final Map cachedInterfaceDump = new HashMap<>(); - - final SwInterfaceDetails ifaceDetails = new SwInterfaceDetails(); - ifaceDetails.subId = VLAN_IF_ID; - ifaceDetails.interfaceName = VLAN_IF_NAME.getBytes(); - ifaceDetails.subDot1Ad = 1; - ifaceDetails.subNumberOfTags = 2; - ifaceDetails.subOuterVlanIdAny = 1; - ifaceDetails.subInnerVlanIdAny = 1; - ifaceDetails.subExactMatch = 1; - cachedInterfaceDump.put(VLAN_IF_INDEX, ifaceDetails); - cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, cachedInterfaceDump); - - final SubInterfaceBuilder builder = mock(SubInterfaceBuilder.class); - getCustomizer().readCurrentAttributes(getSubInterfaceId(VLAN_IF_NAME, VLAN_IF_ID), builder, ctx); - - verify(builder).setIdentifier((long) VLAN_IF_ID); - - ArgumentCaptor tagCaptor = ArgumentCaptor.forClass(Tags.class); - verify(builder).setTags(tagCaptor.capture()); - assertEquals(ifaceDetails.subNumberOfTags, tagCaptor.getValue().getTag().size()); - - ArgumentCaptor matchCaptor = ArgumentCaptor.forClass(Match.class); - verify(builder).setMatch(matchCaptor.capture()); - final VlanTagged matchType = (VlanTagged)matchCaptor.getValue().getMatchType(); - assertTrue(matchType.getVlanTagged().isMatchExactTags()); - } - - @Test - public void testGetAllIds() throws Exception { - final Optional ifcMapping = getMapping(SUPER_IF_NAME, SUPER_IF_INDEX); - doReturn(ifcMapping).when(mappingContext).read(any()); - - final SwInterfaceDetails iface = new SwInterfaceDetails(); - iface.interfaceName = VLAN_IF_NAME.getBytes(); - iface.swIfIndex = VLAN_IF_INDEX; - iface.subId = VLAN_IF_ID; - iface.supSwIfIndex = SUPER_IF_INDEX; - final List ifaces = Collections.singletonList(iface); - whenSwInterfaceDumpThenReturn(api, ifaces); - - final List allIds = - getCustomizer().getAllIds(getSubInterfaceId(VLAN_IF_NAME, VLAN_IF_ID), ctx); - - assertEquals(ifaces.size(), allIds.size()); - - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanCustomizerTest.java deleted file mode 100644 index 14830fe45..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanCustomizerTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppInvocationException; -import org.openvpp.jvpp.dto.SwInterfaceDetails; -import org.openvpp.jvpp.dto.VxlanTunnelDetails; -import org.openvpp.jvpp.dto.VxlanTunnelDetailsReplyDump; -import org.openvpp.jvpp.dto.VxlanTunnelDump; - -public class VxlanCustomizerTest extends ReaderCustomizerTest { - - private NamingContext interfacesContext; - static final InstanceIdentifier IID = - InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey("ifc1")) - .augmentation(VppInterfaceStateAugmentation.class).child(Vxlan.class); - - public VxlanCustomizerTest() { - super(Vxlan.class); - } - - @Override - public void setUpBefore() { - interfacesContext = new NamingContext("vxlan-tunnel", "test-instance"); - doReturn(getMapping("ifc1", 0)).when(mappingContext).read(getMappingIid("ifc1", "test-instance")); - - final SwInterfaceDetails v = new SwInterfaceDetails(); - v.interfaceName = "vxlan-tunnel4".getBytes(); - final Map map = new HashMap<>(); - map.put(0, v); - cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, map); - } - - @Override - protected void setUpAfter() throws UnknownHostException, VppInvocationException { - final CompletableFuture vxlanTunnelDetailsReplyDumpCompletionStage = - new CompletableFuture<>(); - - final VxlanTunnelDetailsReplyDump value = new VxlanTunnelDetailsReplyDump(); - final VxlanTunnelDetails vxlanTunnelDetails = new VxlanTunnelDetails(); - vxlanTunnelDetails.isIpv6 = 0; - vxlanTunnelDetails.decapNextIndex = 1; - vxlanTunnelDetails.dstAddress = InetAddress.getByName("1.2.3.4").getAddress(); - vxlanTunnelDetails.srcAddress = InetAddress.getByName("1.2.3.5").getAddress(); - vxlanTunnelDetails.encapVrfId = 55; - vxlanTunnelDetails.swIfIndex = 0; - vxlanTunnelDetails.vni = 9; - - value.vxlanTunnelDetails = Lists.newArrayList(vxlanTunnelDetails); - vxlanTunnelDetailsReplyDumpCompletionStage.complete(value); - - doReturn(vxlanTunnelDetailsReplyDumpCompletionStage).when(api).vxlanTunnelDump(any(VxlanTunnelDump.class)); - } - - @Test - public void testReadCurrentAttributes() throws Exception { - final VxlanBuilder builder = getCustomizer().getBuilder(IID); - getCustomizer().readCurrentAttributes(IID, builder, ctx); - - assertEquals(9, builder.getVni().getValue().intValue()); - assertEquals(55, builder.getEncapVrfId().intValue()); - - assertNull(builder.getSrc().getIpv6Address()); - assertNotNull(builder.getSrc().getIpv4Address()); - assertEquals("1.2.3.5", builder.getSrc().getIpv4Address().getValue()); - - assertNull(builder.getDst().getIpv6Address()); - assertNotNull(builder.getDst().getIpv4Address()); - assertEquals("1.2.3.4", builder.getDst().getIpv4Address().getValue()); - - verify(api).vxlanTunnelDump(any(VxlanTunnelDump.class)); - } - - @Test(expected = NullPointerException.class) - public void testReadCurrentAttributesVppNameNotCached() throws Exception { - InterfaceCustomizer.getCachedInterfaceDump(cache).remove(0); - - final VxlanBuilder builder = getCustomizer().getBuilder(IID); - getCustomizer().readCurrentAttributes(IID, builder, ctx); - } - - @Test - public void testReadCurrentAttributesWrongType() throws Exception { - final SwInterfaceDetails v = new SwInterfaceDetails(); - v.interfaceName = "tap-2".getBytes(); - InterfaceCustomizer.getCachedInterfaceDump(cache).put(0, v); - - final VxlanBuilder builder = getCustomizer().getBuilder(IID); - getCustomizer().readCurrentAttributes(IID, builder, ctx); - - // Should be ignored - verifyZeroInteractions(api); - } - - @Override - protected ReaderCustomizer initCustomizer() { - return new VxlanCustomizer(api, interfacesContext); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanGpeCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanGpeCustomizerTest.java deleted file mode 100644 index 323bc7e2a..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/VxlanGpeCustomizerTest.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * 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.v3po.interfacesstate; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpe; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanGpeBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceDetails; -import org.openvpp.jvpp.dto.VxlanGpeTunnelDetails; -import org.openvpp.jvpp.dto.VxlanGpeTunnelDetailsReplyDump; -import org.openvpp.jvpp.dto.VxlanGpeTunnelDump; - -public class VxlanGpeCustomizerTest extends ReaderCustomizerTest { - - private NamingContext interfacesContext; - static final InstanceIdentifier VXLAN_GPE_ID = - InstanceIdentifier.create(InterfacesState.class).child(Interface.class, new InterfaceKey("ifc2")) - .augmentation(VppInterfaceStateAugmentation.class).child(VxlanGpe.class); - - public VxlanGpeCustomizerTest() { - super(VxlanGpe.class); - } - - @Override - public void setUpBefore() { - interfacesContext = new NamingContext("vxlan_gpe_inf", "test-instance"); - doReturn(getMapping("ifc2", 0)).when(mappingContext).read(getMappingIid("ifc2", "test-instance")); - - final SwInterfaceDetails v = new SwInterfaceDetails(); - v.interfaceName = "vxlan_gpe_inf2".getBytes(); - final Map map = new HashMap<>(); - map.put(0, v); - cache.put(InterfaceCustomizer.DUMPED_IFCS_CONTEXT_KEY, map); - } - - @Override - protected void setUpAfter() throws UnknownHostException, VppBaseCallException { - final CompletableFuture vxlanGpeTunnelDetailsReplyDumpCompletionStage = - new CompletableFuture<>(); - - final VxlanGpeTunnelDetailsReplyDump value = new VxlanGpeTunnelDetailsReplyDump(); - final VxlanGpeTunnelDetails vxlanGpeTunnelDetails = new VxlanGpeTunnelDetails(); - vxlanGpeTunnelDetails.isIpv6 = 0; - vxlanGpeTunnelDetails.local = InetAddress.getByName("1.2.3.4").getAddress(); - vxlanGpeTunnelDetails.remote = InetAddress.getByName("1.2.3.5").getAddress(); - vxlanGpeTunnelDetails.vni = 9; - vxlanGpeTunnelDetails.protocol = 1; - vxlanGpeTunnelDetails.encapVrfId = 55; - vxlanGpeTunnelDetails.decapVrfId = 66; - vxlanGpeTunnelDetails.swIfIndex = 0; - - value.vxlanGpeTunnelDetails = Lists.newArrayList(vxlanGpeTunnelDetails); - vxlanGpeTunnelDetailsReplyDumpCompletionStage.complete(value); - - doReturn(vxlanGpeTunnelDetailsReplyDumpCompletionStage).when(api).vxlanGpeTunnelDump(any(VxlanGpeTunnelDump.class)); - } - - @Test - public void testReadCurrentAttributes() throws Exception { - final VxlanGpeBuilder builder = getCustomizer().getBuilder(VXLAN_GPE_ID); - getCustomizer().readCurrentAttributes(VXLAN_GPE_ID, builder, ctx); - - assertNull(builder.getLocal().getIpv6Address()); - assertNotNull(builder.getLocal().getIpv4Address()); - assertEquals("1.2.3.4", builder.getLocal().getIpv4Address().getValue()); - - assertNull(builder.getRemote().getIpv6Address()); - assertNotNull(builder.getRemote().getIpv4Address()); - assertEquals("1.2.3.5", builder.getRemote().getIpv4Address().getValue()); - - assertEquals(9, builder.getVni().getValue().intValue()); - assertEquals(1, builder.getNextProtocol().getIntValue()); - assertEquals(55, builder.getEncapVrfId().intValue()); - assertEquals(66, builder.getDecapVrfId().intValue()); - - verify(api).vxlanGpeTunnelDump(any(VxlanGpeTunnelDump.class)); - } - - @Test(expected = NullPointerException.class) - public void testReadCurrentAttributesVppNameNotCached() throws Exception { - InterfaceCustomizer.getCachedInterfaceDump(cache).remove(0); - - final VxlanGpeBuilder builder = getCustomizer().getBuilder(VXLAN_GPE_ID); - getCustomizer().readCurrentAttributes(VXLAN_GPE_ID, builder, ctx); - } - - @Test - public void testReadCurrentAttributesWrongType() throws Exception { - final SwInterfaceDetails v = new SwInterfaceDetails(); - v.interfaceName = "tap-3".getBytes(); - InterfaceCustomizer.getCachedInterfaceDump(cache).put(0, v); - - final VxlanGpeBuilder builder = getCustomizer().getBuilder(VXLAN_GPE_ID); - getCustomizer().readCurrentAttributes(VXLAN_GPE_ID, builder, ctx); - - // Should be ignored - verifyZeroInteractions(api); - } - - @Override - protected ReaderCustomizer initCustomizer() { - return new VxlanGpeCustomizer(api, interfacesContext); - } -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java deleted file mode 100644 index 7d701e453..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * 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.v3po.interfacesstate.ip; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.reverseBytes; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; -import org.hamcrest.CoreMatchers; -import org.junit.Test; -import org.mockito.Mockito; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.openvpp.jvpp.dto.IpAddressDetails; -import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; -import org.openvpp.jvpp.dto.IpAddressDump; - -public class Ipv4AddressCustomizerTest extends ListReaderCustomizerTest { - - private static final String IFACE_NAME = "eth0"; - private static final String IFACE_2_NAME = "eth1"; - private static final int IFACE_ID = 1; - private static final int IFACE_2_ID = 2; - - private NamingContext interfacesContext; - - public Ipv4AddressCustomizerTest() { - super(Address.class); - } - - @Override - public void setUpBefore() { - interfacesContext = new NamingContext("generatedIfaceName", "test-instance"); - } - - @Override - protected ReaderCustomizer initCustomizer() { - final KeyedInstanceIdentifier eth0Id = getMappingIid(IFACE_NAME, "test-instance"); - final KeyedInstanceIdentifier eth1Id = getMappingIid(IFACE_2_NAME, "test-instance"); - final Optional eth0 = getMapping(IFACE_NAME, IFACE_ID); - final Optional eth1 = getMapping(IFACE_2_NAME, IFACE_2_ID); - - final List allMappings = Lists.newArrayList(eth0.get(), eth1.get()); - final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); - doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(eth0Id.firstIdentifierOf(Mappings.class)); - - doReturn(eth0).when(mappingContext).read(eth0Id); - doReturn(eth1).when(mappingContext).read(eth1Id); - - return new Ipv4AddressCustomizer(api, interfacesContext); - } - - private static InstanceIdentifier
getId(final String address, final String ifaceName) { - return InstanceIdentifier.builder(InterfacesState.class) - .child(Interface.class, new InterfaceKey(ifaceName)) - .augmentation(Interface2.class) - .child(Ipv4.class) - .child(Address.class, new AddressKey(new Ipv4AddressNoZone(new Ipv4Address(address)))) - .build(); - } - - @Test - public void testReadCurrentAttributesFromCache() throws ReadFailedException { - ModificationCache cache = new ModificationCache(); - - IpAddressDetails detail1 = new IpAddressDetails(); - IpAddressDetails detail2 = new IpAddressDetails(); - IpAddressDetails detail3 = new IpAddressDetails(); - - detail1.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); - detail2.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); - detail3.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); - - IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); - reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); - - cache.put(Ipv4ReadUtils.CACHE_KEY + IFACE_NAME, reply); - when(ctx.getModificationCache()).thenReturn(cache); - - final AddressBuilder builder = new AddressBuilder(); - final InstanceIdentifier
id = getId("192.168.2.1", IFACE_NAME); - - getCustomizer().readCurrentAttributes(id, builder, ctx); - - assertEquals("192.168.2.1", builder.getIp().getValue()); - } - - @Test - public void testReadCurrentAttributesFor2Ifcs() throws ReadFailedException { - ModificationCache cache = new ModificationCache(); - - IpAddressDetails detail1 = new IpAddressDetails(); - IpAddressDetails detail2 = new IpAddressDetails(); - - detail1.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); - detail2.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); - - IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); - reply.ipAddressDetails = ImmutableList.of(detail1); - IpAddressDetailsReplyDump reply2 = new IpAddressDetailsReplyDump(); - reply2.ipAddressDetails = ImmutableList.of(detail2); - - CompletableFuture future = new CompletableFuture<>(); - future.complete(reply); - CompletableFuture future2 = new CompletableFuture<>(); - future2.complete(reply2); - - when(api.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future).thenReturn(future2); - when(ctx.getModificationCache()).thenReturn(cache); - - final InstanceIdentifier
id = getId("192.168.2.1", IFACE_NAME); - final InstanceIdentifier
id2 = getId("192.168.2.2", IFACE_2_NAME); - - final List ifc1Ids = getCustomizer().getAllIds(id, ctx); - assertThat(ifc1Ids.size(), is(1)); - assertThat(ifc1Ids, CoreMatchers.hasItem(new AddressKey(new Ipv4AddressNoZone("192.168.2.1")))); - final List ifc2Ids = getCustomizer().getAllIds(id2, ctx); - assertThat(ifc2Ids.size(), is(1)); - assertThat(ifc2Ids, CoreMatchers.hasItem(new AddressKey(new Ipv4AddressNoZone("192.168.2.2")))); - - AddressBuilder builder = new AddressBuilder(); - getCustomizer().readCurrentAttributes(id, builder, ctx); - assertEquals(builder.getIp().getValue(), "192.168.2.1"); - builder = new AddressBuilder(); - getCustomizer().readCurrentAttributes(id2, builder, ctx); - assertEquals(builder.getIp().getValue(), "192.168.2.2"); - } - - @Test - public void testReadCurrentAttributesFromOperationalData() throws ReadFailedException { - ModificationCache cache = new ModificationCache(); - - IpAddressDetails detail1 = new IpAddressDetails(); - IpAddressDetails detail2 = new IpAddressDetails(); - IpAddressDetails detail3 = new IpAddressDetails(); - - detail1.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); - detail2.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); - detail3.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); - - IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); - reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); - - CompletableFuture future = new CompletableFuture<>(); - future.complete(reply); - - when(api.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future); - when(ctx.getModificationCache()).thenReturn(cache); - - - final AddressBuilder builder = new AddressBuilder(); - final InstanceIdentifier
id = getId("192.168.2.1", IFACE_NAME); - - getCustomizer().readCurrentAttributes(id, builder, ctx); - - assertEquals("192.168.2.1", builder.getIp().getValue()); - } - - @Test - public void testGetAllIdsFromCache() throws ReadFailedException { - ModificationCache cache = new ModificationCache(); - - IpAddressDetails detail1 = new IpAddressDetails(); - IpAddressDetails detail2 = new IpAddressDetails(); - IpAddressDetails detail3 = new IpAddressDetails(); - - detail1.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); - detail2.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); - detail3.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); - - IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); - reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); - - cache.put(Ipv4ReadUtils.CACHE_KEY + IFACE_NAME, reply); - when(ctx.getModificationCache()).thenReturn(cache); - - final InstanceIdentifier
id = getId("192.168.2.1", IFACE_NAME); - - List ids = getCustomizer().getAllIds(id, ctx).stream() - .map(key -> key.getIp()) - .collect(Collectors.toList()); - - verify(api, times(0)).ipAddressDump(Mockito.any(IpAddressDump.class)); - assertEquals(3, ids.size()); - assertEquals(true, "192.168.2.1".equals(ids.get(0).getValue())); - assertEquals(true, "192.168.2.2".equals(ids.get(1).getValue())); - assertEquals(true, "192.168.2.3".equals(ids.get(2).getValue())); - } - - @Test - public void testGetAllIdsFromOperationalData() throws ReadFailedException { - ModificationCache cache = new ModificationCache(); - - IpAddressDetails detail1 = new IpAddressDetails(); - IpAddressDetails detail2 = new IpAddressDetails(); - IpAddressDetails detail3 = new IpAddressDetails(); - - detail1.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); - detail2.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); - detail3.ip = reverseBytes( - TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); - - IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); - reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); - - CompletableFuture future = new CompletableFuture<>(); - future.complete(reply); - - when(api.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future); - when(ctx.getModificationCache()).thenReturn(cache); - - final InstanceIdentifier
id = getId("192.168.2.1", IFACE_NAME); - - List ids = getCustomizer().getAllIds(id, ctx).stream() - .map(key -> key.getIp()) - .collect(Collectors.toList()); - - assertEquals(3, ids.size()); - assertEquals(true, "192.168.2.1".equals(ids.get(0).getValue())); - assertEquals(true, "192.168.2.2".equals(ids.get(1).getValue())); - assertEquals(true, "192.168.2.3".equals(ids.get(2).getValue())); - } - - @Test - public void testMerge() { - - Address address = new AddressBuilder().build(); - Ipv4Builder ipv4Builder = new Ipv4Builder(); - getCustomizer().merge(ipv4Builder, Arrays.asList(address)); - - assertEquals(1, ipv4Builder.getAddress().size()); - assertEquals(true, ipv4Builder.getAddress().contains(address)); - } - -} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/notification/InterfaceChangeNotificationProducerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/notification/InterfaceChangeNotificationProducerTest.java deleted file mode 100644 index dd5a22d61..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/notification/InterfaceChangeNotificationProducerTest.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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.v3po.notification; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.notification.NotificationCollector; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStateChange; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceStatus; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.openvpp.jvpp.callback.SwInterfaceSetFlagsNotificationCallback; -import org.openvpp.jvpp.dto.SwInterfaceSetFlagsNotification; -import org.openvpp.jvpp.dto.WantInterfaceEvents; -import org.openvpp.jvpp.dto.WantInterfaceEventsReply; -import org.openvpp.jvpp.future.FutureJVpp; -import org.openvpp.jvpp.notification.NotificationRegistry; - -public class InterfaceChangeNotificationProducerTest { - - @Mock - private FutureJVpp jVpp; - private NamingContext namingContext = new NamingContext("test", "test-instance"); - @Mock - private MappingContext mappingContext; - @Mock - private NotificationCollector collector; - @Mock - private NotificationRegistry notificationRegistry; - @Mock - private AutoCloseable notificationListenerReg; - - private ArgumentCaptor callbackArgumentCaptor; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - doReturn(notificationRegistry).when(jVpp).getNotificationRegistry(); - callbackArgumentCaptor = ArgumentCaptor.forClass(SwInterfaceSetFlagsNotificationCallback.class); - doReturn(notificationListenerReg).when(notificationRegistry).registerSwInterfaceSetFlagsNotificationCallback( - callbackArgumentCaptor.capture()); - - final KeyedInstanceIdentifier eth0Id = getMappingIid("eth0", "test-instance"); - final Optional eth0 = getMapping("eth0", 0); - - final List allMappings = Lists.newArrayList(getMapping("eth0", 0).get()); - final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); - doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(eth0Id.firstIdentifierOf(Mappings.class)); - - doReturn(eth0).when(mappingContext).read(eth0Id); - } - - @Test - public void testStart() throws Exception { - final CompletableFuture response = new CompletableFuture<>(); - response.complete(new WantInterfaceEventsReply()); - doReturn(response).when(jVpp).wantInterfaceEvents(any(WantInterfaceEvents.class)); - final InterfaceChangeNotificationProducer interfaceChangeNotificationProducer = - new InterfaceChangeNotificationProducer(jVpp, namingContext, mappingContext); - - interfaceChangeNotificationProducer.start(collector); - verify(jVpp).wantInterfaceEvents(any(WantInterfaceEvents.class)); - verify(jVpp).getNotificationRegistry(); - verify(notificationRegistry).registerSwInterfaceSetFlagsNotificationCallback(any( - SwInterfaceSetFlagsNotificationCallback.class)); - - interfaceChangeNotificationProducer.stop(); - verify(jVpp, times(2)).wantInterfaceEvents(any(WantInterfaceEvents.class)); - verify(notificationListenerReg).close(); - } - - @Test - public void testNotification() throws Exception { - final CompletableFuture response = new CompletableFuture<>(); - response.complete(new WantInterfaceEventsReply()); - doReturn(response).when(jVpp).wantInterfaceEvents(any(WantInterfaceEvents.class)); - final InterfaceChangeNotificationProducer interfaceChangeNotificationProducer = - new InterfaceChangeNotificationProducer(jVpp, namingContext, mappingContext); - - interfaceChangeNotificationProducer.start(collector); - - final SwInterfaceSetFlagsNotification swInterfaceSetFlagsNotification = new SwInterfaceSetFlagsNotification(); - swInterfaceSetFlagsNotification.deleted = 0; - swInterfaceSetFlagsNotification.swIfIndex = 0; - swInterfaceSetFlagsNotification.adminUpDown = 1; - swInterfaceSetFlagsNotification.linkUpDown = 1; - - callbackArgumentCaptor.getValue().onSwInterfaceSetFlagsNotification(swInterfaceSetFlagsNotification); - final ArgumentCaptor notificationCaptor = - ArgumentCaptor.forClass(InterfaceStateChange.class); - verify(collector).onNotification(notificationCaptor.capture()); - - assertEquals("eth0", notificationCaptor.getValue().getName().getString()); - assertEquals(InterfaceStatus.Up, notificationCaptor.getValue().getAdminStatus()); - assertEquals(InterfaceStatus.Up, notificationCaptor.getValue().getOperStatus()); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ContextTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ContextTestUtils.java deleted file mode 100644 index 7e916eaf4..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ContextTestUtils.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.v3po.test; - -import static org.mockito.Mockito.doReturn; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.translate.MappingContext; -import java.util.List; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContextKey; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; - -public class ContextTestUtils { - - public static Optional getMapping(final String name, final int index) { - return Optional.of(new MappingBuilder().setName(name).setIndex(index).build()); - } - - public static KeyedInstanceIdentifier getMappingIid(final String name, - final String namingContextName) { - return InstanceIdentifier.create(Contexts.class).child( - org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.class, - new NamingContextKey(namingContextName)).child(Mappings.class).child(Mapping.class, new MappingKey(name)); - } - - public static void mockMapping(final MappingContext mappingContext, final String name, final int id, - final String namingContextName) { - final InstanceIdentifier mappingsIid = - getMappingIid(name, namingContextName).firstIdentifierOf(Mappings.class); - - final Optional singleMapping = getMapping(name, id); - final Optional previousMappings = mappingContext.read(mappingsIid); - - final MappingsBuilder mappingsBuilder; - if (previousMappings != null && previousMappings.isPresent()) { - mappingsBuilder = new MappingsBuilder(previousMappings.get()); - } else { - mappingsBuilder = new MappingsBuilder(); - mappingsBuilder.setMapping(Lists.newArrayList()); - } - - final List mappingList = mappingsBuilder.getMapping(); - mappingList.add(singleMapping.get()); - doReturn(Optional.of(mappingsBuilder.setMapping(mappingList).build())) - .when(mappingContext).read(mappingsIid); - doReturn(singleMapping).when(mappingContext).read(getMappingIid(name, namingContextName)); - } -} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/InterfaceTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/InterfaceTestUtils.java deleted file mode 100644 index f72aaa571..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/InterfaceTestUtils.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.v3po.test; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.SwInterfaceDetails; -import org.openvpp.jvpp.dto.SwInterfaceDetailsReplyDump; -import org.openvpp.jvpp.dto.SwInterfaceDump; -import org.openvpp.jvpp.future.FutureJVpp; - -public final class InterfaceTestUtils { - private InterfaceTestUtils() { - throw new UnsupportedOperationException("Utility class cannot be instantiated"); - } - - public static void whenSwInterfaceDumpThenReturn(final FutureJVpp api, final List interfaceList) - throws ExecutionException, InterruptedException, VppBaseCallException, TimeoutException { - final CompletionStage replyCS = mock(CompletionStage.class); - final CompletableFuture replyFuture = mock(CompletableFuture.class); - when(replyCS.toCompletableFuture()).thenReturn(replyFuture); - final SwInterfaceDetailsReplyDump reply = new SwInterfaceDetailsReplyDump(); - reply.swInterfaceDetails = interfaceList; - when(replyFuture.get(anyLong(), eq(TimeUnit.SECONDS))).thenReturn(reply); - when(api.swInterfaceDump(any(SwInterfaceDump.class))).thenReturn(replyCS); - } -} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ListReaderCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ListReaderCustomizerTest.java deleted file mode 100644 index f2be3dec9..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ListReaderCustomizerTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.v3po.test; - -import static org.junit.Assert.assertNotNull; - -import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; -import org.junit.Test; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Generic test for classes implementing {@link ListReaderCustomizer} interface. - * - * @param Specific DataObject derived type (Identifiable), that is handled by this customizer - * @param Specific Identifier for handled type (D) - * @param Specific Builder for handled type (D) - */ -public abstract class ListReaderCustomizerTest, K extends Identifier, B extends Builder> extends - ReaderCustomizerTest { - - - protected ListReaderCustomizerTest(Class dataObjectClass) { - super(dataObjectClass); - } - - @Override - protected ListReaderCustomizer getCustomizer() { - return ListReaderCustomizer.class.cast(super.getCustomizer()); - } - - @Test - public void testGetBuilder() throws Exception { - assertNotNull(getCustomizer().getBuilder(InstanceIdentifier.create(dataObjectClass))); - } -} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ReaderCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ReaderCustomizerTest.java deleted file mode 100644 index 29d365ca2..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/ReaderCustomizerTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.v3po.test; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.doReturn; -import static org.mockito.MockitoAnnotations.initMocks; - -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; - -/** - * Generic test for classes implementing {@link ReaderCustomizer} interface. - * - * @param Specific DataObject derived type (Identifiable), that is handled by this customizer - * @param Specific Builder for handled type (D) - */ -public abstract class ReaderCustomizerTest> { - - @Mock - protected FutureJVpp api; - protected ModificationCache cache; - @Mock - protected ReadContext ctx; - @Mock - protected MappingContext mappingContext; - - protected final Class dataObjectClass; - private ReaderCustomizer customizer; - - protected ReaderCustomizerTest(Class dataObjectClass) { - this.dataObjectClass = dataObjectClass; - } - - @Before - public void setUpParent() throws Exception { - initMocks(this); - cache = new ModificationCache(); - doReturn(cache).when(ctx).getModificationCache(); - doReturn(mappingContext).when(ctx).getMappingContext(); - - setUpBefore(); - customizer = initCustomizer(); - setUpAfter(); - } - - /** - * Optional setup for subclasses. Invoked before customizer is initialized. - */ - protected void setUpBefore() { - - } - - /** - * Optional setup for subclasses. Invoked after customizer is initialized. - */ - protected void setUpAfter() throws Exception { - - } - - protected abstract ReaderCustomizer initCustomizer(); - - protected ReaderCustomizer getCustomizer() { - return customizer; - } - - @Test - public void testGetBuilder() throws Exception { - assertNotNull(customizer.getBuilder(InstanceIdentifier.create(dataObjectClass))); - } -} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/TestHelperUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/TestHelperUtils.java deleted file mode 100644 index e82b3ec03..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/test/TestHelperUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.v3po.test; - -import org.openvpp.jvpp.VppCallbackException; -import org.openvpp.jvpp.dto.JVppReply; - -import java.util.concurrent.CompletableFuture; - -public class TestHelperUtils { - private final static int ERROR_RETVAL = -1; - - /** - * Static helper method for creation of Exception failure state in CompletableFuture object - * with retval = -1 - * @return CompletableFuture with VppCallbackException as a cause - */ - public static CompletableFuture createFutureException() { - final CompletableFuture replyFuture = new CompletableFuture<>(); - replyFuture.completeExceptionally(new VppCallbackException("test-call", 1, ERROR_RETVAL)); - return replyFuture; - } -} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainCustomizerTest.java deleted file mode 100644 index ae9b0c29c..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainCustomizerTest.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * 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.v3po.vpp; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; -import org.openvpp.jvpp.VppInvocationException; -import org.openvpp.jvpp.dto.BridgeDomainAddDel; -import org.openvpp.jvpp.dto.BridgeDomainAddDelReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class BridgeDomainCustomizerTest { - - private static final byte ADD_OR_UPDATE_BD = (byte) 1; - private static final byte ZERO = 0; - - @Mock - private FutureJVpp api; - @Mock - private WriteContext ctx; - @Mock - private MappingContext mappingContext; - - private BridgeDomainCustomizer customizer; - - @Before - public void setUp() throws Exception { - initMocks(this); - // TODO create base class for tests using vppApi - NamingContext namingContext = new NamingContext("generatedBDName", "test-instance"); - final ModificationCache toBeReturned = new ModificationCache(); - doReturn(toBeReturned).when(ctx).getModificationCache(); - doReturn(mappingContext).when(ctx).getMappingContext(); - - customizer = new BridgeDomainCustomizer(api, namingContext); - } - - private BridgeDomain generateBridgeDomain(final String bdName) { - final byte arpTerm = 0; - final byte flood = 1; - final byte forward = 0; - final byte learn = 1; - final byte uuf = 0; - return generateBridgeDomain(bdName, arpTerm, flood, forward, learn, uuf); - } - - private BridgeDomain generateBridgeDomain(final String bdName, final int arpTerm, final int flood, - final int forward, final int learn, final int uuf) { - return new BridgeDomainBuilder() - .setName(bdName) - .setArpTermination(BridgeDomainTestUtils.intToBoolean(arpTerm)) - .setFlood(BridgeDomainTestUtils.intToBoolean(flood)) - .setForward(BridgeDomainTestUtils.intToBoolean(forward)) - .setLearn(BridgeDomainTestUtils.intToBoolean(learn)) - .setUnknownUnicastFlood(BridgeDomainTestUtils.intToBoolean(uuf)) - .build(); - } - - private void verifyBridgeDomainAddOrUpdateWasInvoked(final BridgeDomain bd, final int bdId) - throws VppInvocationException { - final byte arpTerm = BridgeDomainTestUtils.booleanToByte(bd.isArpTermination()); - final byte flood = BridgeDomainTestUtils.booleanToByte(bd.isFlood()); - final byte forward = BridgeDomainTestUtils.booleanToByte(bd.isForward()); - final byte learn = BridgeDomainTestUtils.booleanToByte(bd.isLearn()); - final byte uuf = BridgeDomainTestUtils.booleanToByte(bd.isUnknownUnicastFlood()); - - // TODO adding equals methods for jvpp DTOs would make ArgumentCaptor usage obsolete - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BridgeDomainAddDel.class); - verify(api).bridgeDomainAddDel(argumentCaptor.capture()); - final BridgeDomainAddDel actual = argumentCaptor.getValue(); - assertEquals(arpTerm, actual.arpTerm); - assertEquals(flood, actual.flood); - assertEquals(forward, actual.forward); - assertEquals(learn, actual.learn); - assertEquals(uuf, actual.uuFlood); - assertEquals(ADD_OR_UPDATE_BD, actual.isAdd); - assertEquals(bdId, actual.bdId); - } - - private void verifyBridgeDomainDeleteWasInvoked(final int bdId) throws VppInvocationException { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BridgeDomainAddDel.class); - verify(api).bridgeDomainAddDel(argumentCaptor.capture()); - final BridgeDomainAddDel actual = argumentCaptor.getValue(); - assertEquals(bdId, actual.bdId); - assertEquals(ZERO, actual.arpTerm); - assertEquals(ZERO, actual.flood); - assertEquals(ZERO, actual.forward); - assertEquals(ZERO, actual.learn); - assertEquals(ZERO, actual.uuFlood); - assertEquals(ZERO, actual.isAdd); - } - - private void whenBridgeDomainAddDelThenSuccess() - throws ExecutionException, InterruptedException, VppInvocationException { - final CompletionStage replyCS = mock(CompletionStage.class); - final CompletableFuture replyFuture = mock(CompletableFuture.class); - when(replyCS.toCompletableFuture()).thenReturn(replyFuture); - final BridgeDomainAddDelReply reply = new BridgeDomainAddDelReply(); - when(replyFuture.get()).thenReturn(reply); - when(api.bridgeDomainAddDel(any(BridgeDomainAddDel.class))).thenReturn(replyCS); - } - - private void whenBridgeDomainAddDelThenFailure() - throws ExecutionException, InterruptedException, VppInvocationException { - doReturn(TestHelperUtils.createFutureException()).when(api) - .bridgeDomainAddDel(any(BridgeDomainAddDel.class)); - } - - @Test - public void testAddBridgeDomain() throws Exception { - final int bdId = 1; - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain(bdName); - // Make bdContext.containsName() return false - doReturn(Optional.absent()).when(mappingContext) - .read(getMappingIid(bdName, "test-instance").firstIdentifierOf(Mappings.class)); - // Make bdContext.containsIndex() return false - doReturn(Optional.absent()).when(mappingContext) - .read(getMappingIid(bdName, "test-instance")); - - whenBridgeDomainAddDelThenSuccess(); - - customizer.writeCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); - - verifyBridgeDomainAddOrUpdateWasInvoked(bd, bdId); - verify(mappingContext).put(getMappingIid(bdName, "test-instance"), getMapping(bdName, bdId).get()); - } - - @Test - public void testAddBridgeDomainPresentInBdContext() throws Exception { - final int bdId = 1; - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain(bdName); - // Make bdContext.containsIndex() return true - doReturn(Optional.of(new MappingBuilder().setIndex(bdId).build())).when(mappingContext) - .read(getMappingIid(bdName, "test-instance")); - - whenBridgeDomainAddDelThenSuccess(); - - customizer.writeCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); - - verifyBridgeDomainAddOrUpdateWasInvoked(bd, bdId); - verify(mappingContext).put(getMappingIid(bdName, "test-instance"), getMapping(bdName, bdId).get()); - } - - @Test - public void testAddBridgeDomainFailed() throws Exception { - final int bdId = 1; - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain(bdName); - - // Returning no Mappings for "test-instance" makes bdContext.containsName() return false - doReturn(Optional.absent()).when(mappingContext) - .read(getMappingIid(bdName, "test-instance").firstIdentifierOf(Mappings.class)); - // Make bdContext.containsIndex() return false - doReturn(Optional.absent()).when(mappingContext) - .read(getMappingIid(bdName, "test-instance")); - - whenBridgeDomainAddDelThenFailure(); - - try { - customizer.writeCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); - } catch (WriteFailedException.CreateFailedException e) { - verifyBridgeDomainAddOrUpdateWasInvoked(bd, bdId); - return; - } - fail("WriteFailedException.CreateFailedException was expected"); - } - - @Test - public void testDeleteBridgeDomain() throws Exception { - final int bdId = 1; - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain(bdName); - doReturn(getMapping(bdName, bdId)).when(mappingContext).read(getMappingIid(bdName, "test-instance")); - - whenBridgeDomainAddDelThenSuccess(); - - customizer.deleteCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); - - verifyBridgeDomainDeleteWasInvoked(bdId); - } - - @Test - public void testDeleteUnknownBridgeDomain() throws Exception { - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain("bd1"); - doReturn(Optional.absent()).when(mappingContext).read(getMappingIid(bdName, "test-instance")); - - try { - customizer.deleteCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); - } catch (IllegalArgumentException e) { - verify(api, never()).bridgeDomainAddDel(any(BridgeDomainAddDel.class)); - return; - } - fail("IllegalArgumentException was expected"); - } - - @Test - public void testDeleteBridgeDomainFailed() throws Exception { - final int bdId = 1; - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain(bdName); - doReturn(getMapping(bdName, bdId)).when(mappingContext).read(getMappingIid(bdName, "test-instance")); - - whenBridgeDomainAddDelThenFailure(); - - try { - customizer.deleteCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bd, ctx); - } catch (WriteFailedException.DeleteFailedException e) { - verifyBridgeDomainDeleteWasInvoked(bdId); - return; - } - - fail("WriteFailedException.DeleteFailedException was expected"); - } - - @Test - public void testUpdateBridgeDomain() throws Exception { - final int bdId = 1; - final String bdName = "bd1"; - doReturn(getMapping(bdName, bdId)).when(mappingContext).read(getMappingIid(bdName, "test-instance")); - - final byte arpTermBefore = 1; - final byte floodBefore = 1; - final byte forwardBefore = 0; - final byte learnBefore = 1; - final byte uufBefore = 0; - - final BridgeDomain dataBefore = - generateBridgeDomain(bdName, arpTermBefore, floodBefore, forwardBefore, learnBefore, uufBefore); - final BridgeDomain dataAfter = - generateBridgeDomain(bdName, arpTermBefore ^ 1, floodBefore ^ 1, forwardBefore ^ 1, learnBefore ^ 1, - uufBefore ^ 1); - - whenBridgeDomainAddDelThenSuccess(); - - customizer - .updateCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), dataBefore, dataAfter, ctx); - verifyBridgeDomainAddOrUpdateWasInvoked(dataAfter, bdId); - } - - @Test - public void testUpdateUnknownBridgeDomain() throws Exception { - final String bdName = "bd1"; - final BridgeDomain bdBefore = generateBridgeDomain(bdName, 0, 1, 0, 1, 0); - final BridgeDomain bdAfter = generateBridgeDomain(bdName, 1, 1, 0, 1, 0); - doReturn(Optional.absent()).when(mappingContext).read(getMappingIid(bdName, "test-instance")); - - try { - customizer - .updateCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bdBefore, bdAfter, ctx); - } catch (IllegalArgumentException e) { - verify(api, never()).bridgeDomainAddDel(any(BridgeDomainAddDel.class)); - return; - } - fail("IllegalArgumentException was expected"); - } - - @Test - public void testUpdateBridgeDomainFailed() throws Exception { - final int bdId = 1; - final String bdName = "bd1"; - final BridgeDomain bdBefore = generateBridgeDomain(bdName, 0, 1, 0, 1, 0); - final BridgeDomain bdAfter = generateBridgeDomain(bdName, 1, 1, 0, 1, 0); - doReturn(getMapping(bdName, bdId)).when(mappingContext).read(getMappingIid(bdName, "test-instance")); - - whenBridgeDomainAddDelThenFailure(); - - try { - customizer - .updateCurrentAttributes(BridgeDomainTestUtils.bdIdentifierForName(bdName), bdBefore, bdAfter, ctx); - } catch (WriteFailedException.UpdateFailedException e) { - verifyBridgeDomainAddOrUpdateWasInvoked(bdAfter, bdId); - return; - } - fail("IllegalStateException was expected"); - } - -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainTestUtils.java deleted file mode 100644 index ba4df9e49..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/BridgeDomainTestUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.v3po.vpp; - -import javax.annotation.Nullable; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; - -final class BridgeDomainTestUtils { - - private BridgeDomainTestUtils() { - throw new UnsupportedOperationException("Utility class cannot be instantiated."); - } - - public static byte booleanToByte(@Nullable final Boolean value) { - return value != null && value ? (byte) 1 : (byte) 0; - } - - @Nullable - public static Boolean intToBoolean(final int value) { - if (value == 0) { - return Boolean.FALSE; - } - if (value == 1) { - return Boolean.TRUE; - } - return null; - } - - public static int bdNameToID(String bName) { - return Integer.parseInt(((Character)bName.charAt(bName.length() - 1)).toString()); - } - - public static KeyedInstanceIdentifier bdIdentifierForName( - final String bdName) { - return InstanceIdentifier.create(BridgeDomains.class).child(BridgeDomain.class, new BridgeDomainKey(bdName)); - } - - public static final Answer BD_NAME_TO_ID_ANSWER = new Answer() { - @Override - public Integer answer(final InvocationOnMock invocationOnMock) throws Throwable { - return bdNameToID((String) invocationOnMock.getArguments()[0]); - } - }; -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/L2FibEntryCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/L2FibEntryCustomizerTest.java deleted file mode 100644 index fb41b91c7..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vpp/L2FibEntryCustomizerTest.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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.v3po.vpp; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.mockMapping; -import static org.junit.Assert.assertEquals; -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.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletableFuture; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibFilter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.VppInvocationException; -import org.openvpp.jvpp.dto.L2FibAddDel; -import org.openvpp.jvpp.dto.L2FibAddDelReply; -import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class L2FibEntryCustomizerTest { - private static final String BD_CTX_NAME = "bd-test-instance"; - private static final String IFC_CTX_NAME = "ifc-test-instance"; - - private static final String BD_NAME = "testBD0"; - private static final int BD_ID = 111; - private static final String IFACE_NAME = "eth0"; - private static final int IFACE_ID = 123; - - @Mock - private FutureJVpp api; - @Mock - private WriteContext writeContext; - @Mock - private MappingContext mappingContext; - - private NamingContext bdContext; - private NamingContext interfaceContext; - - private L2FibEntryCustomizer customizer; - - @Before - public void setUp() throws Exception { - initMocks(this); - doReturn(mappingContext).when(writeContext).getMappingContext(); - bdContext = new NamingContext("generatedBdName", BD_CTX_NAME); - interfaceContext = new NamingContext("generatedIfaceName", IFC_CTX_NAME); - - customizer = new L2FibEntryCustomizer(api, bdContext, interfaceContext); - } - - private static InstanceIdentifier getL2FibEntryId(final PhysAddress address) { - return InstanceIdentifier.create(BridgeDomains.class).child(BridgeDomain.class, new BridgeDomainKey(BD_NAME)) - .child(L2FibTable.class).child(L2FibEntry.class, new L2FibEntryKey(address)); - } - - private void whenL2FibAddDelThenSuccess() { - final CompletableFuture replyFuture = new CompletableFuture<>(); - final L2FibAddDelReply reply = new L2FibAddDelReply(); - replyFuture.complete(reply); - doReturn(replyFuture).when(api).l2FibAddDel(any(L2FibAddDel.class)); - } - - private void whenL2FibAddDelThenFailure() { - doReturn(TestHelperUtils.createFutureException()).when(api) - .l2FibAddDel(any(L2FibAddDel.class)); - } - - private L2FibAddDel generateL2FibAddDelRequest(final long mac, final byte isAdd) { - final L2FibAddDel request = new L2FibAddDel(); - request.mac = mac; - request.bdId = BD_ID; - request.swIfIndex = IFACE_ID; - request.isAdd = isAdd; - if (isAdd == 1) { - request.staticMac = 1; - request.filterMac = 1; - } - return request; - } - - private L2FibEntry generateL2FibEntry(final PhysAddress address) { - final L2FibEntryBuilder entry = new L2FibEntryBuilder(); - entry.setKey(new L2FibEntryKey(address)); - entry.setPhysAddress(address); - entry.setStaticConfig(true); - entry.setBridgedVirtualInterface(false); - entry.setAction(L2FibFilter.class); - entry.setOutgoingInterface(IFACE_NAME); - return entry.build(); - } - - private void verifyL2FibAddDelWasInvoked(final L2FibAddDel expected) throws - VppInvocationException { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(L2FibAddDel.class); - verify(api).l2FibAddDel(argumentCaptor.capture()); - final L2FibAddDel actual = argumentCaptor.getValue(); - assertEquals(expected.mac, actual.mac); - assertEquals(expected.bdId, actual.bdId); - assertEquals(expected.swIfIndex, actual.swIfIndex); - assertEquals(expected.isAdd, actual.isAdd); - assertEquals(expected.staticMac, actual.staticMac); - assertEquals(expected.filterMac, actual.filterMac); - } - - @Test - public void testCreate() throws Exception { - final long address_vpp = 0x0102030405060000L; - final PhysAddress address = new PhysAddress("01:02:03:04:05:06"); - final L2FibEntry entry = generateL2FibEntry(address); - final InstanceIdentifier id = getL2FibEntryId(address); - - mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); - mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); - - whenL2FibAddDelThenSuccess(); - - customizer.writeCurrentAttributes(id, entry, writeContext); - - verifyL2FibAddDelWasInvoked(generateL2FibAddDelRequest(address_vpp, (byte) 1)); - } - - @Test - public void testCreateFailed() throws Exception { - final long address_vpp = 0x1122334455660000L; - final PhysAddress address = new PhysAddress("11:22:33:44:55:66"); - final L2FibEntry entry = generateL2FibEntry(address); - final InstanceIdentifier id = getL2FibEntryId(address); - - mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); - mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); - - whenL2FibAddDelThenFailure(); - - try { - customizer.writeCurrentAttributes(id, entry, writeContext); - } catch (WriteFailedException.CreateFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyL2FibAddDelWasInvoked(generateL2FibAddDelRequest(address_vpp, (byte) 1)); - return; - } - fail("WriteFailedException.CreateFailedException was expected"); - } - - @Test(expected = UnsupportedOperationException.class) - public void testUpdate() throws Exception { - customizer.updateCurrentAttributes(InstanceIdentifier.create(L2FibEntry.class), mock(L2FibEntry.class), - mock(L2FibEntry.class), writeContext); - } - - @Test - public void testDelete() throws Exception { - final long address_vpp = 0x1122334455660000L; - final PhysAddress address = new PhysAddress("11:22:33:44:55:66"); - final L2FibEntry entry = generateL2FibEntry(address); - final InstanceIdentifier id = getL2FibEntryId(address); - - mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); - mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); - - whenL2FibAddDelThenSuccess(); - - customizer.deleteCurrentAttributes(id, entry, writeContext); - - verifyL2FibAddDelWasInvoked(generateL2FibAddDelRequest(address_vpp, (byte) 0)); - } - - @Test - public void testDeleteFailed() throws Exception { - final long address_vpp = 0x0102030405060000L; - final PhysAddress address = new PhysAddress("01:02:03:04:05:06"); - final L2FibEntry entry = generateL2FibEntry(address); - final InstanceIdentifier id = getL2FibEntryId(address); - - mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); - mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); - - whenL2FibAddDelThenFailure(); - - try { - customizer.deleteCurrentAttributes(id, entry, writeContext); - } catch (WriteFailedException.DeleteFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyL2FibAddDelWasInvoked(generateL2FibAddDelRequest(address_vpp, (byte) 0)); - return; - } - fail("WriteFailedException.DeleteFailedException was expected"); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReaderTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReaderTest.java deleted file mode 100644 index 701f43eb0..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionReaderTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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.v3po.vppclassifier; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.ClassifySessionDetails; -import org.openvpp.jvpp.dto.ClassifySessionDetailsReplyDump; -import org.openvpp.jvpp.dto.ClassifySessionDump; - -public class ClassifySessionReaderTest extends - ListReaderCustomizerTest { - - private static final String MATCH_1 = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"; - private static final String MATCH_2 = "00:00:00:00:00:00:01:02:03:04:05:07:00:00:00:00"; - - private static final int TABLE_INDEX = 1; - private static final String TABLE_NAME = "table1"; - - private NamingContext classifyTableContext; - - public ClassifySessionReaderTest() { - super(ClassifySession.class); - } - - @Override - public void setUpBefore() { - classifyTableContext = new NamingContext("classifyTableContext", "test-instance"); - - final Optional ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX); - doReturn(ifcMapping).when(mappingContext).read(any()); - } - - @Override - protected ReaderCustomizer initCustomizer() { - return new ClassifySessionReader(api, classifyTableContext); - } - - private static InstanceIdentifier getClassifySessionId(final String tableName, - final String match) { - return InstanceIdentifier.create(VppClassifierState.class) - .child(ClassifyTable.class, new ClassifyTableKey(tableName)) - .child(ClassifySession.class, new ClassifySessionKey(new HexString(match))); - } - - @Test - public void testMerge() { - final ClassifyTableBuilder builder = mock(ClassifyTableBuilder.class); - final List value = mock(List.class); - getCustomizer().merge(builder, value); - verify(builder).setClassifySession(value); - } - - @Test - public void testReadWithCache() throws ReadFailedException { - final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, MATCH_1); - final ClassifySessionBuilder builder = mock(ClassifySessionBuilder.class); - final ModificationCache cache = new ModificationCache(); - final ClassifySessionDetailsReplyDump dump = new ClassifySessionDetailsReplyDump(); - final ClassifySessionDetails details = new ClassifySessionDetails(); - details.match = - new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, - (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; - dump.classifySessionDetails = Collections.singletonList(details); - cache.put(ClassifySessionReader.CACHE_KEY + id.firstKeyOf(ClassifyTable.class), dump); - when(ctx.getModificationCache()).thenReturn(cache); - - getCustomizer().readCurrentAttributes(id, builder, ctx); - } - - @Test - public void testGetAllIds() throws ReadFailedException { - final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, MATCH_1); - final ClassifySessionDetailsReplyDump dump = new ClassifySessionDetailsReplyDump(); - final ClassifySessionDetails details1 = new ClassifySessionDetails(); - details1.match = - new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, - (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; - final ClassifySessionDetails details2 = new ClassifySessionDetails(); - details2.match = - new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, - (byte) 0x05, (byte) 0x07, 0x00, 0x00, 0x00, 0x00}; - dump.classifySessionDetails = Arrays.asList(details1, details2); - - final CompletableFuture replyFuture = new CompletableFuture<>(); - replyFuture.complete(dump); - doReturn(replyFuture).when(api).classifySessionDump(any(ClassifySessionDump.class)); - - final List allIds = getCustomizer().getAllIds(id, ctx); - assertEquals(2, allIds.size()); - assertEquals(MATCH_1, allIds.get(0).getMatch().getValue()); - assertEquals(MATCH_2, allIds.get(1).getMatch().getValue()); - } - -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriterTest.java deleted file mode 100644 index e4c13efea..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifySessionWriterTest.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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.v3po.vppclassifier; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.ClassifyAddDelSession; -import org.openvpp.jvpp.dto.ClassifyAddDelSessionReply; -import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class ClassifySessionWriterTest { - - private static final int TABLE_INDEX = 123; - private static final String TABLE_NAME = "table123"; - - @Mock - private FutureJVpp api; - @Mock - private WriteContext writeContext; - @Mock - private MappingContext mappingContext; - - private NamingContext classifyTableContext; - private ClassifySessionWriter customizer; - private static final int SESSION_INDEX = 456; - - @Before - public void setUp() throws Exception { - initMocks(this); - classifyTableContext = new NamingContext("generatedClassifyTableName", "test-instance"); - doReturn(mappingContext).when(writeContext).getMappingContext(); - customizer = new ClassifySessionWriter(api, classifyTableContext); - - final Optional ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX); - doReturn(ifcMapping).when(mappingContext).read(any()); - } - - private static ClassifySession generateClassifySession(final long opaqueIndex, final String match) { - final ClassifySessionBuilder builder = new ClassifySessionBuilder(); - builder.setOpaqueIndex(new OpaqueIndex(opaqueIndex)); - builder.setHitNext(new VppNode(PacketHandlingAction.Deny)); - builder.setAdvance(123); - builder.setMatch(new HexString(match)); - return builder.build(); - } - - private static InstanceIdentifier getClassifySessionId(final String tableName, - final String match) { - return InstanceIdentifier.create(VppClassifier.class) - .child(ClassifyTable.class, new ClassifyTableKey(tableName)) - .child(ClassifySession.class, new ClassifySessionKey(new HexString(match))); - } - - private void whenClassifyAddDelSessionThenSuccess() throws ExecutionException, InterruptedException { - final CompletableFuture replyFuture = new CompletableFuture<>(); - replyFuture.complete(new ClassifyAddDelSessionReply()); - doReturn(replyFuture).when(api).classifyAddDelSession(any(ClassifyAddDelSession.class)); - } - - private void whenClassifyAddDelSessionThenFailure() throws ExecutionException, InterruptedException { - doReturn(TestHelperUtils.createFutureException()).when(api) - .classifyAddDelSession(any(ClassifyAddDelSession.class)); - } - - private void verifyClassifyAddDelSessionWasInvoked(final ClassifyAddDelSession expected) { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelSession.class); - verify(api).classifyAddDelSession(argumentCaptor.capture()); - final ClassifyAddDelSession actual = argumentCaptor.getValue(); - assertEquals(expected.opaqueIndex, actual.opaqueIndex); - assertEquals(expected.isAdd, actual.isAdd); - assertEquals(expected.tableIndex, actual.tableIndex); - assertEquals(expected.hitNextIndex, actual.hitNextIndex); - assertArrayEquals(expected.match, actual.match); - assertEquals(expected.advance, actual.advance); - } - - private void verifyClassifyAddDelSessionDeleteWasInvoked(final ClassifyAddDelSession expected) { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelSession.class); - verify(api).classifyAddDelSession(argumentCaptor.capture()); - final ClassifyAddDelSession actual = argumentCaptor.getValue(); - assertEquals(expected.opaqueIndex, actual.opaqueIndex); - assertEquals(expected.isAdd, actual.isAdd); - assertEquals(expected.tableIndex, actual.tableIndex); - } - - private static ClassifyAddDelSession generateClassifyAddDelSession(final byte isAdd, final int tableIndex, - final int sessionIndex) { - final ClassifyAddDelSession request = new ClassifyAddDelSession(); - request.isAdd = isAdd; - request.tableIndex = tableIndex; - request.opaqueIndex = sessionIndex; - request.hitNextIndex = 0; - request.advance = 123; - request.match = - new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, - (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; - return request; - } - - @Test - public void testCreate() throws Exception { - final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"; - final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match); - final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, match); - - whenClassifyAddDelSessionThenSuccess(); - - customizer.writeCurrentAttributes(id, classifySession, writeContext); - - verifyClassifyAddDelSessionWasInvoked(generateClassifyAddDelSession((byte) 1, TABLE_INDEX, SESSION_INDEX)); - } - - @Test - public void testCreateFailed() throws Exception { - final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"; - final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match); - final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, match); - - whenClassifyAddDelSessionThenFailure(); - - try { - customizer.writeCurrentAttributes(id, classifySession, writeContext); - } catch (WriteFailedException.CreateFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyClassifyAddDelSessionWasInvoked(generateClassifyAddDelSession((byte) 1, TABLE_INDEX, SESSION_INDEX)); - return; - } - fail("WriteFailedException.CreateFailedException was expected"); - } - - @Test(expected = UnsupportedOperationException.class) - public void testUpdate() throws Exception { - customizer.updateCurrentAttributes(null, null, null, writeContext); - } - - @Test - public void testDelete() throws Exception { - final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"; - final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match); - final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, match); - - whenClassifyAddDelSessionThenSuccess(); - - customizer.deleteCurrentAttributes(id, classifySession, writeContext); - - verifyClassifyAddDelSessionDeleteWasInvoked( - generateClassifyAddDelSession((byte) 0, TABLE_INDEX, SESSION_INDEX)); - } - - @Test - public void testDeleteFailed() throws Exception { - final String match = "00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00"; - final ClassifySession classifySession = generateClassifySession(SESSION_INDEX, match); - final InstanceIdentifier id = getClassifySessionId(TABLE_NAME, match); - - whenClassifyAddDelSessionThenFailure(); - - try { - customizer.deleteCurrentAttributes(id, classifySession, writeContext); - } catch (WriteFailedException.DeleteFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyClassifyAddDelSessionDeleteWasInvoked( - generateClassifyAddDelSession((byte) 0, TABLE_INDEX, SESSION_INDEX)); - return; - } - fail("WriteFailedException.DeleteFailedException was expected"); - - customizer.deleteCurrentAttributes(id, classifySession, writeContext); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReaderTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReaderTest.java deleted file mode 100644 index c3c8a5f0a..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableReaderTest.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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.v3po.vppclassifier; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifierStateBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.openvpp.jvpp.dto.ClassifyTableIds; -import org.openvpp.jvpp.dto.ClassifyTableIdsReply; -import org.openvpp.jvpp.dto.ClassifyTableInfo; -import org.openvpp.jvpp.dto.ClassifyTableInfoReply; - -public class ClassifyTableReaderTest extends - ListReaderCustomizerTest { - - private static final int TABLE_INDEX_1 = 1; - private static final String TABLE_NAME_1 = "table1"; - private static final int TABLE_INDEX_2 = 2; - private static final String TABLE_NAME_2 = "table2"; - - private NamingContext classifyTableContext; - - public ClassifyTableReaderTest() { - super(ClassifyTable.class); - } - - @Override - public void setUpBefore() { - classifyTableContext = new NamingContext("classifyTableContext", "test-instance"); - - final KeyedInstanceIdentifier t0Id = getMappingIid(TABLE_NAME_1, "test-instance"); - final KeyedInstanceIdentifier t1Id = getMappingIid(TABLE_NAME_2, "test-instance"); - final Optional t0 = getMapping(TABLE_NAME_1, TABLE_INDEX_1); - final Optional t1 = getMapping(TABLE_NAME_2, TABLE_INDEX_2); - final List allMappings = Lists.newArrayList(t0.get(), t1.get()); - final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); - doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(t0Id.firstIdentifierOf(Mappings.class)); - doReturn(t0).when(mappingContext).read(t0Id); - doReturn(t1).when(mappingContext).read(t1Id); - } - - @Override - protected ReaderCustomizer initCustomizer() { - return new ClassifyTableReader(api, classifyTableContext); - } - - private static InstanceIdentifier getClassifyTableId(final String name) { - return InstanceIdentifier.create(VppClassifierState.class) - .child(ClassifyTable.class, new ClassifyTableKey(name)); - } - - private static ClassifyTableInfoReply generateClassifyTableInfoReply() { - final ClassifyTableInfoReply reply = new ClassifyTableInfoReply(); - reply.tableId = TABLE_INDEX_1; - reply.nbuckets = 2; - reply.skipNVectors = 0; - reply.matchNVectors = 1; - reply.nextTableIndex = ~0; - reply.missNextIndex = ~0; - reply.mask = - new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, - (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; - return reply; - } - - private void verifyClasifyTableRead(final ClassifyTableBuilder builder) { - verify(builder).setName(TABLE_NAME_1); - verify(builder).setNbuckets(2L); - verify(builder, times(0)).setNextTable(anyString()); - verify(builder).setMissNext(new VppNode(PacketHandlingAction.Permit)); - verify(builder).setMask(new HexString("00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00")); - verify(builder).setActiveSessions(0L); - } - - @Test - public void testMerge() { - final VppClassifierStateBuilder builder = mock(VppClassifierStateBuilder.class); - final List value = mock(List.class); - getCustomizer().merge(builder, value); - verify(builder).setClassifyTable(value); - } - - @Test - public void testRead() throws ReadFailedException { - final CompletableFuture replyFuture = new CompletableFuture<>(); - replyFuture.complete(generateClassifyTableInfoReply()); - doReturn(replyFuture).when(api).classifyTableInfo(any(ClassifyTableInfo.class)); - - final ClassifyTableBuilder builder = mock(ClassifyTableBuilder.class); - getCustomizer().readCurrentAttributes(getClassifyTableId(TABLE_NAME_1), builder, ctx); - - verifyClasifyTableRead(builder); - } - - @Test - public void testGetAllIds() throws ReadFailedException { - final CompletableFuture replyFuture = new CompletableFuture<>(); - final ClassifyTableIdsReply reply = new ClassifyTableIdsReply(); - reply.ids = new int[] {1, 2}; - replyFuture.complete(reply); - doReturn(replyFuture).when(api).classifyTableIds(any(ClassifyTableIds.class)); - - final List allIds = getCustomizer().getAllIds(getClassifyTableId(TABLE_NAME_1), ctx); - - assertEquals(reply.ids.length, allIds.size()); - assertEquals(TABLE_NAME_1, allIds.get(0).getName()); - assertEquals(TABLE_NAME_2, allIds.get(1).getName()); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriterTest.java deleted file mode 100644 index 015daf344..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppclassifier/ClassifyTableWriterTest.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * 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.v3po.vppclassifier; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.PacketHandlingAction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.ClassifyAddDelTable; -import org.openvpp.jvpp.dto.ClassifyAddDelTableReply; -import org.openvpp.jvpp.dto.L2InterfaceVlanTagRewriteReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class ClassifyTableWriterTest { - - private static final int TABLE_INDEX = 123; - private static final String TABLE_NAME = "table123"; - - @Mock - private FutureJVpp api; - @Mock - private WriteContext writeContext; - @Mock - private MappingContext mappingContext; - - private NamingContext classifyTableContext; - private ClassifyTableWriter customizer; - - @Before - public void setUp() throws Exception { - initMocks(this); - classifyTableContext = new NamingContext("generatedClassifyTableName", "test-instance"); - doReturn(mappingContext).when(writeContext).getMappingContext(); - customizer = new ClassifyTableWriter(api, classifyTableContext); - } - - private static ClassifyTable generateClassifyTable(final String name) { - final ClassifyTableBuilder builder = new ClassifyTableBuilder(); - builder.setName(name); - builder.setKey(new ClassifyTableKey(name)); - builder.setSkipNVectors(0L); - builder.setNbuckets(2L); - builder.setMemorySize(2L << 20); - builder.setMissNext(new VppNode(PacketHandlingAction.Permit)); - builder.setMask(new HexString("00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00")); - return builder.build(); - } - - private static InstanceIdentifier getClassifyTableId(final String name) { - return InstanceIdentifier.create(VppClassifier.class) - .child(ClassifyTable.class, new ClassifyTableKey(name)); - } - - private void whenClassifyAddDelTableThenSuccess() throws ExecutionException, InterruptedException { - final CompletableFuture replyFuture = new CompletableFuture<>(); - final ClassifyAddDelTableReply reply = new ClassifyAddDelTableReply(); - reply.newTableIndex = TABLE_INDEX; - replyFuture.complete(reply); - doReturn(replyFuture).when(api).classifyAddDelTable(any(ClassifyAddDelTable.class)); - } - - private void whenClassifyAddDelTableThenFailure() throws ExecutionException, InterruptedException { - doReturn(TestHelperUtils.createFutureException()).when(api) - .classifyAddDelTable(any(ClassifyAddDelTable.class)); - } - - private void verifyClassifyAddDelTableAddWasInvoked(final ClassifyAddDelTable expected) { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelTable.class); - verify(api).classifyAddDelTable(argumentCaptor.capture()); - final ClassifyAddDelTable actual = argumentCaptor.getValue(); - assertEquals(expected.isAdd, actual.isAdd); - assertEquals(~0, actual.tableIndex); - assertEquals(expected.nbuckets, actual.nbuckets); - assertEquals(expected.memorySize, actual.memorySize); - assertEquals(expected.skipNVectors, actual.skipNVectors); - assertEquals(expected.matchNVectors, actual.matchNVectors); - assertEquals(expected.nextTableIndex, actual.nextTableIndex); - assertEquals(expected.missNextIndex, actual.missNextIndex); - assertArrayEquals(expected.mask, actual.mask); - } - - private void verifyClassifyAddDelTableDeleteWasInvoked(final ClassifyAddDelTable expected) { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(ClassifyAddDelTable.class); - verify(api).classifyAddDelTable(argumentCaptor.capture()); - final ClassifyAddDelTable actual = argumentCaptor.getValue(); - assertEquals(expected.isAdd, actual.isAdd); - assertEquals(expected.tableIndex, actual.tableIndex); - } - - private static ClassifyAddDelTable generateClassifyAddDelTable(final byte isAdd, final int tableIndex) { - final ClassifyAddDelTable request = new ClassifyAddDelTable(); - request.isAdd = isAdd; - request.tableIndex = tableIndex; - request.nbuckets = 2; - request.memorySize = 2 << 20; - request.skipNVectors = 0; - request.matchNVectors = 1; - request.nextTableIndex = ~0; - request.missNextIndex = ~0; - request.mask = - new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, - (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; - return request; - } - - @Test - public void testCreate() throws Exception { - final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME); - final InstanceIdentifier id = getClassifyTableId(TABLE_NAME); - - whenClassifyAddDelTableThenSuccess(); - - customizer.writeCurrentAttributes(id, classifyTable, writeContext); - - verifyClassifyAddDelTableAddWasInvoked(generateClassifyAddDelTable((byte) 1, TABLE_INDEX)); - verify(mappingContext) - .put(eq(getMappingIid(TABLE_NAME, "test-instance")), eq(getMapping(TABLE_NAME, TABLE_INDEX).get())); - } - - @Test - public void testCreateFailed() throws Exception { - final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME); - final InstanceIdentifier id = getClassifyTableId(TABLE_NAME); - - whenClassifyAddDelTableThenFailure(); - - try { - customizer.writeCurrentAttributes(id, classifyTable, writeContext); - } catch (WriteFailedException.CreateFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyClassifyAddDelTableAddWasInvoked(generateClassifyAddDelTable((byte) 1, TABLE_INDEX)); - verify(mappingContext, times(0)).put( - eq(getMappingIid(TABLE_NAME, "test-instance")), - eq(getMapping(TABLE_NAME, TABLE_INDEX).get())); - return; - } - fail("WriteFailedException.CreateFailedException was expected"); - } - - @Test - public void testDelete() throws Exception { - final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME); - final InstanceIdentifier id = getClassifyTableId(TABLE_NAME); - - final Optional ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX); - doReturn(ifcMapping).when(mappingContext).read(any()); - - whenClassifyAddDelTableThenSuccess(); - - customizer.deleteCurrentAttributes(id, classifyTable, writeContext); - - verifyClassifyAddDelTableDeleteWasInvoked(generateClassifyAddDelTable((byte) 0, TABLE_INDEX)); - } - - @Test - public void testDeleteFailed() throws Exception { - final ClassifyTable classifyTable = generateClassifyTable(TABLE_NAME); - final InstanceIdentifier id = getClassifyTableId(TABLE_NAME); - - final Optional ifcMapping = getMapping(TABLE_NAME, TABLE_INDEX); - doReturn(ifcMapping).when(mappingContext).read(any()); - - whenClassifyAddDelTableThenFailure(); - - try { - customizer.deleteCurrentAttributes(id, classifyTable, writeContext); - } catch (WriteFailedException.DeleteFailedException e) { - assertTrue(e.getCause() instanceof VppBaseCallException); - verifyClassifyAddDelTableDeleteWasInvoked(generateClassifyAddDelTable((byte) 0, TABLE_INDEX)); - return; - } - fail("WriteFailedException.DeleteFailedException was expected"); - - customizer.deleteCurrentAttributes(id, classifyTable, writeContext); - } - - @Test(expected = UnsupportedOperationException.class) - public void testUpdate() throws Exception { - final ClassifyTable classifyTableBefore = generateClassifyTable(TABLE_NAME); - final InstanceIdentifier id = getClassifyTableId(TABLE_NAME); - customizer.updateCurrentAttributes(id, classifyTableBefore, new ClassifyTableBuilder().build(), writeContext); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizerTest.java deleted file mode 100644 index dc02fdac5..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/BridgeDomainCustomizerTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.v3po.vppstate; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.util.Collections; -import java.util.List; -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; - -public class BridgeDomainCustomizerTest - extends ListReaderCustomizerTest { - - private NamingContext bdContext; - private NamingContext interfacesContext; - - public BridgeDomainCustomizerTest() { - super(BridgeDomain.class); - } - - @Override - public void setUpBefore() { - bdContext = new NamingContext("generatedBdName", "bd-test-instance"); - interfacesContext = new NamingContext("generatedIfaceName", "ifc-test-instance"); - } - - @Test - public void testMerge() throws Exception { - final BridgeDomainsBuilder builder = mock(BridgeDomainsBuilder.class); - final List value = Collections.emptyList(); - getCustomizer().merge(builder, value); - verify(builder).setBridgeDomain(value); - } - - @Override - protected ReaderCustomizer initCustomizer() { - return new BridgeDomainCustomizer(api, bdContext); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/L2FibEntryCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/L2FibEntryCustomizerTest.java deleted file mode 100644 index c4be494c3..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/L2FibEntryCustomizerTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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.v3po.vppstate; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.mockMapping; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.L2FibForward; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTableBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppInvocationException; -import org.openvpp.jvpp.dto.L2FibTableDump; -import org.openvpp.jvpp.dto.L2FibTableEntry; -import org.openvpp.jvpp.dto.L2FibTableEntryReplyDump; - -public class L2FibEntryCustomizerTest extends ListReaderCustomizerTest { - - private static final String BD_NAME = "testBD0"; - private static final int BD_ID = 111; - private static final String IFACE_NAME = "eth0"; - private static final int IFACE_ID = 123; - private static final String BD_CTX_NAME = "bd-test-instance"; - private static final String IFC_CTX_NAME = "ifc-test-instance"; - private NamingContext bdContext; - private NamingContext interfacesContext; - - public L2FibEntryCustomizerTest() { - super(L2FibEntry.class); - } - - @Override - public void setUpBefore() { - bdContext = new NamingContext("generatedBdName", BD_CTX_NAME); - interfacesContext = new NamingContext("generatedIfaceName", IFC_CTX_NAME); - } - - @Override - protected ReaderCustomizer initCustomizer() { - return new L2FibEntryCustomizer(api, bdContext, interfacesContext); - } - - @Test - public void testMerge() throws Exception { - final L2FibTableBuilder builder = mock(L2FibTableBuilder.class); - final List value = Collections.emptyList(); - getCustomizer().merge(builder, value); - verify(builder).setL2FibEntry(value); - } - - private static InstanceIdentifier getL2FibEntryId(final String bdName, final PhysAddress address) { - return InstanceIdentifier.create(BridgeDomains.class).child(BridgeDomain.class, new BridgeDomainKey(bdName)) - .child(L2FibTable.class).child(L2FibEntry.class, new L2FibEntryKey(address)); - } - - private void whenL2FibTableDumpThenReturn(final List l2FibTableEntryList) - throws ExecutionException, InterruptedException, VppInvocationException { - final L2FibTableEntryReplyDump reply = new L2FibTableEntryReplyDump(); - reply.l2FibTableEntry = l2FibTableEntryList; - - final CompletableFuture replyFuture = new CompletableFuture<>(); - replyFuture.complete(reply); - when(api.l2FibTableDump(any(L2FibTableDump.class))).thenReturn(replyFuture); - } - - @Test - public void testRead() throws Exception { - final long address_vpp = 0x0000010203040506L; - final PhysAddress address = new PhysAddress("01:02:03:04:05:06"); - - mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); - mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); - - whenL2FibTableDumpThenReturn(Collections.singletonList(generateL2FibEntry(address_vpp))); - - final L2FibEntryBuilder builder = mock(L2FibEntryBuilder.class); - getCustomizer().readCurrentAttributes(getL2FibEntryId(BD_NAME, address), builder, ctx); - - verify(builder).setAction(L2FibForward.class); - verify(builder).setBridgedVirtualInterface(false); - verify(builder).setOutgoingInterface(IFACE_NAME); - verify(builder).setStaticConfig(false); - verify(builder).setPhysAddress(address); - verify(builder).setKey(new L2FibEntryKey(address)); - } - - private L2FibTableEntry generateL2FibEntry(final long mac) { - final L2FibTableEntry entry = new L2FibTableEntry(); - entry.mac = mac; - entry.swIfIndex = IFACE_ID; - return entry; - } - - @Test - public void testGetAllIds() throws Exception { - final long address_vpp = 0x0000112233445566L; - final PhysAddress address = new PhysAddress("11:22:33:44:55:66"); - mockMapping(mappingContext, BD_NAME, BD_ID, BD_CTX_NAME); - - whenL2FibTableDumpThenReturn(Collections.singletonList(generateL2FibEntry(address_vpp))); - - final List ids = getCustomizer().getAllIds(getL2FibEntryId(BD_NAME, address), ctx); - assertEquals(1, ids.size()); - assertEquals(address, ids.get(0).getPhysAddress()); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VersionCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VersionCustomizerTest.java deleted file mode 100644 index 93cd6913e..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VersionCustomizerTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.v3po.vppstate; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.fd.honeycomb.v3po.translate.spi.read.ReaderCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.test.ReaderCustomizerTest; -import java.util.concurrent.CompletableFuture; -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.ShowVersion; -import org.openvpp.jvpp.dto.ShowVersionReply; - -public class VersionCustomizerTest extends ReaderCustomizerTest { - - public VersionCustomizerTest() { - super(Version.class); - } - - @Override - protected ReaderCustomizer initCustomizer() { - return new VersionCustomizer(api); - } - - @Test - public void testMerge() { - final VppStateBuilder builder = mock(VppStateBuilder.class); - final Version value = mock(Version.class); - getCustomizer().merge(builder, value); - verify(builder).setVersion(value); - } - - @Test - public void testReadCurrentAttributes() throws Exception { - final CompletableFuture replyFuture = new CompletableFuture<>(); - final ShowVersionReply reply = new ShowVersionReply(); - reply.version = new byte[]{}; - reply.program = new byte[]{}; - reply.buildDate = new byte[]{}; - reply.buildDirectory = new byte[]{}; - replyFuture.complete(reply); - - when(api.showVersion(any(ShowVersion.class))).thenReturn(replyFuture); - getCustomizer().readCurrentAttributes(InstanceIdentifier.create(Version.class), new VersionBuilder(), ctx); - verify(api).showVersion(any(ShowVersion.class)); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VppStateTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VppStateTest.java deleted file mode 100644 index dad991c13..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VppStateTest.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * 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.v3po.vppstate; - -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; -import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.mockMapping; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import com.google.common.collect.Iterables; -import com.google.common.collect.Multimap; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.L2FibTable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntry; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.l2.fib.attributes.l2.fib.table.L2FibEntryKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppInvocationException; -import org.openvpp.jvpp.dto.BridgeDomainDetails; -import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump; -import org.openvpp.jvpp.dto.BridgeDomainDump; -import org.openvpp.jvpp.dto.L2FibTableDump; -import org.openvpp.jvpp.dto.L2FibTableEntry; -import org.openvpp.jvpp.dto.L2FibTableEntryReplyDump; -import org.openvpp.jvpp.dto.ShowVersion; -import org.openvpp.jvpp.dto.ShowVersionReply; -import org.openvpp.jvpp.future.FutureJVpp; - -public class VppStateTest { - - @Mock - private FutureJVpp api; - @Mock - private ReadContext ctx; - @Mock - private MappingContext mappingContext; - - private NamingContext bdContext; - private NamingContext interfaceContext; - - private ReaderRegistry readerRegistry; - - @Before - public void setUp() throws Exception { - initMocks(this); - final ModificationCache cache = new ModificationCache(); - doReturn(cache).when(ctx).getModificationCache(); - doReturn(mappingContext).when(ctx).getMappingContext(); - - bdContext = new NamingContext("generatedBdName", "bd-test-instance"); - interfaceContext = new NamingContext("generatedIfaceName", "ifc-test-instance"); - readerRegistry = VppStateTestUtils.getVppStateReader(api, bdContext); - } - - private static Version getVersion() { - return new VersionBuilder() - .setName("test") - .setBuildDirectory("1") - .setBranch("2") - .setBuildDate("3") - .build(); - } - - private void whenShowVersionThenReturn(int retval, Version version) - throws ExecutionException, InterruptedException, VppInvocationException { - final CompletableFuture replyFuture = new CompletableFuture<>(); - final ShowVersionReply reply = new ShowVersionReply(); - reply.buildDate = version.getBuildDate().getBytes(); - reply.program = version.getName().getBytes(); - reply.version = version.getBranch().getBytes(); - reply.buildDirectory = version.getBuildDirectory().getBytes(); - - replyFuture.complete(reply); - when(api.showVersion(any(ShowVersion.class))).thenReturn(replyFuture); - } - - private void whenL2FibTableDumpThenReturn(final List entryList) - throws ExecutionException, InterruptedException, VppInvocationException { - final CompletionStage replyCS = mock(CompletionStage.class); - final CompletableFuture replyFuture = mock(CompletableFuture.class); - when(replyCS.toCompletableFuture()).thenReturn(replyFuture); - final L2FibTableEntryReplyDump reply = new L2FibTableEntryReplyDump(); - reply.l2FibTableEntry = entryList; - when(replyFuture.get()).thenReturn(reply); - when(api.l2FibTableDump(any(L2FibTableDump.class))).thenReturn(replyCS); - } - - private void whenBridgeDomainDumpThenReturn(final List bdList) - throws ExecutionException, InterruptedException, VppInvocationException { - final CompletionStage replyCS = mock(CompletionStage.class); - final CompletableFuture replyFuture = mock(CompletableFuture.class); - when(replyCS.toCompletableFuture()).thenReturn(replyFuture); - final BridgeDomainDetailsReplyDump reply = new BridgeDomainDetailsReplyDump(); - reply.bridgeDomainDetails = bdList; - when(replyFuture.get()).thenReturn(reply); - - doAnswer(invocation -> { - BridgeDomainDump request = (BridgeDomainDump) invocation.getArguments()[0]; - if (request.bdId == -1) { - reply.bridgeDomainDetails = bdList; - } else { - reply.bridgeDomainDetails = Collections.singletonList(bdList.get(request.bdId)); - } - return replyCS; - }).when(api).bridgeDomainDump(any(BridgeDomainDump.class)); - } - - @Test - public void testReadAll() throws Exception { - final Version version = getVersion(); - whenShowVersionThenReturn(0, version); - - final BridgeDomainDetails bridgeDomainDetails = new BridgeDomainDetails(); - final BridgeDomainDetails bridgeDomainDetails2 = new BridgeDomainDetails(); - bridgeDomainDetails2.bdId = 1; - - final List bdList = Arrays.asList(bridgeDomainDetails, bridgeDomainDetails2); - mockBdMapping(bridgeDomainDetails, "bd1"); - mockBdMapping(bridgeDomainDetails2, "bd2"); - - whenBridgeDomainDumpThenReturn(bdList); - - final Multimap, ? extends DataObject> dataObjects = - readerRegistry.readAll(ctx); - assertEquals(dataObjects.size(), 1); - final VppState dataObject = - (VppState) Iterables.getOnlyElement(dataObjects.get(Iterables.getOnlyElement(dataObjects.keySet()))); - assertEquals(version, dataObject.getVersion()); - assertEquals(2, dataObject.getBridgeDomains().getBridgeDomain().size()); - } - - @Test - public void testReadSpecific() throws Exception { - final Version version = getVersion(); - whenShowVersionThenReturn(0, version); - whenBridgeDomainDumpThenReturn(Collections.emptyList()); - - final Optional read = readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx); - assertTrue(read.isPresent()); - assertEquals(version, ((VppState) read.get()).getVersion()); - } - - @Test - public void testReadBridgeDomains() throws Exception { - final Version version = getVersion(); - whenShowVersionThenReturn(0, version); - final BridgeDomainDetails details = new BridgeDomainDetails(); - whenBridgeDomainDumpThenReturn(Collections.singletonList(details)); - - mockBdMapping(details, "bdn1"); - VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); - - Optional read = - readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class), ctx); - assertTrue(read.isPresent()); - assertEquals(readRoot.getBridgeDomains(), read.get()); - } - - /** - * L2fib does not have a dedicated reader, relying on auto filtering - */ - @Test - @Ignore("L2 FIB was moved to dedicated customizer. TODO: add infra test that covers such case") - @SuppressWarnings("unchecked") - public void testReadL2Fib() throws Exception { - final BridgeDomainDetails bd = new BridgeDomainDetails(); - bd.bdId = 0; - final String bdName = "bdn1"; - mockBdMapping(bd, bdName); - mockMapping(mappingContext, "eth1", 0, "ifc-test-instance"); - - whenBridgeDomainDumpThenReturn(Collections.singletonList(bd)); - final L2FibTableEntry l2FibEntry = new L2FibTableEntry(); - l2FibEntry.bdId = 0; - l2FibEntry.mac = 0x0605040302010000L; - whenL2FibTableDumpThenReturn(Collections.singletonList(l2FibEntry)); - - // Deep child without a dedicated reader with specific l2fib key - final InstanceIdentifier idExisting = - InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey("bdn1")).child(L2FibTable.class) - .child(L2FibEntry.class, new L2FibEntryKey(new PhysAddress("01:02:03:04:05:06"))); - Optional read = - readerRegistry.read(idExisting, ctx); - assertTrue(read.isPresent()); - - // non existing l2fib - final InstanceIdentifier idNonExisting = - InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey("bdn1")).child(L2FibTable.class) - .child(L2FibEntry.class, new L2FibEntryKey(new PhysAddress("FF:FF:FF:04:05:06"))); - read = readerRegistry.read(idNonExisting, ctx); - assertFalse(read.isPresent()); - } - - private void mockBdMapping(final BridgeDomainDetails bd, final String bdName) { - mockMapping(mappingContext, bdName, bd.bdId, "bd-test-instance"); - } - - @Test - public void testReadBridgeDomainAll() throws Exception { - final Version version = getVersion(); - whenShowVersionThenReturn(0, version); - final BridgeDomainDetails details = new BridgeDomainDetails(); - whenBridgeDomainDumpThenReturn(Collections.singletonList(details)); - mockBdMapping(details, "bd2"); - - VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); - - final GenericListReader bridgeDomainReader = - VppStateTestUtils.getBridgeDomainReader(api, bdContext); - - final List read = - bridgeDomainReader.readList(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class), ctx); - - assertEquals(readRoot.getBridgeDomains().getBridgeDomain(), read); - } - - @Test - public void testReadBridgeDomain() throws Exception { - final BridgeDomainDetails bd = new BridgeDomainDetails(); - bd.bdId = 0; - final String bdName = "bdn1"; - mockBdMapping(bd, bdName); - - whenBridgeDomainDumpThenReturn(Collections.singletonList(bd)); - whenShowVersionThenReturn(0, getVersion()); - - VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); - - final Optional read = - readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey(bdName)), ctx); - - assertTrue(read.isPresent()); - assertEquals(readRoot.getBridgeDomains().getBridgeDomain().stream().filter( - input -> input.getKey().getName().equals(bdName)).findFirst().get(), - read.get()); - } - - @Test(expected = IllegalArgumentException.class) - public void testReadBridgeDomainNotExisting() throws Exception { - doReturn(Optional.absent()).when(mappingContext).read(getMappingIid("NOT EXISTING", "bd-test-instance")); - - final Optional read = - readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey("NOT EXISTING")), ctx); - assertFalse(read.isPresent()); - } - - @Test - public void testReadVersion() throws Exception { - whenShowVersionThenReturn(0, getVersion()); - whenBridgeDomainDumpThenReturn(Collections.emptyList()); - VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); - - Optional read = - readerRegistry.read(InstanceIdentifier.create(VppState.class).child(Version.class), ctx); - assertTrue(read.isPresent()); - assertEquals(readRoot.getVersion(), read.get()); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VppStateTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VppStateTestUtils.java deleted file mode 100644 index 5afc080d6..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/vppstate/VppStateTestUtils.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.v3po.vppstate; - -import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader; -import io.fd.honeycomb.v3po.translate.impl.read.GenericReader; -import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry; -import io.fd.honeycomb.v3po.translate.util.read.registry.CompositeReaderRegistryBuilder; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; - -final class VppStateTestUtils { - - private static InstanceIdentifier bridgeDomainsId; - - public VppStateTestUtils() { - } - - /** - * Create root VppState reader with all its children wired. - */ - static ReaderRegistry getVppStateReader(@Nonnull final FutureJVpp jVpp, - @Nonnull final NamingContext bdContext) { - final CompositeReaderRegistryBuilder registry = new CompositeReaderRegistryBuilder(); - - // VppState(Structural) - final InstanceIdentifier vppStateId = InstanceIdentifier.create(VppState.class); - registry.addStructuralReader(vppStateId, VppStateBuilder.class); - // Version - // Wrap with keepalive reader to detect connection issues - // TODO keepalive reader wrapper relies on VersionReaderCustomizer (to perform timeout on reads) - // Once readers+customizers are asynchronous, pull the timeout to keepalive executor so that keepalive wrapper - // is truly generic - registry.add(new GenericReader<>(vppStateId.child(Version.class), new VersionCustomizer(jVpp))); - // BridgeDomains(Structural) - bridgeDomainsId = vppStateId.child(BridgeDomains.class); - registry.addStructuralReader(bridgeDomainsId, BridgeDomainsBuilder.class); - // BridgeDomain - registry.add(getBridgeDomainReader(jVpp, bdContext)); - return registry.build(); - } - - static GenericListReader getBridgeDomainReader( - final @Nonnull FutureJVpp jVpp, final @Nonnull NamingContext bdContext) { - final InstanceIdentifier bridgeDomainId = bridgeDomainsId.child(BridgeDomain.class); - return new GenericListReader<>(bridgeDomainId, new BridgeDomainCustomizer(jVpp, bdContext)); - } -} diff --git a/vpp-common/naming-context-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/context/impl/rev141210/ContextReaderModule.java b/vpp-common/naming-context-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/context/impl/rev141210/ContextReaderModule.java index 9be762014..da7ab832d 100644 --- a/vpp-common/naming-context-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/context/impl/rev141210/ContextReaderModule.java +++ b/vpp-common/naming-context-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/context/impl/rev141210/ContextReaderModule.java @@ -1,7 +1,7 @@ package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.context.impl.rev141210; -import io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder; -import io.fd.honeycomb.v3po.translate.util.read.BindingBrokerReader; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.honeycomb.translate.util.read.BindingBrokerReader; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts; @@ -30,7 +30,7 @@ public class ContextReaderModule extends org.opendaylight.yang.gen.v1.urn.openda return new ReaderFactory(getContextBindingBrokerDependency()); } - private static final class ReaderFactory implements AutoCloseable, io.fd.honeycomb.v3po.translate.read.ReaderFactory { + private static final class ReaderFactory implements AutoCloseable, io.fd.honeycomb.translate.read.ReaderFactory { private final DataBroker contextBindingBrokerDependency; diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/AbstractInterfaceTypeCustomizer.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/AbstractInterfaceTypeCustomizer.java new file mode 100644 index 000000000..7f3422fb8 --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/AbstractInterfaceTypeCustomizer.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.translate.v3po.util; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.future.FutureJVpp; + +/** + * Validation WriteCustomizers for Interface subnodes. + * Validates the type of interface. + * + * TODO this should be validated on model/DataTree level. However DataTree does not enforce When conditions + * Delete this class when DataTree handles when constraints properly + */ +public abstract class AbstractInterfaceTypeCustomizer + extends FutureJVppCustomizer implements WriterCustomizer { + + protected AbstractInterfaceTypeCustomizer(final FutureJVpp futureJvpp) { + super(futureJvpp); + } + + private void checkProperInterfaceType(@Nonnull final WriteContext writeContext, + @Nonnull final InstanceIdentifier id) { + final InstanceIdentifier ifcTypeFromIid = id.firstIdentifierOf(Interface.class); + checkArgument(ifcTypeFromIid != null, "Instance identifier does not contain {} type", Interface.class); + checkArgument(id.firstKeyOf(Interface.class) != null, "Instance identifier does not contain keyed {} type", + Interface.class); + final Optional interfaceConfig = writeContext.readAfter(ifcTypeFromIid); + checkState(interfaceConfig.isPresent(), + "Unable to get Interface configuration for an interface: %s currently being updated", ifcTypeFromIid); + + IllegalInterfaceTypeException + .checkInterfaceType(interfaceConfig.get(), getExpectedInterfaceType()); + } + + protected abstract Class getExpectedInterfaceType(); + + /** + * Validate expected interface type + */ + @Override + public final void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + checkProperInterfaceType(writeContext, id); + writeInterface(id, dataAfter, writeContext); + } + + protected abstract void writeInterface(final InstanceIdentifier id, final D dataAfter, + final WriteContext writeContext) + throws WriteFailedException; + + // Validation for update and delete is not necessary + + /** + * Indicates unexpected interface type + */ + protected static final class IllegalInterfaceTypeException extends IllegalArgumentException { + + private IllegalInterfaceTypeException(final String msg) { + super(msg); + } + + /** + * Check the type of interface equals expected type + * + * @throws IllegalInterfaceTypeException if type of interface is null or not expected + */ + static void checkInterfaceType(@Nonnull final Interface ifc, + @Nonnull final Class expectedType) { + if (ifc.getType() == null || !expectedType.equals(ifc.getType())) { + throw new IllegalInterfaceTypeException(String.format( + "Unexpected interface type: %s for interface: %s. Expected interface is: %s", ifc.getType(), + ifc.getName(), expectedType)); + } + } + + } +} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/FutureJVppCustomizer.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/FutureJVppCustomizer.java new file mode 100644 index 000000000..45453259f --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/FutureJVppCustomizer.java @@ -0,0 +1,45 @@ +/* + * 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.translate.v3po.util; + +import com.google.common.annotations.Beta; +import com.google.common.base.Preconditions; +import org.openvpp.jvpp.future.FutureJVpp; + +import javax.annotation.Nonnull; + +/** + * Abstract utility to hold the vppApi reference. + */ +@Beta +public abstract class FutureJVppCustomizer { + + private final FutureJVpp futureJvpp; + + public FutureJVppCustomizer(@Nonnull final FutureJVpp futureJvpp) { + this.futureJvpp = Preconditions.checkNotNull(futureJvpp, "futureJvpp should not be null"); + } + + /** + * Get vppApi reference + * + * @return vppApi reference + */ + public FutureJVpp getFutureJVpp() { + return futureJvpp; + } +} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/NamingContext.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/NamingContext.java new file mode 100644 index 000000000..b7d3afa3c --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/NamingContext.java @@ -0,0 +1,188 @@ +/* + * 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.translate.v3po.util; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.util.RWUtils; +import io.fd.honeycomb.translate.MappingContext; +import java.util.stream.Collector; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContextKey; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility adapter on top of {@link MappingContext} storing integer to string mappings according to naming-context yang + * model + */ +public final class NamingContext implements AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(NamingContext.class); + + private final String artificialNamePrefix; + private final KeyedInstanceIdentifier + namingContextIid; + + private static final Collector SINGLE_ITEM_COLLECTOR = RWUtils.singleItemCollector(); + + /** + * Create new naming context + * + * @param artificialNamePrefix artificial name to be used for items without a name in VPP (or not provided) + * @param instanceName name of this context instance. Will be used as list item identifier within context data tree + */ + public NamingContext(@Nonnull final String artificialNamePrefix, @Nonnull final String instanceName) { + this.artificialNamePrefix = artificialNamePrefix; + namingContextIid = InstanceIdentifier.create(Contexts.class).child( + org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.class, + new NamingContextKey(instanceName)); + } + + /** + * Retrieve name for mapping stored provided mappingContext instance. If not present, artificial name will be + * generated. + * + * @param index index of a mapped item + * @param mappingContext mapping context providing context data for current transaction + * + * @return name mapped to provided index + */ + @Nonnull + public synchronized String getName(final int index, @Nonnull final MappingContext mappingContext) { + if (!containsName(index, mappingContext)) { + final String artificialName = getArtificialName(index); + addName(index, artificialName, mappingContext); + } + + final Optional read = mappingContext.read(namingContextIid.child(Mappings.class)); + checkState(read.isPresent(), "Mapping for index: %s is not present. But should be", index); + + return read.get().getMapping().stream() + .filter(mapping -> mapping.getIndex().equals(index)) + .collect(SINGLE_ITEM_COLLECTOR).getName(); + } + + /** + * Retrieve name for mapping stored provided mappingContext instance. if present + * + * @param index index of a mapped item + * @param mappingContext mapping context providing context data for current transaction + * + * @return name mapped to provided index + */ + @Nonnull + public synchronized Optional getNameIfPresent(final int index, + @Nonnull final MappingContext mappingContext) { + final Optional read = mappingContext.read(namingContextIid.child(Mappings.class)); + + return read.isPresent() + ? Optional.of(read.get().getMapping().stream() + .filter(mapping -> mapping.getIndex().equals(index)) + .collect(SINGLE_ITEM_COLLECTOR) + .getName()) + : Optional.absent(); + } + + /** + * Check whether mapping is present for index. + * + * @param index index of a mapped item + * @param mappingContext mapping context providing context data for current transaction + * + * @return true if present, false otherwise + */ + public synchronized boolean containsName(final int index, @Nonnull final MappingContext mappingContext) { + final Optional read = mappingContext.read(namingContextIid.child(Mappings.class)); + return read.isPresent() + ? read.get().getMapping().stream().anyMatch(mapping -> mapping.getIndex().equals(index)) + : false; + } + + + /** + * Add mapping to current context + * + * @param index index of a mapped item + * @param name name of a mapped item + * @param mappingContext mapping context providing context data for current transaction + */ + public synchronized void addName(final int index, final String name, final MappingContext mappingContext) { + final KeyedInstanceIdentifier mappingIid = getMappingIid(name); + mappingContext.put(mappingIid, new MappingBuilder().setIndex(index).setName(name).build()); + } + + private KeyedInstanceIdentifier getMappingIid(final String name) { + return namingContextIid.child(Mappings.class).child(Mapping.class, new MappingKey(name)); + } + + /** + * Remove mapping from current context + * + * @param name name of a mapped item + * @param mappingContext mapping context providing context data for current transaction + */ + public synchronized void removeName(final String name, final MappingContext mappingContext) { + mappingContext.delete(getMappingIid(name)); + } + + /** + * Returns index value associated with the given name. + * + * @param name the name whose associated index value is to be returned + * @param mappingContext mapping context providing context data for current transaction + * + * @return integer index value matching supplied name + * @throws IllegalArgumentException if name was not found + */ + public synchronized int getIndex(final String name, final MappingContext mappingContext) { + final Optional read = mappingContext.read(getMappingIid(name)); + checkArgument(read.isPresent(), "No mapping stored for name: %s", name); + return read.get().getIndex(); + + } + + /** + * Check whether mapping is present for name. + * + * @param name name of a mapped item + * @param mappingContext mapping context providing context data for current transaction + * + * @return true if present, false otherwise + */ + public synchronized boolean containsIndex(final String name, final MappingContext mappingContext) { + return mappingContext.read(getMappingIid(name)).isPresent(); + } + + private String getArtificialName(final int index) { + return artificialNamePrefix + index; + } + + @Override + public void close() throws Exception { + /// Not removing the mapping from backing storage + } +} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/ReadTimeoutException.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/ReadTimeoutException.java new file mode 100644 index 000000000..10babaedc --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/ReadTimeoutException.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.translate.v3po.util; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.read.ReadFailedException; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Thrown when read method invocation times out. + */ +@Beta +public class ReadTimeoutException extends ReadFailedException { + + public ReadTimeoutException(final InstanceIdentifier id, final Throwable cause) { + super(id, cause); + } + +} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/SubInterfaceUtils.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/SubInterfaceUtils.java new file mode 100644 index 000000000..b325f7cc4 --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/SubInterfaceUtils.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.translate.v3po.util; + +public final class SubInterfaceUtils { + + private SubInterfaceUtils() { + throw new UnsupportedOperationException("Utility class cannot be instantiated."); + } + + public static String getSubInterfaceName(final String superIfName, final int subIfaceId) { + return String.format("%s.%d", superIfName, subIfaceId); + } +} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TagRewriteOperation.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TagRewriteOperation.java new file mode 100644 index 000000000..7958aff06 --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TagRewriteOperation.java @@ -0,0 +1,86 @@ +/* + * 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.translate.v3po.util; + +import com.google.common.base.Preconditions; +import com.google.common.primitives.UnsignedBytes; +import javax.annotation.Nonnegative; +import javax.annotation.Nullable; + +/** + * Defines vlan tag rewrite config options for VPP + * + * TODO corresponding enum (defined in l2_vtr.h) should be defined in vpe.api + * (does vpp's IDL support enum type definition?) + * which would allow to generate this class in jvpp + */ +public enum TagRewriteOperation { + disabled(0), + push_1(0), + push_2(0), + pop_1(1), + pop_2(2), + translate_1_to_1(1), + translate_1_to_2(1), + translate_2_to_1(2), + translate_2_to_2(2); + + private final static int MAX_INDEX = 3; + private final int code; + private final byte popTags; + + TagRewriteOperation(final int popTags) { + this.code = this.ordinal(); + this.popTags = UnsignedBytes.checkedCast(popTags); + } + + private static TagRewriteOperation[][] translation = new TagRewriteOperation[][] { + {disabled, push_1, push_2}, + {pop_1, translate_1_to_1, translate_1_to_2}, + {pop_2, translate_2_to_1, translate_2_to_2} + }; + + /** + * Returns VPP tag rewrite operation for given number of tags to pop and tags to push. + * @param toPop number of tags to pop (0..2) + * @param toPush number of tags to push (0..2) + * @return vpp tag rewrite operation for given input parameters + */ + public static TagRewriteOperation get(@Nonnegative final int toPop, @Nonnegative final int toPush) { + Preconditions.checkElementIndex(toPop, MAX_INDEX, "Illegal number of tags to pop"); + Preconditions.checkElementIndex(toPush, MAX_INDEX, "Illegal number of tags to push"); + return translation[toPop][toPush]; + } + + /** + * Returns VPP tag rewrite operation for given operation code. + * @param code VPP tag rewrite operation code + * @return vpp tag rewrite operation for given input parameter + */ + @Nullable + public static TagRewriteOperation get(@Nonnegative final int code) { + for (TagRewriteOperation operation : TagRewriteOperation.values()) { + if (code == operation.code){ + return operation; + } + } + return null; + } + + public byte getPopTags() { + return popTags; + } +} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TranslateUtils.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TranslateUtils.java new file mode 100644 index 000000000..4ecf8ff91 --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/TranslateUtils.java @@ -0,0 +1,225 @@ +/* + * 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.translate.v3po.util; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.base.Splitter; +import com.google.common.net.InetAddresses; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.BiConsumer; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.dto.JVppReply; + +public final class TranslateUtils { + + public static final Splitter COLON_SPLITTER = Splitter.on(':'); + public static final int DEFAULT_TIMEOUT_IN_SECONDS = 5; + + private TranslateUtils() { + } + + public static > REP getReplyForWrite(@Nonnull Future future, + @Nonnull final InstanceIdentifier replyType) + throws VppBaseCallException, WriteTimeoutException { + return getReplyForWrite(future, replyType, DEFAULT_TIMEOUT_IN_SECONDS); + } + + public static > REP getReplyForWrite(@Nonnull Future future, + @Nonnull final InstanceIdentifier replyType, + @Nonnegative final int timeoutInSeconds) + throws VppBaseCallException, WriteTimeoutException { + try { + return getReply(future, timeoutInSeconds); + } catch (TimeoutException e) { + throw new WriteTimeoutException(replyType, e); + } + } + + public static > REP getReplyForRead(@Nonnull Future future, + @Nonnull final InstanceIdentifier replyType) + throws VppBaseCallException, ReadTimeoutException { + return getReplyForRead(future, replyType, DEFAULT_TIMEOUT_IN_SECONDS); + } + + public static > REP getReplyForRead(@Nonnull Future future, + @Nonnull final InstanceIdentifier replyType, + @Nonnegative final int timeoutInSeconds) + throws VppBaseCallException, ReadTimeoutException { + try { + return getReply(future, timeoutInSeconds); + } catch (TimeoutException e) { + throw new ReadTimeoutException(replyType, e); + } + } + + public static > REP getReply(@Nonnull Future future) + throws TimeoutException, VppBaseCallException { + return getReply(future, DEFAULT_TIMEOUT_IN_SECONDS); + } + + public static > REP getReply(@Nonnull Future future, + @Nonnegative final int timeoutInSeconds) + throws TimeoutException, VppBaseCallException { + try { + checkArgument(timeoutInSeconds > 0, "Timeout cannot be < 0"); + return future.get(timeoutInSeconds, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException("Interrupted", e); + } catch (ExecutionException e) { + // Execution exception could generally contains any exception + // when using exceptions instead of return codes just rethrow it for processing on corresponding place + if (e instanceof ExecutionException && (e.getCause() instanceof VppBaseCallException)) { + throw (VppBaseCallException) (e.getCause()); + } + throw new IllegalStateException(e); + } + } + + /** + * Transform Ipv4 address to a byte array acceptable by VPP. VPP expects incoming byte array to be in the same order + * as the address. + * + * @return byte array with address bytes + */ + public static byte[] ipv4AddressNoZoneToArray(final Ipv4AddressNoZone ipv4Addr) { + byte[] retval = new byte[4]; + String[] dots = ipv4Addr.getValue().split("\\."); + + for (int d = 0; d < 4; d++) { + retval[d] = (byte) (Short.parseShort(dots[d]) & 0xff); + } + return retval; + } + + /** + * Parse byte array returned by VPP representing an Ipv4 address. Vpp returns IP byte arrays in reversed order. + * + * @return Ipv4AddressNoZone containing string representation of IPv4 address constructed from submitted bytes. No + * change in order. + */ + @Nonnull + public static Ipv4AddressNoZone arrayToIpv4AddressNoZone(@Nonnull byte[] ip) { + // VPP sends ipv4 in a 16 byte array + if (ip.length == 16) { + ip = Arrays.copyOfRange(ip, 0, 4); + } + try { + // Not reversing the byte array here!! because the IP coming from VPP is in reversed byte order + // compared to byte order it was submitted + return new Ipv4AddressNoZone(InetAddresses.toAddrString(InetAddresses.fromLittleEndianByteArray(ip))); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Unable to parse ipv4", e); + } + } + + /** + * Return (interned) string from byte array while removing \u0000. Strings represented as fixed length byte[] from + * vpp contain \u0000. + */ + public static String toString(final byte[] cString) { + return new String(cString).replaceAll("\\u0000", "").intern(); + } + + /** + * Parse string represented mac address (using ":" as separator) into a byte array + */ + @Nonnull + public static byte[] parseMac(@Nonnull final String macAddress) { + final List parts = COLON_SPLITTER.splitToList(macAddress); + checkArgument(parts.size() == 6, "Mac address is expected to have 6 parts but was: %s", macAddress); + return parseMacLikeString(parts); + } + + private static byte[] parseMacLikeString(final List strings) { + return strings.stream().limit(6).map(TranslateUtils::parseHexByte).collect( + () -> new byte[strings.size()], + new BiConsumer() { + + private int i = -1; + + @Override + public void accept(final byte[] bytes, final Byte aByte) { + bytes[++i] = aByte; + } + }, + (bytes, bytes2) -> { + throw new UnsupportedOperationException("Parallel collect not supported"); + }); + } + + public static byte parseHexByte(final String aByte) { + return (byte) Integer.parseInt(aByte, 16); + } + + /** + * Returns 0 if argument is null or false, 1 otherwise. + * + * @param value Boolean value to be converted + * @return byte value equal to 0 or 1 + */ + public static byte booleanToByte(@Nullable final Boolean value) { + return value != null && value + ? (byte) 1 + : (byte) 0; + } + + /** + * Returns Boolean.TRUE if argument is 0, Boolean.FALSE otherwise. + * + * @param value byte value to be converted + * @return Boolean value + * @throws IllegalArgumentException if argument is neither 0 nor 1 + */ + @Nonnull + public static Boolean byteToBoolean(final byte value) { + if (value == 0) { + return Boolean.FALSE; + } else if (value == 1) { + return Boolean.TRUE; + } + throw new IllegalArgumentException(String.format("0 or 1 was expected but was %d", value)); + } + + /** + * Reverses bytes in the byte array + * + * @param bytes input array + * @return reversed array + */ + public static byte[] reverseBytes(final byte[] bytes) { + final byte[] reversed = new byte[bytes.length]; + int i = 1; + for (byte aByte : bytes) { + reversed[bytes.length - i++] = aByte; + } + + return reversed; + } +} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/WriteTimeoutException.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/WriteTimeoutException.java new file mode 100644 index 000000000..7179f705d --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/WriteTimeoutException.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.translate.v3po.util; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.translate.write.WriteFailedException; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Thrown when write method invocation times out. + */ +@Beta +public class WriteTimeoutException extends WriteFailedException { + + public WriteTimeoutException(final InstanceIdentifier id, final Throwable cause) { + super(id, cause); + } + +} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/cache/DumpCacheManager.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/cache/DumpCacheManager.java index e5adb54ad..1acd9de4b 100644 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/cache/DumpCacheManager.java +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/cache/DumpCacheManager.java @@ -22,7 +22,7 @@ import com.google.common.base.Optional; import io.fd.honeycomb.translate.v3po.util.cache.exceptions.check.DumpCheckFailedException; import io.fd.honeycomb.translate.v3po.util.cache.exceptions.execution.DumpExecutionFailedException; import io.fd.honeycomb.translate.v3po.util.cache.noop.NoopDumpPostProcessingFunction; -import io.fd.honeycomb.v3po.translate.ModificationCache; +import io.fd.honeycomb.translate.ModificationCache; import javax.annotation.Nonnull; import org.openvpp.jvpp.dto.JVppReplyDump; import org.slf4j.Logger; diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/AbstractInterfaceTypeCustomizer.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/AbstractInterfaceTypeCustomizer.java deleted file mode 100644 index 1f2fbd838..000000000 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/AbstractInterfaceTypeCustomizer.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.v3po.util; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.future.FutureJVpp; - -/** - * Validation WriteCustomizers for Interface subnodes. - * Validates the type of interface. - * - * TODO this should be validated on model/DataTree level. However DataTree does not enforce When conditions - * Delete this class when DataTree handles when constraints properly - */ -public abstract class AbstractInterfaceTypeCustomizer - extends FutureJVppCustomizer implements WriterCustomizer { - - protected AbstractInterfaceTypeCustomizer(final FutureJVpp futureJvpp) { - super(futureJvpp); - } - - private void checkProperInterfaceType(@Nonnull final WriteContext writeContext, - @Nonnull final InstanceIdentifier id) { - final InstanceIdentifier ifcTypeFromIid = id.firstIdentifierOf(Interface.class); - checkArgument(ifcTypeFromIid != null, "Instance identifier does not contain {} type", Interface.class); - checkArgument(id.firstKeyOf(Interface.class) != null, "Instance identifier does not contain keyed {} type", - Interface.class); - final Optional interfaceConfig = writeContext.readAfter(ifcTypeFromIid); - checkState(interfaceConfig.isPresent(), - "Unable to get Interface configuration for an interface: %s currently being updated", ifcTypeFromIid); - - IllegalInterfaceTypeException - .checkInterfaceType(interfaceConfig.get(), getExpectedInterfaceType()); - } - - protected abstract Class getExpectedInterfaceType(); - - /** - * Validate expected interface type - */ - @Override - public final void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataAfter, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - checkProperInterfaceType(writeContext, id); - writeInterface(id, dataAfter, writeContext); - } - - protected abstract void writeInterface(final InstanceIdentifier id, final D dataAfter, - final WriteContext writeContext) - throws WriteFailedException; - - // Validation for update and delete is not necessary - - /** - * Indicates unexpected interface type - */ - protected static final class IllegalInterfaceTypeException extends IllegalArgumentException { - - private IllegalInterfaceTypeException(final String msg) { - super(msg); - } - - /** - * Check the type of interface equals expected type - * - * @throws IllegalInterfaceTypeException if type of interface is null or not expected - */ - static void checkInterfaceType(@Nonnull final Interface ifc, - @Nonnull final Class expectedType) { - if (ifc.getType() == null || !expectedType.equals(ifc.getType())) { - throw new IllegalInterfaceTypeException(String.format( - "Unexpected interface type: %s for interface: %s. Expected interface is: %s", ifc.getType(), - ifc.getName(), expectedType)); - } - } - - } -} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/FutureJVppCustomizer.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/FutureJVppCustomizer.java deleted file mode 100644 index 3f4f1f5ce..000000000 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/FutureJVppCustomizer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.v3po.util; - -import com.google.common.annotations.Beta; -import com.google.common.base.Preconditions; -import org.openvpp.jvpp.future.FutureJVpp; - -import javax.annotation.Nonnull; - -/** - * Abstract utility to hold the vppApi reference. - */ -@Beta -public abstract class FutureJVppCustomizer { - - private final FutureJVpp futureJvpp; - - public FutureJVppCustomizer(@Nonnull final FutureJVpp futureJvpp) { - this.futureJvpp = Preconditions.checkNotNull(futureJvpp, "futureJvpp should not be null"); - } - - /** - * Get vppApi reference - * - * @return vppApi reference - */ - public FutureJVpp getFutureJVpp() { - return futureJvpp; - } -} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/NamingContext.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/NamingContext.java deleted file mode 100644 index f6e0e6d48..000000000 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/NamingContext.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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.v3po.util; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.translate.MappingContext; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import java.util.stream.Collector; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContextKey; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility adapter on top of {@link MappingContext} storing integer to string mappings according to naming-context yang - * model - */ -public final class NamingContext implements AutoCloseable { - - private static final Logger LOG = LoggerFactory.getLogger(NamingContext.class); - - private final String artificialNamePrefix; - private final KeyedInstanceIdentifier - namingContextIid; - - private static final Collector SINGLE_ITEM_COLLECTOR = RWUtils.singleItemCollector(); - - /** - * Create new naming context - * - * @param artificialNamePrefix artificial name to be used for items without a name in VPP (or not provided) - * @param instanceName name of this context instance. Will be used as list item identifier within context data tree - */ - public NamingContext(@Nonnull final String artificialNamePrefix, @Nonnull final String instanceName) { - this.artificialNamePrefix = artificialNamePrefix; - namingContextIid = InstanceIdentifier.create(Contexts.class).child( - org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.class, - new NamingContextKey(instanceName)); - } - - /** - * Retrieve name for mapping stored provided mappingContext instance. If not present, artificial name will be - * generated. - * - * @param index index of a mapped item - * @param mappingContext mapping context providing context data for current transaction - * - * @return name mapped to provided index - */ - @Nonnull - public synchronized String getName(final int index, @Nonnull final MappingContext mappingContext) { - if (!containsName(index, mappingContext)) { - final String artificialName = getArtificialName(index); - addName(index, artificialName, mappingContext); - } - - final Optional read = mappingContext.read(namingContextIid.child(Mappings.class)); - checkState(read.isPresent(), "Mapping for index: %s is not present. But should be", index); - - return read.get().getMapping().stream() - .filter(mapping -> mapping.getIndex().equals(index)) - .collect(SINGLE_ITEM_COLLECTOR).getName(); - } - - /** - * Retrieve name for mapping stored provided mappingContext instance. if present - * - * @param index index of a mapped item - * @param mappingContext mapping context providing context data for current transaction - * - * @return name mapped to provided index - */ - @Nonnull - public synchronized Optional getNameIfPresent(final int index, - @Nonnull final MappingContext mappingContext) { - final Optional read = mappingContext.read(namingContextIid.child(Mappings.class)); - - return read.isPresent() - ? Optional.of(read.get().getMapping().stream() - .filter(mapping -> mapping.getIndex().equals(index)) - .collect(SINGLE_ITEM_COLLECTOR) - .getName()) - : Optional.absent(); - } - - /** - * Check whether mapping is present for index. - * - * @param index index of a mapped item - * @param mappingContext mapping context providing context data for current transaction - * - * @return true if present, false otherwise - */ - public synchronized boolean containsName(final int index, @Nonnull final MappingContext mappingContext) { - final Optional read = mappingContext.read(namingContextIid.child(Mappings.class)); - return read.isPresent() - ? read.get().getMapping().stream().anyMatch(mapping -> mapping.getIndex().equals(index)) - : false; - } - - - /** - * Add mapping to current context - * - * @param index index of a mapped item - * @param name name of a mapped item - * @param mappingContext mapping context providing context data for current transaction - */ - public synchronized void addName(final int index, final String name, final MappingContext mappingContext) { - final KeyedInstanceIdentifier mappingIid = getMappingIid(name); - mappingContext.put(mappingIid, new MappingBuilder().setIndex(index).setName(name).build()); - } - - private KeyedInstanceIdentifier getMappingIid(final String name) { - return namingContextIid.child(Mappings.class).child(Mapping.class, new MappingKey(name)); - } - - /** - * Remove mapping from current context - * - * @param name name of a mapped item - * @param mappingContext mapping context providing context data for current transaction - */ - public synchronized void removeName(final String name, final MappingContext mappingContext) { - mappingContext.delete(getMappingIid(name)); - } - - /** - * Returns index value associated with the given name. - * - * @param name the name whose associated index value is to be returned - * @param mappingContext mapping context providing context data for current transaction - * - * @return integer index value matching supplied name - * @throws IllegalArgumentException if name was not found - */ - public synchronized int getIndex(final String name, final MappingContext mappingContext) { - final Optional read = mappingContext.read(getMappingIid(name)); - checkArgument(read.isPresent(), "No mapping stored for name: %s", name); - return read.get().getIndex(); - - } - - /** - * Check whether mapping is present for name. - * - * @param name name of a mapped item - * @param mappingContext mapping context providing context data for current transaction - * - * @return true if present, false otherwise - */ - public synchronized boolean containsIndex(final String name, final MappingContext mappingContext) { - return mappingContext.read(getMappingIid(name)).isPresent(); - } - - private String getArtificialName(final int index) { - return artificialNamePrefix + index; - } - - @Override - public void close() throws Exception { - /// Not removing the mapping from backing storage - } -} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/ReadTimeoutException.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/ReadTimeoutException.java deleted file mode 100644 index 654b13825..000000000 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/ReadTimeoutException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.v3po.util; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Thrown when read method invocation times out. - */ -@Beta -public class ReadTimeoutException extends ReadFailedException { - - public ReadTimeoutException(final InstanceIdentifier id, final Throwable cause) { - super(id, cause); - } - -} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/SubInterfaceUtils.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/SubInterfaceUtils.java deleted file mode 100644 index 1df82af73..000000000 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/SubInterfaceUtils.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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.v3po.util; - -public final class SubInterfaceUtils { - - private SubInterfaceUtils() { - throw new UnsupportedOperationException("Utility class cannot be instantiated."); - } - - public static String getSubInterfaceName(final String superIfName, final int subIfaceId) { - return String.format("%s.%d", superIfName, subIfaceId); - } -} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TagRewriteOperation.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TagRewriteOperation.java deleted file mode 100644 index 316d1f8e2..000000000 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TagRewriteOperation.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.v3po.util; - -import com.google.common.base.Preconditions; -import com.google.common.primitives.UnsignedBytes; -import javax.annotation.Nonnegative; -import javax.annotation.Nullable; - -/** - * Defines vlan tag rewrite config options for VPP - * - * TODO corresponding enum (defined in l2_vtr.h) should be defined in vpe.api - * (does vpp's IDL support enum type definition?) - * which would allow to generate this class in jvpp - */ -public enum TagRewriteOperation { - disabled(0), - push_1(0), - push_2(0), - pop_1(1), - pop_2(2), - translate_1_to_1(1), - translate_1_to_2(1), - translate_2_to_1(2), - translate_2_to_2(2); - - private final static int MAX_INDEX = 3; - private final int code; - private final byte popTags; - - TagRewriteOperation(final int popTags) { - this.code = this.ordinal(); - this.popTags = UnsignedBytes.checkedCast(popTags); - } - - private static TagRewriteOperation[][] translation = new TagRewriteOperation[][] { - {disabled, push_1, push_2}, - {pop_1, translate_1_to_1, translate_1_to_2}, - {pop_2, translate_2_to_1, translate_2_to_2} - }; - - /** - * Returns VPP tag rewrite operation for given number of tags to pop and tags to push. - * @param toPop number of tags to pop (0..2) - * @param toPush number of tags to push (0..2) - * @return vpp tag rewrite operation for given input parameters - */ - public static TagRewriteOperation get(@Nonnegative final int toPop, @Nonnegative final int toPush) { - Preconditions.checkElementIndex(toPop, MAX_INDEX, "Illegal number of tags to pop"); - Preconditions.checkElementIndex(toPush, MAX_INDEX, "Illegal number of tags to push"); - return translation[toPop][toPush]; - } - - /** - * Returns VPP tag rewrite operation for given operation code. - * @param code VPP tag rewrite operation code - * @return vpp tag rewrite operation for given input parameter - */ - @Nullable - public static TagRewriteOperation get(@Nonnegative final int code) { - for (TagRewriteOperation operation : TagRewriteOperation.values()) { - if (code == operation.code){ - return operation; - } - } - return null; - } - - public byte getPopTags() { - return popTags; - } -} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtils.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtils.java deleted file mode 100644 index 1a6a50133..000000000 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtils.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * 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.v3po.util; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.base.Splitter; -import com.google.common.net.InetAddresses; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.BiConsumer; -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.VppBaseCallException; -import org.openvpp.jvpp.dto.JVppReply; - -public final class TranslateUtils { - - public static final Splitter COLON_SPLITTER = Splitter.on(':'); - public static final int DEFAULT_TIMEOUT_IN_SECONDS = 5; - - private TranslateUtils() { - } - - public static > REP getReplyForWrite(@Nonnull Future future, - @Nonnull final InstanceIdentifier replyType) - throws VppBaseCallException, WriteTimeoutException { - return getReplyForWrite(future, replyType, DEFAULT_TIMEOUT_IN_SECONDS); - } - - public static > REP getReplyForWrite(@Nonnull Future future, - @Nonnull final InstanceIdentifier replyType, - @Nonnegative final int timeoutInSeconds) - throws VppBaseCallException, WriteTimeoutException { - try { - return getReply(future, timeoutInSeconds); - } catch (TimeoutException e) { - throw new WriteTimeoutException(replyType, e); - } - } - - public static > REP getReplyForRead(@Nonnull Future future, - @Nonnull final InstanceIdentifier replyType) - throws VppBaseCallException, ReadTimeoutException { - return getReplyForRead(future, replyType, DEFAULT_TIMEOUT_IN_SECONDS); - } - - public static > REP getReplyForRead(@Nonnull Future future, - @Nonnull final InstanceIdentifier replyType, - @Nonnegative final int timeoutInSeconds) - throws VppBaseCallException, ReadTimeoutException { - try { - return getReply(future, timeoutInSeconds); - } catch (TimeoutException e) { - throw new ReadTimeoutException(replyType, e); - } - } - - public static > REP getReply(@Nonnull Future future) - throws TimeoutException, VppBaseCallException { - return getReply(future, DEFAULT_TIMEOUT_IN_SECONDS); - } - - public static > REP getReply(@Nonnull Future future, - @Nonnegative final int timeoutInSeconds) - throws TimeoutException, VppBaseCallException { - try { - checkArgument(timeoutInSeconds > 0, "Timeout cannot be < 0"); - return future.get(timeoutInSeconds, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new IllegalStateException("Interrupted", e); - } catch (ExecutionException e) { - // Execution exception could generally contains any exception - // when using exceptions instead of return codes just rethrow it for processing on corresponding place - if (e instanceof ExecutionException && (e.getCause() instanceof VppBaseCallException)) { - throw (VppBaseCallException) (e.getCause()); - } - throw new IllegalStateException(e); - } - } - - /** - * Transform Ipv4 address to a byte array acceptable by VPP. VPP expects incoming byte array to be in the same order - * as the address. - * - * @return byte array with address bytes - */ - public static byte[] ipv4AddressNoZoneToArray(final Ipv4AddressNoZone ipv4Addr) { - byte[] retval = new byte[4]; - String[] dots = ipv4Addr.getValue().split("\\."); - - for (int d = 0; d < 4; d++) { - retval[d] = (byte) (Short.parseShort(dots[d]) & 0xff); - } - return retval; - } - - /** - * Parse byte array returned by VPP representing an Ipv4 address. Vpp returns IP byte arrays in reversed order. - * - * @return Ipv4AddressNoZone containing string representation of IPv4 address constructed from submitted bytes. No - * change in order. - */ - @Nonnull - public static Ipv4AddressNoZone arrayToIpv4AddressNoZone(@Nonnull byte[] ip) { - // VPP sends ipv4 in a 16 byte array - if (ip.length == 16) { - ip = Arrays.copyOfRange(ip, 0, 4); - } - try { - // Not reversing the byte array here!! because the IP coming from VPP is in reversed byte order - // compared to byte order it was submitted - return new Ipv4AddressNoZone(InetAddresses.toAddrString(InetAddresses.fromLittleEndianByteArray(ip))); - } catch (UnknownHostException e) { - throw new IllegalArgumentException("Unable to parse ipv4", e); - } - } - - /** - * Return (interned) string from byte array while removing \u0000. Strings represented as fixed length byte[] from - * vpp contain \u0000. - */ - public static String toString(final byte[] cString) { - return new String(cString).replaceAll("\\u0000", "").intern(); - } - - /** - * Parse string represented mac address (using ":" as separator) into a byte array - */ - @Nonnull - public static byte[] parseMac(@Nonnull final String macAddress) { - final List parts = COLON_SPLITTER.splitToList(macAddress); - checkArgument(parts.size() == 6, "Mac address is expected to have 6 parts but was: %s", macAddress); - return parseMacLikeString(parts); - } - - private static byte[] parseMacLikeString(final List strings) { - return strings.stream().limit(6).map(TranslateUtils::parseHexByte).collect( - () -> new byte[strings.size()], - new BiConsumer() { - - private int i = -1; - - @Override - public void accept(final byte[] bytes, final Byte aByte) { - bytes[++i] = aByte; - } - }, - (bytes, bytes2) -> { - throw new UnsupportedOperationException("Parallel collect not supported"); - }); - } - - public static byte parseHexByte(final String aByte) { - return (byte) Integer.parseInt(aByte, 16); - } - - /** - * Returns 0 if argument is null or false, 1 otherwise. - * - * @param value Boolean value to be converted - * @return byte value equal to 0 or 1 - */ - public static byte booleanToByte(@Nullable final Boolean value) { - return value != null && value - ? (byte) 1 - : (byte) 0; - } - - /** - * Returns Boolean.TRUE if argument is 0, Boolean.FALSE otherwise. - * - * @param value byte value to be converted - * @return Boolean value - * @throws IllegalArgumentException if argument is neither 0 nor 1 - */ - @Nonnull - public static Boolean byteToBoolean(final byte value) { - if (value == 0) { - return Boolean.FALSE; - } else if (value == 1) { - return Boolean.TRUE; - } - throw new IllegalArgumentException(String.format("0 or 1 was expected but was %d", value)); - } - - /** - * Reverses bytes in the byte array - * - * @param bytes input array - * @return reversed array - */ - public static byte[] reverseBytes(final byte[] bytes) { - final byte[] reversed = new byte[bytes.length]; - int i = 1; - for (byte aByte : bytes) { - reversed[bytes.length - i++] = aByte; - } - - return reversed; - } -} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/WriteTimeoutException.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/WriteTimeoutException.java deleted file mode 100644 index 9516459b2..000000000 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/WriteTimeoutException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.v3po.util; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.write.WriteFailedException; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Thrown when write method invocation times out. - */ -@Beta -public class WriteTimeoutException extends WriteFailedException { - - public WriteTimeoutException(final InstanceIdentifier id, final Throwable cause) { - super(id, cause); - } - -} diff --git a/vpp-common/vpp-translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/util/rev160406/NamingContextImplModule.java b/vpp-common/vpp-translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/util/rev160406/NamingContextImplModule.java index 60a816d89..bff1a3a49 100644 --- a/vpp-common/vpp-translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/util/rev160406/NamingContextImplModule.java +++ b/vpp-common/vpp-translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/util/rev160406/NamingContextImplModule.java @@ -1,6 +1,6 @@ package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.util.rev160406; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; +import io.fd.honeycomb.translate.v3po.util.NamingContext; public class NamingContextImplModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.util.rev160406.AbstractNamingContextImplModule { public NamingContextImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { diff --git a/vpp-common/vpp-translate-utils/src/main/yang/vpp-util.yang b/vpp-common/vpp-translate-utils/src/main/yang/vpp-util.yang index 23615d09e..f9d090c03 100644 --- a/vpp-common/vpp-translate-utils/src/main/yang/vpp-util.yang +++ b/vpp-common/vpp-translate-utils/src/main/yang/vpp-util.yang @@ -16,7 +16,7 @@ module vpp-util { identity naming-context { base "config:service-type"; - config:java-class io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; + config:java-class io.fd.honeycomb.translate.v3po.util.NamingContext; } identity naming-context-impl { diff --git a/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/SubinterfaceUtilsTest.java b/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/SubinterfaceUtilsTest.java new file mode 100644 index 000000000..fb8a8066e --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/SubinterfaceUtilsTest.java @@ -0,0 +1,32 @@ +/* + * 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.translate.v3po.util; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class SubinterfaceUtilsTest { + + @Test + public void testGetSubInterfaceName() throws Exception { + final String superIfName = "GigabitEthernet0/9/0"; + final int subIfaceId = 123; + final String expectedSubIfaceName = "GigabitEthernet0/9/0.123"; + assertEquals(expectedSubIfaceName, SubInterfaceUtils.getSubInterfaceName(superIfName, subIfaceId)); + } +} \ No newline at end of file diff --git a/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/TranslateUtilsTest.java b/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/TranslateUtilsTest.java new file mode 100644 index 000000000..d9cb52f3a --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/TranslateUtilsTest.java @@ -0,0 +1,137 @@ +package io.fd.honeycomb.translate.v3po.util; + +import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.reverseBytes; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.dto.JVppReply; + +public class TranslateUtilsTest { + + private static class AnDataObject implements DataObject { + @Override + public Class getImplementedInterface() { + return null; + } + } + + @Test + public void testGetReplyForWriteTimeout() throws Exception { + final Future> future = mock(Future.class); + when(future.get(anyLong(), eq(TimeUnit.SECONDS))).thenThrow(TimeoutException.class); + final InstanceIdentifier replyType = InstanceIdentifier.create(AnDataObject.class); + try { + TranslateUtils.getReplyForWrite(future, replyType); + } catch (WriteTimeoutException e) { + assertTrue(e.getCause() instanceof TimeoutException); + assertEquals(replyType, e.getFailedId()); + return; + } + fail("WriteTimeoutException was expected"); + } + + @Test + public void testGetReplyForReadTimeout() throws Exception { + final Future> future = mock(Future.class); + final InstanceIdentifier replyType = InstanceIdentifier.create(AnDataObject.class); + when(future.get(anyLong(), eq(TimeUnit.SECONDS))).thenThrow(TimeoutException.class); + try { + TranslateUtils.getReplyForRead(future, replyType); + } catch (ReadTimeoutException e) { + assertTrue(e.getCause() instanceof TimeoutException); + assertEquals(replyType, e.getFailedId()); + return; + } + fail("ReadTimeoutException was expected"); + } + + @Test + public void testIpv4NoZone() throws Exception { + final Ipv4AddressNoZone ipv4Addr = new Ipv4AddressNoZone("192.168.1.1"); + byte[] bytes = TranslateUtils.ipv4AddressNoZoneToArray(ipv4Addr); + assertEquals((byte)192, bytes[0]); + // Simulating the magic of VPP + bytes = reverseBytes(bytes); + final Ipv4AddressNoZone ipv4AddressNoZone = TranslateUtils.arrayToIpv4AddressNoZone(bytes); + assertEquals(ipv4Addr, ipv4AddressNoZone); + } + + @Test + public void testToString() { + final byte[] expected = "test".getBytes(); + final byte[] cString = new byte[expected.length + 10]; + System.arraycopy(expected, 0, cString, 0, expected.length); + final String jString = TranslateUtils.toString(cString); + assertArrayEquals(expected, jString.getBytes()); + } + + @Test + public void testParseMac() throws Exception { + byte[] bytes = TranslateUtils.parseMac("00:fF:7f:15:5e:A9"); + assertMac(bytes); + } + + private void assertMac(final byte[] bytes) { + assertEquals(6, bytes.length); + assertEquals((byte) 0, bytes[0]); + assertEquals((byte) 255, bytes[1]); + assertEquals((byte) 127, bytes[2]); + assertEquals((byte) 21, bytes[3]); + assertEquals((byte) 94, bytes[4]); + assertEquals((byte) 169, bytes[5]); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseMacLonger() throws Exception { + byte[] bytes = TranslateUtils.parseMac("00:fF:7f:15:5e:A9:88:77"); + assertMac(bytes); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseMacShorter() throws Exception { + TranslateUtils.parseMac("00:fF:7f"); + } + + @Test(expected = IllegalArgumentException.class) + public void testParseRandomString() throws Exception { + TranslateUtils.parseMac("random{}}@$*&*!"); + } + + @Test(expected = NumberFormatException.class) + public void testParseMacNumberFormatEx() throws Exception { + TranslateUtils.parseMac("00:XX:7f:15:5e:77\""); + } + + @Test + public void testBooleanToByte() { + assertEquals(0, TranslateUtils.booleanToByte(null)); + assertEquals(0, TranslateUtils.booleanToByte(false)); + assertEquals(1, TranslateUtils.booleanToByte(true)); + } + + @Test + public void testByteToBoolean() { + assertEquals(Boolean.FALSE, TranslateUtils.byteToBoolean((byte) 0)); + assertEquals(Boolean.TRUE, TranslateUtils.byteToBoolean((byte) 1)); + } + + @Test(expected = IllegalArgumentException.class) + public void testByteToBooleanFailed() { + TranslateUtils.byteToBoolean((byte) 123); + } + +} \ No newline at end of file diff --git a/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/cache/DumpCacheManagerTest.java b/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/cache/DumpCacheManagerTest.java index 5b9391305..9eaa024e3 100644 --- a/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/cache/DumpCacheManagerTest.java +++ b/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/cache/DumpCacheManagerTest.java @@ -22,7 +22,7 @@ import static org.mockito.Mockito.when; import com.google.common.base.Optional; import io.fd.honeycomb.translate.v3po.util.cache.exceptions.check.i.DumpEmptyException; import io.fd.honeycomb.translate.v3po.util.cache.exceptions.execution.DumpExecutionFailedException; -import io.fd.honeycomb.v3po.translate.ModificationCache; +import io.fd.honeycomb.translate.ModificationCache; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; diff --git a/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/SubinterfaceUtilsTest.java b/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/SubinterfaceUtilsTest.java deleted file mode 100644 index a61dfea90..000000000 --- a/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/SubinterfaceUtilsTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.v3po.util; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -public class SubinterfaceUtilsTest { - - @Test - public void testGetSubInterfaceName() throws Exception { - final String superIfName = "GigabitEthernet0/9/0"; - final int subIfaceId = 123; - final String expectedSubIfaceName = "GigabitEthernet0/9/0.123"; - assertEquals(expectedSubIfaceName, SubInterfaceUtils.getSubInterfaceName(superIfName, subIfaceId)); - } -} \ No newline at end of file diff --git a/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtilsTest.java b/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtilsTest.java deleted file mode 100644 index 334887430..000000000 --- a/vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtilsTest.java +++ /dev/null @@ -1,137 +0,0 @@ -package io.fd.honeycomb.v3po.translate.v3po.util; - -import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.reverseBytes; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; -import org.opendaylight.yangtools.yang.binding.DataContainer; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.jvpp.dto.JVppReply; - -public class TranslateUtilsTest { - - private static class AnDataObject implements DataObject { - @Override - public Class getImplementedInterface() { - return null; - } - } - - @Test - public void testGetReplyForWriteTimeout() throws Exception { - final Future> future = mock(Future.class); - when(future.get(anyLong(), eq(TimeUnit.SECONDS))).thenThrow(TimeoutException.class); - final InstanceIdentifier replyType = InstanceIdentifier.create(AnDataObject.class); - try { - TranslateUtils.getReplyForWrite(future, replyType); - } catch (WriteTimeoutException e) { - assertTrue(e.getCause() instanceof TimeoutException); - assertEquals(replyType, e.getFailedId()); - return; - } - fail("WriteTimeoutException was expected"); - } - - @Test - public void testGetReplyForReadTimeout() throws Exception { - final Future> future = mock(Future.class); - final InstanceIdentifier replyType = InstanceIdentifier.create(AnDataObject.class); - when(future.get(anyLong(), eq(TimeUnit.SECONDS))).thenThrow(TimeoutException.class); - try { - TranslateUtils.getReplyForRead(future, replyType); - } catch (ReadTimeoutException e) { - assertTrue(e.getCause() instanceof TimeoutException); - assertEquals(replyType, e.getFailedId()); - return; - } - fail("ReadTimeoutException was expected"); - } - - @Test - public void testIpv4NoZone() throws Exception { - final Ipv4AddressNoZone ipv4Addr = new Ipv4AddressNoZone("192.168.1.1"); - byte[] bytes = TranslateUtils.ipv4AddressNoZoneToArray(ipv4Addr); - assertEquals((byte)192, bytes[0]); - // Simulating the magic of VPP - bytes = reverseBytes(bytes); - final Ipv4AddressNoZone ipv4AddressNoZone = TranslateUtils.arrayToIpv4AddressNoZone(bytes); - assertEquals(ipv4Addr, ipv4AddressNoZone); - } - - @Test - public void testToString() { - final byte[] expected = "test".getBytes(); - final byte[] cString = new byte[expected.length + 10]; - System.arraycopy(expected, 0, cString, 0, expected.length); - final String jString = TranslateUtils.toString(cString); - assertArrayEquals(expected, jString.getBytes()); - } - - @Test - public void testParseMac() throws Exception { - byte[] bytes = TranslateUtils.parseMac("00:fF:7f:15:5e:A9"); - assertMac(bytes); - } - - private void assertMac(final byte[] bytes) { - assertEquals(6, bytes.length); - assertEquals((byte) 0, bytes[0]); - assertEquals((byte) 255, bytes[1]); - assertEquals((byte) 127, bytes[2]); - assertEquals((byte) 21, bytes[3]); - assertEquals((byte) 94, bytes[4]); - assertEquals((byte) 169, bytes[5]); - } - - @Test(expected = IllegalArgumentException.class) - public void testParseMacLonger() throws Exception { - byte[] bytes = TranslateUtils.parseMac("00:fF:7f:15:5e:A9:88:77"); - assertMac(bytes); - } - - @Test(expected = IllegalArgumentException.class) - public void testParseMacShorter() throws Exception { - TranslateUtils.parseMac("00:fF:7f"); - } - - @Test(expected = IllegalArgumentException.class) - public void testParseRandomString() throws Exception { - TranslateUtils.parseMac("random{}}@$*&*!"); - } - - @Test(expected = NumberFormatException.class) - public void testParseMacNumberFormatEx() throws Exception { - TranslateUtils.parseMac("00:XX:7f:15:5e:77\""); - } - - @Test - public void testBooleanToByte() { - assertEquals(0, TranslateUtils.booleanToByte(null)); - assertEquals(0, TranslateUtils.booleanToByte(false)); - assertEquals(1, TranslateUtils.booleanToByte(true)); - } - - @Test - public void testByteToBoolean() { - assertEquals(Boolean.FALSE, TranslateUtils.byteToBoolean((byte) 0)); - assertEquals(Boolean.TRUE, TranslateUtils.byteToBoolean((byte) 1)); - } - - @Test(expected = IllegalArgumentException.class) - public void testByteToBooleanFailed() { - TranslateUtils.byteToBoolean((byte) 123); - } - -} \ No newline at end of file -- cgit 1.2.3-korg