Yang models for system testing low level MD-SAL operations 77/51477/27
authorVratko Polak <vrpolak@cisco.com>
Tue, 21 Feb 2017 14:54:29 +0000 (15:54 +0100)
committerTom Pantelis <tpanteli@brocade.com>
Thu, 23 Feb 2017 15:13:59 +0000 (15:13 +0000)
Not every operation is easily available from Restconf.
This defines and agent application to control the tested operations from Java.

There are FIXMEs and TODOs left, to be fixed later,
probably together with Java implementation.
Merging this early will allow Changes for Bugs 7796-7807
to be implemented independently (as opposed to forming a single chain).

Change-Id: Icb9616c156f56f8706a24abe31e5ac097a65cf73
Signed-off-by: Vratko Polak <vrpolak@cisco.com>
opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/odl-mdsal-lowlevel-common.yang [new file with mode: 0644]
opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/odl-mdsal-lowlevel-control.yang [new file with mode: 0644]
opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/odl-mdsal-lowlevel-target.yang [new file with mode: 0644]

diff --git a/opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/odl-mdsal-lowlevel-common.yang b/opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/odl-mdsal-lowlevel-common.yang
new file mode 100644 (file)
index 0000000..1d72d53
--- /dev/null
@@ -0,0 +1,71 @@
+module odl-mdsal-lowlevel-common {
+
+    yang-version 1;
+    namespace "tag:opendaylight.org,2017:controller:yang:lowlevel:common";
+    prefix llc;
+
+    import yang-ext { prefix ext; revision-date 2013-07-09; }
+
+    organization "OpenDaylight";
+    contact "Vratko Polak <vrpolak@cisco.com>";
+
+    revision "2017-02-15" {
+        description "Initial revision for Carbon clustering testing.";
+    }
+    description "Declarations to be used both in odl-mdsal-lowlevel-target (llt)
+            and odl-mdsal-lowlevel-control (ll).";
+
+    grouping id-grouping {
+        leaf id {
+            description "Any string uniquely identifying the publisher, producer or writer,
+                typically containing the member name.";
+            mandatory true;
+            type string;
+        }
+    }
+
+    grouping constant-grouping {
+        leaf constant {
+            description "The string to be returned by llt:get-constant
+                    (or llt:get-contexted-constant) RPC implementation.
+                    The string typically includes (the context and) the name of the member
+                    the user called to cause the RPC implementation registration
+                    (that member may be different from both the member running the implementation,
+                    and member where llt:get-constant is called).";
+            mandatory true;
+            type string;
+        }
+    }
+
+    identity constant-context {
+        description "Routed RPCs context needs to be based on an identity.";
+    }
+
+    list rpc-context {
+        description "Routed RPCs need to be registered with a path.
+            It has to be an instance-identifier within an accessible model,
+            but the instance does not have to be present in data tree.
+            This is config false to signal users they do not need to create any instance.";
+        config false;
+        ordered-by system;
+        key "identifier";
+        leaf identifier {
+            description "Users are free to refer to arbitrary strings
+                if they are testing RPC regstrations to different paths.";
+            type string;
+        }
+    }
+
+    grouping context-grouping {
+        leaf context {
+            description "The context for bound implementation of
+                llt:get-contexted-constant RPC to match.
+                The extension has no data, users are free to use instance identifiers
+                referring to (non-existent) items of rpc-context list.";
+            ext:context-reference constant-context;
+            mandatory true;
+            type instance-identifier;
+        }
+    }
+
+}
diff --git a/opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/odl-mdsal-lowlevel-control.yang b/opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/odl-mdsal-lowlevel-control.yang
new file mode 100644 (file)
index 0000000..e9a6c7a
--- /dev/null
@@ -0,0 +1,447 @@
+module odl-mdsal-lowlevel-control {
+
+    yang-version 1;
+    namespace "tag:opendaylight.org,2017:controller:yang:lowlevel:control";
+    prefix ll;
+
+    import odl-mdsal-lowlevel-common {
+        revision-date "2017-02-15";
+        prefix llc;
+    }
+
+    organization "OpenDaylight";
+    contact "Vratko Polak <vrpolak@cisco.com>";
+    description "Control RPCs used to dynamically register, unregister, start or stop
+        the operations under test, which are defined in odl-mdsal-lowlevel-target (llt).
+        Control RPCs are backed by an implementation upon feature instalation.
+        Their registration shall only affect the local member,
+        but their invocation can interact with Entity Ownership or Singleton.
+
+        The 'mdsal' in the module name refers to the component which defines most APIs
+        accessed by the agent implementation. The intent is to test clustering behavior,
+        but most RPCs do not access APIs from clustering component of Controller project.
+
+        TODO: Unify grammar: present or future tense, or imperative mood.";
+
+    revision "2017-02-15" {
+        description "Initial revision for Carbon clustering testing.";
+    }
+
+    rpc register-constant {
+        description "Upon receiving this, the member has to create llt:get-constant
+            implementation (global RPC). If the registration fails for any reason,
+            propagate the corresponding error.";
+        input {
+            uses llc:constant-grouping;
+        }
+        // No output.
+    }
+
+    rpc unregister-constant {
+        description "Upon receiving this, the member has to unregister
+            any llt:get-constant implementations it has registered.
+            If no implementation has been registered, do nothing.";
+        // No input.
+        // No output.
+    }
+
+    rpc register-bound-constant {
+        description "Upon receiving this, the member has to create and register
+            a bound llt:get-contexted-constant implementation (routed RPC).
+            If the registration fails for any reason, propagate the corresponding error.";
+        input {
+            uses llc:context-grouping;
+            uses llc:constant-grouping;
+        }
+        // No output.
+    }
+
+    rpc unregister-bound-constant {
+        description "Upon receiving this, the member has to unregister
+            any llt:get-contexted-constant implementations bound to the context.
+            If no bound implementation for the context has been registered, do nothing.";
+        input {
+            uses llc:context-grouping;
+        }
+        // No output.
+    }
+
+    rpc register-singleton-constant {
+        description "Upon receiving this, the member checks whether it has already registered
+            a singleton application, and fails if yes. If no, the member creates
+            an application implementation based on the given constant
+            and registers the implementation as a singleton application.
+            If the registration fails for any reason, propagate the corresponding error.
+            If the application is instantiated, it creates and registers
+            a llt:get-singleton-constant implementation, which returns the given costant.
+            When the application instance is closed, it unregisters that
+            llt:get-singleton-constant implementation.";
+        input {
+            uses llc:constant-grouping;
+        }
+        // No output.
+    }
+
+    rpc unregister-singleton-constant {
+        description "Upon receiving this, the member checks whether it has currently registered
+            a singleton application, and fails if no. If yes, the member shall unregister
+            the application, presumably causing application instantiation on other member,
+            and closing of the local application instance (unregistering llt:get-singleton-constant).
+            If the unregistration fails for any reason, propagate the corresponding error.";
+        // No input.
+        // No output.
+    }
+
+    rpc register-flapping-singleton {
+        description "Upon receiving this, the member checks whether it has already created
+            a 'flapping' application implementation and 'active' flag is set, and fails if yes.
+            If no, the member (creates a flapping application implementation,)
+            sets the active flag, initializes local variable flap-count to 0,
+            and registers the implementation as a singleton application.
+            If the registration fails for any reason, propagate the corresponding error.
+            If the application is instantiated, it immediatelly un-registers itself.
+            When the application instance is closed, it increments flap-count
+            and if active flag is set, re-registers the application implementation as a singleton.
+            If either un-registration or re-registration fails, flap-count is set
+            to negative of its previous value (minus one in case of un-registration)
+            to signal a failure has happened.";
+        // No input.
+        // No output.
+    }
+
+    rpc unregister-flapping-singleton {
+        description "Upon receiving this, the member checks whether it has created
+            a flapping application, and fails if no. If yes, the member shall
+            set the active flag to false and return the current flap-count value.";
+        // No input.
+        output {
+            leaf flap-count {
+                description "Number of successful re-registrations. If negative,
+                    (minus) cycle number when a failure occured.";
+                mandatory true;
+                type int64;
+            }
+        }
+    }
+
+    rpc publish-notifications {
+        description "Upon receiving this, the member shall start publishing llt:id-sequence
+            notifications with the given id and sequence numbers, increasing, from 1.
+            .get with a timeout on currently earliest non-complete Future (from .publish)
+            shall be used as the primary wait method to throttle the publish rate.
+            The RPC shall not return until all publishes are confirmed successful,
+            or an exception is raised (the exception should propagate to restconf response).";
+        input {
+            uses llc:id-grouping;
+            leaf seconds {
+                description "This RPC has to work (roughly) this long.";
+                mandatory true;
+                type uint32;
+            }
+            leaf notifications-per-second {
+                description "An upper limit of publishes per second this RPC shall try to achieve.";
+                mandatory true;
+                type uint32;
+            }
+        }
+        // No output.
+    }
+
+    rpc subscribe-ynl {
+        description "Upon receiving this, the member checks whether it has already subscribed
+            a yang listener for the given id, and fails if yes.
+            If no, the member subscribes a Yang notification listener to listen for
+            llt:id-sequence notifications. The member also creates a local variable
+            (called local-number) for the sequence number and initialize that to 0.
+            Also three local counters are initialized to 0: all-not, id-not, err-not.
+            Upon receiving any id-sequence notification, all-not is incremented.
+            Each id-sequence notification of matching id shall increment id-not.
+            If local-number was one less than the sequence number (from a notification matching id),
+            increment local-number, else increment err-not.";
+        input {
+            uses llc:id-grouping;
+        }
+        // No output.
+    }
+
+    rpc unsubscribe-ynl {
+        description "Upon receiving this, the member checks whether it has currently subscribed
+            a yang listener for the given id, and fails if no. If yes, the member
+            shall unsubscribe the listener and return values of the local variables.";
+        input {
+            uses llc:id-grouping;
+        }
+        output {
+            leaf all-not {
+                description "Number of received id-sequence notifications of any id.";
+                mandatory true;
+                type int64;
+            }
+            leaf id-not {
+                description "Number of received id-sequence notifications of matching id
+                    and any sequence number.";
+                mandatory true;
+                type int64;
+            }
+            leaf err-not {
+                description "Number of received id-sequence notifications of matching id,
+                    but out-of-order sequence number.";
+                mandatory true;
+                type int64;
+            }
+            leaf local-number {
+                description "Value of the local number, should be equal to
+                    the sequence number of the last compatible id-sequence notification received.";
+                mandatory true;
+                type int64;
+            }
+        }
+    }
+
+    rpc write-transactions {
+        description "Upon receiving this, the member shall make sure the outer list item
+            of llt:id-ints exists for the given id, and then start creating (one by one)
+            and submitting transactions to randomly add or delete items on the inner list for that id.
+            The randomness should avoid creating conflicting writes (at least for non-chained
+            transactions). The recommended way is to require the random number
+            has low significant bits different than the past ~100k numbers.
+            To ensure balanced number of deletes, the first write can create
+            a random set of numbers. Other writes shall be one per number.
+            The writes shall use the old API, transaction (chains) created directly on datastore
+            (as opposed to DOMDataTreeProducer).
+            .get with a timeout on currently earliest non-complete Future (from .submit)
+            shall be used as the primary wait method to throttle the submission rate.
+            This RPC shall not return until all transactions are confirmed successful,
+            or an exception is raised (the exception should propagate to restconf response).
+            OptimisticLockException is always considered an error.";
+        input {
+            uses llc:id-grouping;
+            leaf seconds {
+                description "This RPC has to work (roughly) this long.";
+                mandatory true;
+                type uint32;
+            }
+            leaf transactions-per-second {
+                description "An upper limit of transactions per second this RPC shall try to achieve.";
+                mandatory true;
+                type uint32;
+            }
+            leaf chained-transactions {
+                description "If true, write transactions shall be created on a transaction chain,
+                    (created at start of the RPC call, and deleted at at its end).
+                    If false, write transactions shall be created separately.";
+                mandatory true;
+                type boolean;
+            }
+        }
+        // No output.
+    }
+
+    rpc produce-transactions {
+        description "Upon receiving this, the member shall make sure the outer list item
+            of llt:in-ints exists for the given id, make sure a shard for
+            the whole (config) id-ints is created (by creating and closing producer
+            for the whole id-ints), and create a DOMDataTreeProducer for that item (using that shard).
+
+            FIXME: Is the above the normal way of creating prefix-based chards?
+
+            Then start creating (one by one) and submitting transactions
+            to randomly add or delete items on the inner list for that id.
+            To ensure balanced number of deletes, the first write can create
+            a random set of random numbers. Other writes shall be one per number.
+            The writes shall use DOMDataTreeProducer API, as opposed to transaction (chains)
+            created directly on datastore.
+            .get with a timeout on currently earliest non-complete Future (from .submit)
+            shall be used as the primary wait method to throttle the submission rate.
+            This RPC shall not return until all transactions are confirmed successful,
+            or an exception is raised (the exception should propagate to restconf response).
+            OptimisticLockException is always considered an error.
+            In either case, the producer should be closed before returning,
+            but the shard and the whole id item shall be kept as they are.";
+        input {
+            uses llc:id-grouping;
+            leaf seconds {
+                description "This RPC has to work (roughly) this long.";
+                mandatory true;
+                type uint32;
+            }
+            leaf transactions-per-second {
+                description "An upper limit of transactions per second this RPC shall try to achieve.";
+                mandatory true;
+                type uint32;
+            }
+            leaf isolated-transactions {
+                description "The value for DOMDataTreeProducer#createTransaction argument.";
+                mandatory true;
+                type boolean;
+            }
+        }
+        // No output.
+    }
+
+    rpc become-prefix-leader {
+        description "Upon receiving this, the member shall ask the appropriate API
+            to become Leader of the given shard (presumably the llt:list-ints one,
+            created by produce-transactions) and return immediatelly.";
+        input {
+            leaf shard-name {
+                description "TBD.
+
+                FIXME: Ask Java implementation developer about the format needed.";
+                mandatory true;
+                type string;
+            }
+        }
+        // No output.
+    }
+
+    rpc become-module-leader {
+        description "Upon receiving this, the member shall ask appropriate API
+            to become Leader of given config shard and return immediatelly.";
+        input {
+            leaf shard-name {
+                description "TBD.
+
+                FIXME: Ask Java implementation developer about the format needed.
+                TODO: Perhaps the names are compatible and one 'become-leader' would suffice?";
+                mandatory true;
+                type string;
+            }
+        }
+        // No output.
+    }
+
+    rpc remove-shard-replica {
+        description "A specialised copy of cluster-admin:remove-shard-replica.
+
+            FIXME: Is this really needed for prefix shards, or even module shards
+                (or is the cluster-admin RPC sufficient)?";
+        input {
+            leaf shard-name {
+                description "The name of the config shard for which
+                    to remove the replica on the current member.";
+                mandatory true;
+                type string;
+            }
+        // No output.
+        }
+    }
+
+    rpc add-shard-replica {
+        description "A specialised copy of cluster-admin:add-shard-replica.
+
+            FIXME: Is this really needed for prefix shards, or even module shards
+                (or is the cluster-admin RPC sufficient)?";
+        input {
+            leaf shard-name {
+                description "The name of the config shard for which
+                    to add the replica on the current member.";
+                mandatory true;
+                type string;
+            }
+        // No output.
+        }
+    }
+
+    rpc is-client-aborted {
+        description "Return state of cds-access-client.
+
+            FIXME: Is an input needed?";
+        output {
+            leaf aborted {
+                description "True if the local client is aborted (or unreachable), false otherwise.";
+                mandatory true;
+                type boolean;
+            }
+        }
+    }
+
+    rpc subscribe-dtcl {
+        description "Upon receiving this, the member checks whether it has already subscribed
+            and fails if yes. If no, the member subscribes a Data Tree Change Listener
+            to listen for changes on whole llt:id-ints, and stores the state
+            from the initial notification to a local variable (called the local copy).
+            Each Data Tree Change from further Notifications shall be applied
+            to the local copy if it is compatible
+            (the old state from notification is equal to the local copy state).
+            If a notification is not compatible, it shall be ignored.";
+        // No input.
+        // No output.
+    }
+
+    rpc unsubscribe-dtcl {
+        description "Upon receiving this, the member checks whether it has currently subscribed
+            a Data Tree Change Listener for llt:id-ints changes, and fails if no. If yes, the member
+            shall unsubscribe the listener, read state of id-ints, compare that
+            to the local copy, and return whether the local copy is the same.";
+        // No input.
+        output {
+            leaf copy-matches {
+                type boolean;
+                mandatory true;
+                description "True if and only if the read id-ints is equal to the local copy.";
+            }
+        }
+    }
+
+    rpc subscribe-ddtl {
+        description "Upon receiving this, the member checks whether it has already subscribed
+            and fails if yes. If no, the member subscribes a DOMDataTreeListener
+            to listen for changes on whole llt:id-ints, and stores
+            the state from the initial notification to a local variable (called the local copy).
+            Each Data Tree Change from further notifications shall be applied
+            to the local copy if it is compatible
+            (the old state from notification is equal to the local copy state).
+            If a notification is not compatible, it shall be ignored.";
+        // No input.
+        // No output.
+    }
+
+    rpc unsubscribe-ddtl {
+        description "Upon receiving this, the member checks whether it has currently subscribed
+            a DOMDataTreeListener for llt:id-ints changes, and fails if no. If yes, the member
+            shall unsubscribe the listener, read state of id-ints (by briefly subscribing
+            and ubsubscribing again), compare that to the local copy,
+            and return whether the local copy is the same.";
+        // No input.
+        output {
+            leaf copy-matches {
+                description "True if and only if the read id-ints is equal to the local copy.";
+                mandatory true;
+                type boolean;
+            }
+        }
+    }
+
+    // The following calls are not required for Carbon testing.
+
+    rpc deconfigure-id-ints-shard {
+        description "Upon receiving this, the member shall ask the appropriate API
+            to remove the llt:id-ints shard (presumably created by produce-transactions)
+            and return immediatelly.
+            It is expected the data would move to the root prefix shard seamlessly.
+
+            TODO: Make shard name configurable by input?";
+        // No input.
+        // No output.
+    }
+
+    rpc register-default-constant {
+        description "Upon receiving this, the member has to create and register
+            a default llt:get-contexted-constant implementation (routed RPC).
+            If the registration fails for any reason, propagate the corresponding error.";
+        input {
+            uses llc:constant-grouping;
+        }
+        // No output.
+    }
+
+    rpc unregister-default-constant {
+        description "Upon receiving this, the member has to unregister
+            any llt:get-contexted-constant default implementations it has registered.
+            If no default implementation has been registered, do nothing.";
+        // No input.
+        // No output.
+    }
+
+}
diff --git a/opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/odl-mdsal-lowlevel-target.yang b/opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/odl-mdsal-lowlevel-target.yang
new file mode 100644 (file)
index 0000000..b4f9c25
--- /dev/null
@@ -0,0 +1,91 @@
+module odl-mdsal-lowlevel-target {
+
+    yang-version 1;
+    namespace "tag:opendaylight.org,2017:controller:yang:lowlevel:target";
+    prefix llt;
+
+    import odl-mdsal-lowlevel-common {
+        revision-date "2017-02-15";
+        prefix llc;
+    }
+
+    organization "OpenDaylight";
+    contact "Vratko Polak <vrpolak@cisco.com>";
+    description "Elements to test, which are not to be backed by any default implementation
+        upon feature installation.
+        See odl-mdsal-lowlevel-control (ll) for methods how to assign implementation in runtime.
+        This is separate module from odl-mdsal-lowlevel-control to simplify binding aware
+        implementation, which requires either all or no RPCs to be backed up by a single Java instance.";
+
+    revision "2017-02-15" {
+        description "Initial revision for Carbon clustering testing.";
+    }
+
+    rpc get-constant {
+        description "Return the constant string provided by the previously registered implementation.
+            Propagate appropriate error if no, unreachable, or failing implementation is found.";
+        // No input.
+        output {
+            uses llc:constant-grouping;
+        }
+    }
+
+    rpc get-contexted-constant {
+        description "Return the constant corresponding to a registered implementation (either bound or default).
+            Propagate appropriate error if no, unreachable, or failing implementation is found.";
+        input {
+            uses llc:context-grouping;
+        }
+        output {
+            uses llc:constant-grouping;
+        }
+    }
+
+    rpc get-singleton-constant {
+        description "Return the constant string provided by the previously registered implementation.
+            Propagate appropriate error if no, unreachable, or failing implementation is found.
+            This is basically the same as get-constant, but it can have a different
+            implementation registered, thus allowing to track both implementations in longevity jobs.";
+        // No input.
+        output {
+            uses llc:constant-grouping;
+        }
+    }
+
+    notification id-sequence {
+        description "Notification where the publisher is identified by the id
+            and each publish increases the sequence number.";
+        uses llc:id-grouping;
+        leaf sequence-number {
+            description "Subscriber shall verify whether this value has increased
+                since the previous notification. The first sequence number published shall be 1.
+                Type is 64 bit to allow longevity tests, and signed to allow exceptional numbers.";
+            mandatory true;
+            type int64;
+        }
+    }
+
+    list id-ints {
+        description "A list of integers nested in list of ids.
+            Ids are there to avoid OptimisticLockFailures from different writers.
+            Typical use of the int list is to generate data change notifications.
+            Config is true, in order to allow Restconf to reset content at will.
+            Expected writes should create and delete items at random, values 0 .. 2^20.";
+        ordered-by system;
+        config true;
+        key "id";
+        uses llc:id-grouping;
+        list item {
+            description "Unsorted keyed list item. One write should create or delete up to one item.";
+            ordered-by system;
+            config true;
+            key "number";
+            leaf number {
+                description "The integer value of this item.
+                    Not range restricted, to allow more scenarios.";
+                type int32;
+            }
+        }
+    }
+
+}