etcd: Rewrite embed etcd implementation

This is a giant cleanup of the etcd code. The earlier version was
written when I was less experienced with golang.

This is still not perfect, and does contain some races, but at least
it's a decent base to start from. The automatic elastic clustering
should be considered an experimental feature. If you need a more
battle-tested cluster, then you should manage etcd manually and point
mgmt at your existing cluster.
This commit is contained in:
James Shubin
2018-05-05 17:35:08 -04:00
parent fb275d9537
commit a5842a41b2
56 changed files with 5459 additions and 2654 deletions

View File

@@ -18,11 +18,13 @@
package lib
import (
"context"
"fmt"
"log"
"os"
"github.com/purpleidea/mgmt/etcd"
"github.com/purpleidea/mgmt/etcd/client"
"github.com/purpleidea/mgmt/etcd/deployer"
etcdfs "github.com/purpleidea/mgmt/etcd/fs"
"github.com/purpleidea/mgmt/gapi"
"github.com/purpleidea/mgmt/util/errwrap"
@@ -34,12 +36,13 @@ import (
const (
// MetadataPrefix is the etcd prefix where all our fs superblocks live.
MetadataPrefix = etcd.NS + "/fs"
MetadataPrefix = "/fs"
// StoragePrefix is the etcd prefix where all our fs data lives.
StoragePrefix = etcd.NS + "/storage"
StoragePrefix = "/storage"
)
// deploy is the cli target to manage deploys to our cluster.
// TODO: add a timeout and/or cancel signal to replace context.TODO()
func deploy(c *cli.Context, name string, gapiObj gapi.GAPI) error {
cliContext := c.Parent()
if cliContext == nil {
@@ -55,7 +58,12 @@ func deploy(c *cli.Context, name string, gapiObj gapi.GAPI) error {
debug = flags.Debug
}
}
Logf := func(format string, v ...interface{}) {
log.Printf("deploy: "+format, v...)
}
hello(program, version, flags) // say hello!
defer Logf("goodbye!")
var hash, pHash string
if !cliContext.Bool("no-git") {
@@ -74,7 +82,7 @@ func deploy(c *cli.Context, name string, gapiObj gapi.GAPI) error {
}
hash = head.Hash().String() // current commit id
log.Printf("deploy: hash: %s", hash)
Logf("hash: %s", hash)
lo := &git.LogOptions{
From: head.Hash(),
@@ -90,7 +98,7 @@ func deploy(c *cli.Context, name string, gapiObj gapi.GAPI) error {
if err == nil { // errors are okay, we might be empty
pHash = commit.Hash.String() // previous commit id
}
log.Printf("deploy: previous deploy hash: %s", pHash)
Logf("previous deploy hash: %s", pHash)
if cliContext.Bool("force") {
pHash = "" // don't check this :(
}
@@ -101,28 +109,58 @@ func deploy(c *cli.Context, name string, gapiObj gapi.GAPI) error {
uniqueid := uuid.New() // panic's if it can't generate one :P
etcdClient := &etcd.ClientEtcd{
Seeds: cliContext.StringSlice("seeds"), // endpoints
etcdClient := client.NewClientFromSeedsNamespace(
cliContext.StringSlice("seeds"), // endpoints
NS,
)
if err := etcdClient.Init(); err != nil {
return errwrap.Wrapf(err, "client Init failed")
}
if err := etcdClient.Connect(); err != nil {
return errwrap.Wrapf(err, "client connection error")
defer func() {
err := errwrap.Wrapf(etcdClient.Close(), "client Close failed")
if err != nil {
// TODO: cause the final exit code to be non-zero
Logf("client cleanup error: %+v", err)
}
}()
simpleDeploy := &deployer.SimpleDeploy{
Client: etcdClient,
Debug: debug,
Logf: func(format string, v ...interface{}) {
Logf("deploy: "+format, v...)
},
}
defer etcdClient.Destroy()
if err := simpleDeploy.Init(); err != nil {
return errwrap.Wrapf(err, "deploy Init failed")
}
defer func() {
err := errwrap.Wrapf(simpleDeploy.Close(), "deploy Close failed")
if err != nil {
// TODO: cause the final exit code to be non-zero
Logf("deploy cleanup error: %+v", err)
}
}()
// get max id (from all the previous deploys)
max, err := etcd.GetMaxDeployID(etcdClient)
max, err := simpleDeploy.GetMaxDeployID(context.TODO())
if err != nil {
return errwrap.Wrapf(err, "error getting max deploy id")
}
// find the latest id
var id = max + 1 // next id
log.Printf("deploy: max deploy id: %d", max)
Logf("previous max deploy id: %d", max)
etcdFs := &etcdfs.Fs{
Client: etcdClient.GetClient(),
Client: etcdClient,
// TODO: using a uuid is meant as a temporary measure, i hate them
Metadata: MetadataPrefix + fmt.Sprintf("/deploy/%d-%s", id, uniqueid),
DataPrefix: StoragePrefix,
Debug: debug,
Logf: func(format string, v ...interface{}) {
Logf("fs: "+format, v...)
},
}
cliInfo := &gapi.CliInfo{
@@ -154,9 +192,9 @@ func deploy(c *cli.Context, name string, gapiObj gapi.GAPI) error {
}
// this nominally checks the previous git hash matches our expectation
if err := etcd.AddDeploy(etcdClient, id, hash, pHash, &str); err != nil {
if err := simpleDeploy.AddDeploy(context.TODO(), id, hash, pHash, &str); err != nil {
return errwrap.Wrapf(err, "could not create deploy id `%d`", id)
}
log.Printf("deploy: success, id: %d", id)
Logf("success, id: %d", id)
return nil
}