From 5276c2f0195c308d862d91b97317d813e754a35e Mon Sep 17 00:00:00 2001 From: Victor Castell Date: Sat, 4 Jan 2020 00:40:15 +0100 Subject: [PATCH] refactor: Allow pro appliers --- dkron/agent.go | 18 +++++++++++++++--- dkron/api.go | 6 +++++- dkron/fsm.go | 20 ++++++++++++++++++-- dkron/job.go | 9 ++------- dkron/job_test.go | 12 +++++------- dkron/leader.go | 2 +- dkron/options.go | 7 +++++++ dkron/queries_test.go | 2 +- dkron/scheduler.go | 9 +++++---- dkron/scheduler_test.go | 6 +++--- dkron/store.go | 24 ++++++++++-------------- dkron/store_test.go | 4 ++-- go.mod | 6 +----- go.sum | 26 ++++++++++++++++++++++++++ 14 files changed, 101 insertions(+), 50 deletions(-) diff --git a/dkron/agent.go b/dkron/agent.go index 5cb1ef33a..edbc94104 100644 --- a/dkron/agent.go +++ b/dkron/agent.go @@ -70,6 +70,7 @@ type Agent struct { // Pro features GlobalLock bool MemberEventHandler func(serf.Event) + ProAppliers LogAppliers serf *serf.Serf config *Config @@ -295,7 +296,7 @@ func (a *Agent) setupRaft() error { if err != nil { return fmt.Errorf("recovery failed to parse peers.json: %v", err) } - tmpFsm := newFSM(nil) + tmpFsm := newFSM(nil, nil) if err := raft.RecoverCluster(config, tmpFsm, logStore, stableStore, snapshots, transport, configuration); err != nil { return fmt.Errorf("recovery failed: %v", err) @@ -331,13 +332,14 @@ func (a *Agent) setupRaft() error { // Instantiate the Raft systems. The second parameter is a finite state machine // which stores the actual kv pairs and is operated upon through Apply(). - fsm := newFSM(a.Store) + fsm := newFSM(a.Store, a.ProAppliers) rft, err := raft.NewRaft(config, fsm, logStore, stableStore, snapshots, transport) if err != nil { return fmt.Errorf("new raft: %s", err) } a.leaderCh = rft.LeaderCh() a.raft = rft + return nil } @@ -462,7 +464,7 @@ func (a *Agent) StartServer() { log.WithError(err).WithField("dir", a.config.DataDir).Fatal("Error Creating Dir") } } - s, err := NewStore(a, filepath.Join(a.config.DataDir, a.config.NodeName)) + s, err := NewStore(filepath.Join(a.config.DataDir, a.config.NodeName)) if err != nil { log.WithError(err).Fatal("dkron: Error initializing store") } @@ -572,6 +574,11 @@ func (a *Agent) LocalMember() serf.Member { return a.serf.LocalMember() } +// Leader is used to return the Raft leader +func (a *Agent) Leader() raft.ServerAddress { + return a.raft.Leader() +} + // Servers returns a list of known server func (a *Agent) Servers() (members []*ServerParts) { for _, member := range a.serf.Members() { @@ -880,3 +887,8 @@ func (a *Agent) applySetJob(job *proto.Job) error { return nil } + +// RaftApply applies a command to the Raft log +func (a *Agent) RaftApply(cmd []byte) raft.ApplyFuture { + return a.raft.Apply(cmd, raftTimeout) +} diff --git a/dkron/api.go b/dkron/api.go index b26b1a0f3..4359a7b3d 100644 --- a/dkron/api.go +++ b/dkron/api.go @@ -117,7 +117,11 @@ func (h *HTTPTransport) indexHandler(c *gin.Context) { func (h *HTTPTransport) jobsHandler(c *gin.Context) { metadata := c.QueryMap("metadata") - jobs, err := h.agent.Store.GetJobs(&JobOptions{Metadata: metadata}) + jobs, err := h.agent.Store.GetJobs( + &JobOptions{ + Metadata: metadata, + }, + ) if err != nil { log.WithError(err).Error("api: Unable to get jobs, store not reachable.") return diff --git a/dkron/fsm.go b/dkron/fsm.go index 7237dfccb..44c60378e 100644 --- a/dkron/fsm.go +++ b/dkron/fsm.go @@ -26,15 +26,26 @@ const ( ExecutionDoneType ) +// LogApplier is the definition of a function that can apply a Raft log +type LogApplier func(buf []byte, index uint64) interface{} + +// LogAppliers is a mapping of the Raft MessageType to the appropriate log +// applier +type LogAppliers map[MessageType]LogApplier + type dkronFSM struct { store Storage mu sync.Mutex + + // proAppliers holds the set of pro only LogAppliers + proAppliers LogAppliers } // NewFSM is used to construct a new FSM with a blank state -func newFSM(store Storage) *dkronFSM { +func newFSM(store Storage, logAppliers LogAppliers) *dkronFSM { return &dkronFSM{ - store: store, + store: store, + proAppliers: logAppliers, } } @@ -56,6 +67,11 @@ func (d *dkronFSM) Apply(l *raft.Log) interface{} { return d.applySetExecution(buf[1:]) } + // Check enterprise only message types. + if applier, ok := d.proAppliers[msgType]; ok { + return applier(buf[1:], l.Index) + } + return nil } diff --git a/dkron/job.go b/dkron/job.go index 410253917..09916c9e6 100644 --- a/dkron/job.go +++ b/dkron/job.go @@ -279,12 +279,7 @@ func (j *Job) GetStatus() string { } // GetParent returns the parent job of a job -func (j *Job) GetParent() (*Job, error) { - // Maybe we are testing - if j.Agent == nil { - return nil, ErrNoAgent - } - +func (j *Job) GetParent(store *Store) (*Job, error) { if j.Name == j.ParentJob { return nil, ErrSameParent } @@ -293,7 +288,7 @@ func (j *Job) GetParent() (*Job, error) { return nil, ErrNoParent } - parentJob, err := j.Agent.Store.GetJob(j.ParentJob, nil) + parentJob, err := store.GetJob(j.ParentJob, nil) if err != nil { if err == badger.ErrKeyNotFound { return nil, ErrParentJobNotFound diff --git a/dkron/job_test.go b/dkron/job_test.go index ee767fe2a..14dc63012 100644 --- a/dkron/job_test.go +++ b/dkron/job_test.go @@ -15,11 +15,9 @@ func TestJobGetParent(t *testing.T) { require.NoError(t, err) defer os.RemoveAll(dir) - a := &Agent{} - s, err := NewStore(a, dir) + s, err := NewStore(dir) defer s.Shutdown() require.NoError(t, err) - a.Store = s parentTestJob := &Job{ Name: "parent_test", @@ -42,11 +40,11 @@ func TestJobGetParent(t *testing.T) { err = s.SetJob(dependentTestJob, true) assert.NoError(t, err) - parentTestJob, err = dependentTestJob.GetParent() + parentTestJob, err = dependentTestJob.GetParent(s) assert.NoError(t, err) assert.Equal(t, []string{dependentTestJob.Name}, parentTestJob.DependentJobs) - ptj, err := dependentTestJob.GetParent() + ptj, err := dependentTestJob.GetParent(s) assert.NoError(t, err) assert.Equal(t, parentTestJob.Name, ptj.Name) @@ -60,7 +58,7 @@ func TestJobGetParent(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "", dtj.ParentJob) - ptj, err = dtj.GetParent() + ptj, err = dtj.GetParent(s) assert.EqualError(t, ErrNoParent, err.Error()) ptj, err = s.GetJob(parentTestJob.Name, nil) @@ -111,7 +109,7 @@ func Test_isRunnable(t *testing.T) { defer os.RemoveAll(dir) a := &Agent{} - s, err := NewStore(a, dir) + s, err := NewStore(dir) a.Store = s defer s.Shutdown() require.NoError(t, err) diff --git a/dkron/leader.go b/dkron/leader.go index 14744167f..a1f2f20a9 100644 --- a/dkron/leader.go +++ b/dkron/leader.go @@ -192,7 +192,7 @@ func (a *Agent) establishLeadership(stopCh chan struct{}) error { if err != nil { log.Fatal(err) } - a.sched.Start(jobs) + a.sched.Start(jobs, a) return nil } diff --git a/dkron/options.go b/dkron/options.go index f6524fcdd..4506f7107 100644 --- a/dkron/options.go +++ b/dkron/options.go @@ -18,3 +18,10 @@ func WithTransportCredentials(tls *tls.Config) AgentOption { agent.TLSConfig = tls } } + +// WithStore set store in the agent +func WithStore(store Storage) AgentOption { + return func(agent *Agent) { + agent.Store = store + } +} diff --git a/dkron/queries_test.go b/dkron/queries_test.go index 36b129e18..61964577f 100644 --- a/dkron/queries_test.go +++ b/dkron/queries_test.go @@ -45,7 +45,7 @@ func TestRunQuery(t *testing.T) { err = a.Store.SetJob(j1, false) require.NoError(t, err) - a.sched.Start([]*Job{j1}) + a.sched.Start([]*Job{j1}, a) _, err = a.RunQuery("test_job", &Execution{}) assert.NoError(t, err) diff --git a/dkron/scheduler.go b/dkron/scheduler.go index 064ab3774..590880e9a 100644 --- a/dkron/scheduler.go +++ b/dkron/scheduler.go @@ -6,8 +6,8 @@ import ( "strings" "github.com/armon/go-metrics" - "github.com/robfig/cron/v3" "github.com/distribworks/dkron/v2/extcron" + "github.com/robfig/cron/v3" "github.com/sirupsen/logrus" ) @@ -39,11 +39,12 @@ func NewScheduler() *Scheduler { // Start the cron scheduler, adding its corresponding jobs and // executing them on time. -func (s *Scheduler) Start(jobs []*Job) error { +func (s *Scheduler) Start(jobs []*Job, agent *Agent) error { s.Cron = cron.New(cron.WithParser(extcron.NewParser())) metrics.IncrCounter([]string{"scheduler", "start"}, 1) for _, job := range jobs { + job.Agent = agent s.AddJob(job) } s.Cron.Start() @@ -70,9 +71,9 @@ func (s *Scheduler) Stop() { } // Restart the scheduler -func (s *Scheduler) Restart(jobs []*Job) { +func (s *Scheduler) Restart(jobs []*Job, agent *Agent) { s.Stop() - s.Start(jobs) + s.Start(jobs, agent) } // GetEntry returns a scheduler entry from a snapshot in diff --git a/dkron/scheduler_test.go b/dkron/scheduler_test.go index aa543fc80..21f287954 100644 --- a/dkron/scheduler_test.go +++ b/dkron/scheduler_test.go @@ -20,7 +20,7 @@ func TestSchedule(t *testing.T) { Owner: "John Dough", OwnerEmail: "foo@bar.com", } - sched.Start([]*Job{testJob1}) + sched.Start([]*Job{testJob1}, &Agent{}) assert.True(t, sched.Started) now := time.Now().Truncate(time.Second) @@ -36,7 +36,7 @@ func TestSchedule(t *testing.T) { Owner: "John Dough", OwnerEmail: "foo@bar.com", } - sched.Restart([]*Job{testJob2}) + sched.Restart([]*Job{testJob2}, &Agent{}) assert.True(t, sched.Started) assert.Len(t, sched.Cron.Entries(), 1) @@ -52,7 +52,7 @@ func TestTimezoneAwareJob(t *testing.T) { Executor: "shell", ExecutorConfig: map[string]string{"command": "echo 'test1'", "shell": "true"}, } - sched.Start([]*Job{tzJob}) + sched.Start([]*Job{tzJob}, &Agent{}) assert.True(t, sched.Started) assert.Len(t, sched.Cron.Entries(), 1) diff --git a/dkron/store.go b/dkron/store.go index eebc11a9e..3a5f7cd04 100644 --- a/dkron/store.go +++ b/dkron/store.go @@ -32,7 +32,6 @@ var ( // It gives dkron the ability to manipulate its embedded storage // BadgerDB. type Store struct { - agent *Agent db *badger.DB lock *sync.Mutex // for closed bool @@ -44,7 +43,7 @@ type JobOptions struct { } // NewStore creates a new Storage instance. -func NewStore(a *Agent, dir string) (*Store, error) { +func NewStore(dir string) (*Store, error) { opts := badger.DefaultOptions(dir). WithLogger(log) @@ -58,9 +57,8 @@ func NewStore(a *Agent, dir string) (*Store, error) { } store := &Store{ - db: db, - agent: a, - lock: &sync.Mutex{}, + db: db, + lock: &sync.Mutex{}, } go store.runGcLoop() @@ -108,14 +106,16 @@ func (s *Store) setJobTxnFunc(pbj *dkronpb.Job) func(txn *badger.Txn) error { } } +// DB is the getter for the BadgerDB instance +func (s *Store) DB() *badger.DB { + return s.db +} + // SetJob stores a job in the storage func (s *Store) SetJob(job *Job, copyDependentJobs bool) error { var pbej dkronpb.Job var ej *Job - // Init the job agent - job.Agent = s.agent - if err := job.Validate(); err != nil { return err } @@ -135,7 +135,6 @@ func (s *Store) SetJob(job *Job, copyDependentJobs bool) error { } ej = NewJobFromProto(&pbej) - ej.Agent = s.agent if ej.Name != "" { // When the job runs, these status vars are updated @@ -193,7 +192,7 @@ func (s *Store) removeFromParent(child *Job) error { return nil } - parent, err := child.GetParent() + parent, err := child.GetParent(s) if err != nil { return err } @@ -221,7 +220,7 @@ func (s *Store) addToParent(child *Job) error { return nil } - parent, err := child.GetParent() + parent, err := child.GetParent(s) if err != nil { return err } @@ -322,7 +321,6 @@ func (s *Store) GetJobs(options *JobOptions) ([]*Job, error) { } job := NewJobFromProto(&pbj) - job.Agent = s.agent if options != nil { if options.Metadata != nil && len(options.Metadata) > 0 && !s.jobHasMetadata(job, options.Metadata) { continue @@ -347,7 +345,6 @@ func (s *Store) GetJob(name string, options *JobOptions) (*Job, error) { } job := NewJobFromProto(&pbj) - job.Agent = s.agent return job, nil } @@ -394,7 +391,6 @@ func (s *Store) DeleteJob(name string) (*Job, error) { return ErrDependentJobs } job = NewJobFromProto(&pbj) - job.Agent = s.agent if err := s.DeleteExecutions(name); err != nil { return err diff --git a/dkron/store_test.go b/dkron/store_test.go index 8485e48a6..e55cee333 100644 --- a/dkron/store_test.go +++ b/dkron/store_test.go @@ -16,7 +16,7 @@ func TestStore(t *testing.T) { require.NoError(t, err) defer os.RemoveAll(dir) - s, err := NewStore(nil, dir) + s, err := NewStore(dir) require.NoError(t, err) defer s.Shutdown() @@ -475,7 +475,7 @@ func setupStore(t *testing.T) (*Store, string) { require.NoError(t, err) a := NewAgent(nil) - s, err := NewStore(a, dir) + s, err := NewStore(dir) require.NoError(t, err) a.Store = s diff --git a/go.mod b/go.mod index 618111f69..0b32e5b4d 100644 --- a/go.mod +++ b/go.mod @@ -10,8 +10,7 @@ require ( github.com/dnaeon/go-vcr v1.0.1 // indirect github.com/gin-contrib/expvar v0.0.0-20180827025536-251166f58ff2 github.com/gin-contrib/multitemplate v0.0.0-20170922032617-bbc6daf6024b - github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect - github.com/gin-gonic/gin v1.3.0 + github.com/gin-gonic/gin v1.5.0 github.com/gogo/protobuf v1.2.0 // indirect github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 github.com/golang/protobuf v1.3.2 @@ -29,7 +28,6 @@ require ( github.com/hashicorp/serf v0.8.2 github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect github.com/jordan-wright/email v0.0.0-20180115032944-94ae17dedda2 - github.com/json-iterator/go v1.1.6 // indirect github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 github.com/mattn/go-shellwords v0.0.0-20160315040826-525bedee691b github.com/mitchellh/go-testing-interface v1.0.0 // indirect @@ -42,12 +40,10 @@ require ( github.com/spf13/pflag v1.0.3 github.com/spf13/viper v1.3.2 github.com/stretchr/testify v1.4.0 - github.com/ugorji/go v1.1.5-pre // indirect golang.org/x/net v0.0.0-20190620200207-3b0461eec859 golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db // indirect google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 // indirect google.golang.org/grpc v1.19.1 - gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v8 v8.18.2 // indirect ) diff --git a/go.sum b/go.sum index 06530aa13..557317e51 100644 --- a/go.sum +++ b/go.sum @@ -67,9 +67,17 @@ github.com/gin-contrib/multitemplate v0.0.0-20170922032617-bbc6daf6024b h1:D/1/e github.com/gin-contrib/multitemplate v0.0.0-20170922032617-bbc6daf6024b/go.mod h1:62qM8p4crGvNKE413gTzn4eMFin1VOJfMDWMRzHdvqM= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs= github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= +github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc= +github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= +github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= +github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -92,6 +100,8 @@ github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOF github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/gophercloud/gophercloud v0.0.0-20180828235145-f29afc2cceca h1:wobTb8SE189AuxzEKClyYxiI4nUGWlpVtl13eLiFlOE= @@ -167,6 +177,8 @@ github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswD github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro= github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= @@ -177,6 +189,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= +github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/linode/linodego v0.7.1 h1:4WZmMpSA2NRwlPZcc0+4Gyn7rr99Evk9bnr0B3gXRKE= github.com/linode/linodego v0.7.1/go.mod h1:ga11n3ivecUrPCHN0rANxKmfWBJVkOXfLMZinAbj2sY= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= @@ -184,6 +198,8 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-shellwords v0.0.0-20160315040826-525bedee691b h1:wdxxNEOv2NWWo/9MbMO/zEMq7DJOcpWQG8CH4YSW1nA= github.com/mattn/go-shellwords v0.0.0-20160315040826-525bedee691b/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= @@ -203,8 +219,10 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 h1:BQ1HW7hr4IVovMwWg0E0PYcyW8CzqDcVmaew9cujU4s= @@ -282,9 +300,13 @@ github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9 h1:/Bsw4C+DEdqPj github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9/go.mod h1:RHkNRtSLfOK7qBTHaeSX1D6BNpI3qw7NTxsmNr4RvN8= github.com/ugorji/go v1.1.5-pre h1:jyJKFOSEbdOc2HODrf2qcCkYOdq7zzXqA9bhW5oV4fM= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.5-pre h1:5YV9PsFAN+ndcCtTM7s60no7nY7eTG3LPtxhSwuxzCs= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= @@ -328,6 +350,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU= @@ -361,6 +385,8 @@ gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXa gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= +gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI=