- add create_key function (fails if key already exists)
- add setkey_match_prev function (set value if previous value matches)
- add missing quotes
- add etcd3.plugin
---
 src/osaf/consensus/plugins/etcd.plugin   |  86 +++++++-
 src/osaf/consensus/plugins/etcd3.plugin  | 366 +++++++++++++++++++++++++++++++
 src/osaf/consensus/plugins/sample.plugin |  67 +++++-
 3 files changed, 501 insertions(+), 18 deletions(-)
 create mode 100644 src/osaf/consensus/plugins/etcd3.plugin

diff --git a/src/osaf/consensus/plugins/etcd.plugin 
b/src/osaf/consensus/plugins/etcd.plugin
index 586059b32..6ed85ac92 100644
--- a/src/osaf/consensus/plugins/etcd.plugin
+++ b/src/osaf/consensus/plugins/etcd.plugin
@@ -29,7 +29,7 @@ readonly etcd_timeout="5s"
 #   0 - success, <value> is echoed to stdout
 #   non-zero - failure
 get() {
-  readonly key=$1
+  readonly key="$1"
 
   if value=$(etcdctl $etcd_options --timeout $etcd_timeout get 
"$directory$key" 2>&1)
   then
@@ -49,8 +49,8 @@ get() {
 #   0 - success
 #   non-zero - failure
 setkey() {
-  readonly key=$1
-  readonly value=$2
+  readonly key="$1"
+  readonly value="$2"
 
   if etcdctl $etcd_options --timeout $etcd_timeout set "$directory$key" \
     "$value" >/dev/null
@@ -61,6 +61,58 @@ setkey() {
   fi
 }
 
+# create
+#   create <key> and set to <value> in key-value store. Fails if the key
+#   already exists
+# params:
+#   $1 - <key>
+#   $2 - <value>
+# returns:
+#   0 - success
+#   1 - already exists
+#   2 or above - other failure
+create_key() {
+  readonly key="$1"
+  readonly value="$2"
+
+  if output=$(etcdctl $etcd_options --timeout $etcd_timeout mk 
"$directory$key" \
+    "$value" 2>&1)
+  then
+    return 0
+  else
+    if echo $output | grep "already exists"
+    then
+      return 1
+    fi
+  fi
+
+  return 2
+}
+
+# set
+#   set <key> to <value> in key-value store, if the existing value matches
+#   <prev>
+# params:
+#   $1 - <key>
+#   $2 - <value>
+#   $3 - <prev>
+# returns:
+#   0 - success
+#   non-zero - failure
+setkey_match_prev() {
+  readonly key="$1"
+  readonly value="$2"
+  readonly prev="$3"
+
+  if etcdctl $etcd_options --timeout $etcd_timeout set "$directory$key" \
+    "$value" --swap-with-value "$prev" >/dev/null
+  then
+    return 0
+  else
+    return 1
+  fi
+}
+
 # erase
 #   erase <key> in key-value store
 # params:
@@ -69,7 +121,7 @@ setkey() {
 #   0 - success
 #   non-zero - failure
 erase() {
-  readonly key=$1
+  readonly key="$1"
 
   if etcdctl $etcd_options --timeout $etcd_timeout \
     rm "$directory$key" >/dev/null 2>&1
@@ -90,8 +142,8 @@ erase() {
 #   2 or above - other failure
 # NOTE: if lock is already acquired by <owner>, then timeout is extended
 lock() {
-  readonly owner=$1
-  readonly timeout=$2
+  readonly owner="$1"
+  readonly timeout="$2"
 
   if etcdctl $etcd_options --timeout $etcd_timeout \
     mk "$directory$keyname" "$owner" \
@@ -145,7 +197,7 @@ lock_owner() {
 #   2 or above - other failure
 #
 unlock() {
-  readonly owner=$1
+  readonly owner="$1"
   readonly forced=${2:-false}
 
   if [ "$forced" = false ]; then
@@ -185,7 +237,7 @@ unlock() {
 #   0 - success, <new_value> is echoed to stdout
 #   non-zero - failure
 watch() {
-  readonly key=$1
+  readonly key="$1"
 
   if value=$(etcdctl $etcd_options --timeout $etcd_timeout \
     watch "$directory$key" 2>&1)
@@ -216,6 +268,22 @@ case "$1" in
     setkey "$2" "$3"
     exit $?
     ;;
+  set_if_prev)
+    if [ "$#" -ne 4 ]; then
+      echo "Usage: $0 set <key> <value> <previous_value>"
+      exit 1
+    fi
+    setkey_match_prev "$2" "$3" "$4"
+    exit $?
+    ;;
+  create)
+    if [ "$#" -ne 3 ]; then
+      echo "Usage: $0 create <key> <value>"
+      exit 1
+    fi
+    create_key "$2" "$3"
+    exit $?
+    ;;
   erase)
     if [ "$#" -ne 2 ]; then
       echo "Usage: $0 erase <key>"
@@ -269,7 +337,7 @@ case "$1" in
     exit $?
     ;;
   *)
-    echo "Usage: $0 {get|set|erase|lock|unlock|lock_owner|watch|watch_lock}"
+    echo "Usage: $0 
{get|set|create|set_if_prev|erase|lock|unlock|lock_owner|watch|watch_lock}"
     ;;
 esac
 
diff --git a/src/osaf/consensus/plugins/etcd3.plugin 
b/src/osaf/consensus/plugins/etcd3.plugin
new file mode 100644
index 000000000..451440567
--- /dev/null
+++ b/src/osaf/consensus/plugins/etcd3.plugin
@@ -0,0 +1,366 @@
+#!/usr/bin/env bash
+#      -*- OpenSAF  -*-
+#
+# (C) Copyright 2018 Ericsson AB 2018 - All Rights Reserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+# under the GNU Lesser General Public License Version 2.1, February 1999.
+# The complete license can be accessed from the following location:
+# http://opensource.org/licenses/lgpl-license.php
+# See the Copying file included with the OpenSAF distribution for full
+# licensing terms.
+#
+# Please note: this API is subject to change and may be modified
+# in a future version of OpenSAF. Future API versions may not be
+# backward compatible. This plugin may need to be adapted.
+
+readonly keyname="opensaf_consensus_lock"
+readonly directory="/opensaf/"
+readonly etcd_options=""
+readonly etcd_timeout="5s"
+
+export ETCDCTL_API=3
+
+# get
+#   retrieve <value> of <key> from key-value store
+# params:
+#   $1 - <key>
+# returns:
+#   0 - success, <value> is echoed to stdout
+#   non-zero - failure
+get() {
+  readonly key="$1"
+
+  if value=$(etcdctl $etcd_options --dial-timeout $etcd_timeout get 
"$directory$key" | tail -n1)
+  then
+    echo "$value"
+    return 0
+  else
+    return 1
+  fi
+}
+
+# set
+#   set <key> to <value> in key-value store
+# params:
+#   $1 - <key>
+#   $2 - <value>
+# returns:
+#   0 - success
+#   non-zero - failure
+setkey() {
+  readonly key="$1"
+  readonly value="$2"
+
+  if etcdctl $etcd_options --dial-timeout $etcd_timeout put "$directory$key" \
+    "$value" >/dev/null
+  then
+    return 0
+  else
+    return 1
+  fi
+}
+
+# create
+#   create <key> and set to <value> in key-value store. Fails if the key
+#   already exists
+# params:
+#   $1 - <key>
+#   $2 - <value>
+# returns:
+#   0 - success
+#   1 - already exists
+#   2 or above - other failure
+create_key() {
+  readonly key="$1"
+  readonly value="$2"
+  # first try to create the key
+  transaction="create(\""$directory$key"\") = \"0\"
+
+    put \""$directory$key"\" \""$value"\"
+
+  "
+  output=$(etcdctl $etcd_options --dial-timeout $etcd_timeout txn <<< 
"$transaction")
+  if [[ "$output" == *"OK"* ]]; then
+    return 0
+  fi
+
+  if output=$(etcdctl $etcd_options --dial-timeout $etcd_timeout get 
"$directory$key" | tail -n1)
+  then
+    return 1
+  else
+    return 2
+  fi
+}
+
+# set
+#   set <key> to <value> in key-value store, if the existing value matches
+#   <prev>
+# params:
+#   $1 - <key>
+#   $2 - <value>
+#   $3 - <prev>
+# returns:
+#   0 - success
+#   non-zero - failure
+setkey_match_prev() {
+  readonly key="$1"
+  readonly value="$2"
+  readonly prev="$3"
+
+  # key already exists, make sure it's empty
+  transaction="value(\""$directory$key"\") = \"$prev\"
+
+    put \""$directory$key"\" \""$value"\"
+
+  "
+  output=$(etcdctl $etcd_options --dial-timeout $etcd_timeout txn <<< 
"$transaction")
+  if [[ "$output" == *"OK"* ]]; then
+    return 0
+  fi
+
+  return 1
+}
+
+# erase
+#   erase <key> in key-value store
+# params:
+#   $1 - <key>
+# returns:
+#   0 - success
+#   non-zero - failure
+erase() {
+  readonly key="$1"
+
+  if etcdctl $etcd_options --dial-timeout $etcd_timeout \
+    del "$directory$key" >/dev/null 2>&1
+  then
+    return 0
+  else
+    return 1
+  fi
+}
+
+# lock
+# params:
+#   $1 - <owner>, owner of the lock is set to this
+#   $2 - <timeout>, will automatically unlock after <timeout> seconds
+# returns:
+#   0 - success
+#   1 - the lock is owned by someone else
+#   2 or above - other failure
+# NOTE: if lock is already acquired by <owner>, then timeout is extended
+# TODO: timeout not yet implemented
+lock() {
+  readonly owner="$1"
+  readonly timeout="$2"
+  # first try to create the key
+  transaction="create(\""$directory$keyname"\") = \"0\"
+
+    put \""$directory$keyname"\" \""$owner"\"
+
+  "
+  output=$(etcdctl $etcd_options --dial-timeout $etcd_timeout txn <<< 
"$transaction")
+  if [[ "$output" == *"OK"* ]]; then
+    return 0
+  fi
+
+  # key already exists, make sure it's empty
+  transaction="value(\""$directory$keyname"\") = \"\"
+
+    put \""$directory$keyname"\" \""$owner"\"
+
+  "
+  output=$(etcdctl $etcd_options --dial-timeout $etcd_timeout txn <<< 
"$transaction")
+  if [[ "$output" == *"OK"* ]]; then
+    return 0
+  fi
+
+  current_owner=$(etcdctl $etcd_options --dial-timeout $etcd_timeout get 
"$directory$keyname" | tail -n1)
+  # see if we already hold the lock
+  if [ "$current_owner" = "$owner" ]; then
+    return 0
+  fi
+
+  if [ -n "$current_owner" ]; then
+    # owned by someone else
+    echo "$current_owner"
+    return 1
+  fi
+
+  # for troubleshooting
+  echo "$output"
+  return 2
+}
+
+# get
+#   retrieve <owner> of lock
+# params:
+#   none
+# returns:
+#   0 - success, <owner> is echoed to stdout
+#   non-zero - failure or not locked
+lock_owner() {
+  get "$keyname"
+  return $?
+}
+
+# unlock
+# params:
+#   $1 - owner
+#   $2 - <forced>
+#      - (optional parameter)
+#      - if set 'true', will unlock even if lock is not held by node
+#      - defaults to 'false'
+# returns:
+#   0 - success
+#   1 - the lock is owned by someone else
+#   2 or above - other failure
+#
+unlock() {
+  readonly owner="$1"
+  readonly forced=${2:-false}
+  if [ "$forced" = false ]; then
+    # unlock on succeeds if owner matches
+    transaction="value(\""$directory$keyname"\") = \""$owner"\"
+
+    put \""$directory$keyname"\" \"\"
+
+    "
+    output=$(etcdctl $etcd_options --dial-timeout $etcd_timeout txn <<< 
"$transaction")
+    if [[ "$output" == *"OK"* ]]; then
+      return 0
+    fi
+
+    # failed! check we own the lock
+    current_owner=lock_owner
+    if [[ "$owner" != "$current_owner" && -n "$current_owner" ]]; then
+      # for troubleshooting
+      echo "$output"
+      echo "$current_owner"
+      return 1
+    fi
+
+    # for troubleshooting
+    echo "$output"
+    return 2
+  fi
+
+  if etcdctl $etcd_options --dial-timeout $etcd_timeout \
+    del "$directory$keyname" >/dev/null 2>&1
+  then
+    return 0
+  else
+    return 2
+  fi
+}
+
+# watch
+#   watch <key> in key-value store
+# params:
+#   $1 - <key>
+# returns:
+#   0 - success, <new_value> is echoed to stdout
+#   non-zero - failure
+watch() {
+  readonly watch_key="$1"
+  etcdctl $etcd_options --dial-timeout $etcd_timeout \
+    watch "$directory$watch_key" | grep -m0 \"\" 2>&1
+  get "$watch_key"
+  return 0
+}
+
+# argument parsing
+case "$1" in
+  get)
+    if [ "$#" -ne 2 ]; then
+      echo "Usage: $0 get <key>"
+      exit 1
+    fi
+    get "$2"
+    exit $?
+    ;;
+  set)
+    if [ "$#" -ne 3 ]; then
+      echo "Usage: $0 set <key> <value>"
+      exit 1
+    fi
+    setkey "$2" "$3"
+    exit $?
+    ;;
+  set_if_prev)
+    if [ "$#" -ne 4 ]; then
+      echo "Usage: $0 set <key> <value> <previous_value>"
+      exit 1
+    fi
+    setkey_match_prev "$2" "$3" "$4"
+    exit $?
+    ;;
+  create)
+    if [ "$#" -ne 3 ]; then
+      echo "Usage: $0 create <key> <value>"
+      exit 1
+    fi
+    create_key "$2" "$3"
+    exit $?
+    ;;
+  erase)
+    if [ "$#" -ne 2 ]; then
+      echo "Usage: $0 erase <key>"
+      exit 1
+    fi
+    erase "$2"
+    exit $?
+    ;;
+  lock)
+    if [ "$#" -ne 3 ]; then
+      echo "Usage: $0 lock <owner> <timeout>"
+      exit 1
+    fi
+    lock "$2" "$3"
+    exit $?
+    ;;
+  lock_owner)
+    if [ "$#" -ne 1 ]; then
+      echo "Usage: $0 lock_owner"
+      exit 1
+    fi
+    lock_owner
+    exit $?
+    ;;
+  unlock)
+    if [ "$#" -eq 2 ]; then
+      unlock "$2"
+      exit $?
+    elif [ "$#" -eq 3 ] && [ "$3" = "--force" ]; then
+      unlock "$2" 1
+      exit $?
+    else
+      echo "Usage: $0 unlock <owner> [--force]"
+      exit 1
+    fi
+    ;;
+  watch)
+    if [ "$#" -ne 2 ]; then
+      echo "Usage: $0 watch <key>"
+      exit 1
+    fi
+    watch "$2"
+    exit $?
+    ;;
+  watch_lock)
+    if [ "$#" -ne 1 ]; then
+      echo "Usage: $0 watch_lock"
+      exit 1
+    fi
+    watch "$keyname"
+    exit $?
+    ;;
+  *)
+    echo "Usage: $0 
{get|set|create|set_if_prev|erase|lock|unlock|lock_owner|watch|watch_lock}"
+    ;;
+esac
+
+exit 1
diff --git a/src/osaf/consensus/plugins/sample.plugin 
b/src/osaf/consensus/plugins/sample.plugin
index 433d23d98..445cf8d84 100644
--- a/src/osaf/consensus/plugins/sample.plugin
+++ b/src/osaf/consensus/plugins/sample.plugin
@@ -26,7 +26,7 @@ readonly keyname="opensaf_consensus_lock"
 #   0 - success, <value> is echoed to stdout
 #   non-zero - failure
 get() {
-  readonly key=$1
+  readonly key="$1"
   ...
 }
 
