Provide IntentServiceManager and MplsLabelManagerService classes 57/31357/26
authorRashmi Pujar <rpujar@inocybe.com>
Fri, 22 Jan 2016 17:18:30 +0000 (12:18 -0500)
committerRashmi Pujar <rpujar@inocybe.com>
Fri, 22 Jan 2016 17:34:36 +0000 (12:34 -0500)
- YANG model to support failover constraints - slow & fast-reroute
  YANG model to support MPLS labels
- Utility class to ad/remove intents from vpnservice with
  constraints set to intent object
- Utility class to allocate unique MPLS label for each endpoint
  and label management. Labels are stored to operational data tree

Change-Id: I905ad2c08c3cade745539b0cf489a71a98f24f78
Signed-off-by: Rashmi Pujar <rpujar@inocybe.com>
vpnintent/api/src/main/yang/vpnintent.yang
vpnintent/impl/pom.xml
vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/IntentServiceManager.java [new file with mode: 0644]
vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MplsLabelManagerService.java [new file with mode: 0644]
vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/VpnintentProvider.java
vpnintent/impl/src/main/java/org/opendaylight/vpnservice/utils/IidFactory.java [new file with mode: 0644]
vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/IntentServiceManagerTest.java [new file with mode: 0644]

index bb2528f2cf0b6cbf30ffe990eba93733f1212a6c..e9a971db1e976e08dd30de6e2778efbc0b514e71 100644 (file)
@@ -24,12 +24,29 @@ module vpnintent {
         }
     }
 
