Merge "Tests for neutron-ovsdb"
authorMartin Sunal <msunal@cisco.com>
Wed, 13 Jul 2016 09:56:30 +0000 (09:56 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 13 Jul 2016 09:56:30 +0000 (09:56 +0000)
35 files changed:
artifacts/pom.xml
features/pom.xml
features/src/main/features/features.xml
groupbasedpolicy-ise-adapter/pom.xml [new file with mode: 0755]
groupbasedpolicy-ise-adapter/src/main/config/default-config.xml [new file with mode: 0755]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/controller/config/yang/config/groupbasedpolicy/gbp_ise_adapter/GpbIseAdapterProviderModule.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/controller/config/yang/config/groupbasedpolicy/gbp_ise_adapter/GpbIseAdapterProviderModuleFactory.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseAdapterProvider.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseConfigListener.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseConfigListenerImpl.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseSgtHarvester.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseSgtHarvesterImpl.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtInfo.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtInfoProcessor.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEPTemplateGeneratorImpl.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEpgGeneratorImpl.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/util/RestClientFactory.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/yang/gbp-ise-adapter-cfg.yang [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/main/yang/gbp-ise-adapter-model.yang [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseAdapterProviderTest.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseConfigListenerImplTest.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseSgtHarvesterImplTest.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEPTemplateGeneratorImplTest.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEpgGeneratorImplTest.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/util/RestClientFactoryTest.java [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/test/resources/log4j.xml [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/test/resources/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/rawIse-allSgts.xml [new file with mode: 0644]
groupbasedpolicy-ise-adapter/src/test/resources/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/rawIse-sgtDetail.xml [new file with mode: 0644]
groupbasedpolicy-ui/bundle/pom.xml
groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/renderer/RendererManager.java
pom.xml
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/ServiceChainingUtil.java
renderers/ios-xe/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/writer/PolicyWriter.java
renderers/ios-xe/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ios_xe_provider/impl/util/ServiceChainingUtilTest.java
sxp-mapper/src/main/java/org/opendaylight/groupbasedpolicy/sxp/mapper/impl/SxpMapperReactorImpl.java

index e6d732605682328b74caf012dd78a94f58a3e422..df5c6732d411946d42d57cd413405e09da4665e5 100755 (executable)
         <artifactId>sxp-mapper</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>groupbasedpolicy-ise-adapter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
 
       <!-- GBP configuration -->
       <dependency>
         <type>xml</type>
         <classifier>config</classifier>
       </dependency>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>groupbasedpolicy-ise-adapter</artifactId>
+        <version>${project.version}</version>
+        <type>xml</type>
+        <classifier>config</classifier>
+      </dependency>
 
 
       <!-- GBP features -->
index 41364081fe28654a516801adf50aa6c63bc7849b..02e33de353caf1c06d4458313bd86c8961e9f61c 100755 (executable)
       <groupId>org.opendaylight.groupbasedpolicy</groupId>
       <artifactId>ios-xe-renderer</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.groupbasedpolicy</groupId>
+      <artifactId>groupbasedpolicy-ise-adapter</artifactId>
+    </dependency>
 
     <!-- GBP configuration -->
     <dependency>
       <type>xml</type>
       <classifier>config</classifier>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.groupbasedpolicy</groupId>
+      <artifactId>groupbasedpolicy-ise-adapter</artifactId>
+      <type>xml</type>
+      <classifier>config</classifier>
+    </dependency>
   </dependencies>
 </project>
index cea8f8dbc889a48d6da1cdbabd8e288742542819..0d87284cdac5c1c055e79385c75f71469830fdfc 100755 (executable)
         <configfile finalname="${config.configfile.directory}/15-l2-l3-domain-extension.xml">mvn:org.opendaylight.groupbasedpolicy/l2-l3-domain-extension/{{VERSION}}/xml/config</configfile>
         <configfile finalname="${config.configfile.directory}/15-groupbasedpolicy-ios-xe-renderer.xml">mvn:org.opendaylight.groupbasedpolicy/ios-xe-renderer/{{VERSION}}/xml/config</configfile>
     </feature>
+
+    <!--
+       GBP-ISE ADAPTER
+   -->
+    <feature name='odl-groupbasedpolicy-ise-adapter' version='${project.version}' description='OpenDaylight :: groupbasedpolicy :: gbp-ise adapter'>
+        <feature version="${project.version}">odl-groupbasedpolicy-sxp-mapper</feature>
+        <feature version="${sxp.version}">odl-sxp-core</feature>
+        <bundle>mvn:commons-net/commons-net/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-client/{{VERSION}}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-core/{{VERSION}}</bundle>
+        <bundle>mvn:org.opendaylight.groupbasedpolicy/groupbasedpolicy-ise-adapter/{{VERSION}}</bundle>
+        <configfile finalname="${config.configfile.directory}/16-groupbasedpolicy-ise-adapter.xml">mvn:org.opendaylight.groupbasedpolicy/groupbasedpolicy-ise-adapter/{{VERSION}}/xml/config</configfile>
+    </feature>
 </features>
diff --git a/groupbasedpolicy-ise-adapter/pom.xml b/groupbasedpolicy-ise-adapter/pom.xml
new file mode 100755 (executable)
index 0000000..4300f46
--- /dev/null
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+  This program and the accompanying materials are made available under the
+  terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>config-parent</artifactId>
+        <version>0.5.0-SNAPSHOT</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.opendaylight.groupbasedpolicy</groupId>
+    <artifactId>groupbasedpolicy-ise-adapter</artifactId>
+    <version>0.4.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+    <name>groupbasedpolicy-ise-adapter</name>
+
+    <properties>
+        <sxp.version>1.3.0-SNAPSHOT</sxp.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.opendaylight.groupbasedpolicy</groupId>
+                <artifactId>groupbasedpolicy-artifacts</artifactId>
+                <version>${project.version}</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+             <dependency>
+                <groupId>org.opendaylight.sxp</groupId>
+                <artifactId>sxp-api</artifactId>
+                <version>${sxp.version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <!-- model dependencies -->
+        <dependency>
+            <groupId>org.opendaylight.groupbasedpolicy</groupId>
+            <artifactId>sxp-mapper</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.sxp</groupId>
+            <artifactId>sxp-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.mdsal.model</groupId>
+            <artifactId>ietf-inet-types</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.model</groupId>
+            <artifactId>ietf-yang-types</artifactId>
+        </dependency>
+
+        <!-- util -->
+        <dependency>
+            <groupId>commons-net</groupId>
+            <artifactId>commons-net</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-client</artifactId>
+        </dependency>
+
+        <!-- testing dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-module-junit4</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-broker-impl</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <!-- project build -->
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/groupbasedpolicy-ise-adapter/src/main/config/default-config.xml b/groupbasedpolicy-ise-adapter/src/main/config/default-config.xml
new file mode 100755 (executable)
index 0000000..2f71a2c
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+  ~
+  ~ This program and the accompanying materials are made available under the
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+  -->
+
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+
+<snapshot>
+    <configuration>
+        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                <module>
+                    <type xmlns:gbp-ise-adapter="urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy:gbp-ise-adapter">
+                        gbp-ise-adapter:gbp-ise-adapter-impl
+                    </type>
+                    <name>gbp-ise-adapter</name>
+
+                    <data-broker>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+                        <name>binding-data-broker</name>
+                    </data-broker>
+                    <broker>
+                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+                        <name>binding-osgi-broker</name>
+                    </broker>
+                </module>
+            </modules>
+        </data>
+    </configuration>
+
+    <required-capabilities>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy:gbp-ise-adapter?module=gbp-ise-adapter-cfg&amp;revision=2016-06-30</capability>
+        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy:gbp-ise-adapter:model?module=gbp-ise-adapter-model&amp;revision=2016-06-30</capability>
+    </required-capabilities>
+
+</snapshot>
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/controller/config/yang/config/groupbasedpolicy/gbp_ise_adapter/GpbIseAdapterProviderModule.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/controller/config/yang/config/groupbasedpolicy/gbp_ise_adapter/GpbIseAdapterProviderModule.java
new file mode 100644 (file)
index 0000000..415f9e9
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.yang.config.groupbasedpolicy.gbp_ise_adapter;
+
+import org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl.GbpIseAdapterProvider;
+
+/**
+* gbp-ise-adapter impl module
+*/
+public class GpbIseAdapterProviderModule extends org.opendaylight.controller.config.yang.config.groupbasedpolicy.gbp_ise_adapter.AbstractGpbIseAdapterProviderModule {
+    public GpbIseAdapterProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public GpbIseAdapterProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.config.groupbasedpolicy.gbp_ise_adapter.GpbIseAdapterProviderModule 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 GbpIseAdapterProvider(getDataBrokerDependency(), getBrokerDependency());
+    }
+
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/controller/config/yang/config/groupbasedpolicy/gbp_ise_adapter/GpbIseAdapterProviderModuleFactory.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/controller/config/yang/config/groupbasedpolicy/gbp_ise_adapter/GpbIseAdapterProviderModuleFactory.java
new file mode 100644 (file)
index 0000000..4c15447
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+/*
+* Generated file
+*
+* Generated from: yang module name: gbp-ise-adapter-cfg yang module local name: gbp-ise-adapter-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Thu Jun 30 17:44:55 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.groupbasedpolicy.gbp_ise_adapter;
+public class GpbIseAdapterProviderModuleFactory extends org.opendaylight.controller.config.yang.config.groupbasedpolicy.gbp_ise_adapter.AbstractGpbIseAdapterProviderModuleFactory {
+
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseAdapterProvider.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseAdapterProvider.java
new file mode 100644 (file)
index 0000000..b295097
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.GbpIseAdapter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestConfig;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Purpose: main provider of gbp-ise adapter (for reading sgts and generating EndpointPolicyTemplates)
+ */
+public class GbpIseAdapterProvider implements AutoCloseable, BindingAwareProvider {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GbpIseAdapterProvider.class);
+
+    private final DataBroker dataBroker;
+    private ListenerRegistration<DataTreeChangeListener<IseHarvestConfig>> registration;
+
+    public GbpIseAdapterProvider(final DataBroker dataBroker, final BindingAwareBroker brokerDependency) {
+        this.dataBroker = Preconditions.checkNotNull(dataBroker, "provided dataBroker must not be null");
+        brokerDependency.registerProvider(this);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (registration != null) {
+            LOG.info("closing GbpIseAdapterProvider");
+            registration.close();
+            registration = null;
+        }
+    }
+
+    @Override
+    public void onSessionInitiated(final BindingAwareBroker.ProviderContext providerContext) {
+        LOG.info("Starting GbpIseAdapterProvider ..");
+
+        // setup harvesting and processing pipeline
+        final SgtInfoProcessor epgGenerator = new SgtToEpgGeneratorImpl(dataBroker);
+        final SgtInfoProcessor templateGenerator = new SgtToEPTemplateGeneratorImpl(dataBroker);
+        final GbpIseSgtHarvester gbpIseSgtHarvester = new GbpIseSgtHarvesterImpl(epgGenerator, templateGenerator);
+        final GbpIseConfigListenerImpl gbpIseConfigListener = new GbpIseConfigListenerImpl(dataBroker, gbpIseSgtHarvester);
+
+        // build data-tree path
+        final DataTreeIdentifier<IseHarvestConfig> dataTreePath = new DataTreeIdentifier<>(
+                LogicalDatastoreType.CONFIGURATION,
+                InstanceIdentifier.create(GbpIseAdapter.class).child(IseHarvestConfig.class));
+
+        // register config listener
+        registration = dataBroker.registerDataTreeChangeListener(dataTreePath,
+                gbpIseConfigListener);
+
+        LOG.info("Started");
+    }
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseConfigListener.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseConfigListener.java
new file mode 100644 (file)
index 0000000..399ca5f
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestConfig;
+
+/**
+ * Purpose: dtcl for {@link IseHarvestConfig}
+ */
+public interface GbpIseConfigListener extends DataTreeChangeListener<IseHarvestConfig>, AutoCloseable {
+    // nobody
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseConfigListenerImpl.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseConfigListenerImpl.java
new file mode 100644 (file)
index 0000000..e613ca9
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.DateAndTime;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.GbpIseAdapter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestStatusBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Purpose: listen for harvest configuration and trigger harvesting
+ */
+public class GbpIseConfigListenerImpl implements GbpIseConfigListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GbpIseConfigListenerImpl.class);
+
+    private static final String DATE_AND_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
+
+    private final DataBroker dataBroker;
+    private final GbpIseSgtHarvester gbpIseSgtHarvester;
+    private final ThreadPoolExecutor pool;
+
+    public GbpIseConfigListenerImpl(@Nonnull final DataBroker dataBroker, @Nonnull final GbpIseSgtHarvester gbpIseSgtHarvester) {
+        this.dataBroker = dataBroker;
+        this.gbpIseSgtHarvester = gbpIseSgtHarvester;
+        pool = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10),
+                new ThreadFactoryBuilder().setNameFormat("ise-sgt-harverster-%d").build()) {
+            @Override
+            protected void afterExecute(final Runnable r, final Throwable t) {
+                super.afterExecute(r, t);
+                if (t != null) {
+                    LOG.warn("ise harvest task failed", t);
+                }
+            }
+        };
+    }
+
+    @Override
+    public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<IseHarvestConfig>> collection) {
+        for (DataTreeModification<IseHarvestConfig> modification : collection) {
+            final IseHarvestConfig iseHarvestConfig = modification.getRootNode().getDataAfter();
+            if (iseHarvestConfig != null) {
+                pool.submit(() -> {
+                    final ListenableFuture<Integer> harvestResult = gbpIseSgtHarvester.harvest(iseHarvestConfig);
+                    Futures.addCallback(harvestResult, new FutureCallback<Integer>() {
+                        @Override
+                        public void onSuccess(@Nullable final Integer result) {
+                            LOG.debug("ise harvest finished, outcome: {}", result);
+                            storeOutcome(true, result.intValue(), null);
+                        }
+
+                        @Override
+                        public void onFailure(final Throwable t) {
+                            LOG.debug("ise harvest failed", t);
+                            storeOutcome(false, 0, t.getMessage());
+                        }
+                    });
+
+                    try {
+                        harvestResult.get(30, TimeUnit.SECONDS);
+                    } catch (InterruptedException | ExecutionException | TimeoutException e) {
+                        LOG.debug("failed to finish ise-sgt-harvest task properly on time", e);
+                    }
+                });
+            }
+        }
+    }
+
+    private CheckedFuture<Void, TransactionCommitFailedException> storeOutcome(final boolean succeeded, final int counter, final String reason) {
+        final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
+        final InstanceIdentifier<IseHarvestStatus> harvestStatusPath = InstanceIdentifier.create(GbpIseAdapter.class)
+                .child(IseHarvestStatus.class);
+        final IseHarvestStatus harvestStatus = new IseHarvestStatusBuilder()
+                .setReason(reason)
+                .setSuccess(succeeded)
+                .setTemplatesWritten(counter)
+                .setTimestamp(createDateTime(new Date()))
+                .build();
+        wTx.put(LogicalDatastoreType.OPERATIONAL, harvestStatusPath, harvestStatus, true);
+        return wTx.submit();
+    }
+
+    private static DateAndTime createDateTime(Date when) {
+        final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_AND_TIME_FORMAT);
+        return new DateAndTime(simpleDateFormat.format(when));
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (!pool.isTerminated()) {
+            pool.shutdown();
+            final boolean terminated = pool.awaitTermination(10, TimeUnit.SECONDS);
+            if (! terminated) {
+                pool.shutdownNow();
+            }
+        }
+    }
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseSgtHarvester.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseSgtHarvester.java
new file mode 100644 (file)
index 0000000..d551e7a
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestConfig;
+
+/**
+ * Purpose: read sgts and naming from ISE via rest-API and have apropriate templates generated and stored
+ */
+public interface GbpIseSgtHarvester {
+
+    /**
+     * @param configuration user given
+     * @return amount of successfully written items
+     */
+    ListenableFuture<Integer> harvest(@Nonnull IseHarvestConfig configuration);
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseSgtHarvesterImpl.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseSgtHarvesterImpl.java
new file mode 100644 (file)
index 0000000..bff6d7e
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import java.io.StringReader;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl.util.RestClientFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.ise.harvest.config.ConnectionConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.ise.harvest.config.connection.config.Header;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+/**
+ * Purpose: harvest sgt + names available via ise-rest-api
+ */
+public class GbpIseSgtHarvesterImpl implements GbpIseSgtHarvester {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GbpIseSgtHarvesterImpl.class);
+
+    public static final String PATH_ERS_CONFIG_SGT = "/ers/config/sgt";
+    public static final String EXPRESSION_SGT_ALL_LINK_HREFS = "/ns3:searchResult/ns3:resources/ns5:resource/link/@href";
+    public static final String EXPRESSION_SGT_DETAIL  = "./ns4:sgt";
+    public static final String EXPRESSION_SGT_NAME_ATTR = "./@name";
+    public static final String EXPRESSION_SGT_VALUE = "./value/text()";
+
+    private final SgtInfoProcessor[] sgtInfoProcessors;
+
+    /**
+     * @param sgtInfoProcessors generator delegate
+     */
+    public GbpIseSgtHarvesterImpl(final SgtInfoProcessor... sgtInfoProcessors) {
+        this.sgtInfoProcessors = sgtInfoProcessors;
+    }
+
+    @Override
+    public ListenableFuture<Integer> harvest(@Nonnull final IseHarvestConfig configuration) {
+        final ConnectionConfig connectionConfig = configuration.getConnectionConfig();
+        ListenableFuture<Integer> result;
+        try {
+            final Client iseClient = RestClientFactory.createIseClient(connectionConfig);
+            final WebResource baseWebResource = iseClient.resource(connectionConfig.getIseRestUrl().getValue());
+
+            final WebResource.Builder requestBuilder = createRequestBuilder(baseWebResource,
+                    connectionConfig.getHeader(), PATH_ERS_CONFIG_SGT);
+            final String rawSgtSummary = deliverResponse(requestBuilder);
+
+            final List<SgtInfo> sgtInfos = harvestDetails(rawSgtSummary, baseWebResource, connectionConfig.getHeader());
+
+            ListenableFuture<Void> processingResult = Futures.immediateCheckedFuture(null);
+            for (SgtInfoProcessor processor : sgtInfoProcessors) {
+                processingResult = Futures.transform(processingResult, new AsyncFunction<Void, Void>() {
+                    @Override
+                    public ListenableFuture<Void> apply(final Void input) throws Exception {
+                        LOG.debug("entering stg-info processor {}", processor.getClass().getSimpleName());
+                        return processor.processSgtInfo(configuration.getTenant(), sgtInfos);
+                    }
+                });
+            }
+            result = Futures.transform(processingResult, new Function<Void, Integer>() {
+                @Nullable
+                @Override
+                public Integer apply(@Nullable final Void input) {
+                    // always success, otherwise there will be TransactionCommitFailedException thrown
+                    return sgtInfos.size();
+                }
+            });
+        } catch (Exception e) {
+            LOG.debug("failed to harvest ise", e);
+            result = Futures.immediateFailedFuture(e);
+        }
+
+        return result;
+    }
+
+    private static String deliverResponse(final WebResource.Builder requestBuilder) {
+        return requestBuilder.get(ClientResponse.class).getEntity(String.class);
+    }
+
+    private static WebResource.Builder createRequestBuilder(final WebResource resource, final List<Header> headers,
+                                                            final String path) {
+        final WebResource webResource = resource.path(path);
+        final WebResource.Builder requestBuilder = webResource.getRequestBuilder();
+        headers.stream().forEach(
+                (header) -> requestBuilder.header(header.getName(), header.getValue()));
+        return requestBuilder;
+    }
+
+    private List<SgtInfo> harvestDetails(final String rawSgtSummary, final WebResource baseWebResource, final List<Header> headers) {
+        LOG.trace("rawSgtSummary: {}", rawSgtSummary);
+        final List<SgtInfo> sgtInfos = new ArrayList<>();
+
+        // parse sgtSummary
+        final XPath xpath = setupXpath();
+
+        InputSource inputSource = new InputSource(new StringReader(rawSgtSummary));
+        try {
+            final NodeList sgtLinkNodes = (NodeList) xpath.evaluate(EXPRESSION_SGT_ALL_LINK_HREFS, inputSource,
+                    XPathConstants.NODESET);
+            for (int i = 0; i < sgtLinkNodes.getLength(); i++) {
+                final String sgtLinkHrefValue = sgtLinkNodes.item(i).getNodeValue();
+                LOG.debug("found sgt resource [{}]: {}", i, sgtLinkHrefValue);
+
+                // query all sgt entries (serial-vise)
+                final URI hrefToSgtDetailUri = URI.create(sgtLinkHrefValue);
+                final WebResource.Builder requestBuilder = createRequestBuilder(baseWebResource, headers, hrefToSgtDetailUri.getPath());
+                final String rawSgtDetail = deliverResponse(requestBuilder);
+                LOG.trace("rawSgtDetail: {}", rawSgtDetail);
+
+                final Node sgtNode = (Node) xpath.evaluate(EXPRESSION_SGT_DETAIL,  new InputSource(new StringReader(rawSgtDetail)),
+                        XPathConstants.NODE);
+                final Node sgtName = (Node) xpath.evaluate(EXPRESSION_SGT_NAME_ATTR,  sgtNode, XPathConstants.NODE);
+                final Node sgtValue = (Node) xpath.evaluate(EXPRESSION_SGT_VALUE,  sgtNode, XPathConstants.NODE);
+                LOG.debug("sgt value [{}]: {} -> {}", i, sgtValue, sgtName);
+
+                // store replies into list of SgtInfo
+                final Sgt sgt = new Sgt(Integer.parseInt(sgtValue.getNodeValue(), 10));
+                final SgtInfo sgtInfo = new SgtInfo(sgt, sgtName.getNodeValue());
+                sgtInfos.add(sgtInfo);
+            }
+        } catch (XPathExpressionException e) {
+            LOG.warn("failed to parse all-sgt response", e);
+        }
+
+        return sgtInfos;
+    }
+
+    /**
+     * @return initiated xpath with ise namespace context injected
+     */
+    private static XPath setupXpath() {
+        final NamespaceContext nsContext = new NamespaceContext() {
+            public String getNamespaceURI(String prefix) {
+                final String outcome;
+                if (prefix == null) {
+                    throw new NullPointerException("Null prefix");
+                }
+
+                if ("ns5".equals(prefix)) {
+                    outcome = "ers.ise.cisco.com";
+                } else if ("ns3".equals(prefix)) {
+                    outcome = "v2.ers.ise.cisco.com";
+                } else if ("ns4".equals(prefix)) {
+                    outcome = "trustsec.ers.ise.cisco.com";
+                } else {
+                    outcome = XMLConstants.NULL_NS_URI;
+                }
+                return outcome;
+            }
+
+            // This method isn't necessary for XPath processing.
+            public String getPrefix(String uri) {
+                throw new UnsupportedOperationException();
+            }
+
+            // This method isn't necessary for XPath processing either.
+            public Iterator getPrefixes(String uri) {
+                throw new UnsupportedOperationException();
+            }
+        };
+
+        XPath xpath = XPathFactory.newInstance().newXPath();
+        xpath.setNamespaceContext(nsContext);
+        return xpath;
+    }
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtInfo.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtInfo.java
new file mode 100644 (file)
index 0000000..015e282
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+
+/**
+ * Purpose: simple holder for {@link Sgt} and name
+ */
+public class SgtInfo {
+
+    private final Sgt sgt;
+    private final String name;
+
+    /**
+     * @param sgt  value to hold
+     * @param name value to hold
+     */
+    public SgtInfo(@Nonnull final Sgt sgt, @Nullable final String name) {
+        this.sgt = sgt;
+        this.name = name;
+    }
+
+    /**
+     * @return sgt
+     */
+    public Sgt getSgt() {
+        return sgt;
+    }
+
+    /**
+     * @return name associated to sgt
+     */
+    public String getName() {
+        return name;
+    }
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtInfoProcessor.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtInfoProcessor.java
new file mode 100644 (file)
index 0000000..e281515
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import java.util.List;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+
+/**
+ * Purpose: process given sgt+name
+ */
+public interface SgtInfoProcessor {
+
+    /**
+     * @param tenant   shared by all processed epgs
+     * @param sgtInfos list of sgts to process
+     * @return outcome of dataStore write operation
+     */
+    CheckedFuture<Void, TransactionCommitFailedException> processSgtInfo(final TenantId tenant, List<SgtInfo> sgtInfos);
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEPTemplateGeneratorImpl.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEPTemplateGeneratorImpl.java
new file mode 100644 (file)
index 0000000..c5521e3
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import java.util.Collections;
+import java.util.List;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+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.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.SxpMapper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgtBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgtKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Purpose: process given sgt+name - create {@link EndpointPolicyTemplateBySgt} and write it to sxp-mapper templates
+ */
+public class SgtToEPTemplateGeneratorImpl implements SgtInfoProcessor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SgtToEPTemplateGeneratorImpl.class);
+
+    private final DataBroker dataBroker;
+
+    public SgtToEPTemplateGeneratorImpl(final DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+    }
+
+    @Override
+    public CheckedFuture<Void, TransactionCommitFailedException> processSgtInfo(final TenantId tenantId, final List<SgtInfo> sgtInfos) {
+        final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
+
+        // write endpoint-policy-templates
+        boolean createParent = true;
+        for (SgtInfo sgtInfo : sgtInfos) {
+            final Sgt sgt = sgtInfo.getSgt();
+            final String sgtName = sgtInfo.getName();
+            LOG.trace("processing sgtInfo: {} - {}", sgt.getValue(), sgtName);
+
+            final EndpointGroupId epgId = new EndpointGroupId(sgtInfo.getName());
+
+            final InstanceIdentifier<EndpointPolicyTemplateBySgt> epPolicyTemplatePath = InstanceIdentifier
+                    .create(SxpMapper.class)
+                    .child(EndpointPolicyTemplateBySgt.class, new EndpointPolicyTemplateBySgtKey(sgt));
+
+            final EndpointPolicyTemplateBySgt epPolicyTemplate = new EndpointPolicyTemplateBySgtBuilder()
+                    .setSgt(sgt)
+                    .setEndpointGroups(Collections.singletonList(epgId))
+                    .setTenant(tenantId)
+                    .build();
+            wTx.put(LogicalDatastoreType.CONFIGURATION, epPolicyTemplatePath, epPolicyTemplate, createParent);
+            createParent = false;
+        }
+        return wTx.submit();
+    }
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEpgGeneratorImpl.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEpgGeneratorImpl.java
new file mode 100644 (file)
index 0000000..3628137
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import java.util.List;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+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.groupbasedpolicy.util.IidFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroupBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Purpose: process given sgt+name - create {@link EndpointGroup} and write it to tenants/tenant/policy/endpoint-group
+ */
+public class SgtToEpgGeneratorImpl implements SgtInfoProcessor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SgtToEpgGeneratorImpl.class);
+
+    private final DataBroker dataBroker;
+
+    public SgtToEpgGeneratorImpl(final DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+    }
+
+    @Override
+    public CheckedFuture<Void, TransactionCommitFailedException> processSgtInfo(final TenantId tenantId, final List<SgtInfo> sgtInfos) {
+        final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
+
+        // create and write endpointgroups
+        boolean createParent = true;
+        for (SgtInfo sgtInfo : sgtInfos) {
+            final Integer sgtValue = sgtInfo.getSgt().getValue();
+            final String sgtName = sgtInfo.getName();
+            LOG.trace("processing sgtInfo: {} - {}", sgtValue, sgtName);
+
+            final EndpointGroupId epgId = new EndpointGroupId(sgtName);
+            final InstanceIdentifier<EndpointGroup> epgPath = IidFactory.endpointGroupIid(tenantId, epgId);
+            final EndpointGroup epg = new EndpointGroupBuilder()
+                    .setId(epgId)
+                    .setDescription(new Description("imported from ISE for sgt=" + sgtValue))
+                    .setName(new Name(sgtName.replaceAll(" ", "_") + "--" + sgtValue))
+                    .build();
+            wTx.put(LogicalDatastoreType.CONFIGURATION, epgPath, epg, createParent);
+            createParent = false;
+        }
+        return wTx.submit();
+    }
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/util/RestClientFactory.java b/groupbasedpolicy-ise-adapter/src/main/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/util/RestClientFactory.java
new file mode 100644 (file)
index 0000000..26cc304
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl.util;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+import com.sun.jersey.client.urlconnection.HTTPSProperties;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import org.apache.commons.net.util.TrustManagerUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.ise.harvest.config.ConnectionConfig;
+
+/**
+ * Purpose: setup ise-ready jersey {@link Client}
+ */
+public class RestClientFactory {
+
+    private RestClientFactory() {
+        throw new IllegalAccessError("factory class - no instances supported");
+    }
+
+    /**
+     * @param connectionConfig config provided
+     * @return initiated jersey client - ready to talk to ise
+     *
+     * @throws GeneralSecurityException in case when insecure certificate hack fails
+     */
+    public static Client createIseClient(final ConnectionConfig connectionConfig) throws GeneralSecurityException {
+        final DefaultClientConfig clientConfig = new DefaultClientConfig();
+        clientConfig.getProperties()
+                .put(ClientConfig.PROPERTY_CONNECT_TIMEOUT, connectionConfig.getConnectionTimeout());
+        clientConfig.getProperties()
+                .put(ClientConfig.PROPERTY_READ_TIMEOUT, connectionConfig.getReadTimeout());
+
+        hackInsecureCertificate(clientConfig);
+        return Client.create(clientConfig);
+    }
+
+    private static void hackInsecureCertificate(final ClientConfig clientConfigArg)
+            throws NoSuchAlgorithmException, KeyManagementException {
+        final TrustManager[] trustAllCerts = new TrustManager[]{TrustManagerUtils.getAcceptAllTrustManager()};
+
+        SSLContext sslContext = SSLContext.getInstance("SSL");
+        sslContext.init(null, trustAllCerts, null);
+
+        clientConfigArg.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(
+                (s, sslSession) -> true,
+                sslContext
+        ));
+    }
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/yang/gbp-ise-adapter-cfg.yang b/groupbasedpolicy-ise-adapter/src/main/yang/gbp-ise-adapter-cfg.yang
new file mode 100644 (file)
index 0000000..90548b0
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+module gbp-ise-adapter-cfg {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy:gbp-ise-adapter";
+    prefix "gpb-ise-adapter-cfg";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+
+    description
+        "This module contains the base YANG definitions for
+          gbp-ise-adapter impl configuration.";
+
+    revision "2016-06-30" {
+        description
+            "Initial revision.";
+    }
+
+    identity gbp-ise-adapter-impl {
+        description
+            "gbp-ise-adapter impl module";
+
+        base "config:module-type";
+        config:java-name-prefix GpbIseAdapterProvider;
+    }
+
+    // Augments the 'configuration' choice node under modules/module.
+    augment "/config:modules/config:module/config:configuration" {
+        case gbp-ise-adapter-impl {
+            when "/config:modules/config:module/config:type = 'gbp-ise-adapter-impl'";
+
+            //wires in the data-broker service
+            container data-broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-async-data-broker;
+                    }
+                }
+            }
+
+            container broker {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-broker-osgi-registry;
+                    }
+                }
+            }
+
+        }
+    }
+}
diff --git a/groupbasedpolicy-ise-adapter/src/main/yang/gbp-ise-adapter-model.yang b/groupbasedpolicy-ise-adapter/src/main/yang/gbp-ise-adapter-model.yang
new file mode 100644 (file)
index 0000000..bc59cc5
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+module gbp-ise-adapter-model {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:groupbasedpolicy:gbp-ise-adapter:model";
+    prefix "gbp-ise-adapter-model";
+
+    import gbp-common { prefix gbp-common; revision-date 2014-04-21; }
+    import ietf-inet-types { prefix inet; revision-date 2010-09-24; }
+    import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
+
+    description
+        "This module contains the YANG definitions for
+          gbp-ise-adapter implementation.";
+
+    revision "2016-06-30" {
+        description
+            "Initial revision.";
+    }
+
+    container gbp-ise-adapter {
+        description "root point for ise connection info and sgt harvest status";
+
+        container ise-harvest-config {
+            description "connection + credentials for ise-rest-api connection and target tennant";
+            config true;
+
+            leaf tenant {
+               type gbp-common:tenant-id;
+               mandatory true;
+               description
+                    "tenant for all extracted sgt";
+            }
+
+            container connection-config {
+                description "rest connection configuration part";
+
+                leaf ise-rest-url {
+                    description "base uri to ise-rest-api";
+                    mandatory true;
+                    type inet:uri;
+                }
+
+                leaf connection-timeout {
+                    description "connection timeout in milliseconds";
+                    type uint16;
+                    default 5000;
+                }
+
+                leaf read-timeout {
+                    description "read from rest timeout in milliseconds";
+                    type uint16;
+                    default 5000;
+                }
+
+                list header {
+                    description "request headers in form key+value";
+                    key name;
+
+                    leaf name {
+                        type string;
+                    }
+                    leaf value {
+                        type string;
+                    }
+                }
+            }
+        }
+
+        container ise-harvest-status {
+            description "result of sgt harvest from ise-rest-api and generating endpoint policy templates";
+            config false;
+
+            leaf success {
+                description "true if all operations succeeded";
+                type boolean;
+            }
+
+            leaf reason {
+                description "failure detail";
+                type string;
+            }
+
+            leaf templates-written {
+                description "amount of endpoint templates written";
+                type uint16;
+            }
+
+            leaf timestamp {
+                description "stamped upon sgts harvested and templates written";
+                type yang:date-and-time;
+            }
+        }
+    }
+}
diff --git a/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseAdapterProviderTest.java b/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseAdapterProviderTest.java
new file mode 100644 (file)
index 0000000..236195d
--- /dev/null
@@ -0,0 +1,75 @@
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import static org.powermock.api.mockito.PowerMockito.verifyNew;
+import static org.powermock.api.mockito.PowerMockito.whenNew;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestConfig;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+/**
+ * Purpose: cover {@link GbpIseAdapterProvider}
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({GbpIseAdapterProvider.class})
+public class GbpIseAdapterProviderTest {
+
+    @Mock
+    private DataBroker dataBroker;
+    @Mock
+    private BindingAwareBroker broker;
+    @Mock
+    private BindingAwareBroker.ProviderContext providerContext;
+    @Mock
+    private ListenerRegistration<GbpIseConfigListener> registration;
+    @Mock
+    private SgtToEpgGeneratorImpl generator1;
+    @Mock
+    private SgtToEPTemplateGeneratorImpl generator2;
+    @Mock
+    private GbpIseSgtHarvesterImpl harvester;
+    @Mock
+    private GbpIseConfigListenerImpl listener;
+
+    private GbpIseAdapterProvider provider;
+
+    @Before
+    public void setUp() throws Exception {
+        provider = new GbpIseAdapterProvider(dataBroker, broker);
+        Mockito.verify(broker).registerProvider(provider);
+    }
+
+    @Test
+    public void testOnSessionInitiated() throws Exception {
+        Mockito.when(dataBroker.registerDataTreeChangeListener(
+                Matchers.<DataTreeIdentifier<IseHarvestConfig>>any(),
+                Matchers.<GbpIseConfigListener>any())).thenReturn(registration);
+
+        // prepare expectation for objects in onSessionInitiated (powerMock requirement for later checking)
+        whenNew(SgtToEpgGeneratorImpl.class).withAnyArguments().thenReturn(generator1);
+        whenNew(SgtToEPTemplateGeneratorImpl.class).withAnyArguments().thenReturn(generator2);
+        whenNew(GbpIseSgtHarvesterImpl.class).withArguments(generator1, generator2).thenReturn(harvester);
+        whenNew(GbpIseConfigListenerImpl.class).withAnyArguments().thenReturn(listener);
+        provider.onSessionInitiated(providerContext);
+
+        // check if all expected object got constructed and wired
+        verifyNew(SgtToEpgGeneratorImpl.class).withArguments(dataBroker);
+        verifyNew(SgtToEPTemplateGeneratorImpl.class).withArguments(dataBroker);
+        verifyNew(GbpIseSgtHarvesterImpl.class).withArguments(generator1, generator2);
+        verifyNew(GbpIseConfigListenerImpl.class).withArguments(dataBroker, harvester);
+
+        // close provider check
+        provider.close();
+        Mockito.verify(registration).close();
+    }
+}
\ No newline at end of file
diff --git a/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseConfigListenerImplTest.java b/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseConfigListenerImplTest.java
new file mode 100644 (file)
index 0000000..105c3cb
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import com.google.common.util.concurrent.Futures;
+import java.util.Collections;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestStatus;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Test for {@link GbpIseConfigListenerImpl}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class GbpIseConfigListenerImplTest {
+
+    @Mock
+    private DataBroker dataBroker;
+    @Mock
+    private GbpIseSgtHarvester harvester;
+    @Mock
+    private DataTreeModification<IseHarvestConfig> treeModification;
+    @Mock
+    private DataObjectModification<IseHarvestConfig> dataModification;
+    @Mock
+    private WriteTransaction wTx;
+    @Mock
+    private IseHarvestConfig config;
+
+    private GbpIseConfigListenerImpl listener;
+
+    @Before
+    public void setUp() throws Exception {
+        listener = new GbpIseConfigListenerImpl(dataBroker, harvester);
+    }
+
+    @Test
+    public void testOnDataTreeChanged_noop() throws Exception {
+        Mockito.when(dataModification.getDataAfter()).thenReturn(null);
+        Mockito.when(treeModification.getRootNode()).thenReturn(dataModification);
+
+        listener.onDataTreeChanged(Collections.singleton(treeModification));
+        Mockito.verifyNoMoreInteractions(harvester, dataBroker);
+    }
+
+    @Test
+    public void testOnDataTreeChanged_succeeded() throws Exception {
+        Mockito.when(dataModification.getDataAfter()).thenReturn(config);
+        Mockito.when(treeModification.getRootNode()).thenReturn(dataModification);
+
+        Mockito.when(harvester.harvest(config)).thenReturn(Futures.immediateFuture(42));
+
+        Mockito.when(wTx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
+        Mockito.when(dataBroker.newWriteOnlyTransaction()).thenReturn(wTx);
+
+        listener.onDataTreeChanged(Collections.singleton(treeModification));
+        listener.close();
+
+        final InOrder inOrder = Mockito.inOrder(harvester, dataBroker, wTx);
+        inOrder.verify(harvester).harvest(config);
+        inOrder.verify(dataBroker).newWriteOnlyTransaction();
+        inOrder.verify(wTx).put(Matchers.eq(LogicalDatastoreType.OPERATIONAL),
+                Matchers.<InstanceIdentifier<IseHarvestStatus>>any(),
+                Matchers.<IseHarvestStatus>any(),
+                Matchers.eq(true));
+        inOrder.verify(wTx).submit();
+        inOrder.verifyNoMoreInteractions();
+    }
+
+    @Test
+    public void testOnDataTreeChanged_failed() throws Exception {
+        Mockito.when(dataModification.getDataAfter()).thenReturn(config);
+        Mockito.when(treeModification.getRootNode()).thenReturn(dataModification);
+
+        Mockito.when(harvester.harvest(config)).thenReturn(Futures.immediateFailedFuture(
+                new Exception("extremely poor harvest occurred")));
+
+        Mockito.when(wTx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
+        Mockito.when(dataBroker.newWriteOnlyTransaction()).thenReturn(wTx);
+
+        listener.onDataTreeChanged(Collections.singleton(treeModification));
+        listener.close();
+
+        final InOrder inOrder = Mockito.inOrder(harvester, dataBroker, wTx);
+        inOrder.verify(harvester).harvest(config);
+        inOrder.verify(dataBroker).newWriteOnlyTransaction();
+        inOrder.verify(wTx).put(Matchers.eq(LogicalDatastoreType.OPERATIONAL),
+                Matchers.<InstanceIdentifier<IseHarvestStatus>>any(),
+                Matchers.<IseHarvestStatus>any(),
+                Matchers.eq(true));
+        inOrder.verify(wTx).submit();
+        inOrder.verifyNoMoreInteractions();
+    }
+}
\ No newline at end of file
diff --git a/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseSgtHarvesterImplTest.java b/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/GbpIseSgtHarvesterImplTest.java
new file mode 100644 (file)
index 0000000..85212b6
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import static org.powermock.api.support.membermodification.MemberMatcher.method;
+import static org.powermock.api.support.membermodification.MemberModifier.stub;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl.util.RestClientFactory;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.IseHarvestConfigBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.ise.harvest.config.ConnectionConfigBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.ise.harvest.config.connection.config.HeaderBuilder;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test for {@link GbpIseSgtHarvesterImpl}.
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({RestClientFactory.class})
+public class GbpIseSgtHarvesterImplTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GbpIseSgtHarvesterImplTest.class);
+
+    public static final TenantId TENANT_ID = new TenantId("unit-tenant-id-1");
+    public static final Uri ISE_REST_URL = new Uri("https://example.org:9060");
+    public final String iseReplyAllSgts;
+    public final String iseReplySgtDetail;
+
+    @Mock
+    private SgtInfoProcessor processor;
+    @Mock
+    private Client client;
+    @Mock
+    private WebResource webResource;
+    @Mock
+    private WebResource.Builder builder;
+    @Mock
+    private ClientResponse response;
+
+    private IseHarvestConfig config;
+
+    private GbpIseSgtHarvesterImpl harvester;
+
+    public GbpIseSgtHarvesterImplTest() throws IOException {
+        iseReplyAllSgts = readLocalResource("./rawIse-allSgts.xml");
+        iseReplySgtDetail = readLocalResource("./rawIse-sgtDetail.xml");
+    }
+
+    private static String readLocalResource(final String resourcePath) throws IOException {
+        final StringBuilder collector = new StringBuilder();
+        try (
+                final InputStream iseReplySource = GbpIseSgtHarvesterImplTest.class.getResourceAsStream(resourcePath);
+                final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(iseReplySource))
+        ) {
+            String line;
+            while ((line = bufferedReader.readLine()) != null) {
+                collector.append(line);
+            }
+        }
+        return collector.toString();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        config = new IseHarvestConfigBuilder()
+                .setTenant(TENANT_ID)
+                .setConnectionConfig(new ConnectionConfigBuilder()
+                        .setConnectionTimeout(10)
+                        .setReadTimeout(20)
+                        .setHeader(Collections.singletonList(new HeaderBuilder()
+                                .setName("hName")
+                                .setValue("hValue")
+                                .build()))
+                        .setIseRestUrl(ISE_REST_URL)
+                        .build())
+                .build();
+
+        harvester = new GbpIseSgtHarvesterImpl(processor);
+    }
+
+    @Test
+    public void testHarvest() throws Exception {
+        Mockito.when(response.getEntity(String.class)).thenReturn(iseReplyAllSgts, iseReplySgtDetail);
+        Mockito.when(builder.get(Matchers.<Class<ClientResponse>>any())).thenReturn(response);
+        Mockito.when(webResource.getRequestBuilder()).thenReturn(builder);
+        Mockito.when(webResource.path(Matchers.anyString())).thenReturn(webResource);
+        Mockito.when(client.resource(Matchers.<String>any())).thenReturn(webResource);
+        stub(method(RestClientFactory.class, "createIseClient")).toReturn(client);
+
+        Mockito.when(processor.processSgtInfo(Matchers.eq(TENANT_ID), Matchers.<List<SgtInfo>>any())).thenReturn(
+                Futures.immediateCheckedFuture(null));
+
+        final ListenableFuture<Integer> harvestResult = harvester.harvest(config);
+
+        final InOrder inOrder = Mockito.inOrder(client, webResource, builder);
+        inOrder.verify(client).resource(ISE_REST_URL.getValue());
+        // all sgts
+        inOrder.verify(webResource).path("/ers/config/sgt");
+        inOrder.verify(webResource).getRequestBuilder();
+        inOrder.verify(builder).header(Matchers.anyString(),Matchers.anyString());
+        inOrder.verify(builder).get(ClientResponse.class);
+        // sgt detail
+        inOrder.verify(webResource).path("/ers/config/sgt/abc123");
+        inOrder.verify(webResource).getRequestBuilder();
+        inOrder.verify(builder).header(Matchers.anyString(),Matchers.anyString());
+        inOrder.verify(builder).get(ClientResponse.class);
+        inOrder.verifyNoMoreInteractions();
+
+        final Integer count = harvestResult.get(2, TimeUnit.SECONDS);
+        Assert.assertEquals(1, count.intValue());
+    }
+}
\ No newline at end of file
diff --git a/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEPTemplateGeneratorImplTest.java b/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEPTemplateGeneratorImplTest.java
new file mode 100644 (file)
index 0000000..6f6f0bb
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+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.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.SxpMapper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgtBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointPolicyTemplateBySgtKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+/**
+ * Test for {@link SgtToEPTemplateGeneratorImpl}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class SgtToEPTemplateGeneratorImplTest {
+
+    public static final TenantId TENANT_ID = new TenantId("tenant-unit-1");
+    public static final Sgt SGT_1 = new Sgt(1);
+    public static final String EPG_NAME_1 = "epg-unit-1";
+    public static final Sgt SGT_2 = new Sgt(2);
+    public static final String EPG_NAME_2 = "epg-unit-2";
+
+    @Mock
+    private DataBroker dataBroker;
+    @Mock
+    private WriteTransaction wTx;
+
+    private SgtToEPTemplateGeneratorImpl generator;
+
+    @Before
+    public void setUp() throws Exception {
+        Mockito.when(wTx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
+        Mockito.when(dataBroker.newWriteOnlyTransaction()).thenReturn(wTx);
+        generator = new SgtToEPTemplateGeneratorImpl(dataBroker);
+    }
+
+    @Test
+    public void testProcessSgtInfo() throws Exception {
+        final SgtInfo sgtInfo1 = new SgtInfo(SGT_1, EPG_NAME_1);
+        final SgtInfo sgtInfo2 = new SgtInfo(SGT_2, EPG_NAME_2);
+
+        final CheckedFuture<Void, TransactionCommitFailedException> outcome =
+                generator.processSgtInfo(TENANT_ID, Lists.newArrayList(sgtInfo1, sgtInfo2));
+
+        outcome.get(10, TimeUnit.SECONDS);
+
+        final KeyedInstanceIdentifier<EndpointPolicyTemplateBySgt, EndpointPolicyTemplateBySgtKey> epTemplatePath1 =
+                InstanceIdentifier.create(SxpMapper.class)
+                        .child(EndpointPolicyTemplateBySgt.class, new EndpointPolicyTemplateBySgtKey(SGT_1));
+        final EndpointPolicyTemplateBySgt epTemplate1 = new EndpointPolicyTemplateBySgtBuilder()
+                .setSgt(SGT_1)
+                .setEndpointGroups(Collections.singletonList(new EndpointGroupId(EPG_NAME_1)))
+                .setTenant(TENANT_ID)
+                .build();
+
+        final KeyedInstanceIdentifier<EndpointPolicyTemplateBySgt, EndpointPolicyTemplateBySgtKey> epTemplatePath2 =
+                InstanceIdentifier.create(SxpMapper.class)
+                        .child(EndpointPolicyTemplateBySgt.class, new EndpointPolicyTemplateBySgtKey(SGT_2));
+        final EndpointPolicyTemplateBySgt epTemplate2 = new EndpointPolicyTemplateBySgtBuilder()
+                .setSgt(SGT_2)
+                .setEndpointGroups(Collections.singletonList(new EndpointGroupId(EPG_NAME_2)))
+                .setTenant(TENANT_ID)
+                .build();
+
+
+        final InOrder inOrder = Mockito.inOrder(wTx);
+        inOrder.verify(wTx, Mockito.calls(1)).put(LogicalDatastoreType.CONFIGURATION, epTemplatePath1, epTemplate1, true);
+        inOrder.verify(wTx, Mockito.calls(1)).put(LogicalDatastoreType.CONFIGURATION, epTemplatePath2, epTemplate2, false);
+        inOrder.verify(wTx).submit();
+
+        Mockito.verifyZeroInteractions(wTx);
+
+    }
+}
\ No newline at end of file
diff --git a/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEpgGeneratorImplTest.java b/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/SgtToEpgGeneratorImplTest.java
new file mode 100644 (file)
index 0000000..415e35f
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import java.util.concurrent.TimeUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+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.groupbasedpolicy.util.IidFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Test for {@link SgtToEpgGeneratorImpl}.
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class SgtToEpgGeneratorImplTest {
+
+    public static final TenantId TENANT_ID = new TenantId("tenant-unit-1");
+    public static final Sgt SGT_1 = new Sgt(1);
+    public static final String EPG_NAME_1 = "epg-unit-1";
+    public static final Sgt SGT_2 = new Sgt(2);
+    public static final String EPG_NAME_2 = "epg-unit-2";
+
+    @Mock
+    private DataBroker dataBroker;
+    @Mock
+    private WriteTransaction wTx;
+
+    private SgtToEpgGeneratorImpl generator;
+
+    @Before
+    public void setUp() throws Exception {
+        Mockito.when(wTx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
+        Mockito.when(dataBroker.newWriteOnlyTransaction()).thenReturn(wTx);
+        generator = new SgtToEpgGeneratorImpl(dataBroker);
+    }
+
+    @Test
+    public void testProcessSgtInfo() throws Exception {
+        final SgtInfo sgtInfo1 = new SgtInfo(SGT_1, EPG_NAME_1);
+        final SgtInfo sgtInfo2 = new SgtInfo(SGT_2, EPG_NAME_2);
+
+        final CheckedFuture<Void, TransactionCommitFailedException> outcome =
+                generator.processSgtInfo(TENANT_ID, Lists.newArrayList(sgtInfo1, sgtInfo2));
+
+        outcome.get(10, TimeUnit.SECONDS);
+
+        final EndpointGroupId epgId1 = new EndpointGroupId(EPG_NAME_1);
+        final InstanceIdentifier<EndpointGroup> epgPath1 = IidFactory.endpointGroupIid(TENANT_ID, epgId1);
+        final EndpointGroup epg1 = createEpg(epgId1, SGT_1.getValue());
+
+        final EndpointGroupId epgId2 = new EndpointGroupId(EPG_NAME_2);
+        final InstanceIdentifier<EndpointGroup> epgPath2 = IidFactory.endpointGroupIid(TENANT_ID, epgId2);
+        final EndpointGroup epg2 = createEpg(epgId2, SGT_2.getValue());
+
+        final InOrder inOrder = Mockito.inOrder(wTx);
+        inOrder.verify(wTx, Mockito.calls(1)).put(LogicalDatastoreType.CONFIGURATION, epgPath1, epg1, true);
+        inOrder.verify(wTx, Mockito.calls(1)).put(LogicalDatastoreType.CONFIGURATION, epgPath2, epg2, false);
+        inOrder.verify(wTx).submit();
+
+        Mockito.verifyZeroInteractions(wTx);
+    }
+
+    private EndpointGroup createEpg(final EndpointGroupId epgId1, final int sgt) {
+        final String epgIdValue = epgId1.getValue();
+        return new EndpointGroupBuilder()
+                .setId(epgId1)
+                .setName(new Name(epgIdValue + "--"+sgt))
+                .setDescription(new Description("imported from ISE for sgt="+sgt))
+                .build();
+    }
+}
\ No newline at end of file
diff --git a/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/util/RestClientFactoryTest.java b/groupbasedpolicy-ise-adapter/src/test/java/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/util/RestClientFactoryTest.java
new file mode 100644 (file)
index 0000000..3a2d69a
--- /dev/null
@@ -0,0 +1,42 @@
+package org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl.util;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.client.urlconnection.HTTPSProperties;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.ise.harvest.config.ConnectionConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.gbp.ise.adapter.model.rev160630.gbp.ise.adapter.ise.harvest.config.ConnectionConfigBuilder;
+
+import javax.net.ssl.SSLSession;
+import java.util.Map;
+
+/**
+ * Purpose: cover {@link RestClientFactory}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class RestClientFactoryTest {
+
+    @Mock
+    private SSLSession sslSession;
+
+    @Test
+    public void testCreateIseClient() throws Exception {
+        ConnectionConfig connectionConfig = new ConnectionConfigBuilder()
+                .setConnectionTimeout(1)
+                .setReadTimeout(2)
+                .build();
+
+        final Client iseClient = RestClientFactory.createIseClient(connectionConfig);
+        final Map<String, Object> properties = iseClient.getProperties();
+        Assert.assertEquals(3, properties.size());
+        Assert.assertEquals(1, properties.get("com.sun.jersey.client.property.connectTimeout"));
+        Assert.assertEquals(2, properties.get("com.sun.jersey.client.property.readTimeout"));
+
+        Assert.assertTrue(properties.get(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES) instanceof HTTPSProperties);
+        final HTTPSProperties httpsProperties = (HTTPSProperties) properties.get(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES);
+        Assert.assertTrue(httpsProperties.getHostnameVerifier().verify("xxx", sslSession));
+    }
+}
\ No newline at end of file
diff --git a/groupbasedpolicy-ise-adapter/src/test/resources/log4j.xml b/groupbasedpolicy-ise-adapter/src/test/resources/log4j.xml
new file mode 100644 (file)
index 0000000..3dee945
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!--\r
+  ~ Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.\r
+  ~\r
+  ~ This program and the accompanying materials are made available under the\r
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html\r
+  -->\r
+\r
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">\r
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">\r
+\r
+    <appender name="console" class="org.apache.log4j.ConsoleAppender">\r
+        <layout class="org.apache.log4j.PatternLayout">\r
+            <param name="ConversionPattern" value="%-6p %d{HH:mm:ss.SSS} [%10.10t] %30.30c %x - %m%n"/>\r
+        </layout>\r
+        <!--         <param name="Threshold" value="DEBUG" /> -->\r
+    </appender>\r
+\r
+    <logger name="org.opendaylight.groupbasedpolicy.gbp_ise_adapter.impl" additivity="false">\r
+        <level value="TRACE"/>\r
+        <appender-ref ref="console"/>\r
+    </logger>\r
+\r
+    <root>\r
+        <priority value="INFO"/>\r
+        <appender-ref ref="console"/>\r
+    </root>\r
+</log4j:configuration>\r
diff --git a/groupbasedpolicy-ise-adapter/src/test/resources/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/rawIse-allSgts.xml b/groupbasedpolicy-ise-adapter/src/test/resources/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/rawIse-allSgts.xml
new file mode 100644 (file)
index 0000000..c5dc929
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!--
+  ~ Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+  ~
+  ~ This program and the accompanying materials are made available under the
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+  -->
+
+<ns3:searchResult xmlns:ns5="ers.ise.cisco.com"
+                  xmlns:ns3="v2.ers.ise.cisco.com"
+                  total="1">
+    <ns3:nextPage rel="next" href="" type="application/xml"/>
+    <ns3:resources>
+        <ns5:resource description="" id="abc123" name="boss_group">
+            <link rel="self" href="https://example.org:9060/ers/config/sgt/abc123" type="application/xml"/>
+        </ns5:resource>
+    </ns3:resources>
+</ns3:searchResult>
diff --git a/groupbasedpolicy-ise-adapter/src/test/resources/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/rawIse-sgtDetail.xml b/groupbasedpolicy-ise-adapter/src/test/resources/org/opendaylight/groupbasedpolicy/gbp_ise_adapter/impl/rawIse-sgtDetail.xml
new file mode 100644 (file)
index 0000000..7d3b880
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!--
+  ~ Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+  ~
+  ~ This program and the accompanying materials are made available under the
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+  -->
+
+<ns4:sgt xmlns:ers="ers.ise.cisco.com"
+         xmlns:xs="http://www.w3.org/2001/XMLSchema"
+         xmlns:ns4="trustsec.ers.ise.cisco.com"
+         description=""
+         id="abc123"
+         name="boss-group">
+    <link rel="self" href="https://example.com:9060/ers/config/sgt/abc123" type="application/xml"/>
+    <generationId>0</generationId>
+    <value>42</value>
+</ns4:sgt>
index 50752b0589ac8e36dad9ec241b8061154d96c4da..27ccd904b3455f33299e9002c26063ccff60fe2a 100644 (file)
@@ -25,6 +25,7 @@
       <groupId>org.opendaylight.groupbasedpolicy</groupId>
       <artifactId>groupbasedpolicy-ui-module</artifactId>
       <version>${project.version}</version>
+      <scope>provided</scope>
     </dependency>
   </dependencies>
  <build>
index 6200db755446ad6199220280c7379ff60b855af7..0b278565ec342fefb73f81403095abc12647b9ed 100644 (file)
@@ -232,7 +232,9 @@ public class RendererManager implements AutoCloseable {
                         && renderer.getRendererPolicy().getVersion().equals(version)) {
                     processingRenderers.remove(configuredRenderer);
                     Status status = rendererPolicy.getStatus();
-                    if (status != null && status.getUnconfiguredEndpoints() != null) {
+                    if (status != null && status.getUnconfiguredEndpoints() != null
+                            && status.getUnconfiguredEndpoints().getUnconfiguredRendererEndpoint() != null
+                            && !status.getUnconfiguredEndpoints().getUnconfiguredRendererEndpoint().isEmpty()) {
                         LOG.warn("Renderer {} did not configure policy with version {} successfully. \n{}",
                                 configuredRenderer.getValue(), version, status);
                     } else {
diff --git a/pom.xml b/pom.xml
index ba05e3a48344d403b6649fb115a5d3c80da6c10c..90e1c4fd0671d70ba8b3b8d30c589ef15b81c15c 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -35,6 +35,7 @@
     <module>distribution-karaf</module>
     <module>features</module>
     <module>sxp-mapper</module>
+    <module>groupbasedpolicy-ise-adapter</module>
   </modules>
 
   <build>
index 5a202ce5ecf4eeebe69adedfefcef1d2b8636d04..e69a690817c7dbbaad50b6cfd9f78e0a112764a2 100644 (file)
@@ -38,9 +38,13 @@ import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev1407
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.CreateRenderedPathInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePath;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocator;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.sff.data.plane.locator.DataPlaneLocator;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.LocatorType;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.Ip;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.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.ios.rev160308.Native;
@@ -53,8 +57,6 @@ import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePath;
 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathBuilder;
 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathKey;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.Local;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.LocalBuilder;
 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameBuilder;
 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameKey;
 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.path.ConfigServiceChainPathModeBuilder;
@@ -73,7 +75,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.security.cert.PKIXRevocationChecker;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -258,39 +259,6 @@ public class ServiceChainingUtil {
         return reversedRenderedPath;
     }
 
-    /**
-     * Method checks up, whether a {@link Local} Service Function Forwarder is present on device or not.
-     *
-     * @param mountpoint used to access specific device
-     * @return true if Local Forwarder is present, false otherwise
-     */
-    private static boolean checkLocalForwarderPresence(DataBroker mountpoint) {
-        InstanceIdentifier<Local> localSffIid = InstanceIdentifier.builder(Native.class)
-                .child(ServiceChain.class)
-                .child(org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServiceFunctionForwarder.class)
-                .child(Local.class).build();
-        try {
-            java.util.Optional<ReadOnlyTransaction> optionalTransaction =
-                    NetconfTransactionCreator.netconfReadOnlyTransaction(mountpoint);
-            if (!optionalTransaction.isPresent()) {
-                LOG.warn("Failed to create transaction, mountpoint: {}", mountpoint);
-                return false;
-            }
-            ReadOnlyTransaction transaction = optionalTransaction.get();
-            CheckedFuture<Optional<Local>, ReadFailedException> submitFuture =
-                    transaction.read(LogicalDatastoreType.CONFIGURATION,
-                    localSffIid);
-            Optional<Local> optionalLocalSff = submitFuture.checkedGet();
-            transaction.close(); // Release lock
-            return optionalLocalSff.isPresent();
-        } catch (ReadFailedException e) {
-            LOG.warn("Read transaction failed to {} ", e);
-        } catch (Exception e) {
-            LOG.error("Failed to .. {}", e.getMessage());
-        }
-        return false;
-    }
-
     /**
      * Method checks up, if some {@link ServicePath} is present on device.
      *
@@ -353,11 +321,6 @@ public class ServiceChainingUtil {
 
     static boolean setSfcPart(final ServiceFunctionPath serviceFunctionPath, final RenderedServicePath renderedServicePath,
                               final RenderedServicePath reversedRenderedServicePath, PolicyWriter policyWriter) {
-        if (!checkLocalForwarderPresence(policyWriter.getCurrentMountpoint())) {
-            appendLocalSff(policyWriter);
-        } else {
-            LOG.info("Local forwarder for node {} is already created", policyWriter.getCurrentNodeId());
-        }
         boolean outcome = true;
         // Direct path
         final java.util.Optional<RenderedServicePath> renderedServicePathSafe = java.util.Optional.ofNullable(renderedServicePath);
@@ -367,14 +330,12 @@ public class ServiceChainingUtil {
                 if (!resolveRenderedServicePath(renderedServicePath, policyWriter)) {
                     outcome = false;
                 }
-            }
-            else {
+            } else {
                 LOG.warn("Rendered service path {} does not contain any hop",
                         renderedServicePathSafe.map(RenderedServicePath::getName).map(RspName::getValue).orElse("n/a"));
                 outcome = false;
             }
-        }
-        else {
+        } else {
             LOG.warn("Rendered service path is null");
             outcome = false;
         }
@@ -416,10 +377,30 @@ public class ServiceChainingUtil {
         // forwarder (Remote case)
 
         final java.util.Optional<ServiceFunctionForwarder> serviceFunctionForwarder = java.util.Optional.ofNullable(
-                    SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sffName));
-        return serviceFunctionForwarder.map(sff -> java.util.Optional.ofNullable(IetfModelCodec.ipAddress2010(sff.getIpMgmtAddress()))
-                    .map(IpAddress::getIpv4Address)
-                    .map((ipv4Address) -> ipv4Address.getValue())
+                SfcProviderServiceForwarderAPI.readServiceFunctionForwarder(sffName));
+        if (!serviceFunctionForwarder.isPresent()) {
+            LOG.warn("Service function forwarder {} does not exist", sffName.getValue());
+            return false;
+        }
+        final ServiceFunctionForwarder forwarder = serviceFunctionForwarder.get();
+        if (forwarder.getSffDataPlaneLocator() == null || forwarder.getSffDataPlaneLocator().isEmpty()) {
+            LOG.warn("Service function forwarder {} does not contain data plane locator", sffName.getValue());
+            return false;
+        }
+        // TODO only first dpl resolved
+        final SffDataPlaneLocator sffDataPlaneLocator = forwarder.getSffDataPlaneLocator().get(0);
+        final DataPlaneLocator dataPlaneLocator = sffDataPlaneLocator.getDataPlaneLocator();
+        final LocatorType locatorType = dataPlaneLocator.getLocatorType();
+        if (locatorType != null && locatorType instanceof Ip) {
+            final IpAddress remoteForwarderIpAddress = IetfModelCodec.ipAddress2010(((Ip) locatorType).getIp());
+            if (remoteForwarderIpAddress == null || remoteForwarderIpAddress.getIpv4Address() == null) {
+                LOG.warn("Service function forwarder {} data plane locator does not contain ip address", sffName.getValue());
+                return false;
+            }
+            final String remoteForwarderStringIp = remoteForwarderIpAddress.getIpv4Address().getValue();
+            return serviceFunctionForwarder.map(sff -> java.util.Optional.ofNullable(sff.getIpMgmtAddress())
+                    .map(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress::getIpv4Address)
+                    .map(Ipv4Address::getValue)
                     .map(addressValue -> {
                         // Set up choice. If remote, this choice is overwritten
                         final ServiceTypeChoice serviceTypeChoice;
@@ -427,7 +408,7 @@ public class ServiceChainingUtil {
                             final ServiceFfNameBuilder remoteSffBuilder = new ServiceFfNameBuilder();
                             remoteSffBuilder.setName(sffName.getValue())
                                     .setKey(new ServiceFfNameKey(sffName.getValue()))
-                                    .setIp(new IpBuilder().setAddress(new Ipv4Address(addressValue)).build());
+                                    .setIp(new IpBuilder().setAddress(new Ipv4Address(remoteForwarderStringIp)).build());
                             policyWriter.cache(remoteSffBuilder.build());
                             serviceTypeChoice = forwarderTypeChoice(sffName.getValue());
                         } else {
@@ -461,13 +442,8 @@ public class ServiceChainingUtil {
             ).orElseGet(createNegativePathWithLogSupplier(sffName.getValue(),
                     (value) -> LOG.error("Sff with name {} does not exist", value))
             );
-    }
-
-    private static void appendLocalSff(final PolicyWriter policyWriter) {
-        final LocalBuilder localSffBuilder = new LocalBuilder();
-        localSffBuilder.setIp(new IpBuilder().setAddress(new Ipv4Address(policyWriter.getManagementIpAddress()))
-                .build());
-        policyWriter.cache(localSffBuilder.build());
+        }
+        return false;
     }
 
     static ServiceTypeChoice forwarderTypeChoice(final String forwarderName) {
@@ -485,7 +461,7 @@ public class ServiceChainingUtil {
     private static void checkSfcRspStatus(final RspName rspName, final DataBroker dataBroker) {
         /** TODO A better way to do this is to register listener and wait for notification than using hardcoded timeout
          *  with Thread.sleep(). Example in class BridgeDomainManagerImpl
-        */
+         */
         ConfiguredRenderedPath renderedPath = null;
         LOG.info("Waiting for SFC to configure path {} ...", rspName.getValue());
 