@@ -39,8 +39,41 @@ get() {
 #   0 - success
 #   non-zero - failure
 setkey() {
-  readonly key=$1
-  readonly value=$2
+  readonly key="$1"
+  readonly value="$2"
+  ...
+}
+
+# create
+#   create <key> and set to <value> in key-value store. Fails if the key
+#   already exists
+# params:
+#   $1 - <key>
+#   $2 - <value>
+# returns:
+#   0 - success
+#   1 - already exists
+#   2 or above - other failure
+create_key() {
+  readonly key="$1"
+  readonly value="$2"
+  ...
+}
+
+# set
+#   set <key> to <value> in key-value store, if the existing value matches
+#   <prev>
+# params:
+#   $1 - <key>
+#   $2 - <value>
+#   $3 - <prev>
+# returns:
+#   0 - success
+#   non-zero - failure
+setkey_match_prev() {
+  readonly key="$1"
+  readonly value="$2"
+  readonly prev="$3"
   ...
 }
 
@@ -52,7 +85,7 @@ setkey() {
 #   0 - success
 #   non-zero - failure
 erase() {
-  readonly key=$1
+  readonly key="$1"
   ...
 }
 
@@ -64,8 +97,8 @@ erase() {
 #   0 - success
 #   non-zero - failure
 lock() {
-  readonly owner=$1
-  readonly timeout=$2
+  readonly owner="$1"
+  readonly timeout="$2"
   ...
 }
 
@@ -92,7 +125,7 @@ lock_owner() {
 #   1 - the lock is owned by someone else
 #   2 or above - other failure#
 unlock() {
-  readonly owner=$1
+  readonly owner="$1"
   readonly forced=${2:-false}
   ...
 }
@@ -105,7 +138,7 @@ unlock() {
 #   0 - success, <new_value> is echoed to stdout
 #   non-zero - failure
 watch() {
-  readonly key=$1
+  readonly key="$1"
   ..
 }
 
@@ -127,6 +160,22 @@ case "$1" in
     setkey "$2" "$3"
     exit $?
     ;;
+  set_if_prev)
+    if [ "$#" -ne 4 ]; then
+      echo "Usage: $0 set <key> <value> <previous_value>"
+      exit 1
+    fi
+    setkey_match_prev "$2" "$3" "$4"
+    exit $?
+    ;;
+  create)
+    if [ "$#" -ne 3 ]; then
+      echo "Usage: $0 create <key> <value>"
+      exit 1
+    fi
+    create_key "$2" "$3"
+    exit $?
+    ;;
   erase)
     if [ "$#" -ne 2 ]; then
       echo "Usage: $0 erase <key>"
@@ -180,7 +229,7 @@ case "$1" in
     exit $?
     ;;
   *)
-    echo "Usage: $0 {get|set|erase|lock|unlock|lock_owner|watch|watch_lock}"
+    echo "Usage: $0 
{get|set|create|set_if_prev|erase|lock|unlock|lock_owner|watch|watch_lock}"
     ;;
 esac
 
-- 
2.14.1


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to