+    typedef failover-type {
+        type enumeration {
+            enum fast-reroute {
+                value 1;
+            }
+            enum slow-reroute {
+                value 2;
+            }
+        }
+    }
+
     grouping vpn-intent {
         leaf vpn-name {
             type string;
             description "VPN name";
             mandatory true;
         }
+        leaf path-protection {
+            type boolean;
+        }
+        leaf failover-type {
+            type failover-type;
+        }
         list endpoint {
             key "site-name";
             uses endpoint-fields;
@@ -58,12 +75,18 @@ module vpnintent {
         list label {
             key "label-id";
             leaf "label-id"{
-                type uint64;
-                description "MPLS or other label ID.";
+                type uint32 {
+                    range "0 .. 524288";
+                }
+                description "20 bit MPLS label ID";
                 mandatory true;
             }
             uses endpoint-fields;
             description "Keep track of MPLS/other label endpoint relation.";
         }
      }
+
+    container mpls-labels {
+        uses labels;
+   }
   }
index 546b1e130a873b67bcc2474ecf6b0c2feeeeced2..ab00412ea74218230cd6fdef336c07666474f3bf 100644 (file)
@@ -21,6 +21,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
 
   <properties>
     <nic.version>1.2.0-SNAPSHOT</nic.version>
+    <powermock.version>1.5.2</powermock.version>
   </properties>
 
   <dependencies>
@@ -34,6 +35,19 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <artifactId>vpnintent-api</artifactId>
       <version>${project.version}</version>
     </dependency>
+
+    <!-- NIC dependency -->
+    <dependency>
+      <groupId>org.opendaylight.nic</groupId>
+      <artifactId>intent-api</artifactId>
+      <version>${nic.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.nic</groupId>
+      <artifactId>utils</artifactId>
+      <version>${nic.version}</version>
+    </dependency>
+
     <!-- Testing Dependencies -->
     <dependency>
       <groupId>junit</groupId>
@@ -46,6 +60,18 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <artifactId>mockito-all</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <version>${powermock.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <version>${powermock.version}</version>
+      <scope>test</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.opendaylight.nic</groupId>
diff --git a/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/IntentServiceManager.java b/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/IntentServiceManager.java
new file mode 100644 (file)
index 0000000..99d0edc
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.nic.utils.MdsalUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.constraints.rev150122.FailoverType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.Intents;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.IntentsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.Actions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.ActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.Constraints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.ConstraintsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.Subjects;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.SubjectsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action.allow.AllowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action.block.BlockBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints.constraints.failover.constraint.FailoverConstraintBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints.constraints.protection.constraint.ProtectionConstraintBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.end.point.group.EndPointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.end.point.group.EndPointGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.Intent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.IntentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.IntentKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.types.rev150122.Uuid;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+
+public class IntentServiceManager {
+
+    /**
+     * This class is used to build Intents object and
+     * write it to Network Intent Composition md-sal tree
+     * in order to create/delete intents between two endpoint groups.
+     */
+
+    private static final Logger LOG = LoggerFactory.getLogger(IntentServiceManager.class);
+    private static final short FIRST_SUBJECT = 1;
+    private static final short SECOND_SUBJECT = 2;
+    public static final String ACTION_ALLOW = "ALLOW";
+    public static final String ACTION_BLOCK = "BLOCK";
+    public static final String FAST_REROUTE = "fast-reroute";
+    public static final String SLOW_REROUTE = "slow-reroute";
+    private final DataBroker dataBroker;
+    private static final InstanceIdentifier<Intents> INTENTS_IID = InstanceIdentifier.builder(Intents.class).build();
+    private MdsalUtils mdsal;
+
+    public IntentServiceManager(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+        this.mdsal = new MdsalUtils(dataBroker);
+    }
+
+    /**
+     * Create Intents object and write to to config tree to trigger intents
+     * @param src :Source Site Name
+     * @param dst :Destination Site Name
+     * @param intentAction :Intent verb: ALLOW or BLOCK
+     * @param failOverType
+     */
+    public void addIntent(String src, String dst, String intentAction, String failOverType) {
+        Preconditions.checkNotNull(src);
+        Preconditions.checkNotNull(dst);
+        Preconditions.checkNotNull(intentAction);
+
+        List<Intent> intentList = null;
+        List<Subjects> subjects = createSubjects(dst, src);
+        List<Actions> intentActions = createActions(intentAction);
+        List<Constraints> intentConstraints = createConstraints(failOverType);
+
+        Intent intent  = new IntentBuilder().setId(new Uuid(UUID.randomUUID().toString()))
+                .setSubjects(subjects).setActions(intentActions)
+                .setConstraints(intentConstraints)
+                .build();
+
+        Intents currentIntents = mdsal.read(LogicalDatastoreType.CONFIGURATION, INTENTS_IID);
+        if (currentIntents == null) {
+            intentList = new ArrayList<>();
+        } else {
+            intentList = currentIntents.getIntent();
+        }
+        intentList.add(intent);
+        Intents intents = new IntentsBuilder().setIntent(intentList).build();
+        mdsal.put(LogicalDatastoreType.CONFIGURATION, INTENTS_IID, intents);
+        LOG.info("AddIntent: config populated: {}", intents);
+    }
+
+    /**
+     * Delete an Intent
+     * @param id :Uuid of the Intent to be deleted
+     */
+    public void removeIntent(Uuid id) {
+        Preconditions.checkNotNull(id);
+        InstanceIdentifier<Intent> iid = InstanceIdentifier.create(Intents.class).child(Intent.class, new IntentKey(id));
+        mdsal.delete(LogicalDatastoreType.CONFIGURATION, iid);
+        LOG.info("RemoveIntent succeeded");
+    }
+
+    /**
+     * Remove all associated intents by endpointGroupName
+     * @param endpointGroupName
+     */
+    public void removeIntentsByEndpoint(String endpointGroupName) {
+        Preconditions.checkNotNull(endpointGroupName);
+
+        Intents intents = mdsal.read(LogicalDatastoreType.CONFIGURATION, INTENTS_IID);
+
+        if (intents != null && intents.getIntent() != null) {
+            for (Intent intent : intents.getIntent()) {
+                if (intent.getSubjects() != null && intent.getSubjects().size() > 0) {
+                    String endpointValue = "";
+                    for (Subjects subject : intent.getSubjects()) {
+                        if (subject
+                                .getSubject() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroup) {
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroup epg = (org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroup) subject
+                                    .getSubject();
+                            endpointValue = epg.getEndPointGroup().getName();
+                        } else if (subject
+                                .getSubject() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointSelector) {
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointSelector epg = (org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointSelector) subject
+                                    .getSubject();
+                            endpointValue = epg.getEndPointSelector().getEndPointSelector();
+                        } else if (subject
+                                .getSubject() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroupSelector) {
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroupSelector epg = (org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroupSelector) subject
+                                    .getSubject();
+                            endpointValue = epg.getEndPointGroupSelector().getEndPointGroupSelector();
+                        }
+                        if (endpointValue.equalsIgnoreCase(endpointGroupName)) {
+                            removeIntent(intent.getId());
+                            LOG.info("Deleted Intent ID : {} for endpoint: {}", intent.getId(), endpointGroupName);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a list of Intent actions
+     * @param intentAction
+     * @return :a list of Actions
+     */
+    private List<Actions> createActions(String intentAction) {
+        List<Actions> actionsList = new ArrayList<Actions>();
+        short order = 1;
+        org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.Action action = null;
+        if (intentAction.equalsIgnoreCase(ACTION_ALLOW)) {
+            action = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action
+                    .AllowBuilder().setAllow(new AllowBuilder().build()).build();
+        } else if (intentAction.equalsIgnoreCase(ACTION_BLOCK)) {
+            action = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action
+                    .BlockBuilder().setBlock(new BlockBuilder().build()).build();
+        }
+
+        Actions intentActions = new ActionsBuilder().setOrder(order).setAction(action).build();
+        actionsList.add(intentActions);
+        return actionsList;
+    }
+
+    /**
+     * Create a list of Intent subjects
+     * @param src :Source Site Name
+     * @param dst :Destination Site Name
+     * @return :a list of Subjects
+     */
+    private List<Subjects> createSubjects(String src, String dst) {
+        List<Subjects> subjectList = new ArrayList<Subjects>();
+
+        EndPointGroup endpointGroupFrom = new EndPointGroupBuilder().setName(src).build();
+        org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroup fromEPG =
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject
+                .EndPointGroupBuilder().setEndPointGroup(endpointGroupFrom).build();
+        Subjects subjects1 = new SubjectsBuilder().setOrder(FIRST_SUBJECT).setSubject(fromEPG).build();
+
+        EndPointGroup endpointGroupTo = new EndPointGroupBuilder().setName(dst).build();
+        org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject.EndPointGroup toEPG =
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.subjects.subject
+                .EndPointGroupBuilder().setEndPointGroup(endpointGroupTo).build();
+        Subjects subjects2 = new SubjectsBuilder().setOrder(SECOND_SUBJECT).setSubject(toEPG).build();
+
+        subjectList.add(subjects1);
+        subjectList.add(subjects2);
+        return subjectList;
+    }
+
+    /**
+     * Create a list of Intent constraints
+     * @param failOverType :Type of failover, fast-reroute or slow-reroute
+     * @return
+     */
+    private List<Constraints> createConstraints(String failOverType) {
+        List<Constraints> intentConstraints = new ArrayList<Constraints>();
+        if (failOverType==null) {
+            return intentConstraints;
+        }
+        short order = 1;
+        org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints.Constraints
+            protectionConstraint = null;
+        org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints.Constraints
+            failoverConstraint = null;
+        if (failOverType.equals(FAST_REROUTE)) {
+            protectionConstraint = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent
+                    .constraints.constraints.ProtectionConstraintBuilder()
+                    .setProtectionConstraint(new ProtectionConstraintBuilder().setIsProtected(true).build()).build();
+            failoverConstraint = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints
+                    .constraints.FailoverConstraintBuilder()
+                    .setFailoverConstraint(new FailoverConstraintBuilder().setFailoverSelector(FailoverType.FastReroute).build())
+                    .build();
+        } else if (failOverType.equals(SLOW_REROUTE)) {
+            protectionConstraint = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent
+                    .constraints.constraints.ProtectionConstraintBuilder()
+                    .setProtectionConstraint(new ProtectionConstraintBuilder().setIsProtected(true).build()).build();
+            failoverConstraint = new org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints
+                    .constraints.FailoverConstraintBuilder()
+                    .setFailoverConstraint(new FailoverConstraintBuilder().setFailoverSelector(FailoverType.SlowReroute).build())
+                    .build();
+        }
+        Constraints constraint1 = new ConstraintsBuilder().setOrder(order).setConstraints(protectionConstraint).build();
+        Constraints constraint2 = new ConstraintsBuilder().setOrder(++order).setConstraints(failoverConstraint).build();
+        intentConstraints.add(constraint1);
+        intentConstraints.add(constraint2);
+        return intentConstraints;
+    }
+}
diff --git a/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MplsLabelManagerService.java b/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/impl/MplsLabelManagerService.java
new file mode 100644 (file)
index 0000000..48b4986
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.nic.utils.MdsalUtils;
+import org.opendaylight.vpnservice.utils.IidFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.MplsLabels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.labels.Label;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.labels.LabelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.labels.LabelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.vpn.intent.Endpoint;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MplsLabelManagerService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MplsLabelManagerService.class);
+    private static final Integer MAX_MPLS_LABEL = 524288;
+    private static InstanceIdentifier<Label> LABEL_IID = null;
+    public static final InstanceIdentifier<MplsLabels> MPLS_LABELS_IID = IidFactory.getMplsLabelsIid();
+    private final DataBroker dataBroker;
+    private final Random random = new Random();
+    private MdsalUtils mdsal;
+
+    public MplsLabelManagerService(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+        this.mdsal = new MdsalUtils(this.dataBroker);
+    }
+
+    /**
+     * Generate a unique Mpls Label
+     * Mpls label is of length 20 bits maximum
+     * @return :next unique Mpls label value
+     */
+    public Long getUniqueLabel(Endpoint endpoint)  {
+        Long nextUniqueLabel = (long) random.nextInt(MAX_MPLS_LABEL);
+        while(checkIsLabelUsed(nextUniqueLabel)) {
+            nextUniqueLabel = (long) random.nextInt(MAX_MPLS_LABEL);
+        }
+        updateToLabelStore(nextUniqueLabel, endpoint, true);
+        return nextUniqueLabel;
+    }
+
+    /**
+     * Delete label from datastore
+     * @param endpoint :endpoint whose label needs to be deleted
+     */
+    public void deleteLabel(Endpoint endpoint)  {
+        Map<Long, String> labelMap = getAllLabels();
+        for (Map.Entry<Long, String> labelEntry : labelMap.entrySet()) {
+            if(labelEntry.getValue().equalsIgnoreCase(endpoint.getSiteName())) {
+                updateToLabelStore(labelEntry.getKey(), endpoint, false);
+            }
+        }
+    }
+
+    /**
+     * Update the model for Labels with used Mpls label values
+     * @param label :mpls label allocated to an endpoint
+     * @param endpoint :endpoint to which mpls label is allocated to
+     * @param add :true if add label to datastore, false to delete label from datastore
+     */
+    private void updateToLabelStore(Long label, Endpoint endpoint, boolean add) {
+        LABEL_IID = IidFactory.getLabelIid(label);
+        Label mplsLabel = new LabelBuilder().
+                setKey(new LabelKey(label)).
+                setLabelId(label).
+                setSiteName(endpoint.getSiteName()).
+                setIpPrefix(endpoint.getIpPrefix()).
+                setSwitchPortId(endpoint.getSwitchPortId()).build();
+
+        if(add) {
+            mdsal.put(LogicalDatastoreType.OPERATIONAL, LABEL_IID, mplsLabel);
+            LOG.info("Add mpls label to operational datastore: {} for endpoint: {}", label, endpoint.getSiteName());
+        } else {
+            mdsal.delete(LogicalDatastoreType.OPERATIONAL, LABEL_IID);
+            LOG.info("Delete mpls label from operational datastore: {} for endpoint: {}", label, endpoint.getSiteName());
+        }
+    }
+
+    /**
+     * Check if label is already allocated to any endpoint
+     * @param nextUniqueLabel :value of mpls label
+     * @return :true is label is already used else false
+     */
+    private boolean checkIsLabelUsed(Long nextUniqueLabel) {
+        Map<Long, String> labelMap = getAllLabels();
+        if(labelMap.containsKey(nextUniqueLabel)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Get a map of all the labels allocated to the endpoints
+     * @return :hashmap of labels as key, site names as value
+     */
+    private Map<Long, String> getAllLabels() {
+        Map<Long, String> labelMap = new HashMap<>();
+        MplsLabels mplsLabels = mdsal.read(LogicalDatastoreType.OPERATIONAL, MPLS_LABELS_IID);
+        if(mplsLabels != null) {
+            for (Label label : mplsLabels.getLabel()) {
+                labelMap.put(label.getLabelId(), label.getSiteName());
+            }
+        }
+        return labelMap;
+    }
+}
index 637d8150ec365962e3ecb727c5d7c558dcbb7ca5..715c1735163fe4ee40428da0ddcf8c58065a13d4 100644 (file)
@@ -12,8 +12,11 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.MplsLabels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.MplsLabelsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.Vpns;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.VpnsBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -25,6 +28,7 @@ public class VpnintentProvider implements BindingAwareProvider, AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(VpnintentProvider.class);
     public static final InstanceIdentifier<Vpns> VPN_INTENT_IID = InstanceIdentifier.builder(Vpns.class).build();
+    public static final InstanceIdentifier<MplsLabels> LABELS_IID = InstanceIdentifier.builder(MplsLabels.class).build();
 
     private DataBroker dataBroker;
 
@@ -34,9 +38,11 @@ public class VpnintentProvider implements BindingAwareProvider, AutoCloseable {
         dataBroker = session.getSALService(DataBroker.class);
 
         Vpns vpns = new VpnsBuilder().build();
+        MplsLabels labels = new MplsLabelsBuilder().build();
 
-        // Initialize default config data in MD-SAL data store
+        // Initialize MD-SAL data store for vpn-intents and mpls-labels
         initDatastore(LogicalDatastoreType.CONFIGURATION, VPN_INTENT_IID, vpns);
+        initDatastore(LogicalDatastoreType.OPERATIONAL, LABELS_IID, labels);
     }
 
     @Override
@@ -44,10 +50,10 @@ public class VpnintentProvider implements BindingAwareProvider, AutoCloseable {
         LOG.info("VpnintentProvider Closed");
     }
 
-    private void initDatastore(LogicalDatastoreType store, InstanceIdentifier<Vpns> iid, Vpns mappings) {
-        // Put the Mapping data to MD-SAL data store
+    private <T extends DataObject> void initDatastore(LogicalDatastoreType store, InstanceIdentifier<T> iid, T object) {
+        // Put data to MD-SAL data store
         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
-        transaction.put(store, iid, mappings);
+        transaction.put(store, iid, object);
 
         // Perform the tx.submit asynchronously
         Futures.addCallback(transaction.submit(), new FutureCallback<Void>() {
@@ -61,6 +67,6 @@ public class VpnintentProvider implements BindingAwareProvider, AutoCloseable {
                 LOG.error("initDatastore for VPN-Intents: transaction failed");
             }
         });
-        LOG.info("initDatastore: VPN-Intents data populated: {}", store, iid, mappings);
+        LOG.info("initDatastore: data populated: {}, {}, {}", store, iid, object);
     }
 }
diff --git a/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/utils/IidFactory.java b/vpnintent/impl/src/main/java/org/opendaylight/vpnservice/utils/IidFactory.java
new file mode 100644 (file)
index 0000000..d05b69f
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.utils;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.MplsLabels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.labels.Label;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpnintent.rev150105.labels.LabelKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class IidFactory {
+
+    public static InstanceIdentifier<MplsLabels> getMplsLabelsIid() {
+        return InstanceIdentifier.builder(MplsLabels.class).build();
+    }
+
+    public static InstanceIdentifier<Label> getLabelIid(Long label) {
+        return InstanceIdentifier.create(MplsLabels.class).child(Label.class, new LabelKey(label));
+    }
+}
diff --git a/vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/IntentServiceManagerTest.java b/vpnintent/impl/src/test/java/org/opendaylight/vpnservice/impl/IntentServiceManagerTest.java
new file mode 100644 (file)
index 0000000..71ef33c
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016 Inocybe Technologies 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.vpnservice.impl;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.nic.utils.MdsalUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.Intents;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.IntentsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.Intent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.IntentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.types.rev150122.Uuid;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.api.support.membermodification.MemberModifier;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@PrepareForTest({IntentServiceManager.class})
+@RunWith(PowerMockRunner.class)
+public class IntentServiceManagerTest {
+
+    private static final String SRC_SITE_NAME = "site a";
+    private static final String DST_SITE_NAME = "site b";
+    private static final String INTENT_ALLOW_ACTION = "ALLOW";
+    private IntentServiceManager intentServiceManager;
+    @Mock private MdsalUtils mdsal;
+
+    @Before
+    public void setUp() throws Exception {
+        intentServiceManager = mock(IntentServiceManager.class, Mockito.CALLS_REAL_METHODS);
+        MemberModifier.field(IntentServiceManager.class, "mdsal").set(intentServiceManager, mdsal);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testAddIntent() throws Exception {
+        IntentBuilder intentBldr = mock(IntentBuilder.class);
+        PowerMockito.whenNew(IntentBuilder.class).withNoArguments().thenReturn(intentBldr);
+        when(intentBldr.setId(any(Uuid.class))).thenReturn(intentBldr);
+        when(intentBldr.setSubjects(any(List.class))).thenReturn(intentBldr);
+        when(intentBldr.setActions(any(List.class))).thenReturn(intentBldr);
+        when(intentBldr.setConstraints(any(List.class))).thenReturn(intentBldr);
+        when(intentBldr.build()).thenReturn(mock(Intent.class));
+
+        Intents currentIntents = mock(Intents.class);
+        PowerMockito.when(mdsal.read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class))).thenReturn(currentIntents);
+        IntentsBuilder intentsBldr = mock(IntentsBuilder.class);
+        PowerMockito.whenNew(IntentsBuilder.class).withNoArguments().thenReturn(intentsBldr);
+        when(intentsBldr.setIntent(any(List.class))).thenReturn(intentsBldr);
+        PowerMockito.when(mdsal.put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Intents.class))).thenReturn(true);
+
+        intentServiceManager.addIntent(SRC_SITE_NAME, DST_SITE_NAME, INTENT_ALLOW_ACTION, "fast-reroute");
+        verify(intentBldr).setId(any(Uuid.class));
+        verify(mdsal).read(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+        verify(mdsal).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Intents.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testRemoveIntents() {
+        Uuid id = mock(Uuid.class);
+        when(mdsal.delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class))).thenReturn(true);
+
+        intentServiceManager.removeIntent(id);
+        verify(mdsal).delete(any(LogicalDatastoreType.class), any(InstanceIdentifier.class));
+    }
+}