Merge pull request #262 from ipfs/fix/lock-service
ipfs-cluster-service lock
This commit is contained in:
commit
9f8849fb18
|
@ -17,7 +17,8 @@ script:
|
||||||
- make test_sharness && make clean_sharness
|
- make test_sharness && make clean_sharness
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
secure: M3K3y9+D933tCda7+blW3qqVV8fA6PBDRdJoQvmQc1f0XYbWinJ+bAziFp6diKkF8sMQ+cPwLMONYJuaNT2h7/PkG+sIwF0PuUo5VVCbhGmSDrn2qOjmSnfawNs8wW31f44FQA8ICka1EFZcihohoIMf0e5xZ0tXA9jqw+ngPJiRnv4zyzC3r6t4JMAZcbS9w4KTYpIev5Yj72eCvk6lGjadSVCDVXo2sVs27tNt+BSgtMXiH6Sv8GLOnN2kFspGITgivHgB/jtU6QVtFXB+cbBJJAs3lUYnzmQZ5INecbjweYll07ilwFiCVNCX67+L15gpymKGJbQggloIGyTWrAOa2TMaB/bvblzwwQZ8wE5P3Rss5L0TFkUAcdU+3BUHM+TwV4e8F9x10v1PjgWNBRJQzd1sjKKgGUBCeyCY7VeYDKn9AXI5llISgY/AAfCZwm2cbckMHZZJciMjm+U3Q1FCF+rfhlvUcMG1VEj8r9cGpmWIRjFYVm0NmpUDDNjlC3/lUfTCOOJJyM254EUw63XxabbK6EtDN1yQe8kYRcXH//2rtEwgtMBgqHVY+OOkekzGz8Ra3EBkh6jXrAQL3zKu/GwRlK7/a1OU5MQ7dWcTjbx1AQ6Zfyjg5bZ+idqPgMbqM9Zn2+OaSby8HEEXS0QeZVooDVf/6wdYO4MQ/0A=
|
- secure: M3K3y9+D933tCda7+blW3qqVV8fA6PBDRdJoQvmQc1f0XYbWinJ+bAziFp6diKkF8sMQ+cPwLMONYJuaNT2h7/PkG+sIwF0PuUo5VVCbhGmSDrn2qOjmSnfawNs8wW31f44FQA8ICka1EFZcihohoIMf0e5xZ0tXA9jqw+ngPJiRnv4zyzC3r6t4JMAZcbS9w4KTYpIev5Yj72eCvk6lGjadSVCDVXo2sVs27tNt+BSgtMXiH6Sv8GLOnN2kFspGITgivHgB/jtU6QVtFXB+cbBJJAs3lUYnzmQZ5INecbjweYll07ilwFiCVNCX67+L15gpymKGJbQggloIGyTWrAOa2TMaB/bvblzwwQZ8wE5P3Rss5L0TFkUAcdU+3BUHM+TwV4e8F9x10v1PjgWNBRJQzd1sjKKgGUBCeyCY7VeYDKn9AXI5llISgY/AAfCZwm2cbckMHZZJciMjm+U3Q1FCF+rfhlvUcMG1VEj8r9cGpmWIRjFYVm0NmpUDDNjlC3/lUfTCOOJJyM254EUw63XxabbK6EtDN1yQe8kYRcXH//2rtEwgtMBgqHVY+OOkekzGz8Ra3EBkh6jXrAQL3zKu/GwRlK7/a1OU5MQ7dWcTjbx1AQ6Zfyjg5bZ+idqPgMbqM9Zn2+OaSby8HEEXS0QeZVooDVf/6wdYO4MQ/0A=
|
||||||
|
- verbose=t
|
||||||
after_success:
|
after_success:
|
||||||
- openssl aes-256-cbc -K $encrypted_5a1cb914c6c9_key -iv $encrypted_5a1cb914c6c9_iv
|
- openssl aes-256-cbc -K $encrypted_5a1cb914c6c9_key -iv $encrypted_5a1cb914c6c9_iv
|
||||||
-in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d
|
-in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d
|
||||||
|
|
58
ipfs-cluster-service/lock.go
Normal file
58
ipfs-cluster-service/lock.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
// lock logic heavily inspired by go-ipfs/repo/fsrepo/lock/lock.go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
filelock "go4.org/lock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The name of the file used for locking
|
||||||
|
const lockFileName = "cluster.lock"
|
||||||
|
|
||||||
|
var locker *Locker
|
||||||
|
|
||||||
|
// Global file, close to relinquish lock access
|
||||||
|
type Locker struct {
|
||||||
|
lockCloser io.Closer
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (locker *Locker) lock() error {
|
||||||
|
if locker.lockCloser != nil {
|
||||||
|
return fmt.Errorf("cannot acquire lock twice")
|
||||||
|
}
|
||||||
|
// set the lock file within this function
|
||||||
|
logger.Debug("checking lock")
|
||||||
|
lk, err := filelock.Lock(path.Join(locker.path, lockFileName))
|
||||||
|
if err != nil {
|
||||||
|
logger.Debug(err)
|
||||||
|
locker.lockCloser = nil
|
||||||
|
errStr := `could not obtain execution lock. If no other process
|
||||||
|
is running, remove ~/path/to/lock, or make sure that the config folder is
|
||||||
|
writable for the user running ipfs-cluster. Run with -d for more information
|
||||||
|
about the error`
|
||||||
|
logger.Error(errStr)
|
||||||
|
return fmt.Errorf("could not obtain execution lock.")
|
||||||
|
}
|
||||||
|
logger.Debug("Success! ipfs-cluster-service lock acquired")
|
||||||
|
locker.lockCloser = lk
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (locker *Locker) tryUnlock() error {
|
||||||
|
// Noop in the uninitialized case
|
||||||
|
if locker.lockCloser == nil {
|
||||||
|
logger.Debug("locking not initialized, unlock is noop")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := locker.lockCloser.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Debug("Successfully released execution lock")
|
||||||
|
locker.lockCloser = nil
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -139,6 +139,10 @@ func out(m string, a ...interface{}) {
|
||||||
func checkErr(doing string, err error) {
|
func checkErr(doing string, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
out("error %s: %s\n", doing, err)
|
out("error %s: %s\n", doing, err)
|
||||||
|
err = locker.tryUnlock()
|
||||||
|
if err != nil {
|
||||||
|
out("error releasing execution lock: %s\n", err)
|
||||||
|
}
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,7 +261,7 @@ removal, upgrade state using this command, and restart every peer.
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
err := upgrade()
|
err := upgrade()
|
||||||
checkErr("upgrading state", err)
|
checkErr("upgrading state", err)
|
||||||
return nil
|
return err
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -276,6 +280,9 @@ removal, upgrade state using this command, and restart every peer.
|
||||||
if c.Bool("debug") {
|
if c.Bool("debug") {
|
||||||
setupDebug()
|
setupDebug()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
locker = &Locker{path: absPath}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,10 +302,16 @@ func run(c *cli.Context) error {
|
||||||
func daemon(c *cli.Context) error {
|
func daemon(c *cli.Context) error {
|
||||||
// Load all the configurations
|
// Load all the configurations
|
||||||
cfg, clusterCfg, apiCfg, ipfshttpCfg, consensusCfg, trackerCfg, monCfg, diskInfCfg, numpinInfCfg := makeConfigs()
|
cfg, clusterCfg, apiCfg, ipfshttpCfg, consensusCfg, trackerCfg, monCfg, diskInfCfg, numpinInfCfg := makeConfigs()
|
||||||
|
// Execution lock
|
||||||
|
err := locker.lock()
|
||||||
|
checkErr("acquiring execution lock", err)
|
||||||
|
defer locker.tryUnlock()
|
||||||
|
|
||||||
|
// Load all the configurations
|
||||||
// always wait for configuration to be saved
|
// always wait for configuration to be saved
|
||||||
defer cfg.Shutdown()
|
defer cfg.Shutdown()
|
||||||
|
|
||||||
err := cfg.LoadJSONFromFile(configPath)
|
err = cfg.LoadJSONFromFile(configPath)
|
||||||
checkErr("loading configuration", err)
|
checkErr("loading configuration", err)
|
||||||
|
|
||||||
if a := c.String("bootstrap"); a != "" {
|
if a := c.String("bootstrap"); a != "" {
|
||||||
|
|
|
@ -9,10 +9,18 @@ import (
|
||||||
"github.com/ipfs/ipfs-cluster/state/mapstate"
|
"github.com/ipfs/ipfs-cluster/state/mapstate"
|
||||||
)
|
)
|
||||||
|
|
||||||
func upgrade() error {
|
func upgrade() error {
|
||||||
//Load configs
|
// Load configs
|
||||||
cfg, clusterCfg, _, _, consensusCfg, _, _, _, _ := makeConfigs()
|
cfg, clusterCfg, _, _, consensusCfg, _, _, _, _ := makeConfigs()
|
||||||
err := cfg.LoadJSONFromFile(configPath)
|
|
||||||
|
// Execution lock
|
||||||
|
err := locker.lock()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer locker.tryUnlock()
|
||||||
|
|
||||||
|
err = cfg.LoadJSONFromFile(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,12 @@
|
||||||
"hash": "QmcWmYQEQCrezztaQ81nXzMx2jaAEow17wdesDAjjR769r",
|
"hash": "QmcWmYQEQCrezztaQ81nXzMx2jaAEow17wdesDAjjR769r",
|
||||||
"name": "go-libp2p-pnet",
|
"name": "go-libp2p-pnet",
|
||||||
"version": "2.3.1"
|
"version": "2.3.1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"author": "whyrusleeping",
|
||||||
|
"hash": "QmWi28zbQG6B1xfaaWx5cYoLn3kBFU6pQ6GWQNRV5P6dNe",
|
||||||
|
"name": "lock",
|
||||||
|
"version": "0.0.0"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"gxVersion": "0.11.0",
|
"gxVersion": "0.11.0",
|
||||||
|
|
|
@ -27,4 +27,8 @@ test_expect_success "cluster-service --version succeeds and matches ctl" '
|
||||||
[ "$SERV_VERSION" = "$CTL_VERSION" ]
|
[ "$SERV_VERSION" = "$CTL_VERSION" ]
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success "starting a second cluster-service process fails" '
|
||||||
|
test_expect_code 1 ipfs-cluster-service --config "test-config"
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
|
@ -14,7 +14,8 @@ test_expect_success IPFS,CLUSTER "cluster-service state upgrade works" '
|
||||||
ipfs-cluster-ctl pin add "$cid" &&
|
ipfs-cluster-ctl pin add "$cid" &&
|
||||||
sleep 5 &&
|
sleep 5 &&
|
||||||
cluster_kill &&
|
cluster_kill &&
|
||||||
ipfs-cluster-service --config "test-config" state upgrade
|
sleep 5 &&
|
||||||
|
ipfs-cluster-service --debug --config "test-config" state upgrade
|
||||||
'
|
'
|
||||||
|
|
||||||
# previous test kills the cluster, we need to re-start
|
# previous test kills the cluster, we need to re-start
|
||||||
|
|
Loading…
Reference in New Issue
Block a user