index 67948290eca79871c2c127bb51cf3094cf307709..711b576387913aea454db0ef2def51a85b6a89fe 100644 (file)
@@ -16,7 +16,6 @@ import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFaile
 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain;
 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
-import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.Local;
 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfName;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.slf4j.Logger;
@@ -39,7 +38,6 @@ public class PolicyWriter {
     private final String interfaceName;
     private final String policyMapName;
     private final String managementIpAddress;
-    private Local localForwarder;
 
     public PolicyWriter(final DataBroker dataBroker, final String interfaceName, final String ipAddress,
                         final String policyMapName, final NodeId nodeId) {
@@ -63,10 +61,6 @@ public class PolicyWriter {
         this.policyMapEntries.addAll(policyMapEntries);
     }
 
-    public void cache(Local localForwarder) {
-        this.localForwarder = localForwarder;
-    }
-
     public void cache(ServiceFfName remoteForwarder) {
         remoteForwarders.add(remoteForwarder);
     }
@@ -78,7 +72,6 @@ public class PolicyWriter {
     public CheckedFuture<Boolean, TransactionCommitFailedException> commitToDatastore() {
         LOG.info("Configuring policy on node {} ... ", nodeId.getValue());
         // SFC
-        boolean localResult = PolicyWriterUtil.writeLocal(localForwarder, nodeId, mountpoint);
         boolean remoteResult = PolicyWriterUtil.writeRemote(remoteForwarders, nodeId, mountpoint);
         boolean servicePathsResult = PolicyWriterUtil.writeServicePaths(serviceChains, nodeId, mountpoint);
         // GBP - maintain order!
@@ -87,8 +80,8 @@ public class PolicyWriter {
         boolean interfaceResult = PolicyWriterUtil.writeInterface(policyMapName, interfaceName, nodeId, mountpoint);
         // Result
         LOG.info("Policy configuration on node {} completed", nodeId.getValue());
-        return Futures.immediateCheckedFuture(classMapResult && policyMapResult && interfaceResult && localResult
-                && remoteResult && servicePathsResult);
+        return Futures.immediateCheckedFuture(classMapResult && policyMapResult && interfaceResult && remoteResult
+                && servicePathsResult);
     }
 
     public CheckedFuture<Boolean, TransactionCommitFailedException> removeFromDatastore() {
@@ -100,12 +93,10 @@ public class PolicyWriter {
         // TODO remove class map?
         // SFC
         boolean servicePathsResult = PolicyWriterUtil.removeServicePaths(serviceChains, nodeId, mountpoint);
-        boolean localResult = PolicyWriterUtil.removeLocal(nodeId, mountpoint);
         // TODO remove remote forwarders
         // Result
         LOG.info("Policy removed from node {}", nodeId.getValue());
-        return Futures.immediateCheckedFuture(classMapResult && policyMapEntriesResult && servicePathsResult
-                && localResult);
+        return Futures.immediateCheckedFuture(classMapResult && policyMapEntriesResult && servicePathsResult);
     }
 
     public String getManagementIpAddress() {
index 48cc53a07b62aa11854c2347f6875c36317def59..13c380a2b43d4943bcd9717a79cb54e4c6792f3d 100644 (file)
@@ -14,10 +14,6 @@ import static org.powermock.api.support.membermodification.MemberModifier.stub;
 import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.Futures;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -49,11 +45,14 @@ import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev1407
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.RenderedServicePathBuilder;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHop;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.paths.rendered.service.path.RenderedServicePathHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.SffDataPlaneLocatorBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarder.base.sff.data.plane.locator.DataPlaneLocatorBuilder;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarderBuilder;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPaths;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.ServiceFunctionPathsBuilder;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPathBuilder;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sl.rev140701.data.plane.locator.locator.type.IpBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
@@ -85,6 +84,11 @@ import org.powermock.api.mockito.PowerMockito;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  * Test for {@link ServiceChainingUtil}.
  */
@@ -483,17 +487,22 @@ public class ServiceChainingUtilTest {
     @Test
     public void testSetSfcPart_success() throws Exception {
         final RenderedServicePath rsp = createRsp("unit-rsp-03");
+        final DataPlaneLocatorBuilder dataPlaneLocatorBuilder = new DataPlaneLocatorBuilder();
+        final IpBuilder ipBuilderLocatorType = new IpBuilder();
+        ipBuilderLocatorType.setIp(IetfModelCodec.ipAddress2013(new IpAddress(new Ipv4Address("1.2.3.4"))));
+        dataPlaneLocatorBuilder.setLocatorType(ipBuilderLocatorType.build());
+        final SffDataPlaneLocatorBuilder sffDataPlaneLocatorBuilder = new SffDataPlaneLocatorBuilder();
+        sffDataPlaneLocatorBuilder.setDataPlaneLocator(dataPlaneLocatorBuilder.build());
         final org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder
                 sff = new ServiceFunctionForwarderBuilder()
                 .setName(new SffName("unit-sff-03"))
                 .setIpMgmtAddress(IetfModelCodec.ipAddress2013(new IpAddress(new Ipv4Address("1.2.3.4"))))
+                .setSffDataPlaneLocator(Collections.singletonList(sffDataPlaneLocatorBuilder.build()))
                 .build();
         final ServiceFunctionPathBuilder sfpBuilder = new ServiceFunctionPathBuilder();
         sfpBuilder.setSymmetric(false);
         final ServiceFunctionPath sfp = sfpBuilder.build();
 
-        stub(method(ServiceChainingUtil.class, "checkLocalForwarderPresence")).toReturn(true);
-
         PowerMockito.mockStatic(SfcProviderServiceForwarderAPI.class);
         final SfcProviderServiceForwarderAPI api = PowerMockito.mock(SfcProviderServiceForwarderAPI.class);
         PowerMockito.when(api.readServiceFunctionForwarder(sffNameCaptor.capture())).thenReturn(sff);
@@ -505,8 +514,6 @@ public class ServiceChainingUtilTest {
 
         Mockito.verify(policyWriter).cache(Matchers.<ServiceFfName>any());
         Mockito.verify(policyWriter).cache(Matchers.<ServiceChain>any());
-        Mockito.verify(policyWriter).getCurrentNodeId();
-        Mockito.verify(policyWriter).getCurrentMountpoint();
         Mockito.verify(policyWriter).getManagementIpAddress();
         Mockito.verifyNoMoreInteractions(policyWriter);
     }
@@ -514,17 +521,22 @@ public class ServiceChainingUtilTest {
     @Test
     public void testSetSfcPart_success_newRsp() throws Exception {
         final RenderedServicePath rsp = createRsp("unit-rsp-03");
+        final DataPlaneLocatorBuilder dataPlaneLocatorBuilder = new DataPlaneLocatorBuilder();
+        final IpBuilder ipBuilderLocatorType = new IpBuilder();
+        ipBuilderLocatorType.setIp(IetfModelCodec.ipAddress2013(new IpAddress(new Ipv4Address("1.2.3.4"))));
+        dataPlaneLocatorBuilder.setLocatorType(ipBuilderLocatorType.build());
+        final SffDataPlaneLocatorBuilder sffDataPlaneLocatorBuilder = new SffDataPlaneLocatorBuilder();
+        sffDataPlaneLocatorBuilder.setDataPlaneLocator(dataPlaneLocatorBuilder.build());
         final org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder
                 sff = new ServiceFunctionForwarderBuilder()
                 .setName(new SffName("unit-sff-03"))
                 .setIpMgmtAddress(IetfModelCodec.ipAddress2013(new IpAddress(new Ipv4Address("1.2.3.4"))))
+                .setSffDataPlaneLocator(Collections.singletonList(sffDataPlaneLocatorBuilder.build()))
                 .build();
         final ServiceFunctionPathBuilder sfpBuilder = new ServiceFunctionPathBuilder();
         sfpBuilder.setSymmetric(false);
         final ServiceFunctionPath sfp = sfpBuilder.build();
 
-        stub(method(ServiceChainingUtil.class, "checkLocalForwarderPresence")).toReturn(false);
-
         PowerMockito.mockStatic(SfcProviderServiceForwarderAPI.class);
         final SfcProviderServiceForwarderAPI api = PowerMockito.mock(SfcProviderServiceForwarderAPI.class);
         PowerMockito.when(api.readServiceFunctionForwarder(sffNameCaptor.capture())).thenReturn(sff);
@@ -534,11 +546,9 @@ public class ServiceChainingUtilTest {
         Assert.assertEquals("rsp-hop-01-sf+sff", sffNameCaptor.getValue().getValue());
         Assert.assertTrue(outcome);
 
-        Mockito.verify(policyWriter).cache(Matchers.<Local>any());
         Mockito.verify(policyWriter).cache(Matchers.<ServiceFfName>any());
         Mockito.verify(policyWriter).cache(Matchers.<ServiceChain>any());
-        Mockito.verify(policyWriter).getCurrentMountpoint();
-        Mockito.verify(policyWriter, Mockito.times(2)).getManagementIpAddress();
+        Mockito.verify(policyWriter).getManagementIpAddress();
         Mockito.verifyNoMoreInteractions(policyWriter);
     }
 
@@ -579,9 +589,6 @@ public class ServiceChainingUtilTest {
         Assert.assertEquals("rsp-hop-01-sf+sff", sffNameCaptor.getValue().getValue());
         Assert.assertFalse(outcome);
 
-        Mockito.verify(policyWriter).getCurrentMountpoint();
-        Mockito.verify(policyWriter).getManagementIpAddress();
-        Mockito.verify(policyWriter).cache(Matchers.<Local>any());
         Mockito.verifyNoMoreInteractions(policyWriter);
     }
 
@@ -595,8 +602,6 @@ public class ServiceChainingUtilTest {
         sfpBuilder.setSymmetric(false);
         final ServiceFunctionPath sfp = sfpBuilder.build();
 
-        stub(method(ServiceChainingUtil.class, "checkLocalForwarderPresence")).toReturn(true);
-
         PowerMockito.mockStatic(SfcProviderServiceForwarderAPI.class);
         final SfcProviderServiceForwarderAPI api = PowerMockito.mock(SfcProviderServiceForwarderAPI.class);
         PowerMockito.when(api.readServiceFunctionForwarder(sffNameCaptor.capture())).thenReturn(
@@ -606,8 +611,6 @@ public class ServiceChainingUtilTest {
 
         Assert.assertEquals("rsp-hop-01-sf+sff", sffNameCaptor.getValue().getValue());
 
-        Mockito.verify(policyWriter).getCurrentMountpoint();
-        Mockito.verify(policyWriter).getCurrentNodeId();
         Mockito.verifyNoMoreInteractions(policyWriter);
     }
 
@@ -621,8 +624,6 @@ public class ServiceChainingUtilTest {
         sfpBuilder.setSymmetric(false);
         final ServiceFunctionPath sfp = sfpBuilder.build();
 
-        stub(method(ServiceChainingUtil.class, "checkLocalForwarderPresence")).toReturn(true);
-
         PowerMockito.mockStatic(SfcProviderServiceForwarderAPI.class);
         final SfcProviderServiceForwarderAPI api = PowerMockito.mock(SfcProviderServiceForwarderAPI.class);
         PowerMockito.when(api.readServiceFunctionForwarder(sffNameCaptor.capture())).thenReturn(
@@ -632,8 +633,6 @@ public class ServiceChainingUtilTest {
 
         Assert.assertEquals("rsp-hop-01-sf+sff", sffNameCaptor.getValue().getValue());
 
-        Mockito.verify(policyWriter).getCurrentMountpoint();
-        Mockito.verify(policyWriter).getCurrentNodeId();
         Mockito.verifyNoMoreInteractions(policyWriter);
     }
 
index 0fc67a517cbeefdf95c3c8b2fba01e6ce58d82f1..fe44d4ea616725c65681f4abef2d7b9241a69151 100644 (file)
@@ -15,7 +15,6 @@ import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.JdkFutureAdapters;
 import com.google.common.util.concurrent.ListenableFuture;
-import java.util.Collections;
 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;
@@ -36,6 +35,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpo
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointReg;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointRegBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L3Context;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.mapper.model.rev160302.sxp.mapper.EndpointForwardingTemplateBySubnet;
@@ -47,6 +47,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Collections;
+
 /**
  * Purpose: exclusively processes sxp master database changes and EGP templates changes
  */
@@ -114,7 +116,7 @@ public class SxpMapperReactorImpl implements SxpMapperReactor {
             @Override
             public ListenableFuture<RpcResult<Void>> apply(final Optional<AddressEndpoint> input) throws Exception {
                 final ListenableFuture<RpcResult<Void>> nextResult;
-                if (input == null || !input.isPresent()) {
+                if (input == null || !input.isPresent() || !isSameEpg(epInput, input.get())) {
                     // invoke service
                     return JdkFutureAdapters.listenInPoolThread(l3EndpointService.registerEndpoint(epInput));
                 } else {
@@ -127,5 +129,21 @@ public class SxpMapperReactorImpl implements SxpMapperReactor {
         });
     }
 
+    private boolean isSameEpg(RegisterEndpointInput epInput, AddressEndpoint input) {
+        if (epInput == null || epInput.getAddressEndpointReg() == null || epInput.getAddressEndpointReg().isEmpty()) {
+            return true;
+        }
+        final AddressEndpointReg epInputAddressEndpoint = epInput.getAddressEndpointReg().get(0);
+        if (epInputAddressEndpoint.getEndpointGroup() == null || epInputAddressEndpoint.getEndpointGroup().isEmpty()) {
+            return true;
+        }
+        if (input == null || input.getEndpointGroup() == null || input.getEndpointGroup().isEmpty()) {
+            return true;
+        }
+        final EndpointGroupId addressEndpointGroupId = epInputAddressEndpoint.getEndpointGroup().get(0);
+        final EndpointGroupId existingEndpointGroupId = input.getEndpointGroup().get(0);
+        return addressEndpointGroupId.equals(existingEndpointGroupId);
+    }
+
 }