diff --git a/api/api_test.go b/api/api_test.go index a4144871..3294ce07 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -9,6 +9,7 @@ import ( "os" "strconv" "strings" + "sync" "testing" "time" @@ -61,7 +62,8 @@ func TestMain(m *testing.M) { auth.Init(store) ctx := context.Background() - if err := engine.Init(ctx, store); err != nil { + var wg sync.WaitGroup + if err := engine.Init(ctx, &wg, store); err != nil { panic(err) } diff --git a/api/handler/resolution.go b/api/handler/resolution.go index 638ecee9..9b1225c1 100644 --- a/api/handler/resolution.go +++ b/api/handler/resolution.go @@ -252,7 +252,7 @@ func RunResolution(c *gin.Context, in *runResolutionIn) error { logrus.WithFields(logrus.Fields{"resolution_id": r.PublicID}).Debugf("Handler RunResolution: manual resolve %s", r.PublicID) - return engine.GetEngine().Resolve(in.PublicID) + return engine.GetEngine().Resolve(in.PublicID, nil) } type extendResolutionIn struct { diff --git a/cmd/utask/root.go b/cmd/utask/root.go index 44b3b1ba..b2be401a 100644 --- a/cmd/utask/root.go +++ b/cmd/utask/root.go @@ -7,6 +7,7 @@ import ( "fmt" "net/http" "os" + "sync" "time" "github.com/juju/errors" @@ -164,19 +165,34 @@ var rootCmd = &cobra.Command{ if err := tasktemplate.LoadFromDir(dbp, utask.FTemplatesFolder); err != nil { return err } - + var wg sync.WaitGroup ctx, cancel := context.WithCancel(context.Background()) defer func() { // Stop collectors cancel() + log.Info("Exiting...") - // Grace period to commit still-running resolutions - time.Sleep(time.Second) + gracePeriodWaitGroup := make(chan struct{}) + go func() { + wg.Wait() + close(gracePeriodWaitGroup) + }() + + t := time.NewTicker(5 * time.Second) + // Running steps have 3 seconds to stop running after context cancelation + // Grace period of 2 seconds (3+2=5) to commit still-running resolutions + select { + case <-gracePeriodWaitGroup: + // all important goroutines exited successfully, bye-bye! + case <-t.C: + // game over, exiting before everyone said bye :( + log.Warn("5 seconds timeout for exiting expired") + } - log.Info("Exiting...") + log.Info("Bye!") }() - if err := engine.Init(ctx, store); err != nil { + if err := engine.Init(ctx, &wg, store); err != nil { return err } diff --git a/config/README.md b/config/README.md index 1527ca9e..0323ff28 100644 --- a/config/README.md +++ b/config/README.md @@ -81,14 +81,43 @@ postgres://user:pass@db/utask?sslmode=disable "config_name": "database" // configuration entry where connection info can be found, default "database" }, // concealed_secrets allows you to render some configstore items inaccessible to the task engine - "concealed_secrets": ["database", "encryption-key", "utask-cfg"], - // resource_limits allows you to define named resources and allocate a maximum number of concurrent actions on them (see Authoring task templates below) - "resource_limits": { - "openstack": 15, - }, - // max_concurrent_executions defines a global maximum of concurrent actions running at any given time - // if none provided, no upper bound is enforced - "max_concurrent_executions": 100 + "concealed_secrets": ["database", "encryption-key", "utask-cfg"], + // resource_limits allows you to define named resources and allocate a maximum number of concurrent actions on them (see Authoring task templates in /README.md) + "resource_limits": { + "openstack": 15, + "socket": 1024, + "fork": 50, + "url:example.org": 10 + }, + // max_concurrent_executions defines a global maximum of concurrent tasks running at any given time + // default value: 100; 0 will stop all tasks processing; -1 to indicate no limit + "max_concurrent_executions": 100, + // max_concurrent_executions_from_crashed defines a maximum of concurrent tasks from a crashed instance running at any given time + // default value: 20; 0 will stop all tasks processing; -1 to indicate no limit + "max_concurrent_executions_from_crashed": 20, + // delay_between_crashed_tasks_resolution defines a wait duration between two tasks from a crashed instance will be schedule in the current uTask instance + // default 1, unit: seconds + "delay_between_crashed_tasks_resolution": 1, + // dashboard_path_prefix defines the path prefix for the dashboard UI. Should be used if the uTask instance is hosted with a ProxyPass, on a custom path + // default: empty, no prefix + "dashboard_path_prefix": "/my-utask-instance", + // editor_path_prefix defines the path prefix for the editor UI. Should be used if the uTask instance is hosted with a ProxyPass, on a custom path + // default: empty, no prefix + "editor_path_prefix": "/my-utask-instance", + // dashboard_api_path_prefix defines the path prefix for the uTask API. Should be used if the uTask instance is hosted with a ProxyPass, on a custom path. + // dashboard_api_path_prefix will be used by Dashboard UI to contact the uTask API + // default: empty, no prefix + "dashboard_api_path_prefix": "/my-utask-instance", + // dashboard_sentry_dsn defines the Sentry DSN for the Dashboard UI. Used to retrieve Javascript execution errors inside a Sentry instance. + // default: empty, no SENTRY_DSN + "dashboard_sentry_dsn": "", + // server_options holds configuration to fine-tune DB connection + "server_options": { + // max_body_bytes defines the maximum size that will be read when sending a body to the uTask server. + // value can't be smaller than 1KB (1024), and can't be bigger than 10MB (10*1024*1024) + // default: 262144 (256KB), unit: byte + "max_body_bytes": 262144 + } } ``` diff --git a/engine/collector_autorun.go b/engine/collector_autorun.go index e65c490b..1cf0a549 100644 --- a/engine/collector_autorun.go +++ b/engine/collector_autorun.go @@ -33,7 +33,7 @@ func AutorunCollector(ctx context.Context) error { if r != nil { sl.wakeup() logrus.WithFields(logrus.Fields{"resolution_id": r.PublicID}).Debugf("Autorun Collector: collected resolution %s", r.PublicID) - _ = GetEngine().Resolve(r.PublicID) + _ = GetEngine().Resolve(r.PublicID, nil) } } } diff --git a/engine/collector_instance.go b/engine/collector_instance.go index e8194c40..b85db977 100644 --- a/engine/collector_instance.go +++ b/engine/collector_instance.go @@ -11,20 +11,26 @@ import ( "github.com/ovh/utask/models/resolution" "github.com/ovh/utask/models/runnerinstance" "github.com/sirupsen/logrus" + "golang.org/x/sync/semaphore" ) // InstanceCollector launches a process that retrieves resolutions // which might have been running on a dead instance and marks them as // crashed, for examination -func InstanceCollector(ctx context.Context) error { +func InstanceCollector(ctx context.Context, maxConcurrentExecutions int, waitDuration time.Duration) error { dbp, err := zesty.NewDBProvider(utask.DBName) if err != nil { return err } + var sm *semaphore.Weighted + if maxConcurrentExecutions >= 0 { + sm = semaphore.NewWeighted(int64(maxConcurrentExecutions)) + } + go func() { // Start immediately - collect(dbp) + collect(dbp, sm, waitDuration) for running := true; running; { // wake up every minute @@ -34,7 +40,7 @@ func InstanceCollector(ctx context.Context) error { case <-ctx.Done(): running = false default: - collect(dbp) + collect(dbp, sm, waitDuration) } } }() @@ -42,12 +48,13 @@ func InstanceCollector(ctx context.Context) error { return nil } -func collect(dbp zesty.DBProvider) error { +func collect(dbp zesty.DBProvider, sm *semaphore.Weighted, waitDuration time.Duration) error { // get a list of all instances instances, err := runnerinstance.ListInstances(dbp) if err != nil { return err } + log := logrus.WithFields(logrus.Fields{"instance_id": utask.InstanceID, "collector": "instance_collector"}) for _, i := range instances { // if an instance is dead if i.IsDead() { @@ -61,12 +68,18 @@ func collect(dbp zesty.DBProvider) error { } } else { // run found resolution - logrus.WithFields(logrus.Fields{"resolution_id": r.PublicID}).Debugf("Instance Collector: collected crashed resolution %s", r.PublicID) - _ = GetEngine().Resolve(r.PublicID) + log.WithFields(logrus.Fields{"resolution_id": r.PublicID}).Debugf("collected crashed resolution %s", r.PublicID) + _ = GetEngine().Resolve(r.PublicID, sm) + + // waiting between two resolve, so others instances can also select tasks + time.Sleep(waitDuration) } } // no resolutions left to retry, delete instance - i.Delete(dbp) + if remaining, err := getRemainingResolution(dbp, i); err == nil && remaining == 0 { + log.Infof("collected all resolution from %d, deleting instance from instance list", i.ID) + i.Delete(dbp) + } } } @@ -103,3 +116,17 @@ func getUpdateRunningResolution(dbp zesty.DBProvider, i *runnerinstance.Instance return &r, nil } + +func getRemainingResolution(dbp zesty.DBProvider, i *runnerinstance.Instance) (int64, error) { + sqlStmt := `SELECT COUNT(id) + FROM "resolution" + WHERE instance_id = $1 AND state IN ($2,$3,$4,$5)` + + return dbp.DB().SelectInt(sqlStmt, + i.ID, + resolution.StateCrashed, + resolution.StateRunning, + resolution.StateRetry, + resolution.StateAutorunning, + ) +} diff --git a/engine/collector_retry.go b/engine/collector_retry.go index bb79dc68..bb3b6498 100644 --- a/engine/collector_retry.go +++ b/engine/collector_retry.go @@ -33,7 +33,7 @@ func RetryCollector(ctx context.Context) error { if r != nil { sl.wakeup() logrus.WithFields(logrus.Fields{"resolution_id": r.PublicID}).Debugf("Retry Collector: collected resolution %s", r.PublicID) - _ = GetEngine().Resolve(r.PublicID) + _ = GetEngine().Resolve(r.PublicID, nil) } } } diff --git a/engine/engine.go b/engine/engine.go index bcb0a680..08c31526 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "strings" + "sync" "time" "github.com/cenkalti/backoff" @@ -15,6 +16,7 @@ import ( "github.com/loopfz/gadgeto/zesty" "github.com/ovh/configstore" "github.com/sirupsen/logrus" + "golang.org/x/sync/semaphore" "github.com/ovh/utask" "github.com/ovh/utask/engine/step" @@ -50,11 +52,12 @@ type Engine struct { // available to steps during execution // ie. credentials needed for http calls, etc... config map[string]interface{} + wg *sync.WaitGroup } // Init launches the task orchestration engine, providing it with a global context // and with a store from which to inherit configuration items needed for task execution -func Init(ctx context.Context, store *configstore.Store) error { +func Init(ctx context.Context, wg *sync.WaitGroup, store *configstore.Store) error { cfg, err := utask.Config(store) if err != nil { return err @@ -91,6 +94,7 @@ func Init(ctx context.Context, store *configstore.Store) error { // channels for handling graceful shutdown stopRunningSteps = make(chan struct{}) gracePeriodEnd = make(chan struct{}) + eng.wg = wg go func() { <-ctx.Done() // Stop running new steps @@ -131,7 +135,7 @@ func Init(ctx context.Context, store *configstore.Store) error { return err } // init crashed instance collector - if err := InstanceCollector(ctx); err != nil { + if err := InstanceCollector(ctx, cfg.MaxConcurrentExecutionsFromCrashedComputed, cfg.InstanceCollectorWaitDuration); err != nil { return err } // init retry collector (retry resolutions with state == error) @@ -169,18 +173,19 @@ func GetEngine() Engine { } // Resolve launches the asynchronous execution of a resolution, given its ID -func (e Engine) Resolve(publicID string) error { - _, err := e.launchResolution(publicID, true) +func (e Engine) Resolve(publicID string, sm *semaphore.Weighted) error { + _, err := e.launchResolution(publicID, true, sm) return err } // SyncResolve launches the synchronous execution of a resolution, given its ID -func (e Engine) SyncResolve(publicID string) (*resolution.Resolution, error) { - return e.launchResolution(publicID, false) +func (e Engine) SyncResolve(publicID string, sm *semaphore.Weighted) (*resolution.Resolution, error) { + return e.launchResolution(publicID, false, sm) } -func (e Engine) launchResolution(publicID string, async bool) (*resolution.Resolution, error) { - +func (e Engine) launchResolution(publicID string, async bool, sm *semaphore.Weighted) (*resolution.Resolution, error) { + e.wg.Add(1) + defer e.wg.Done() debugLogger := logrus.WithFields(logrus.Fields{"resolution_id": publicID}) debugLogger.Debugf("Engine: Resolve() starting for %s", publicID) @@ -209,6 +214,10 @@ func (e Engine) launchResolution(publicID string, async bool) (*resolution.Resol utask.AcquireExecutionSlot() + if sm != nil { + sm.Acquire(context.Background(), 1) + } + recap := make([]string, 0) for name, s := range res.Steps { recap = append(recap, fmt.Sprintf("step %s = %s", name, s.State)) @@ -218,10 +227,11 @@ func (e Engine) launchResolution(publicID string, async bool) (*resolution.Resol debugLogger = debugLogger.WithField("instance_id", *res.InstanceID) } debugLogger.Debugf("Engine: Resolve() %s RECAP BEFORE resolve: state: %s, steps: %s", publicID, res.State, strings.Join(recap, ", ")) + e.wg.Add(1) if async { - go resolve(dbp, res, t, debugLogger) + go resolve(dbp, res, t, sm, e.wg, debugLogger) } else { - resolve(dbp, res, t, debugLogger) + resolve(dbp, res, t, sm, e.wg, debugLogger) } return res, nil } @@ -331,13 +341,13 @@ func initialize(dbp zesty.DBProvider, publicID string, debugLogger *logrus.Entry return res, t, nil } -func resolve(dbp zesty.DBProvider, res *resolution.Resolution, t *task.Task, debugLogger *logrus.Entry) { - +func resolve(dbp zesty.DBProvider, res *resolution.Resolution, t *task.Task, sm *semaphore.Weighted, wg *sync.WaitGroup, debugLogger *logrus.Entry) { + defer wg.Done() // keep track of steps which get executed during each run, to avoid looping+retrying the same failing step endlessly executedSteps := map[string]bool{} stepChan := make(chan *step.Step) - expectedMessages := runAvailableSteps(dbp, map[string]bool{}, res, t, stepChan, executedSteps, []string{}, debugLogger) + expectedMessages := runAvailableSteps(dbp, map[string]bool{}, res, t, stepChan, executedSteps, []string{}, wg, debugLogger) for expectedMessages > 0 { debugLogger.Debugf("Engine: resolve() %s loop, %d expected steps", res.PublicID, expectedMessages) @@ -395,7 +405,7 @@ func resolve(dbp zesty.DBProvider, res *resolution.Resolution, t *task.Task, deb // one less step to go expectedMessages-- // state change might unlock more steps for execution - expectedMessages += runAvailableSteps(dbp, modifiedSteps, res, t, stepChan, executedSteps, []string{}, debugLogger) + expectedMessages += runAvailableSteps(dbp, modifiedSteps, res, t, stepChan, executedSteps, []string{}, wg, debugLogger) // attempt to persist all changes in db if err := commit(dbp, res, t); err != nil { @@ -405,6 +415,7 @@ func resolve(dbp zesty.DBProvider, res *resolution.Resolution, t *task.Task, deb } case <-gracePeriodEnd: // shutting down, time is up: exit the loop no matter how many steps might be pending + expectedMessages = 0 break } } @@ -513,6 +524,10 @@ func resolve(dbp zesty.DBProvider, res *resolution.Resolution, t *task.Task, deb time.Sleep(bkoff.NextBackOff()) } + if sm != nil { + sm.Release(1) + } + utask.ReleaseExecutionSlot() } @@ -535,7 +550,7 @@ func commit(dbp zesty.DBProvider, res *resolution.Resolution, t *task.Task) erro return dbp.Commit() } -func runAvailableSteps(dbp zesty.DBProvider, modifiedSteps map[string]bool, res *resolution.Resolution, t *task.Task, stepChan chan<- *step.Step, executedSteps map[string]bool, expandedSteps []string, debugLogger *logrus.Entry) int { +func runAvailableSteps(dbp zesty.DBProvider, modifiedSteps map[string]bool, res *resolution.Resolution, t *task.Task, stepChan chan<- *step.Step, executedSteps map[string]bool, expandedSteps []string, wg *sync.WaitGroup, debugLogger *logrus.Entry) int { av := availableSteps(modifiedSteps, res, executedSteps, expandedSteps, debugLogger) expandedSteps = []string{} preRunModifiedSteps := map[string]bool{} @@ -589,7 +604,7 @@ func runAvailableSteps(dbp zesty.DBProvider, modifiedSteps map[string]bool, res // run stepCopy := *s - step.Run(&stepCopy, res.BaseConfigurations, res.Values, stepChan, stopRunningSteps) + step.Run(&stepCopy, res.BaseConfigurations, res.Values, stepChan, wg, stopRunningSteps) } } } @@ -599,7 +614,7 @@ func runAvailableSteps(dbp zesty.DBProvider, modifiedSteps map[string]bool, res // - loop step generated new steps if len(preRunModifiedSteps) > 0 || expanded > 0 { pruneSteps(res, preRunModifiedSteps) - return len(av) + runAvailableSteps(dbp, preRunModifiedSteps, res, t, stepChan, executedSteps, expandedSteps, debugLogger) + return len(av) + runAvailableSteps(dbp, preRunModifiedSteps, res, t, stepChan, executedSteps, expandedSteps, wg, debugLogger) } return len(av) @@ -625,6 +640,7 @@ func expandStep(s *step.Step, res *resolution.Resolution) { res.Steps[childStepName] = &step.Step{ Name: childStepName, Description: fmt.Sprintf("%d - %s", i, s.Description), + Idempotent: s.Idempotent, Action: s.Action, Schema: s.Schema, State: step.StateTODO, @@ -633,6 +649,7 @@ func expandStep(s *step.Step, res *resolution.Resolution) { Dependencies: s.Dependencies, CustomStates: s.CustomStates, Conditions: s.Conditions, + Resources: s.Resources, Item: item, } delete(res.ForeachChildrenAlreadyContracted, childStepName) diff --git a/engine/engine_test.go b/engine/engine_test.go index 1a8ca395..2dc11a90 100644 --- a/engine/engine_test.go +++ b/engine/engine_test.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "os" "path/filepath" + "sync" "testing" "time" @@ -48,7 +49,9 @@ func TestMain(m *testing.M) { now.Init() - if err := engine.Init(context.Background(), store); err != nil { + var wg sync.WaitGroup + + if err := engine.Init(context.Background(), &wg, store); err != nil { panic(err) } @@ -84,7 +87,7 @@ func runTask(tmplName string, inputs, resolverInputs map[string]interface{}) (*r if err != nil { return nil, err } - return engine.GetEngine().SyncResolve(res.PublicID) + return engine.GetEngine().SyncResolve(res.PublicID, nil) } func createResolution(tmplName string, inputs, resolverInputs map[string]interface{}) (*resolution.Resolution, error) { @@ -119,7 +122,7 @@ func runResolution(res *resolution.Resolution) (*resolution.Resolution, error) { if res == nil { return nil, errors.New("Nil resolution") } - return engine.GetEngine().SyncResolve(res.PublicID) + return engine.GetEngine().SyncResolve(res.PublicID, nil) } func templateFromYAML(dbp zesty.DBProvider, filename string) (*tasktemplate.TaskTemplate, error) { @@ -442,7 +445,7 @@ func TestAsyncResolve(t *testing.T) { assert.Equal(t, resolution.StateTODO, res.State) assert.Equal(t, 0, res.Steps["stepOne"].TryCount) - err = engine.GetEngine().Resolve(res.PublicID) + err = engine.GetEngine().Resolve(res.PublicID, nil) assert.Nil(t, err) } diff --git a/engine/step/step.go b/engine/step/step.go index 8510ef94..79d142dc 100644 --- a/engine/step/step.go +++ b/engine/step/step.go @@ -6,6 +6,7 @@ import ( "fmt" "sort" "strings" + "sync" "time" "github.com/juju/errors" @@ -146,7 +147,7 @@ func uniqueSortedList(s []string) []string { // - a stepChan channel is provided for committing the result back // - a stopRunningSteps channel is provided to interrupt execution in flight // values IS NOT CONCURRENT SAFE, DO NOT SHARE WITH OTHER GOROUTINES -func Run(st *Step, baseConfig map[string]json.RawMessage, values *values.Values, stepChan chan<- *Step, stopRunningSteps <-chan struct{}) { +func Run(st *Step, baseConfig map[string]json.RawMessage, values *values.Values, stepChan chan<- *Step, wg *sync.WaitGroup, stopRunningSteps <-chan struct{}) { // Step already ran, directly going to afterrun process if st.State == StateAfterrunError { @@ -252,8 +253,11 @@ func Run(st *Step, baseConfig map[string]json.RawMessage, values *values.Values, } } + wg.Add(1) go func() { - limits := uniqueSortedList(st.Resources) + defer wg.Done() + resources := append(runner.Resources(baseCfgRaw, config), st.Resources...) + limits := uniqueSortedList(resources) for _, limit := range limits { utask.AcquireResource(limit) } diff --git a/engine/step/util.go b/engine/step/util.go index 99a405b7..e532e57e 100644 --- a/engine/step/util.go +++ b/engine/step/util.go @@ -12,6 +12,7 @@ type Runner interface { Exec(stepName string, baseConfig json.RawMessage, config json.RawMessage, ctx interface{}) (interface{}, interface{}, map[string]string, error) ValidConfig(baseConfig json.RawMessage, config json.RawMessage) error Context(stepName string) interface{} + Resources(baseConfig json.RawMessage, config json.RawMessage) []string MetadataSchema() json.RawMessage } diff --git a/engine/values/values.go b/engine/values/values.go index 186bb841..a4f3e0f5 100644 --- a/engine/values/values.go +++ b/engine/values/values.go @@ -7,7 +7,7 @@ import ( "text/template" "time" - "github.com/Masterminds/sprig" + "github.com/Masterminds/sprig/v3" "github.com/juju/errors" "github.com/ovh/utask" "github.com/robertkrimen/otto" diff --git a/go.mod b/go.mod index d10e02d3..f5eaf8e0 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,8 @@ module github.com/ovh/utask go 1.13 require ( - github.com/Masterminds/goutils v1.1.0 // indirect - github.com/Masterminds/semver v1.4.2 // indirect - github.com/Masterminds/sprig v2.20.0+incompatible - github.com/Masterminds/squirrel v1.1.0 + github.com/Masterminds/sprig/v3 v3.1.0 + github.com/Masterminds/squirrel v1.2.0 github.com/SSSaaS/sssa-golang v0.0.0-20170502204618-d37d7782d752 // indirect github.com/cenkalti/backoff v2.2.1+incompatible github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect @@ -15,40 +13,36 @@ require ( github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 - github.com/gin-gonic/gin v1.4.0 + github.com/gin-gonic/gin v1.6.2 github.com/go-gorp/gorp v2.0.0+incompatible github.com/go-sql-driver/mysql v1.4.1 // indirect github.com/gofrs/uuid v3.2.0+incompatible - github.com/huandu/xstrings v1.2.0 // indirect - github.com/imdario/mergo v0.3.7 // indirect + github.com/golang/protobuf v1.4.0 // indirect github.com/jinzhu/now v1.0.1 // indirect github.com/jpillora/backoff v1.0.0 - github.com/juju/errors v0.0.0-20190207033735-e65537c515d7 - github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 // indirect - github.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2 // indirect + github.com/juju/errors v0.0.0-20200330140219-3fe23663418f github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect - github.com/lib/pq v1.2.0 - github.com/loopfz/gadgeto v0.9.1 + github.com/lib/pq v1.4.0 + github.com/loopfz/gadgeto v0.10.0 github.com/magiconair/properties v1.8.1 // indirect github.com/markusthoemmes/goautoneg v0.0.0-20190713162725-c6008fefa5b1 github.com/mattn/go-sqlite3 v1.11.0 // indirect - github.com/miscreant/miscreant-go v0.0.0-20190615163012-4f5dc8c406f6 // indirect github.com/miscreant/miscreant.go v0.0.0-20190615163012-4f5dc8c406f6 // indirect + github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/onsi/ginkgo v1.8.0 // indirect github.com/onsi/gomega v1.5.0 // indirect github.com/ovh/configstore v0.3.2 github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 - github.com/ovh/symmecrypt v0.3.0 + github.com/ovh/symmecrypt v0.4.2 github.com/ovh/tat v5.2.5+incompatible github.com/pelletier/go-toml v1.4.0 // indirect github.com/prometheus/client_golang v1.1.0 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect github.com/prometheus/common v0.7.0 // indirect github.com/prometheus/procfs v0.0.5 // indirect - github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d + github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff github.com/santhosh-tekuri/jsonschema v1.2.4 - github.com/satori/go.uuid v1.2.0 // indirect - github.com/sirupsen/logrus v1.4.2 + github.com/sirupsen/logrus v1.5.0 github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect github.com/sparrc/go-ping v0.0.0-20190613174326-4e5b6552494c github.com/spf13/afero v1.2.2 // indirect @@ -56,19 +50,17 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.4.0 - github.com/stretchr/testify v1.4.0 - github.com/tjarratt/babble v0.0.0-20191126185718-ccc47f626248 // indirect - github.com/ugorji/go v1.1.7 // indirect - github.com/wI2L/fizz v0.0.0-20190425144348-6274bc96d962 + github.com/stretchr/testify v1.5.1 + github.com/wI2L/fizz v0.13.4 github.com/ziutek/mymysql v1.5.4 // indirect - golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 + golang.org/x/crypto v0.0.0-20200422194213-44a606286825 golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72 // indirect - golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e + golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a + golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f // indirect google.golang.org/appengine v1.6.3 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/ini.v1 v1.46.0 // indirect gopkg.in/mail.v2 v2.3.1 - gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect ) diff --git a/go.sum b/go.sum index 24cccf1a..5d18e7bc 100644 --- a/go.sum +++ b/go.sum @@ -3,13 +3,15 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.20.0+incompatible h1:dJTKKuUkYW3RMFdQFXPU/s6hg10RgctmTjRcbZ98Ap8= -github.com/Masterminds/sprig v2.20.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Masterminds/squirrel v1.1.0 h1:baP1qLdoQCeTw3ifCdOq2dkYc6vGcmRdaociKLbEJXs= -github.com/Masterminds/squirrel v1.1.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= +github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk= +github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig/v3 v3.1.0 h1:j7GpgZ7PdFqNsmncycTHsLmVPf5/3wJtlgW9TNDYD9Y= +github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA= +github.com/Masterminds/squirrel v1.2.0 h1:K1NhbTO21BWG47IVR0OnIZuE0LZcXAYqywrC3Ko53KI= +github.com/Masterminds/squirrel v1.2.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Pallinder/go-randomdata v1.2.0 h1:DZ41wBchNRb/0GfsePLiSwb0PHZmT67XY00lCDlaYPg= +github.com/Pallinder/go-randomdata v1.2.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y= github.com/SSSaaS/sssa-golang v0.0.0-20170502204618-d37d7782d752 h1:NMpC6M+PtNNDYpq7ozB7kINpv10L5yeli5GJpka2PX8= github.com/SSSaaS/sssa-golang v0.0.0-20170502204618-d37d7782d752/go.mod h1:PbJ8S5YaSYAvDPTiEuUsBHQwTUlPs6VM+Av8Oi3v570= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -52,22 +54,37 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= +github.com/gin-contrib/cors v1.3.0/go.mod h1:artPvLlhkF7oG06nK8v3U8TNz6IeX+w1uzCSEId5/Vc= github.com/gin-contrib/sse v0.0.0-20190125020943-a7658810eb74/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/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/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y= github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/gin-gonic/gin v1.6.1 h1:o2JrfzL6NvnLVI/h1x4E+E9nocCp66GEKqPfhoCjlTs= +github.com/gin-gonic/gin v1.6.1/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.6.2 h1:88crIK23zO6TqlQBt+f9FrPJNKm9ZEr7qjp9vl/d5TM= +github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-gorp/gorp v2.0.0+incompatible h1:dIQPsBtl6/H1MjVseWuWPXa7ET4p6Dve4j3Hg+UjqYw= github.com/go-gorp/gorp v2.0.0+incompatible/go.mod h1:7IfkAQnO7jfT/9IQ3R9wL1dFhukN6aQxzKTHnkxzA/E= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 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/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 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/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -82,13 +99,27 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -99,10 +130,10 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0= -github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= -github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= -github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= @@ -113,10 +144,14 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX 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/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/errors v0.0.0-20190207033735-e65537c515d7 h1:dMIPRDg6gi7CUp0Kj2+HxqJ5kTr1iAdzsXYIrLCNSmU= -github.com/juju/errors v0.0.0-20190207033735-e65537c515d7/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/errors v0.0.0-20190930114154-d42613fe1ab9/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/errors v0.0.0-20200330140219-3fe23663418f h1:MCOvExGLpaSIzLYB4iQXEHP4jYVU6vmzLNQPdMVrxnM= +github.com/juju/errors v0.0.0-20200330140219-3fe23663418f/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 h1:UUHMLvzt/31azWTN/ifGWef4WUqvXk0iRqdhdy/2uzI= github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2 h1:Pp8RxiF4rSoXP9SED26WCfNB28/dwTDpPXS8XMJR8rc= @@ -139,10 +174,13 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhR github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= -github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/loopfz/gadgeto v0.9.1 h1:wsPXbFtru3bJarEiRawKiMDU1CdvgIVDvaF0S7GT81w= -github.com/loopfz/gadgeto v0.9.1/go.mod h1:S3tK5SXmKY3l39rUpPZw1B/iiy1CftV13QABFhj32Ss= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.4.0 h1:TmtCFbH+Aw0AixwyttznSMQDgbR5Yed/Gg6S8Funrhc= +github.com/lib/pq v1.4.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/loopfz/gadgeto v0.9.0/go.mod h1:S3tK5SXmKY3l39rUpPZw1B/iiy1CftV13QABFhj32Ss= +github.com/loopfz/gadgeto v0.10.0 h1:ANxTcmPebSC6bcVW0VfUBjkWXUk+PitdiDXygUVHnQI= +github.com/loopfz/gadgeto v0.10.0/go.mod h1:BeqRJlgmhZ/wJ8w+CA6uXNegCb6ZpvTiF9ZK/wcMBmg= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -151,17 +189,24 @@ github.com/markusthoemmes/goautoneg v0.0.0-20190713162725-c6008fefa5b1/go.mod h1 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miscreant/miscreant-go v0.0.0-20190615163012-4f5dc8c406f6 h1:W3EPtKt0Tpp66xfOUR+mrO/mtbVRdUxEfLfTo9a5Ig4= -github.com/miscreant/miscreant-go v0.0.0-20190615163012-4f5dc8c406f6/go.mod h1:Vj6lPE3LxPymcFxg7hm9aDIJWCyhJMnxSNC/y9ZHtN8= github.com/miscreant/miscreant.go v0.0.0-20190615163012-4f5dc8c406f6 h1:+fq8RvH8U53fPvZV9WaudwJPC4Pxcpy+fHC8VKxO/uY= github.com/miscreant/miscreant.go v0.0.0-20190615163012-4f5dc8c406f6/go.mod h1:cjDg/CiyNrPgSCnh5j20e6bEueGTijqk5H/uL7VH2JU= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= @@ -179,8 +224,8 @@ github.com/ovh/configstore v0.3.2 h1:/kr1B27JVzW4Eiz20muZSnQ5UyizFjLy5+2CVfp/mKs github.com/ovh/configstore v0.3.2/go.mod h1:bBc7U++7HXgf9lrtmmJb31DK3Tp+Zv8GaIn0Bjolv/o= github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 h1:37VE5TYj2m/FLA9SNr4z0+A0JefvTmR60Zwf8XSEV7c= github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ= -github.com/ovh/symmecrypt v0.3.0 h1:mEG0uL28jpClU8Dz7L1T0JzcOP2ESYJAwNpkTRL08xQ= -github.com/ovh/symmecrypt v0.3.0/go.mod h1:39tehz0mgJfrpQOGUMf5J29rK1GzPiTxLFiVuk9XPO0= +github.com/ovh/symmecrypt v0.4.2 h1:xDyr7IJzIrD3vCAsJRUgivVo2Hss743vE1dckB1KkDg= +github.com/ovh/symmecrypt v0.4.2/go.mod h1:39tehz0mgJfrpQOGUMf5J29rK1GzPiTxLFiVuk9XPO0= github.com/ovh/tat v5.2.5+incompatible h1:UjzEBUy0zfDyhucSlEYDWuZ52+BNVR9FsYRbVfuobLE= github.com/ovh/tat v5.2.5+incompatible/go.mod h1:eRL842a3T+2ept8tEg5IxitkGJL6X8wh1JkRa9DNzo0= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -212,17 +257,17 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d h1:1VUlQbCfkoSGv7qP7Y+ro3ap1P1pPZxgdGVqiTVy5C4= -github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= +github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff h1:+6NUiITWwE5q1KO6SAfUX918c+Tab0+tGAM/mtdlUyA= +github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis= github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q= +github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= @@ -236,6 +281,8 @@ github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= @@ -254,8 +301,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/tjarratt/babble v0.0.0-20191126185718-ccc47f626248 h1:38nznt/SqA29s/Yh4mmrbtNX9FBC+qAHvdSKBfy23Sw= -github.com/tjarratt/babble v0.0.0-20191126185718-ccc47f626248/go.mod h1:O5hBrCGqzfb+8WyY8ico2AyQau7XQwAfEQeEQ5/5V9E= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -265,8 +312,8 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT github.com/ugorji/go/codec v0.0.0-20190128213124-ee1426cffec0/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA= 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/wI2L/fizz v0.0.0-20190425144348-6274bc96d962 h1:3nJUBJAiHUF9+T1loL9NQZ8ISRvToH7NbLa1z1bG7AQ= -github.com/wI2L/fizz v0.0.0-20190425144348-6274bc96d962/go.mod h1:rceB7wPNR2dmu6TF+/4lBbsb/Xl4T3oCqwlJXzDKRTc= +github.com/wI2L/fizz v0.13.4 h1:4G48MVzMXSC4SmWagQlgSnUgDrZ5eLr43RutM2dnM8Q= +github.com/wI2L/fizz v0.13.4/go.mod h1:R7UIV/FdYUnOZbfkTMwoV9zpnqzZSRl2CaxWUMpwDuo= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= @@ -279,8 +326,9 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 h1:ACG4HJsFiNMf47Y4PeRoebLNy/2lXT9EtprMuTFWt1M= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200422194213-44a606286825 h1:dSChiwOTvzwbHFTMq2l6uRardHH7/E6SqEkqccinS/o= +golang.org/x/crypto v0.0.0-20200422194213-44a606286825/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -300,8 +348,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -312,10 +360,16 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -326,12 +380,20 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.6.3 h1:hvZejVcIxAKHR8Pq2gXaDggf6CWT1QEqO+JEBeOKCG8= google.golang.org/appengine v1.6.3/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= @@ -347,12 +409,15 @@ gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2G gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.26.0 h1:2NPPsBpD0ZoxshmLWewQru8rWmbT5JqSzz9D1ZrAjYQ= gopkg.in/go-playground/validator.v9 v9.26.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= +gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/ini.v1 v1.46.0 h1:VeDZbLYGaupuvIrsYCEOe/L/2Pcs5n7hdO1ZTjporag= gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= @@ -362,4 +427,7 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/plugins/builtin/apiovh/README.md b/pkg/plugins/builtin/apiovh/README.md index f02de544..deeef8a9 100644 --- a/pkg/plugins/builtin/apiovh/README.md +++ b/pkg/plugins/builtin/apiovh/README.md @@ -23,17 +23,17 @@ action: path: /dbaas/logs/{{.input.serviceName}}/output/graylog/stream credendials: ovh-api-credentials # body is optional, not used for method GET - body: | + body: | { "title": "{{.input.applicationName}}", - "description": "{{.input.applicationDescription}}", + "description": "{{.input.applicationDescription}}", "autoSelectOption": true } ``` ## Requirements -The `apiovh` plugin requires a config item to be found under the key given in the `credentials` config field. It's content should match the following schema (see [go-ovh](https://github.com/ovh/go-ovh) for more details): +The `apiovh` plugin requires a config item to be found under the key given in the `credentials` config field. It's content should match the following schema (see [go-ovh](https://github.com/ovh/go-ovh) for more details): ```js { @@ -42,4 +42,10 @@ The `apiovh` plugin requires a config item to be found under the key given in th "appSecret": "YYYY", "consumerKey": "ZZZZ" } -``` \ No newline at end of file +``` + +## Resources + +The `apiovh` plugin declares automatically resources for its steps: +- `socket` to rate-limit concurrent execution on the number of open outgoing sockets +- `url:api.ovh.com` or `url:ca.api.ovh.com`, ... (depending on the region) to rate-limit concurrent executions on an endpoint of the OVH API \ No newline at end of file diff --git a/pkg/plugins/builtin/apiovh/apiovh.go b/pkg/plugins/builtin/apiovh/apiovh.go index 4bc23788..71cf635e 100644 --- a/pkg/plugins/builtin/apiovh/apiovh.go +++ b/pkg/plugins/builtin/apiovh/apiovh.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "net/url" "github.com/ovh/configstore" "github.com/ovh/go-ovh/ovh" @@ -17,6 +18,7 @@ var ( Plugin = taskplugin.New("apiovh", "0.6", exec, taskplugin.WithConfig(validConfig, APIOVHConfig{}), taskplugin.WithExecutorMetadata(ExecutorMetadata), + taskplugin.WithResources(resourcesapiovh), ) ) @@ -71,6 +73,35 @@ func validConfig(config interface{}) error { return nil } +func resourcesapiovh(i interface{}) []string { + cfg := i.(*APIOVHConfig) + resources := []string{ + "socket", + } + + ovhCfgStr, err := configstore.GetItemValue(cfg.Credentials) + if err != nil { + return resources + } + + var ovhcfg ovhConfig + if err := json.Unmarshal([]byte(ovhCfgStr), &ovhcfg); err != nil { + return resources + } + + endpoint := "ovh-eu" // default value + if ovhcfg.Endpoint != "" { + endpoint = ovhcfg.Endpoint + } + if host, ok := ovh.Endpoints[endpoint]; ok { + uri, _ := url.Parse(host) + if uri.Host != "" { + resources = append(resources, "url:"+uri.Host) + } + } + return resources +} + func exec(stepName string, config interface{}, ctx interface{}) (interface{}, interface{}, error) { cfg := config.(*APIOVHConfig) diff --git a/pkg/plugins/builtin/email/README.md b/pkg/plugins/builtin/email/README.md index 6dc776f7..8274d0c4 100644 --- a/pkg/plugins/builtin/email/README.md +++ b/pkg/plugins/builtin/email/README.md @@ -62,4 +62,10 @@ The plugin returns an object to reuse the parameters in a future component: } ``` -Sensitive data should be retrieved from configstore and accessed through `{{.config.[itemKey]}}` rather than hardcoded in your template. \ No newline at end of file +Sensitive data should be retrieved from configstore and accessed through `{{.config.[itemKey]}}` rather than hardcoded in your template. + +## Resources + +The `email` plugin declares automatically resources for its steps: +- `socket` to rate-limit concurrent execution on the number of open outgoing sockets +- `url:smtp_hostname` (where `smtp_hostname` is the outgoing SMTP server of the plugin configuration) to rate-limit concurrent execution on a specific outgoing SMTP server \ No newline at end of file diff --git a/pkg/plugins/builtin/email/email.go b/pkg/plugins/builtin/email/email.go index 7190b1da..dd045116 100644 --- a/pkg/plugins/builtin/email/email.go +++ b/pkg/plugins/builtin/email/email.go @@ -16,6 +16,7 @@ import ( var ( Plugin = taskplugin.New("email", "0.2", exec, taskplugin.WithConfig(validConfig, Config{}), + taskplugin.WithResources(resourcesemail), ) ) @@ -85,6 +86,15 @@ func validConfig(config interface{}) error { return nil } +func resourcesemail(i interface{}) []string { + cfg := i.(*Config) + + return []string{ + "socket", + "url:" + cfg.SMTPHostname, + } +} + func exec(stepName string, config interface{}, ctx interface{}) (interface{}, interface{}, error) { cfg := config.(*Config) diff --git a/pkg/plugins/builtin/http/README.md b/pkg/plugins/builtin/http/README.md index b0ce63b3..bf63c3b0 100644 --- a/pkg/plugins/builtin/http/README.md +++ b/pkg/plugins/builtin/http/README.md @@ -13,7 +13,7 @@ This plugin permorms an HTTP request. | `body` | a string representing the payload to be sent with the request | `headers` | a list of headers, represented as (`name`, `value`) pairs | `timeout` | timeout expressed as a duration (e.g. `30s`) -| `auth` | a single object composed of either a `basic` object with `user` and `password` fields to enable HTTP basic auth, or `bearer` field to enable Bearer Token Authorization +| `auth` | a single object composed of either a `basic` object with `user` and `password` fields to enable HTTP basic auth, or `bearer` field to enable Bearer Token Authorization | `follow_redirect` | if `true` (string) the plugin will follow up to 10 redirects (302, ...) | `query_parameters` | a list of query parameters, represented as (`name`, `value`) pairs; these will appended the query parameters present in the `url` field; parameters can be repeated (in either `url` or `query_parameters`) which will produce e.g. `?param=value1¶m=value2` | `trim_prefix`| prefix in the response that must be removed before unmarshalling (optional) @@ -34,7 +34,7 @@ action: timeout: "5s" # optional, authentication you can use either basic or bearer auth auth: - basic: + basic: user: {{.config.basicAuth.user}} password: {{.config.basicAuth.password}} bearer: {{.config.auth.token}} @@ -58,3 +58,9 @@ action: ## Requirements None by default. Sensitive data should stored in the configuration and accessed through `{{.config.[itemKey]}}` rather than hardcoded in your template. + +## Resources + +The `http` plugin declares automatically resources for its steps: +- `socket` to rate-limit concurrent execution on the number of open outgoing sockets +- `url:hostname` (where `hostname` is e.g. `www.ovh.com`) to rate-limit concurrent execution on a specific destination web-server/API diff --git a/pkg/plugins/builtin/http/http.go b/pkg/plugins/builtin/http/http.go index 2e085160..49be2cb0 100644 --- a/pkg/plugins/builtin/http/http.go +++ b/pkg/plugins/builtin/http/http.go @@ -21,6 +21,7 @@ import ( var ( Plugin = taskplugin.New("http", "1.0", exec, taskplugin.WithConfig(validConfig, HTTPConfig{}), + taskplugin.WithResources(resourceshttp), ) ) @@ -97,6 +98,27 @@ func validConfig(config interface{}) error { return nil } +func resourceshttp(i interface{}) []string { + cfg := i.(*HTTPConfig) + + var host string + if cfg.Host == "" { + uri, _ := url.Parse(cfg.URL) + host = uri.Host + } else { + uri, _ := url.Parse(cfg.Host) + host = uri.Host + } + + if host == "" { + return []string{"socket"} + } + return []string{ + "socket", + "url:" + host, + } +} + func exec(stepName string, config interface{}, ctx interface{}) (interface{}, interface{}, error) { cfg := config.(*HTTPConfig) diff --git a/pkg/plugins/builtin/ping/README.md b/pkg/plugins/builtin/ping/README.md index ba73bc8a..7c553524 100644 --- a/pkg/plugins/builtin/ping/README.md +++ b/pkg/plugins/builtin/ping/README.md @@ -55,3 +55,9 @@ The `Metadata` to reuse the parameters in a future component: "interval_second": "1" } ``` + +## Resources + +The `ping` plugin declares automatically resources for its steps: +- `socket` to rate-limit concurrent execution on the number of open outgoing sockets +- `url:hostname` (where `hostname` is the ping destination host of the plugin configuration) to rate-limit concurrent execution on a specific destination host \ No newline at end of file diff --git a/pkg/plugins/builtin/ping/ping.go b/pkg/plugins/builtin/ping/ping.go index cd09f02b..64acfca9 100644 --- a/pkg/plugins/builtin/ping/ping.go +++ b/pkg/plugins/builtin/ping/ping.go @@ -15,6 +15,7 @@ import ( var ( Plugin = taskplugin.New("ping", "0.1", exec, taskplugin.WithConfig(validConfig, Config{}), + taskplugin.WithResources(resourcesping), ) ) @@ -60,6 +61,15 @@ func validConfig(config interface{}) error { return nil } +func resourcesping(i interface{}) []string { + cfg := i.(*Config) + + return []string{ + "socket", + "url:" + cfg.Hostname, + } +} + func exec(stepName string, config interface{}, ctx interface{}) (interface{}, interface{}, error) { cfg := config.(*Config) diff --git a/pkg/plugins/builtin/script/README.md b/pkg/plugins/builtin/script/README.md index 1ad63556..538126a6 100644 --- a/pkg/plugins/builtin/script/README.md +++ b/pkg/plugins/builtin/script/README.md @@ -74,3 +74,9 @@ The plugin returns two objects, `output` and `metadata`. "error":"" } ``` + +## Resources + +The `script` plugin declares automatically resources for its steps: +- `fork` to rate-limit concurrent execution on the number of forked processes started by the uTask instance +- `script:file_path` (where `file_path` is the script path of the plugin configuration) to rate-limit concurrent execution of a specific script diff --git a/pkg/plugins/builtin/script/script.go b/pkg/plugins/builtin/script/script.go index 4f3124f5..24e93924 100644 --- a/pkg/plugins/builtin/script/script.go +++ b/pkg/plugins/builtin/script/script.go @@ -22,6 +22,7 @@ import ( var ( Plugin = taskplugin.New("script", "0.2", exec, taskplugin.WithConfig(validConfig, Config{}), + taskplugin.WithResources(resourcesscript), ) ) @@ -53,6 +54,15 @@ type Config struct { ExitCodesUnrecoverable []string `json:"exit_codes_unrecoverable"` } +func resourcesscript(i interface{}) []string { + cfg := i.(*Config) + + return []string{ + "fork", + fmt.Sprintf("script:%s", cfg.File), + } +} + func validConfig(config interface{}) error { cfg := config.(*Config) diff --git a/pkg/plugins/builtin/ssh/README.md b/pkg/plugins/builtin/ssh/README.md index 635d354e..7f851a89 100644 --- a/pkg/plugins/builtin/ssh/README.md +++ b/pkg/plugins/builtin/ssh/README.md @@ -88,3 +88,10 @@ The default `output_mode` (`auto-result`) injects an escaped `echo` command as t "exit_msg": "exited 0" } ``` + +## Resources + +The `ssh` plugin declares automatically resources for its steps: +- `socket` to rate-limit concurrent execution on the number of open outgoing sockets +- `url:target` (where `target` is the outgoing SSH target of the plugin configuration) to rate-limit concurrent execution on a specific target +- `url:hop` (where `hop` is one of the intermediate machine of the plugin configuration) to rate-limit concurrent execution on the intermediate machines diff --git a/pkg/plugins/builtin/ssh/ssh.go b/pkg/plugins/builtin/ssh/ssh.go index 04947786..9f825649 100644 --- a/pkg/plugins/builtin/ssh/ssh.go +++ b/pkg/plugins/builtin/ssh/ssh.go @@ -25,6 +25,7 @@ const ( var ( Plugin = taskplugin.New("ssh", "0.2", execssh, taskplugin.WithConfig(configssh, ConfigSSH{}), + taskplugin.WithResources(resourcesssh), ) ) @@ -42,6 +43,20 @@ type ConfigSSH struct { ExitCodesUnrecoverable []string `json:"exit_codes_unrecoverable"` } +func resourcesssh(i interface{}) []string { + cfg := i.(*ConfigSSH) + + resources := []string{ + "socket", + "url:" + cfg.Target, + } + for _, hop := range cfg.Hops { + resources = append(resources, "url:"+hop) + } + + return resources +} + func configssh(i interface{}) error { cfg := i.(*ConfigSSH) diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 170f7e39..c29ec6dd 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -17,6 +17,7 @@ import ( // TaskPlugin represents the interface for every executor for µtask step actions type TaskPlugin interface { ValidConfig(baseConfig json.RawMessage, config json.RawMessage) error + Resources(baseConfig json.RawMessage, config json.RawMessage) []string Exec(stepName string, baseConfig json.RawMessage, config json.RawMessage, ctx interface{}) (interface{}, interface{}, map[string]string, error) Context(stepName string) interface{} PluginName() string diff --git a/pkg/plugins/taskplugin/taskplugin.go b/pkg/plugins/taskplugin/taskplugin.go index 36a449b4..d9ca874d 100644 --- a/pkg/plugins/taskplugin/taskplugin.go +++ b/pkg/plugins/taskplugin/taskplugin.go @@ -22,6 +22,7 @@ type ExecFunc func(string, interface{}, interface{}) (interface{}, interface{}, type PluginExecutor struct { configfunc ConfigFunc execfunc ExecFunc + resourcesFunc func(interface{}) []string configFactory func() interface{} pluginName string pluginVersion string @@ -38,6 +39,30 @@ func (r PluginExecutor) Context(stepName string) interface{} { return nil } +// Resources returns a list of resources to be used by uTask engine for this plugin +func (r PluginExecutor) Resources(baseConfig json.RawMessage, config json.RawMessage) []string { + if r.resourcesFunc == nil { + return []string{} + } + + var cfg interface{} + + if r.configFactory != nil { + cfg = r.configFactory() + if len(baseConfig) > 0 { + err := utils.JSONnumberUnmarshal(bytes.NewReader(baseConfig), cfg) + if err != nil { + return []string{} + } + } + err := utils.JSONnumberUnmarshal(bytes.NewReader(config), cfg) + if err != nil { + return []string{} + } + } + return r.resourcesFunc(cfg) +} + // ValidConfig asserts that a given configuration payload complies with the executor's definition func (r PluginExecutor) ValidConfig(baseConfig json.RawMessage, config json.RawMessage) error { if r.configFactory != nil { @@ -107,6 +132,7 @@ type PluginOpt struct { configObj interface{} contextObj interface{} contextFunc func(string) interface{} + resourcesFunc func(interface{}) []string metadataFunc func() string tagsFunc tagsFunc } @@ -148,6 +174,13 @@ func WithTags(fn tagsFunc) func(*PluginOpt) { } } +// WithResources defines a function indicating what resources will be needed by the plugin +func WithResources(resourcesFunc func(interface{}) []string) func(*PluginOpt) { + return func(o *PluginOpt) { + o.resourcesFunc = resourcesFunc + } +} + // New generates a step action executor from a given plugin func New(pluginName string, pluginVersion string, execfunc ExecFunc, opts ...func(*PluginOpt)) PluginExecutor { @@ -217,6 +250,7 @@ func New(pluginName string, pluginVersion string, execfunc ExecFunc, opts ...fun pluginVersion: pluginVersion, configfunc: pOpt.configCheckFunc, execfunc: execfunc, + resourcesFunc: pOpt.resourcesFunc, configFactory: configFactory, contextFactory: contextFactory, metadataSchema: schema, diff --git a/utask.go b/utask.go index 3c019b88..540ea130 100644 --- a/utask.go +++ b/utask.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "time" "golang.org/x/sync/semaphore" @@ -60,6 +61,13 @@ const ( // DefaultRetryMax is the default number of retries allowed for a task's execution DefaultRetryMax = 100 + // defaultInstanceCollectorWaitDuration is the default duration between two crashed tasks being resolved + defaultInstanceCollectorWaitDuration = time.Second + // defaultMaxConcurrentExecutions is the default maximum concurrent task executions in the instance + defaultMaxConcurrentExecutions = 100 + // defaultMaxConcurrentExecutionsFromCrashed is the default maximum concurrent crashed task executions in the instance + defaultMaxConcurrentExecutionsFromCrashed = 20 + // MaxTextSizeLong is the maximum number of characters accepted in a text-type field MaxTextSizeLong = 100000 // ~100 kB // MaxTextSize is the maximum number of characters accepted in a simple string field @@ -76,20 +84,24 @@ const ( // Cfg holds global configuration data type Cfg struct { - ApplicationName string `json:"application_name"` - AdminUsernames []string `json:"admin_usernames"` - CompletedTaskExpiration string `json:"completed_task_expiration"` - NotifyConfig map[string]NotifyBackend `json:"notify_config"` - NotifyActions NotifyActions `json:"notify_actions"` - DatabaseConfig *DatabaseConfig `json:"database_config"` - ConcealedSecrets []string `json:"concealed_secrets"` - ResourceLimits map[string]uint `json:"resource_limits"` - MaxConcurrentExecutions uint `json:"max_concurrent_executions"` - DashboardPathPrefix string `json:"dashboard_path_prefix"` - DashboardAPIPathPrefix string `json:"dashboard_api_path_prefix"` - DashboardSentryDSN string `json:"dashboard_sentry_dsn"` - EditorPathPrefix string `json:"editor_path_prefix"` - ServerOptions ServerOpt `json:"server_options"` + ApplicationName string `json:"application_name"` + AdminUsernames []string `json:"admin_usernames"` + CompletedTaskExpiration string `json:"completed_task_expiration"` + NotifyConfig map[string]NotifyBackend `json:"notify_config"` + NotifyActions NotifyActions `json:"notify_actions"` + DatabaseConfig *DatabaseConfig `json:"database_config"` + ConcealedSecrets []string `json:"concealed_secrets"` + ResourceLimits map[string]uint `json:"resource_limits"` + MaxConcurrentExecutions *int `json:"max_concurrent_executions"` + MaxConcurrentExecutionsFromCrashed *int `json:"max_concurrent_executions_from_crashed"` + MaxConcurrentExecutionsFromCrashedComputed int `json:"-"` + DelayBetweenCrashedTasksResolution string `json:"delay_between_crashed_tasks_resolution"` + InstanceCollectorWaitDuration time.Duration `json:"-"` + DashboardPathPrefix string `json:"dashboard_path_prefix"` + DashboardAPIPathPrefix string `json:"dashboard_api_path_prefix"` + DashboardSentryDSN string `json:"dashboard_sentry_dsn"` + EditorPathPrefix string `json:"editor_path_prefix"` + ServerOptions ServerOpt `json:"server_options"` resourceSemaphores map[string]*semaphore.Weighted executionSemaphore *semaphore.Weighted @@ -147,8 +159,13 @@ func (c *Cfg) buildLimits() { c.resourceSemaphores[k] = semaphore.NewWeighted(int64(v)) } - if c.MaxConcurrentExecutions > 0 { - c.executionSemaphore = semaphore.NewWeighted(int64(c.MaxConcurrentExecutions)) + maxConcurrentExecutions := defaultMaxConcurrentExecutions + if c.MaxConcurrentExecutions != nil { + maxConcurrentExecutions = *c.MaxConcurrentExecutions + } + + if maxConcurrentExecutions >= 0 { + c.executionSemaphore = semaphore.NewWeighted(int64(maxConcurrentExecutions)) } } @@ -217,6 +234,19 @@ func Config(store *configstore.Store) (*Cfg, error) { return nil, fmt.Errorf("failed to unmarshal utask configuration: %s", err) } + if global.DelayBetweenCrashedTasksResolution != "" { + global.InstanceCollectorWaitDuration, err = time.ParseDuration(global.DelayBetweenCrashedTasksResolution) + if err != nil { + return nil, fmt.Errorf("failed to parse \"delay_between_crashed_tasks_resolution\": %s", err) + } + } else { + global.InstanceCollectorWaitDuration = defaultInstanceCollectorWaitDuration + } + global.MaxConcurrentExecutionsFromCrashedComputed = defaultMaxConcurrentExecutionsFromCrashed + if global.MaxConcurrentExecutionsFromCrashed != nil { + global.MaxConcurrentExecutionsFromCrashedComputed = *global.MaxConcurrentExecutionsFromCrashed + } + App = global.ApplicationName global.buildLimits()