Kaynağa Gözat

Merge pull request #7983 from heyitsanthony/etcdctl-lock-exec

etcdctl: support exec on lock
Anthony Romano 8 yıl önce
ebeveyn
işleme
967fc70173
2 değiştirilmiş dosya ile 38 ekleme ve 7 silme
  1. 12 1
      etcdctl/README.md
  2. 26 6
      etcdctl/ctlv3/command/lock_command.go

+ 12 - 1
etcdctl/README.md

@@ -790,7 +790,7 @@ Prints a line of JSON encoding the database hash, revision, total keys, and size
 
 
 ## Concurrency commands
 ## Concurrency commands
 
 
-### LOCK \<lockname\>
+### LOCK \<lockname\> [command arg1 arg2 ...]
 
 
 LOCK acquires a distributed named mutex with a given name. Once the lock is acquired, it will be held until etcdctl is terminated.
 LOCK acquires a distributed named mutex with a given name. Once the lock is acquired, it will be held until etcdctl is terminated.
 
 
@@ -798,13 +798,24 @@ LOCK acquires a distributed named mutex with a given name. Once the lock is acqu
 
 
 Once the lock is acquired, the result for the GET on the unique lock holder key is displayed.
 Once the lock is acquired, the result for the GET on the unique lock holder key is displayed.
 
 
+If a command is given, it will be launched with environment variables `ETCD_LOCK_KEY` and `ETCD_LOCK_REV` set to the lock's holder key and revision.
+
 #### Example
 #### Example
 
 
+Acquire lock with standard output display:
+
 ```bash
 ```bash
 ./etcdctl lock mylock
 ./etcdctl lock mylock
 # mylock/1234534535445
 # mylock/1234534535445
 ```
 ```
 
 
+Acquire lock and execute `echo lock acquired`:
+
+```bash
+./etcdctl lock mylock echo lock acquired
+# lock acquired
+```
+
 #### Remarks
 #### Remarks
 
 
 LOCK returns a zero exit code only if it is terminated by a signal and releases the lock.
 LOCK returns a zero exit code only if it is terminated by a signal and releases the lock.

+ 26 - 6
etcdctl/ctlv3/command/lock_command.go

@@ -16,7 +16,9 @@ package command
 
 
 import (
 import (
 	"errors"
 	"errors"
+	"fmt"
 	"os"
 	"os"
+	"os/exec"
 	"os/signal"
 	"os/signal"
 	"syscall"
 	"syscall"
 
 
@@ -29,7 +31,7 @@ import (
 // NewLockCommand returns the cobra command for "lock".
 // NewLockCommand returns the cobra command for "lock".
 func NewLockCommand() *cobra.Command {
 func NewLockCommand() *cobra.Command {
 	c := &cobra.Command{
 	c := &cobra.Command{
-		Use:   "lock <lockname>",
+		Use:   "lock <lockname> [exec-command arg1 arg2 ...]",
 		Short: "Acquires a named lock",
 		Short: "Acquires a named lock",
 		Run:   lockCommandFunc,
 		Run:   lockCommandFunc,
 	}
 	}
@@ -37,16 +39,16 @@ func NewLockCommand() *cobra.Command {
 }
 }
 
 
 func lockCommandFunc(cmd *cobra.Command, args []string) {
 func lockCommandFunc(cmd *cobra.Command, args []string) {
-	if len(args) != 1 {
-		ExitWithError(ExitBadArgs, errors.New("lock takes one lock name argument."))
+	if len(args) == 0 {
+		ExitWithError(ExitBadArgs, errors.New("lock takes a lock name argument and an optional command to execute."))
 	}
 	}
 	c := mustClientFromCmd(cmd)
 	c := mustClientFromCmd(cmd)
-	if err := lockUntilSignal(c, args[0]); err != nil {
+	if err := lockUntilSignal(c, args[0], args[1:]); err != nil {
 		ExitWithError(ExitError, err)
 		ExitWithError(ExitError, err)
 	}
 	}
 }
 }
 
 
-func lockUntilSignal(c *clientv3.Client, lockname string) error {
+func lockUntilSignal(c *clientv3.Client, lockname string, cmdArgs []string) error {
 	s, err := concurrency.NewSession(c)
 	s, err := concurrency.NewSession(c)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -69,6 +71,18 @@ func lockUntilSignal(c *clientv3.Client, lockname string) error {
 		return err
 		return err
 	}
 	}
 
 
+	if len(cmdArgs) > 0 {
+		cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
+		cmd.Env = append(environLockResponse(m), os.Environ()...)
+		cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
+		err := cmd.Run()
+		unlockErr := m.Unlock(context.TODO())
+		if err != nil {
+			return err
+		}
+		return unlockErr
+	}
+
 	k, kerr := c.Get(ctx, m.Key())
 	k, kerr := c.Get(ctx, m.Key())
 	if kerr != nil {
 	if kerr != nil {
 		return kerr
 		return kerr
@@ -76,7 +90,6 @@ func lockUntilSignal(c *clientv3.Client, lockname string) error {
 	if len(k.Kvs) == 0 {
 	if len(k.Kvs) == 0 {
 		return errors.New("lock lost on init")
 		return errors.New("lock lost on init")
 	}
 	}
-
 	display.Get(*k)
 	display.Get(*k)
 
 
 	select {
 	select {
@@ -87,3 +100,10 @@ func lockUntilSignal(c *clientv3.Client, lockname string) error {
 
 
 	return errors.New("session expired")
 	return errors.New("session expired")
 }
 }
+
+func environLockResponse(m *concurrency.Mutex) []string {
+	return []string{
+		"ETCD_LOCK_KEY=" + m.Key(),
+		fmt.Sprintf("ETCD_LOCK_REV=%d", m.Header().Revision),
+	}
+}