From 44d15f1b7bb55c572b6419ea1329a0be8deb9e9f Mon Sep 17 00:00:00 2001 From: Simon Behar Date: Thu, 16 Jan 2020 12:02:43 -0800 Subject: [PATCH 01/75] feat: Add ability to submit CronWorkflow and WorflowTemplate from CLI. Closes #1963 --- cmd/argo/commands/submit.go | 90 ++++++++++++++++++++++++------ test/e2e/argo_server_test.go | 4 +- test/e2e/cli_test.go | 45 ++++++++++++++- test/e2e/cron_test.go | 6 +- test/e2e/fixtures/given.go | 2 +- test/e2e/fixtures/then.go | 13 +++-- test/e2e/fixtures/when.go | 14 ++++- test/e2e/functional_test.go | 4 +- test/e2e/smoke_test.go | 6 +- test/e2e/workflow_template_test.go | 2 +- workflow/common/util.go | 23 +++++++- workflow/cron/operator.go | 2 +- workflow/validate/validate.go | 2 +- 13 files changed, 174 insertions(+), 39 deletions(-) diff --git a/cmd/argo/commands/submit.go b/cmd/argo/commands/submit.go index 0c6fa5eab9d3..19db11003e1b 100644 --- a/cmd/argo/commands/submit.go +++ b/cmd/argo/commands/submit.go @@ -5,6 +5,13 @@ import ( "log" "os" "strconv" + "strings" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/argoproj/argo/cmd/argo/commands/cron" + "github.com/argoproj/argo/cmd/argo/commands/template" + "github.com/argoproj/argo/pkg/apis/workflow" "github.com/spf13/cobra" apimachineryversion "k8s.io/apimachinery/pkg/version" @@ -34,20 +41,25 @@ func NewSubmitCommand() *cobra.Command { submitOpts util.SubmitOpts cliSubmitOpts cliSubmitOpts priority int32 + from string ) var command = &cobra.Command{ Use: "submit FILE1 FILE2...", Short: "submit a workflow", Run: func(cmd *cobra.Command, args []string) { - if len(args) == 0 { - cmd.HelpFunc()(cmd, args) - os.Exit(1) - } if cmd.Flag("priority").Changed { cliSubmitOpts.priority = &priority } - SubmitWorkflows(args, &submitOpts, &cliSubmitOpts) + if from != "" { + SubmitWorkflowFromResource(from, &submitOpts, &cliSubmitOpts) + } else { + if len(args) == 0 { + cmd.HelpFunc()(cmd, args) + os.Exit(1) + } + SubmitWorkflowsFromFile(args, &submitOpts, &cliSubmitOpts) + } }, } command.Flags().StringVar(&submitOpts.Name, "name", "", "override metadata.name") @@ -65,6 +77,7 @@ func NewSubmitCommand() *cobra.Command { command.Flags().Int32Var(&priority, "priority", 0, "workflow priority") command.Flags().StringVarP(&submitOpts.ParameterFile, "parameter-file", "f", "", "pass a file containing all input parameters") command.Flags().StringVarP(&submitOpts.Labels, "labels", "l", "", "Comma separated labels to apply to the workflow. Will override previous values.") + command.Flags().StringVar(&from, "from", "", "Submit from a WorkflowTempalte or CronWorkflow. E.g., --from=CronWorkflow/hello-world-cwf") // Only complete files with appropriate extension. err := command.Flags().SetAnnotation("parameter-file", cobra.BashCompFilenameExt, []string{"json", "yaml", "yml"}) if err != nil { @@ -73,7 +86,61 @@ func NewSubmitCommand() *cobra.Command { return command } -func SubmitWorkflows(filePaths []string, submitOpts *util.SubmitOpts, cliOpts *cliSubmitOpts) { +func SubmitWorkflowsFromFile(filePaths []string, submitOpts *util.SubmitOpts, cliOpts *cliSubmitOpts) { + fileContents, err := util.ReadManifest(filePaths...) + if err != nil { + log.Fatal(err) + } + + var workflows []wfv1.Workflow + for _, body := range fileContents { + wfs := unmarshalWorkflows(body, cliOpts.strict) + workflows = append(workflows, wfs...) + } + + submitWorkflows(workflows, submitOpts, cliOpts) +} + +func SubmitWorkflowFromResource(resourceIdentifier string, submitOpts *util.SubmitOpts, cliOpts *cliSubmitOpts) { + + resIdSplit := strings.Split(resourceIdentifier, "/") + if len(resIdSplit) != 2 { + log.Fatalf("resource identifier '%s' is malformed. Expected is KIND/NAME, e.g. CronWorkflow/hello-world-cwf", resourceIdentifier) + } + + var workflowToSubmit *wfv1.Workflow + switch resIdSplit[0] { + case workflow.CronWorkflowKind: + cwfIf := cron.InitCronWorkflowClient() + cwf, err := cwfIf.Get(resIdSplit[1], v1.GetOptions{}) + if err != nil { + log.Fatalf("Unable to get CronWorkflow '%s': %s", resIdSplit[1], err) + } + workflowToSubmit, err = common.ConvertCronWorkflowToWorkflow(cwf) + if err != nil { + log.Fatalf("Unable to create Workflow from CronWorkflow '%s': %s", resIdSplit[1], err) + } + case workflow.WorkflowTemplateKind: + if submitOpts.Entrypoint == "" { + log.Fatalf("When submitting a Workflow from a WorkflowTemplate an entrypoint must be passed with --entrypoint") + } + wftmplIf := template.InitWorkflowTemplateClient() + wfTmpl, err := wftmplIf.Get(resIdSplit[1], v1.GetOptions{}) + if err != nil { + log.Fatalf("Unable to get WorkflowTemplate '%s'", resIdSplit[1]) + } + workflowToSubmit, err = common.ConvertWorkflowTemplateToWorkflow(wfTmpl, submitOpts.Entrypoint) + if err != nil { + log.Fatalf("Unable to create Workflow from WorkflowTemplate '%s': %s", resIdSplit[1], err) + } + default: + log.Fatalf("Resource Kind '%s' is not supported with --from", resIdSplit[0]) + } + + submitWorkflows([]wfv1.Workflow{*workflowToSubmit}, submitOpts, cliOpts) +} + +func submitWorkflows(workflows []wfv1.Workflow, submitOpts *util.SubmitOpts, cliOpts *cliSubmitOpts) { if submitOpts == nil { submitOpts = &util.SubmitOpts{} } @@ -88,17 +155,6 @@ func SubmitWorkflows(filePaths []string, submitOpts *util.SubmitOpts, cliOpts *c log.Fatal(err) } - fileContents, err := util.ReadManifest(filePaths...) - if err != nil { - log.Fatal(err) - } - - var workflows []wfv1.Workflow - for _, body := range fileContents { - wfs := unmarshalWorkflows(body, cliOpts.strict) - workflows = append(workflows, wfs...) - } - if cliOpts.watch { if len(workflows) > 1 { log.Fatalf("Cannot watch more than one workflow") diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index 16b4653a7e6b..7e6a33051fcf 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -542,7 +542,7 @@ func (s *ArgoServerSuite) TestWorkflowArtifact() { SubmitWorkflow(). WaitForWorkflow(15 * time.Second). Then(). - Expect(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { uid = metadata.UID }) @@ -657,7 +657,7 @@ func (s *ArgoServerSuite) TestArchivedWorkflow() { SubmitWorkflow(). WaitForWorkflow(20 * time.Second). Then(). - Expect(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { uid = metadata.UID }) s.Given(). diff --git a/test/e2e/cli_test.go b/test/e2e/cli_test.go index 0284cf9f2640..f04d541ec7fb 100644 --- a/test/e2e/cli_test.go +++ b/test/e2e/cli_test.go @@ -2,6 +2,7 @@ package e2e import ( "os" + "regexp" "testing" "time" @@ -67,6 +68,48 @@ func (s *CLISuite) TestRoot() { assert.Contains(t, output, "Started:") assert.Contains(t, output, "Duration:") }) + + var createdWorkflowName string + s.Given().CronWorkflow("@testdata/basic.yaml"). + When(). + CreateCronWorkflow(). + RunCli([]string{"submit", "--from", "CronWorkflow/test-cron-wf-basic"}, func(t *testing.T, output string, err error) { + assert.NoError(t, err) + assert.Contains(t, output, "Name: test-cron-wf-basic-") + r := regexp.MustCompile(`Name:\s+?(test-cron-wf-basic-[a-z0-9]+)`) + res := r.FindStringSubmatch(output) + if len(res) != 2 { + assert.Fail(t, "Internal test error, please report a bug") + } + createdWorkflowName = res[1] + }). + WaitForWorkflowFromName(createdWorkflowName, 15*time.Second). + Then(). + ExpectWorkflowFromName(createdWorkflowName, func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + assert.Equal(t, wfv1.NodeSucceeded, status.Phase) + }) + + s.Given().WorkflowTemplate("@smoke/workflow-template-whalesay-template.yaml"). + When(). + CreateWorkflowTemplates(). + RunCli([]string{"submit", "--from", "WorkflowTemplate/workflow-template-whalesay-template"}, func(t *testing.T, output string, err error) { + assert.Errorf(t, err, "When submitting a Workflow from a WorkflowTemplate an entrypoint must be passed with --entrypoint") + }). + RunCli([]string{"submit", "--from", "WorkflowTemplate/workflow-template-whalesay-template", "--entrypoint", "whalesay-template", "--parameter", "message=TEST"}, func(t *testing.T, output string, err error) { + assert.NoError(t, err) + assert.Contains(t, output, "Name: workflow-template-whalesay-template-") + r := regexp.MustCompile(`Name:\s+?(workflow-template-whalesay-template-[a-z0-9]+)`) + res := r.FindStringSubmatch(output) + if len(res) != 2 { + assert.Fail(t, "Internal test error, please report a bug") + } + createdWorkflowName = res[1] + }). + WaitForWorkflowFromName(createdWorkflowName, 15*time.Second). + Then(). + ExpectWorkflowFromName(createdWorkflowName, func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + assert.Equal(t, wfv1.NodeSucceeded, status.Phase) + }) } func (s *CLISuite) TestTemplate() { @@ -154,7 +197,7 @@ func (s *CLISuite) TestArchive() { SubmitWorkflow(). WaitForWorkflow(30*time.Second). Then(). - Expect(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { uid = metadata.UID }).RunCli([]string{"archive", "list"}, func(t *testing.T, output string, err error) { assert.NoError(t, err) diff --git a/test/e2e/cron_test.go b/test/e2e/cron_test.go index 670651a3a15f..e4d8af422bec 100644 --- a/test/e2e/cron_test.go +++ b/test/e2e/cron_test.go @@ -35,9 +35,9 @@ func (s *CronSuite) TestBasic() { } func (s *CronSuite) TestBasicTimezone() { - // This test works by scheduling a CronWorkflow for the next minute, but using the local time of another timezone - // then seeing if the Workflow was ran within the next minute. Since this test would be trivial if the selected - // timezone was the same as the local timezone, a little-used timezone is used. + // This test works by scheduling a CronWorkflow for the next minute, but using the local time of another timezone + // then seeing if the Workflow was ran within the next minute. Since this test would be trivial if the selected + // timezone was the same as the local timezone, a little-used timezone is used. testTimezone := "Pacific/Niue" testLocation, err := time.LoadLocation(testTimezone) if err != nil { diff --git a/test/e2e/fixtures/given.go b/test/e2e/fixtures/given.go index 7ef14f5f79c5..0ab8acc2a6bb 100644 --- a/test/e2e/fixtures/given.go +++ b/test/e2e/fixtures/given.go @@ -139,7 +139,7 @@ func (g *Given) CronWorkflow(text string) *Given { return g } -func (g *Given) RunCli(args []string, block func(*testing.T, string, error)) *Given { +func (g *Given) RunCli(args []string, block func(t *testing.T, output string, err error)) *Given { output, err := runCli(g.diagnostics, args) block(g.t, output, err) return g diff --git a/test/e2e/fixtures/then.go b/test/e2e/fixtures/then.go index bd3996693f2d..c11c9445b1b5 100644 --- a/test/e2e/fixtures/then.go +++ b/test/e2e/fixtures/then.go @@ -22,12 +22,16 @@ type Then struct { offloadNodeStatusRepo sqldb.OffloadNodeStatusRepo } -func (t *Then) Expect(block func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus)) *Then { - if t.workflowName == "" { +func (t *Then) ExpectWorkflow(block func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus)) *Then { + return t.ExpectWorkflowFromName(t.workflowName, block) +} + +func (t *Then) ExpectWorkflowFromName(workflowName string, block func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus)) *Then { + if workflowName == "" { t.t.Fatal("No workflow to test") } - log.WithFields(log.Fields{"test": t.t.Name(), "workflow": t.workflowName}).Info("Checking expectation") - wf, err := t.client.Get(t.workflowName, metav1.GetOptions{}) + log.WithFields(log.Fields{"test": t.t.Name(), "workflow": workflowName}).Info("Checking expectation") + wf, err := t.client.Get(workflowName, metav1.GetOptions{}) if err != nil { t.t.Fatal(err) } @@ -40,6 +44,7 @@ func (t *Then) Expect(block func(t *testing.T, metadata *metav1.ObjectMeta, stat } block(t.t, &wf.ObjectMeta, &wf.Status) return t + } func (t *Then) ExpectCron(block func(t *testing.T, cronWf *wfv1.CronWorkflow)) *Then { diff --git a/test/e2e/fixtures/when.go b/test/e2e/fixtures/when.go index 1ee9142b2d9c..1c5383e76a5a 100644 --- a/test/e2e/fixtures/when.go +++ b/test/e2e/fixtures/when.go @@ -79,9 +79,13 @@ func (w *When) CreateCronWorkflow() *When { } func (w *When) WaitForWorkflow(timeout time.Duration) *When { - logCtx := log.WithFields(log.Fields{"test": w.t.Name(), "workflow": w.workflowName}) + return w.WaitForWorkflowFromName(w.workflowName, timeout) +} + +func (w *When) WaitForWorkflowFromName(workflowName string, timeout time.Duration) *When { + logCtx := log.WithFields(log.Fields{"test": w.t.Name(), "workflow": workflowName}) logCtx.Info("Waiting on workflow") - opts := metav1.ListOptions{FieldSelector: fields.ParseSelectorOrDie(fmt.Sprintf("metadata.name=%s", w.workflowName)).String()} + opts := metav1.ListOptions{FieldSelector: fields.ParseSelectorOrDie(fmt.Sprintf("metadata.name=%s", workflowName)).String()} watch, err := w.client.Watch(opts) if err != nil { w.t.Fatal(err) @@ -126,6 +130,12 @@ func (w *When) DeleteWorkflow() *When { return w } +func (w *When) RunCli(args []string, block func(t *testing.T, output string, err error)) *When { + output, err := runCli(w.diagnostics, args) + block(w.t, output, err) + return w +} + func (w *When) Then() *Then { return &Then{ t: w.t, diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index 62b632e69be5..46fda4e54275 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -62,7 +62,7 @@ spec: SubmitWorkflow(). WaitForWorkflow(30 * time.Second). Then(). - Expect(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { assert.Equal(t, wfv1.NodeSucceeded, status.Phase) assert.Len(t, status.Nodes, 7) nodeStatus := status.Nodes.FindByDisplayName("B") @@ -84,7 +84,7 @@ func (s *FunctionalSuite) TestFastFailOnPodTermination() { SubmitWorkflow(). WaitForWorkflow(120 * time.Second). Then(). - Expect(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { assert.Equal(t, wfv1.NodeFailed, status.Phase) assert.Len(t, status.Nodes, 4) nodeStatus := status.Nodes.FindByDisplayName("sleep") diff --git a/test/e2e/smoke_test.go b/test/e2e/smoke_test.go index e903ec8f52ed..5bd1af7b5188 100644 --- a/test/e2e/smoke_test.go +++ b/test/e2e/smoke_test.go @@ -23,7 +23,7 @@ func (s *SmokeSuite) TestBasic() { SubmitWorkflow(). WaitForWorkflow(10 * time.Second). Then(). - Expect(func(t *testing.T, _ *metav1.ObjectMeta, wf *wfv1.WorkflowStatus) { + ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, wf *wfv1.WorkflowStatus) { assert.Equal(t, wfv1.NodeSucceeded, wf.Phase) assert.NotEmpty(t, wf.Nodes) }) @@ -36,7 +36,7 @@ func (s *SmokeSuite) TestArtifactPassing() { SubmitWorkflow(). WaitForWorkflow(20 * time.Second). Then(). - Expect(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { assert.Equal(t, wfv1.NodeSucceeded, status.Phase) }) } @@ -50,7 +50,7 @@ func (s *SmokeSuite) TestWorkflowTemplateBasic() { SubmitWorkflow(). WaitForWorkflow(15 * time.Second). Then(). - Expect(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { assert.Equal(t, wfv1.NodeSucceeded, status.Phase) }) } diff --git a/test/e2e/workflow_template_test.go b/test/e2e/workflow_template_test.go index def88fd13979..c9b13379f777 100644 --- a/test/e2e/workflow_template_test.go +++ b/test/e2e/workflow_template_test.go @@ -37,7 +37,7 @@ spec: SubmitWorkflow(). WaitForWorkflow(15 * time.Second). Then(). - Expect(func(t *testing.T, metadata *v1.ObjectMeta, status *v1alpha1.WorkflowStatus) { + ExpectWorkflow(func(t *testing.T, metadata *v1.ObjectMeta, status *v1alpha1.WorkflowStatus) { assert.Equal(t, status.Phase, v1alpha1.NodeSucceeded) }) diff --git a/workflow/common/util.go b/workflow/common/util.go index efcb818c3395..9e2f6fd8893c 100644 --- a/workflow/common/util.go +++ b/workflow/common/util.go @@ -681,7 +681,7 @@ func GetTemplateHolderString(tmplHolder wfv1.TemplateHolder) string { } } -func ConvertToWorkflow(cronWf *wfv1.CronWorkflow) (*wfv1.Workflow, error) { +func ConvertCronWorkflowToWorkflow(cronWf *wfv1.CronWorkflow) (*wfv1.Workflow, error) { newTypeMeta := metav1.TypeMeta{ Kind: workflow.WorkflowKind, APIVersion: cronWf.TypeMeta.APIVersion, @@ -701,3 +701,24 @@ func ConvertToWorkflow(cronWf *wfv1.CronWorkflow) (*wfv1.Workflow, error) { wf.SetOwnerReferences(append(wf.GetOwnerReferences(), *metav1.NewControllerRef(cronWf, wfv1.SchemeGroupVersion.WithKind(workflow.CronWorkflowKind)))) return wf, nil } + +func ConvertWorkflowTemplateToWorkflow(wfTemplate *wfv1.WorkflowTemplate, entrypoint string) (*wfv1.Workflow, error) { + newTypeMeta := metav1.TypeMeta{ + Kind: workflow.WorkflowKind, + APIVersion: wfTemplate.TypeMeta.APIVersion, + } + + newObjectMeta := metav1.ObjectMeta{} + newObjectMeta.GenerateName = wfTemplate.Name + "-" + + wf := &wfv1.Workflow{ + TypeMeta: newTypeMeta, + ObjectMeta: newObjectMeta, + Spec: wfv1.WorkflowSpec{ + Templates: wfTemplate.Spec.Templates, + Entrypoint: entrypoint, + Arguments: wfTemplate.Spec.Arguments, + }, + } + return wf, nil +} diff --git a/workflow/cron/operator.go b/workflow/cron/operator.go index 7683388e0d3f..5d213940bd59 100644 --- a/workflow/cron/operator.go +++ b/workflow/cron/operator.go @@ -47,7 +47,7 @@ func (woc *cronWfOperationCtx) Run() { return } - wf, err := common.ConvertToWorkflow(woc.cronWf) + wf, err := common.ConvertCronWorkflowToWorkflow(woc.cronWf) if err != nil { log.Errorf("Unable to create Workflow for CronWorkflow %s", woc.name) return diff --git a/workflow/validate/validate.go b/workflow/validate/validate.go index 68be5e8d3a39..a8facd1b6803 100644 --- a/workflow/validate/validate.go +++ b/workflow/validate/validate.go @@ -192,7 +192,7 @@ func ValidateCronWorkflow(wftmplGetter templateresolution.WorkflowTemplateNamesp return errors.Errorf(errors.CodeBadRequest, "startingDeadlineSeconds must be positive") } - wf, err := common.ConvertToWorkflow(cronWf) + wf, err := common.ConvertCronWorkflowToWorkflow(cronWf) if err != nil { return errors.Errorf(errors.CodeBadRequest, "cannot convert to Workflow: %s", err) } From 9325f168dda1ef5a3e5ea3b11f70fe08a316341d Mon Sep 17 00:00:00 2001 From: Simon Behar Date: Thu, 16 Jan 2020 15:15:39 -0800 Subject: [PATCH 02/75] goimports --- cmd/argo/commands/submit.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/cmd/argo/commands/submit.go b/cmd/argo/commands/submit.go index 19db11003e1b..48e5be70e022 100644 --- a/cmd/argo/commands/submit.go +++ b/cmd/argo/commands/submit.go @@ -7,24 +7,20 @@ import ( "strconv" "strings" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - + "github.com/argoproj/argo/cmd/argo/commands/client" "github.com/argoproj/argo/cmd/argo/commands/cron" "github.com/argoproj/argo/cmd/argo/commands/template" - "github.com/argoproj/argo/pkg/apis/workflow" - - "github.com/spf13/cobra" - apimachineryversion "k8s.io/apimachinery/pkg/version" - - "github.com/argoproj/pkg/errors" - argoJson "github.com/argoproj/pkg/json" - - "github.com/argoproj/argo/cmd/argo/commands/client" apiwf "github.com/argoproj/argo/cmd/server/workflow" + "github.com/argoproj/argo/pkg/apis/workflow" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" apiUtil "github.com/argoproj/argo/util/api" "github.com/argoproj/argo/workflow/common" "github.com/argoproj/argo/workflow/util" + "github.com/argoproj/pkg/errors" + argoJson "github.com/argoproj/pkg/json" + "github.com/spf13/cobra" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apimachineryversion "k8s.io/apimachinery/pkg/version" ) // cliSubmitOpts holds submition options specific to CLI submission (e.g. controlling output) From 502b1f4b24b5d9695157218deeaf403952f49bb7 Mon Sep 17 00:00:00 2001 From: Simon Behar Date: Mon, 27 Jan 2020 11:04:59 -0800 Subject: [PATCH 03/75] Merge --- .circleci/config.yml | 128 ++-- .codecov.yml | 2 +- .dockerignore | 1 + .github/workflows/dockerimage.yaml | 14 - .golangci.yml | 16 +- Dockerfile | 6 - Gopkg.lock | 2 + Makefile | 226 ++++-- README.md | 17 +- VERSION | 2 +- api/openapi-spec/swagger.json | 14 +- cmd/argo/commands/archive/delete.go | 4 +- cmd/argo/commands/archive/get.go | 4 +- cmd/argo/commands/archive/list.go | 4 +- cmd/argo/commands/client/conn.go | 8 +- cmd/argo/commands/common.go | 4 +- cmd/argo/commands/delete.go | 2 +- cmd/argo/commands/get.go | 2 +- cmd/argo/commands/lint.go | 4 +- cmd/argo/commands/list.go | 2 +- cmd/argo/commands/logs.go | 2 +- cmd/argo/commands/resubmit.go | 2 +- cmd/argo/commands/resume.go | 2 +- cmd/argo/commands/retry.go | 2 +- cmd/argo/commands/server.go | 2 +- cmd/argo/commands/submit.go | 9 +- cmd/argo/commands/suspend.go | 2 +- cmd/argo/commands/template/common.go | 4 +- cmd/argo/commands/template/create.go | 2 +- cmd/argo/commands/template/delete.go | 2 +- cmd/argo/commands/template/get.go | 2 +- cmd/argo/commands/template/lint.go | 4 +- cmd/argo/commands/template/list.go | 2 +- cmd/argo/commands/terminate.go | 2 +- cmd/argo/commands/token.go | 2 +- cmd/argo/commands/wait.go | 2 +- cmd/argo/commands/watch.go | 2 +- cmd/workflow-controller/main.go | 24 +- docs/rest-api.md | 8 +- docs/workflow-controller-configmap.yaml | 6 +- examples/README.md | 4 +- examples/gc-ttl.yaml | 8 +- gometalinter.json | 25 - hack/auto-gen-msg.sh | 5 + hack/update-manifests.sh | 12 +- .../argo-server/argo-server-deployment.yaml | 2 +- .../argo-server-clusterole.yaml | 2 + .../workflow-controller-clusterrole.yaml | 7 +- manifests/install.yaml | 9 +- manifests/namespace-install.yaml | 10 +- .../argo-server-rbac/argo-server-role.yaml | 2 + .../workflow-controller-role.yaml | 8 +- manifests/quick-start-mysql.yaml | 494 ++++++++++++ manifests/quick-start-no-db.yaml | 409 ++++++++++ manifests/quick-start-postgres.yaml | 486 ++++++++++++ .../quick-start/base/minio/minio-pod.yaml | 2 +- .../quick-start/mysql/mysql-deployment.yaml | 7 +- .../quick-start/no-db/kustomization.yaml | 8 + .../workflow-controller-configmap.yaml | 18 + .../postgres/postgres-deployment.yaml | 7 +- persist/sqldb/ansi_sql_change.go | 11 + persist/sqldb/backfill_cluster_name.go | 56 ++ persist/sqldb/backfill_nodes.go | 66 ++ .../explosive_offload_node_status_repo.go | 25 +- persist/sqldb/mappers.go | 93 --- persist/sqldb/migrate.go | 229 ++++-- persist/sqldb/mocks/DBRepository.go | 153 ---- persist/sqldb/mocks/OffloadNodeStatusRepo.go | 87 ++- persist/sqldb/null_workflow_archive.go | 2 +- persist/sqldb/offload_node_status_repo.go | 232 +++--- .../sqldb/offload_node_status_repo_test.go | 26 + persist/sqldb/sqldb.go | 29 +- persist/sqldb/workflow_archive.go | 150 +++- pkg/apis/workflow/v1alpha1/generated.pb.go | 712 +++++++++--------- pkg/apis/workflow/v1alpha1/generated.proto | 13 +- .../workflow/v1alpha1/openapi_generated.go | 12 +- pkg/apis/workflow/v1alpha1/register.go | 3 +- .../v1alpha1/workflow_template_types.go | 2 +- pkg/apis/workflow/v1alpha1/workflow_types.go | 25 +- .../workflow/v1alpha1/workflow_types_test.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 8 +- {cmd/server => server}/.gitignore | 0 .../server => server}/apiserver/argoserver.go | 42 +- .../artifacts/artifact_server.go | 20 +- {cmd/server => server}/artifacts/resources.go | 0 {cmd/server => server}/auth/authorizer.go | 7 + .../server => server}/auth/authorizer_test.go | 0 {cmd/server => server}/auth/gatekeeper.go | 44 +- .../server => server}/auth/gatekeeper_test.go | 21 +- .../cronworkflow/cron-workflow.pb.go | 167 ++-- .../cronworkflow/cron-workflow.pb.gw.go | 60 +- .../cronworkflow/cron-workflow.proto | 14 +- .../cronworkflow/cron-workflow.swagger.json | 18 +- .../cronworkflow/cron_workflow_server.go | 6 +- .../cronworkflow/cron_workflow_server_test.go | 11 +- {cmd/server => server}/info/info.pb.go | 56 +- {cmd/server => server}/info/info.pb.gw.go | 2 +- {cmd/server => server}/info/info.proto | 2 +- {cmd/server => server}/info/info.swagger.json | 2 +- {cmd/server => server}/info/info_server.go | 0 {cmd/server => server}/static/static.go | 0 .../workflow/forwarder_overwrite.go | 0 .../server => server}/workflow/workflow.pb.go | 432 ++++++++--- .../workflow/workflow.pb.gw.go | 6 +- .../server => server}/workflow/workflow.proto | 10 +- .../workflow/workflow.swagger.json | 26 +- .../workflow/workflow_server.go | 44 +- .../workflow/workflow_server_test.go | 15 +- .../archived_workflow_server.go | 18 +- .../archived_workflow_server_test.go | 3 +- .../workflowarchive/workflow-archive.pb.go | 73 +- .../workflowarchive/workflow-archive.pb.gw.go | 2 +- .../workflowarchive/workflow-archive.proto | 2 +- .../workflow-archive.swagger.json | 15 +- .../workflowtemplate/workflow-template.pb.go | 427 +++++++++-- .../workflow-template.pb.gw.go | 6 +- .../workflowtemplate/workflow-template.proto | 10 +- .../workflow-template.swagger.json | 16 +- .../workflow_template_server.go | 4 +- .../workflow_template_server_test.go | 10 +- test/e2e/README.md | 22 +- test/e2e/argo_server_test.go | 359 ++++++--- test/e2e/cli_test.go | 53 +- test/e2e/cron_test.go | 14 +- .../dag-disable-failFast.yaml | 4 +- .../dag-disbale-failFast-2.yaml | 2 +- .../dag-noroot-branch-failed.yaml | 4 +- .../expectedfailures/failed-step-event.yaml | 14 + .../output-artifact-not-optional.yaml | 2 +- .../pod-termination-failure.yaml | 4 +- .../volumes-pvc-fail-event.yaml | 42 ++ test/e2e/fixtures/e2e_suite.go | 119 ++- test/e2e/fixtures/env.go | 15 + test/e2e/fixtures/given.go | 24 +- test/e2e/fixtures/persistence.go | 71 ++ test/e2e/fixtures/then.go | 41 +- test/e2e/fixtures/util.go | 30 + test/e2e/fixtures/when.go | 71 +- .../artifact-input-output-samedir.yaml | 4 +- test/e2e/functional/continue-on-failed.yaml | 4 +- .../functional/custom_template_variable.yaml | 2 +- .../functional/global-parameters-complex.yaml | 2 +- test/e2e/functional/hello-world.json | 2 +- test/e2e/functional/nested-dag-outputs.yaml | 2 +- .../functional/output-artifact-optional.yaml | 2 +- .../output-input-artifact-optional.yaml | 2 +- .../output-param-different-uid.yaml | 2 +- test/e2e/functional/pns-output-params.yaml | 4 +- test/e2e/functional/retry-with-artifacts.yaml | 2 +- test/e2e/functional/success-event.yaml | 13 + test/e2e/functional_test.go | 74 +- test/e2e/images/cowsay/Dockerfile | 8 + test/e2e/lintfail/disallow-unknown.yaml | 2 +- test/e2e/lintfail/invalid-spec.yaml | 2 +- test/e2e/lintfail/malformed-spec.yaml | 2 +- test/e2e/manifests/mysql.yaml | 518 +++++++++++++ test/e2e/manifests/mysql/kustomization.yaml | 19 + .../overlays/argo-server-deployment.yaml | 23 + .../workflow-controller-deployment.yaml | 31 + test/e2e/manifests/no-db.yaml | 433 +++++++++++ test/e2e/manifests/no-db/kustomization.yaml | 19 + .../overlays/argo-server-deployment.yaml | 23 + .../workflow-controller-deployment.yaml | 31 + test/e2e/manifests/postgres.yaml | 510 +++++++++++++ .../e2e/manifests/postgres/kustomization.yaml | 19 + .../overlays/argo-server-deployment.yaml | 22 + .../workflow-controller-deployment.yaml | 30 + test/e2e/smoke/artifact-passing.yaml | 4 +- test/e2e/smoke/basic-2.yaml | 2 +- test/e2e/smoke/basic.yaml | 4 +- .../workflow-template-whalesay-template.yaml | 2 +- test/e2e/smoke_test.go | 8 +- test/e2e/testdata/argo-server-test-role.yaml | 16 + test/e2e/workflow_template_test.go | 14 +- ui/package.json | 2 +- ui/src/app/app.tsx | 20 +- .../archived-workflow-container.tsx | 4 +- .../archived-workflow-list.tsx | 18 +- .../components/cron-workflow-container.tsx | 2 +- .../cron-workflow-list/cron-workflow-list.tsx | 18 +- ui/src/app/login/components/login.tsx | 14 +- ui/src/app/shared/components/base-page.tsx | 8 +- .../shared/components/namespace-filter.tsx | 11 +- ui/src/app/shared/services/requests.ts | 12 +- .../workflow-template-container.tsx | 2 +- .../workflow-template-list.tsx | 20 +- .../workflows/components/workflow-submit.tsx | 122 +++ .../components/workflows-container.tsx | 2 +- .../workflows-list/workflows-list.tsx | 31 +- ui/yarn.lock | 57 +- util/api/util.go | 2 +- util/argo/audit_logger.go | 106 +++ util/kubeconfig/kubeconfig.go | 194 ++--- util/kubeconfig/kubeconfig_test.go | 21 - util/kubeconfig/token.go | 44 -- util/kubeconfig/token_test.go | 49 +- workflow/artifacts/s3/s3.go | 3 + workflow/common/common.go | 2 + workflow/common/placeholder.go | 9 +- workflow/config/config.go | 9 + workflow/controller/config_controller.go | 13 +- workflow/controller/controller.go | 80 +- workflow/controller/operator.go | 127 ++-- workflow/controller/operator_persist_test.go | 25 +- workflow/controller/operator_test.go | 121 ++- workflow/controller/workflowpod.go | 33 +- workflow/ttlcontroller/ttlcontroller.go | 14 +- workflow/ttlcontroller/ttlcontroller_test.go | 26 +- workflow/util/util.go | 6 +- workflow/validate/validate.go | 24 +- workflow/validate/validate_test.go | 103 +++ 211 files changed, 7364 insertions(+), 2335 deletions(-) delete mode 100644 .github/workflows/dockerimage.yaml delete mode 100644 gometalinter.json create mode 100755 hack/auto-gen-msg.sh create mode 100644 manifests/quick-start-mysql.yaml create mode 100644 manifests/quick-start-no-db.yaml create mode 100644 manifests/quick-start-postgres.yaml create mode 100644 manifests/quick-start/no-db/kustomization.yaml create mode 100644 manifests/quick-start/no-db/overlays/workflow-controller-configmap.yaml create mode 100644 persist/sqldb/ansi_sql_change.go create mode 100644 persist/sqldb/backfill_cluster_name.go create mode 100644 persist/sqldb/backfill_nodes.go delete mode 100644 persist/sqldb/mappers.go delete mode 100644 persist/sqldb/mocks/DBRepository.go create mode 100644 persist/sqldb/offload_node_status_repo_test.go rename {cmd/server => server}/.gitignore (100%) rename {cmd/server => server}/apiserver/argoserver.go (89%) rename {cmd/server => server}/artifacts/artifact_server.go (90%) rename {cmd/server => server}/artifacts/resources.go (100%) rename {cmd/server => server}/auth/authorizer.go (80%) rename {cmd/server => server}/auth/authorizer_test.go (100%) rename {cmd/server => server}/auth/gatekeeper.go (82%) rename {cmd/server => server}/auth/gatekeeper_test.go (67%) rename {cmd/server => server}/cronworkflow/cron-workflow.pb.go (89%) rename {cmd/server => server}/cronworkflow/cron-workflow.pb.gw.go (93%) rename {cmd/server => server}/cronworkflow/cron-workflow.proto (87%) rename {cmd/server => server}/cronworkflow/cron-workflow.swagger.json (99%) rename {cmd/server => server}/cronworkflow/cron_workflow_server.go (91%) rename {cmd/server => server}/cronworkflow/cron_workflow_server_test.go (84%) rename {cmd/server => server}/info/info.pb.go (85%) rename {cmd/server => server}/info/info.pb.gw.go (99%) rename {cmd/server => server}/info/info.proto (89%) rename {cmd/server => server}/info/info.swagger.json (94%) rename {cmd/server => server}/info/info_server.go (100%) rename {cmd/server => server}/static/static.go (100%) rename {cmd/server => server}/workflow/forwarder_overwrite.go (100%) rename {cmd/server => server}/workflow/workflow.pb.go (88%) rename {cmd/server => server}/workflow/workflow.pb.gw.go (99%) rename {cmd/server => server}/workflow/workflow.proto (93%) rename {cmd/server => server}/workflow/workflow.swagger.json (99%) rename {cmd/server => server}/workflow/workflow_server.go (88%) rename {cmd/server => server}/workflow/workflow_server_test.go (96%) rename {cmd/server => server}/workflowarchive/archived_workflow_server.go (83%) rename {cmd/server => server}/workflowarchive/archived_workflow_server_test.go (98%) rename {cmd/server => server}/workflowarchive/workflow-archive.pb.go (89%) rename {cmd/server => server}/workflowarchive/workflow-archive.pb.gw.go (99%) rename {cmd/server => server}/workflowarchive/workflow-archive.proto (94%) rename {cmd/server => server}/workflowarchive/workflow-archive.swagger.json (99%) rename {cmd/server => server}/workflowtemplate/workflow-template.pb.go (80%) rename {cmd/server => server}/workflowtemplate/workflow-template.pb.gw.go (99%) rename {cmd/server => server}/workflowtemplate/workflow-template.proto (85%) rename {cmd/server => server}/workflowtemplate/workflow-template.swagger.json (99%) rename {cmd/server => server}/workflowtemplate/workflow_template_server.go (96%) rename {cmd/server => server}/workflowtemplate/workflow_template_server_test.go (97%) create mode 100644 test/e2e/expectedfailures/failed-step-event.yaml create mode 100644 test/e2e/expectedfailures/volumes-pvc-fail-event.yaml create mode 100644 test/e2e/fixtures/env.go create mode 100644 test/e2e/fixtures/persistence.go create mode 100644 test/e2e/functional/success-event.yaml create mode 100644 test/e2e/images/cowsay/Dockerfile create mode 100644 test/e2e/manifests/mysql.yaml create mode 100644 test/e2e/manifests/mysql/kustomization.yaml create mode 100644 test/e2e/manifests/mysql/overlays/argo-server-deployment.yaml create mode 100644 test/e2e/manifests/mysql/overlays/workflow-controller-deployment.yaml create mode 100644 test/e2e/manifests/no-db.yaml create mode 100644 test/e2e/manifests/no-db/kustomization.yaml create mode 100644 test/e2e/manifests/no-db/overlays/argo-server-deployment.yaml create mode 100644 test/e2e/manifests/no-db/overlays/workflow-controller-deployment.yaml create mode 100644 test/e2e/manifests/postgres.yaml create mode 100644 test/e2e/manifests/postgres/kustomization.yaml create mode 100644 test/e2e/manifests/postgres/overlays/argo-server-deployment.yaml create mode 100644 test/e2e/manifests/postgres/overlays/workflow-controller-deployment.yaml create mode 100644 test/e2e/testdata/argo-server-test-role.yaml create mode 100644 ui/src/app/workflows/components/workflow-submit.tsx create mode 100644 util/argo/audit_logger.go delete mode 100644 util/kubeconfig/kubeconfig_test.go delete mode 100644 util/kubeconfig/token.go diff --git a/.circleci/config.yml b/.circleci/config.yml index 6c87ab18bbfc..769d7d9ea765 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -47,44 +47,7 @@ commands: - go-v5-master-{{ .Environment.CIRCLE_JOB }} - go-v4-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }} - go-v4-master-{{ .Environment.CIRCLE_JOB }} - go_junit_report: - steps: - - run: - name: Install Go test report to Junit test report - command: go get github.com/jstemmer/go-junit-report -jobs: - test: - working_directory: /home/circleci/.go_workspace/src/github.com/argoproj/argo - machine: - image: ubuntu-1604:201903-01 - steps: - - restore_go_cache - - install_golang - - go_junit_report - - checkout - - dep_ensure - - run: - name: Run tests - command: | - mkdir -p test-results - trap 'go-junit-report < test-results/test.out > test-results/junit.xml' EXIT - make test 2>&1 | tee test-results/test.out - - run: - name: Verify code generation - command: make verify-codegen - - save_go_cache - - run: - name: Uploading code coverage - command: bash <(curl -s https://codecov.io/bash) -f coverage.out - - store_test_results: - path: test-results - - store_artifacts: - path: test-results - destination: . e2e: - working_directory: /home/circleci/.go_workspace/src/github.com/argoproj/argo - machine: - image: ubuntu-1604:201903-01 steps: - run: name: Install Kustomize @@ -93,14 +56,6 @@ jobs: name: Install and start K3S v1.0.0 command: curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.0.0 INSTALL_K3S_EXEC=--docker K3S_KUBECONFIG_MODE=644 sh - background: true - - run: - name: Pull some Docker images now, to save time later - command: | - docker pull golang:1.11.5 - docker pull minio/minio - docker pull docker/whalesay:latest - docker pull bitnami/kubectl - background: true - restore_go_cache - install_golang - go_junit_report @@ -115,17 +70,20 @@ jobs: name: Watch Docker events, to help diagnose failures command: docker events background: true - - run: - name: Watch Kubernetes events, to help diagnose failures - command: kubectl -n argo get events --watch - background: true - run: name: Start Argo - command: mkdir dist && KUBECONFIG=~/.kube/config make start + command: mkdir dist && KUBECONFIG=~/.kube/config make start DB=$DB E2E_EXECUTOR=docker - run: name: Establish port forward command: make pf background: true + - run: + name: Watch Kubernetes events, to help diagnose failures + command: kubectl -n argo get events --watch + background: true + - run: + name: Sleep for short while + command: sleep 10s - run: name: Follow logs, to help diagnose failures command: make logs @@ -145,6 +103,71 @@ jobs: - store_artifacts: path: test-results destination: . + go_junit_report: + steps: + - run: + name: Install Go test report to Junit test report + command: go get github.com/jstemmer/go-junit-report +jobs: + test: + working_directory: /home/circleci/.go_workspace/src/github.com/argoproj/argo + machine: + image: ubuntu-1604:201903-01 + steps: + - restore_go_cache + - install_golang + - go_junit_report + - checkout + - dep_ensure + - run: + name: Run tests + command: | + mkdir -p test-results + trap 'go-junit-report < test-results/test.out > test-results/junit.xml' EXIT + make test 2>&1 | tee test-results/test.out + - run: + name: Verify code generation + command: make verify-codegen + - save_go_cache + - run: + name: Uploading code coverage + command: bash <(curl -s https://codecov.io/bash) -f coverage.out + - store_test_results: + path: test-results + - store_artifacts: + path: test-results + destination: . + e2e-no-db: + working_directory: /home/circleci/.go_workspace/src/github.com/argoproj/argo + machine: + image: ubuntu-1604:201903-01 + environment: + DB: no-db + steps: + - e2e + e2e-postgres: + working_directory: /home/circleci/.go_workspace/src/github.com/argoproj/argo + machine: + image: ubuntu-1604:201903-01 + environment: + DB: postgres + steps: + - e2e + e2e-mysql: + working_directory: /home/circleci/.go_workspace/src/github.com/argoproj/argo + machine: + image: ubuntu-1604:201903-01 + environment: + DB: mysql + steps: + - e2e + docker-build: + working_directory: /home/circleci/.go_workspace/src/github.com/argoproj/argo + machine: + image: ubuntu-1604:201903-01 + steps: + - checkout + - run: docker build . ui: docker: - image: node:11.15.0 @@ -177,4 +200,7 @@ workflows: jobs: - test - ui - - e2e + - e2e-no-db + - e2e-postgres + - e2e-mysql + - docker-build \ No newline at end of file diff --git a/.codecov.yml b/.codecov.yml index db5454daa98d..9c251044255d 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,5 +1,5 @@ ignore: - - "cmd/server/static/files.go" + - "server/static/files.go" - "pkg/client" coverage: status: diff --git a/.dockerignore b/.dockerignore index 6066612e95aa..0c92e0bbaefa 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,6 +5,7 @@ assets coverage.out dist +sdks vendor ui/dist ui/node_modules diff --git a/.github/workflows/dockerimage.yaml b/.github/workflows/dockerimage.yaml deleted file mode 100644 index 91113d0e4820..000000000000 --- a/.github/workflows/dockerimage.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: Docker Image CI - -on: [push] - -jobs: - - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: Build the Docker image - run: docker build . --file Dockerfile --tag my-image-name:$(date +%s) diff --git a/.golangci.yml b/.golangci.yml index ff122d5d66da..fd934fc5df02 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,14 +1,20 @@ +# https://github.com/golangci/golangci/wiki/Configuration run: - tests: false deadline: 2m + skip-dirs: + - pkg/client + - vendor + - ui skip-files: - - "cmd/server/static/files.go" - - "pkg/client" - - "vendor/" - - "ui/" + - server/static/files.go linters: enable: - goimports linters-settings: goimports: local-prefixes: github.com/argoproj/argo +service: + golangci-lint-version: 1.21.x + project-path: github.com/argoproj/argo + prepare: + - make vendor server/static/files.go CI=true \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 1c6524e71b78..4ad7b6b6c7ab 100644 --- a/Dockerfile +++ b/Dockerfile @@ -97,9 +97,3 @@ FROM scratch as argocli COPY --from=argo-build /go/src/github.com/argoproj/argo/dist/argo-linux-amd64 /bin/argo ENTRYPOINT [ "argo" ] -#################################################################################################### -# argo-server -#################################################################################################### -FROM scratch as argo-server -COPY --from=argo-build /go/src/github.com/argoproj/argo/dist/argo-server-linux-amd64 /usr/local/bin/argo-server -ENTRYPOINT [ "argo-server" ] diff --git a/Gopkg.lock b/Gopkg.lock index dddf6a16b767..4080ef3f4e35 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1632,6 +1632,7 @@ "github.com/evanphx/json-patch", "github.com/ghodss/yaml", "github.com/go-openapi/spec", + "github.com/go-sql-driver/mysql", "github.com/gogo/protobuf/gogoproto", "github.com/gogo/protobuf/proto", "github.com/gogo/protobuf/sortkeys", @@ -1703,6 +1704,7 @@ "k8s.io/client-go/informers/internalinterfaces", "k8s.io/client-go/kubernetes", "k8s.io/client-go/kubernetes/fake", + "k8s.io/client-go/kubernetes/scheme", "k8s.io/client-go/plugin/pkg/client/auth", "k8s.io/client-go/plugin/pkg/client/auth/azure", "k8s.io/client-go/plugin/pkg/client/auth/exec", diff --git a/Makefile b/Makefile index 281fcfded81a..cb5b07f3e078 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ -PACKAGE := github.com/argoproj/argo BUILD_DATE = $(shell date -u +'%Y-%m-%dT%H:%M:%SZ') GIT_COMMIT = $(shell git rev-parse HEAD) GIT_BRANCH = $(shell git rev-parse --abbrev-ref=loose HEAD | sed 's/heads\///') +GIT_REMOTE ?= upstream GIT_TAG = $(shell if [ -z "`git status --porcelain`" ]; then git describe --exact-match --tags HEAD 2>/dev/null; fi) GIT_TREE_STATE = $(shell if [ -z "`git status --porcelain`" ]; then echo "clean" ; else echo "dirty"; fi) @@ -10,8 +10,8 @@ export DOCKER_BUILDKIT = 1 # docker image publishing options IMAGE_NAMESPACE ?= argoproj -ifeq ($(GIT_BRANCH),MASTER) -VERSION := latest +ifeq ($(GIT_BRANCH),master) +VERSION := $(shell cat VERSION) IMAGE_TAG := latest DEV_IMAGE := true else @@ -28,6 +28,8 @@ endif # perform static compilation STATIC_BUILD ?= true CI ?= false +DB ?= postgres +K3D := $(shell if [ "`kubectl config current-context`" = "k3s-default" ]; then echo true; else echo false; fi) override LDFLAGS += \ -X ${PACKAGE}.version=$(VERSION) \ @@ -47,11 +49,14 @@ endif ARGOEXEC_PKGS := $(shell echo cmd/argoexec && go list -f '{{ join .Deps "\n" }}' ./cmd/argoexec/ | grep 'argoproj/argo' | grep -v vendor | cut -c 26-) CLI_PKGS := $(shell echo cmd/argo && go list -f '{{ join .Deps "\n" }}' ./cmd/argo/ | grep 'argoproj/argo' | grep -v vendor | cut -c 26-) CONTROLLER_PKGS := $(shell echo cmd/workflow-controller && go list -f '{{ join .Deps "\n" }}' ./cmd/workflow-controller/ | grep 'argoproj/argo' | grep -v vendor | cut -c 26-) +MANIFESTS := $(shell find manifests -mindepth 2 -type f) +E2E_MANIFESTS := $(shell find test/e2e/manifests -mindepth 2 -type f) +E2E_EXECUTOR ?= pns .PHONY: build -build: clis executor-image controller-image dist/install.yaml dist/namespace-install.yaml dist/quick-start-postgres.yaml dist/quick-start-mysql.yaml +build: clis executor-image controller-image manifests/install.yaml manifests/namespace-install.yaml manifests/quick-start-postgres.yaml manifests/quick-start-mysql.yaml -vendor: Gopkg.toml +vendor: Gopkg.toml Gopkg.lock # Get Go dependencies rm -Rf .vendor-new dep ensure -v @@ -80,34 +85,36 @@ else endif touch ui/dist/app -$(GOPATH)/bin/staticfiles: +$(HOME)/go/bin/staticfiles: # Install the "staticfiles" tool go get bou.ke/staticfiles -cmd/server/static/files.go: ui/dist/app $(GOPATH)/bin/staticfiles +server/static/files.go: $(HOME)/go/bin/staticfiles ui/dist/app # Pack UI into a Go file. - staticfiles -o cmd/server/static/files.go ui/dist/app + staticfiles -o server/static/files.go ui/dist/app -dist/argo: vendor cmd/server/static/files.go $(CLI_PKGS) +dist/argo: vendor server/static/files.go $(CLI_PKGS) go build -v -i -ldflags '${LDFLAGS}' -o dist/argo ./cmd/argo -dist/argo-linux-amd64: vendor cmd/server/static/files.go $(CLI_PKGS) +dist/argo-linux-amd64: vendor server/static/files.go $(CLI_PKGS) CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -i -ldflags '${LDFLAGS}' -o dist/argo-linux-amd64 ./cmd/argo -dist/argo-linux-ppc64le: vendor cmd/server/static/files.go $(CLI_PKGS) +dist/argo-linux-ppc64le: vendor server/static/files.go $(CLI_PKGS) CGO_ENABLED=0 GOOS=linux GOARCH=ppc64le go build -v -i -ldflags '${LDFLAGS}' -o dist/argo-linux-ppc64le ./cmd/argo -dist/argo-linux-s390x: vendor cmd/server/static/files.go $(CLI_PKGS) +dist/argo-linux-s390x: vendor server/static/files.go $(CLI_PKGS) CGO_ENABLED=0 GOOS=linux GOARCH=ppc64le go build -v -i -ldflags '${LDFLAGS}' -o dist/argo-linux-s390x ./cmd/argo -dist/argo-darwin-amd64: vendor cmd/server/static/files.go $(CLI_PKGS) +dist/argo-darwin-amd64: vendor server/static/files.go $(CLI_PKGS) CGO_ENABLED=0 GOOS=darwin go build -v -i -ldflags '${LDFLAGS}' -o dist/argo-darwin-amd64 ./cmd/argo -dist/argo-windows-amd64: vendor cmd/server/static/files.go $(CLI_PKGS) +dist/argo-windows-amd64: vendor server/static/files.go $(CLI_PKGS) CGO_ENABLED=0 GOARCH=amd64 GOOS=windows go build -v -i -ldflags '${LDFLAGS}' -o dist/argo-windows-amd64 ./cmd/argo .PHONY: cli-image -cli-image: dist/argo-linux-amd64 +cli-image: dist/cli-image + +dist/cli-image: dist/argo-linux-amd64 # Create CLI image ifeq ($(DEV_IMAGE),true) cp dist/argo-linux-amd64 argo @@ -116,6 +123,10 @@ ifeq ($(DEV_IMAGE),true) else docker build -t $(IMAGE_NAMESPACE)/argocli:$(IMAGE_TAG) --target argocli . endif + touch dist/cli-image +ifeq ($(K3D),true) + k3d import-images $(IMAGE_NAMESPACE)/argocli:$(IMAGE_TAG) +endif .PHONY: clis clis: dist/argo-linux-amd64 dist/argo-linux-ppc64le dist/argo-linux-s390x dist/argo-darwin-amd64 dist/argo-windows-amd64 cli-image @@ -126,7 +137,9 @@ dist/workflow-controller-linux-amd64: vendor $(CONTROLLER_PKGS) CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -i -ldflags '${LDFLAGS}' -o dist/workflow-controller-linux-amd64 ./cmd/workflow-controller .PHONY: controller-image -controller-image: dist/workflow-controller-linux-amd64 +controller-image: dist/controller-image + +dist/controller-image: dist/workflow-controller-linux-amd64 # Create controller image ifeq ($(DEV_IMAGE),true) cp dist/workflow-controller-linux-amd64 workflow-controller @@ -135,6 +148,11 @@ ifeq ($(DEV_IMAGE),true) else docker build -t $(IMAGE_NAMESPACE)/workflow-controller:$(IMAGE_TAG) --target workflow-controller . endif + touch dist/controller-image +ifeq ($(K3D),true) + # importing images into k3d + k3d import-images $(IMAGE_NAMESPACE)/workflow-controller:$(IMAGE_TAG) +endif # argoexec @@ -142,7 +160,9 @@ dist/argoexec-linux-amd64: vendor $(ARGOEXEC_PKGS) CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -i -ldflags '${LDFLAGS}' -o dist/argoexec-linux-amd64 ./cmd/argoexec .PHONY: executor-image -executor-image: dist/argoexec-linux-amd64 +executor-image: dist/executor-image + +dist/executor-image: dist/argoexec-linux-amd64 # Create executor image ifeq ($(DEV_IMAGE),true) cp dist/argoexec-linux-amd64 argoexec @@ -151,6 +171,10 @@ ifeq ($(DEV_IMAGE),true) else docker build -t $(IMAGE_NAMESPACE)/argoexec:$(IMAGE_TAG) --target argoexec . endif + touch dist/executor-image +ifeq ($(K3D),true) + k3d import-images $(IMAGE_NAMESPACE)/argoexec:$(IMAGE_TAG) +endif # generation @@ -172,14 +196,31 @@ verify-codegen: diff ./dist/swagger.json ./api/openapi-spec/swagger.json .PHONY: manifests -manifests: - # Create manifests +manifests: manifests/install.yaml manifests/namespace-install.yaml manifests/quick-start-mysql.yaml manifests/quick-start-postgres.yaml test/e2e/manifests/postgres.yaml test/e2e/manifests/mysql.yaml + +# we use a different file to ./VERSION to force updating manifests after a `make clean` +dist/VERSION: + echo $(VERSION) > dist/VERSION + +manifests/install.yaml: dist/VERSION $(MANIFESTS) + env VERSION=$(VERSION) ./hack/update-manifests.sh + +manifests/namespace-install.yaml: dist/VERSION $(MANIFESTS) + env VERSION=$(VERSION) ./hack/update-manifests.sh + +manifests/quick-start-no-db.yaml: dist/VERSION $(MANIFESTS) + env VERSION=$(VERSION) ./hack/update-manifests.sh + +manifests/quick-start-mysql.yaml: dist/VERSION $(MANIFESTS) + env VERSION=$(VERSION) ./hack/update-manifests.sh + +manifests/quick-start-postgres.yaml: dist/VERSION $(MANIFESTS) env VERSION=$(VERSION) ./hack/update-manifests.sh # lint/test/etc .PHONY: lint -lint: cmd/server/static/files.go +lint: server/static/files.go # Lint Go files golangci-lint run --fix --verbose ifeq ($(CI),false) @@ -188,7 +229,7 @@ ifeq ($(CI),false) endif .PHONY: test -test: cmd/server/static/files.go vendor +test: server/static/files.go vendor # Run unit tests ifeq ($(CI),false) go test `go list ./... | grep -v 'test/e2e'` @@ -196,50 +237,87 @@ else go test -covermode=count -coverprofile=coverage.out `go list ./... | grep -v 'test/e2e'` endif -dist/install.yaml: manifests/cluster-install - # Create cluster install manifests - cat manifests/install.yaml | sed 's/:latest/:$(IMAGE_TAG)/' > dist/install.yaml +test/e2e/manifests/postgres.yaml: $(MANIFESTS) $(E2E_MANIFESTS) + # Create Postgres e2e manifests + kustomize build test/e2e/manifests/postgres | ./hack/auto-gen-msg.sh > test/e2e/manifests/postgres.yaml -dist/namespace-install.yaml: manifests/namespace-install - # Create namespace instnall manifests - cat manifests/namespace-install.yaml | sed 's/:latest/:$(IMAGE_TAG)/' > dist/namespace-install.yaml +dist/postgres.yaml: test/e2e/manifests/postgres.yaml + # Create Postgres e2e manifests + cat test/e2e/manifests/postgres.yaml | sed 's/:latest/:$(IMAGE_TAG)/' | sed 's/pns/$(E2E_EXECUTOR)/' > dist/postgres.yaml -dist/quick-start-mysql.yaml: manifests/namespace-install.yaml - # Create MySQL quick-start manifests - kustomize build manifests/quick-start/mysql | sed 's/:latest/:$(IMAGE_TAG)/' > dist/quick-start-mysql.yaml +test/e2e/manifests/no-db/overlays/argo-server-deployment.yaml: test/e2e/manifests/postgres/overlays/argo-server-deployment.yaml +test/e2e/manifests/no-db/overlays/argo-server-deployment.yaml: + cat test/e2e/manifests/postgres/overlays/argo-server-deployment.yaml | ./hack/auto-gen-msg.sh > test/e2e/manifests/no-db/overlays/argo-server-deployment.yaml -.PHONY: install-mysql -install-mysql: dist/quick-start-mysql.yaml - # Install MySQL quick-start - kubectl get ns argo || kubectl create ns argo - kubectl -n argo apply -f dist/quick-start-mysql.yaml +test/e2e/manifests/no-db/overlays/workflow-controller-deployment.yaml: test/e2e/manifests/postgres/overlays/workflow-controller-deployment.yaml +test/e2e/manifests/no-db/overlays/workflow-controller-deployment.yaml: + cat test/e2e/manifests/postgres/overlays/workflow-controller-deployment.yaml | ./hack/auto-gen-msg.sh > test/e2e/manifests/no-db/overlays/workflow-controller-deployment.yaml + +test/e2e/manifests/no-db.yaml: $(MANIFESTS) $(E2E_MANIFESTS) test/e2e/manifests/no-db/overlays/argo-server-deployment.yaml test/e2e/manifests/no-db/overlays/workflow-controller-deployment.yaml + # Create no DB e2e manifests + kustomize build test/e2e/manifests/no-db | ./hack/auto-gen-msg.sh > test/e2e/manifests/no-db.yaml + +dist/no-db.yaml: test/e2e/manifests/no-db.yaml + # Create no DB e2e manifests + # We additionlly disable ALWAY_OFFLOAD_NODE_STATUS + cat test/e2e/manifests/no-db.yaml | sed 's/:latest/:$(IMAGE_TAG)/' | sed 's/pns/$(E2E_EXECUTOR)/' | sed 's/"true"/"false"/' > dist/no-db.yaml -dist/quick-start-postgres.yaml: manifests/namespace-install.yaml - # Create Postgres quick-start manifests - kustomize build manifests/quick-start/postgres | sed 's/:latest/:$(IMAGE_TAG)/' > dist/quick-start-postgres.yaml -.PHONY: install-postgres -install-postgres: dist/quick-start-postgres.yaml +test/e2e/manifests/mysql/overlays/argo-server-deployment.yaml: test/e2e/manifests/postgres/overlays/argo-server-deployment.yaml +test/e2e/manifests/mysql/overlays/argo-server-deployment.yaml: + cat test/e2e/manifests/postgres/overlays/argo-server-deployment.yaml | ./hack/auto-gen-msg.sh > test/e2e/manifests/mysql/overlays/argo-server-deployment.yaml + +test/e2e/manifests/mysql/overlays/workflow-controller-deployment.yaml: test/e2e/manifests/postgres/overlays/workflow-controller-deployment.yaml +test/e2e/manifests/mysql/overlays/workflow-controller-deployment.yaml: + cat test/e2e/manifests/postgres/overlays/workflow-controller-deployment.yaml | ./hack/auto-gen-msg.sh > test/e2e/manifests/mysql/overlays/workflow-controller-deployment.yaml + +test/e2e/manifests/mysql.yaml: $(MANIFESTS) $(E2E_MANIFESTS) test/e2e/manifests/mysql/overlays/argo-server-deployment.yaml test/e2e/manifests/mysql/overlays/workflow-controller-deployment.yaml + # Create MySQL e2e manifests + kustomize build test/e2e/manifests/mysql | ./hack/auto-gen-msg.sh > test/e2e/manifests/mysql.yaml + +dist/mysql.yaml: test/e2e/manifests/mysql.yaml + # Create MySQL e2e manifests + cat test/e2e/manifests/mysql.yaml | sed 's/:latest/:$(IMAGE_TAG)/' | sed 's/pns/$(E2E_EXECUTOR)/' > dist/mysql.yaml + +.PHONY: install +install: dist/postgres.yaml dist/mysql.yaml dist/no-db.yaml # Install Postgres quick-start kubectl get ns argo || kubectl create ns argo - kubectl -n argo apply -f dist/quick-start-postgres.yaml +ifeq ($(DB),postgres) + kubectl -n argo apply -f dist/postgres.yaml +else +ifeq ($(DB),mysql) + kubectl -n argo apply -f dist/mysql.yaml +else + kubectl -n argo apply -f dist/no-db.yaml +endif +endif -.PHONY: install -install: install-postgres +.PHONY: test-images +test-images: dist/cowsay-v1 dist/bitnami-kubectl-1.15.3-ol-7-r165 dist/python-alpine3.6 + +dist/cowsay-v1: + docker build -t cowsay:v1 test/e2e/images/cowsay +ifeq ($(K3D),true) + k3d import-images cowsay:v1 +endif + touch dist/cowsay-v1 + +dist/bitnami-kubectl-1.15.3-ol-7-r165: + docker pull bitnami/kubectl:1.15.3-ol-7-r165 + touch dist/bitnami-kubectl-1.15.3-ol-7-r165 + +dist/python-alpine3.6: + docker pull python:alpine3.6 + touch dist/python-alpine3.6 .PHONY: start -start: controller-image cli-image install +start: controller-image cli-image executor-image install # Start development environment ifeq ($(CI),false) make down endif - # Patch deployments - kubectl -n argo patch deployment/workflow-controller --type json --patch '[{"op": "replace", "path": "/spec/template/spec/containers/0/imagePullPolicy", "value": "Never"}, {"op": "replace", "path": "/spec/template/spec/containers/0/args", "value": ["--loglevel", "debug", "--executor-image", "$(IMAGE_NAMESPACE)/argoexec:$(IMAGE_TAG)", "--executor-image-pull-policy", "Never", "--namespaced"]}]}]' - kubectl -n argo patch deployment/argo-server --type json --patch '[{"op": "replace", "path": "/spec/template/spec/containers/0/imagePullPolicy", "value": "Never"}, {"op": "replace", "path": "/spec/template/spec/containers/0/args", "value": ["server", "--loglevel", "debug", "--auth-mode", "client", "--namespaced"]}, {"op": "add", "path": "/spec/template/spec/containers/0/env", "value": [{"name": "ARGO_V2_TOKEN", "value": "password"}]}]' -ifeq ($(CI),false) make up -endif - make executor-image # Make the CLI make cli # Switch to "argo" ns. @@ -261,6 +339,8 @@ up: kubectl -n argo scale deployment/argo-server --replicas 1 # Wait for pods to be ready kubectl -n argo wait --for=condition=Ready pod --all -l app --timeout 2m + # Token + kubectl -n argo get `kubectl -n argo get secret -o name | grep argo-server` -o jsonpath='{.data.token}' | base64 --decode .PHONY: pf pf: @@ -275,7 +355,7 @@ pf-bg: .PHONY: logs logs: # Tail logs - kubectl -n argo logs -f -l app --max-log-requests 10 + kubectl -n argo logs -f -l app --max-log-requests 10 --tail 100 .PHONY: postgres-cli postgres-cli: @@ -286,24 +366,24 @@ mysql-cli: kubectl exec -ti `kubectl get pod -l app=mysql -o name|cut -c 5-` -- mysql -u mysql -ppassword argo .PHONY: test-e2e -test-e2e: +test-e2e: test-images # Run E2E tests go test -timeout 20m -v -count 1 -p 1 ./test/e2e/... .PHONY: smoke -smoke: +smoke: test-images # Run smoke tests - go test -timeout 45s -v -count 1 -p 1 -run SmokeSuite ./test/e2e + go test -timeout 2m -v -count 1 -p 1 -run SmokeSuite ./test/e2e .PHONY: test-api -test-api: +test-api: test-images # Run API tests - go test -timeout 2m -v -count 1 -p 1 -run ArgoServerSuite ./test/e2e + go test -timeout 3m -v -count 1 -p 1 -run ArgoServerSuite ./test/e2e .PHONY: test-cli -test-cli: +test-cli: test-images # Run CLI tests - go test -timeout 30s -v -count 1 -p 1 -run CliSuite ./test/e2e + go test -timeout 1m -v -count 1 -p 1 -run CliSuite ./test/e2e # clean @@ -314,7 +394,7 @@ clean: [ "`docker images -q $(IMAGE_NAMESPACE)/argoexec:$(IMAGE_TAG)`" = "" ] || docker rmi $(IMAGE_NAMESPACE)/argoexec:$(IMAGE_TAG) [ "`docker images -q $(IMAGE_NAMESPACE)/workflow-controller:$(IMAGE_TAG)`" = "" ] || docker rmi $(IMAGE_NAMESPACE)/workflow-controller:$(IMAGE_TAG) # Delete build files - git clean -fxd -e .idea -e vendor -e ui/node_modules + rm -Rf dist ui/dist # pre-push @@ -359,44 +439,26 @@ ifeq ($(findstring release,$(GIT_BRANCH)),release) # Check we have tagged the latest commit @if [ -z "$(GIT_TAG)" ]; then echo 'commit must be tagged to perform release' ; exit 1; fi # Check the tag is correct - @if [ "$(GIT_TAG)" != "v$(VERSION)" ]; then echo 'git tag ($(GIT_TAG)) does not match VERSION (v$(VERSION))'; exit 1; fi + @if [ "$(GIT_TAG)" != "$(VERSION)" ]; then echo 'git tag ($(GIT_TAG)) does not match VERSION ($(VERSION))'; exit 1; fi endif .PHONY: publish publish: ifeq ($(VERSION),latest) ifneq ($(GIT_BRANCH),master) - echo "you cannot publish latest version unless you are on master" >&2 + echo "you cannot publish 'latest' unless you are on master" >&2 exit 1 endif endif # Publish release -ifeq ($(GITHUB_TOKEN),) - echo "GITHUB_TOKEN not found, please visit https://github.com/settings/tokens to create one, it needs the "public_repo" role" >&2 - exit 1 -endif - # Upload assets to Github - ./hack/upload-asset.sh $(VERSION) cmd/server/workflow/workflow.swagger.json - ./hack/upload-asset.sh $(VERSION) cmd/server/cronworkflow/cron-workflow.swagger.json - ./hack/upload-asset.sh $(VERSION) cmd/server/workflowarchive/workflow-archive.swagger.json - ./hack/upload-asset.sh $(VERSION) cmd/server/workflowtemplate/workflow-template.swagger.json - ./hack/upload-asset.sh $(VERSION) dist/install.yaml - ./hack/upload-asset.sh $(VERSION) dist/namespace-install.yaml - ./hack/upload-asset.sh $(VERSION) dist/quick-start-postgres.yaml - ./hack/upload-asset.sh $(VERSION) dist/quick-start-mysql.yaml - ./hack/upload-asset.sh $(VERSION) dist/argo-darwin-amd64 - ./hack/upload-asset.sh $(VERSION) dist/argo-linux-amd64 - ./hack/upload-asset.sh $(VERSION) dist/argo-linux-ppc64le - ./hack/upload-asset.sh $(VERSION) dist/argo-linux-s390x - ./hack/upload-asset.sh $(VERSION) dist/argo-windows-amd64 # Push images to Docker Hub docker push $(IMAGE_NAMESPACE)/argocli:$(IMAGE_TAG) docker push $(IMAGE_NAMESPACE)/argoexec:$(IMAGE_TAG) docker push $(IMAGE_NAMESPACE)/workflow-controller:$(IMAGE_TAG) -ifeq ($(SNAPSHOT),false) +ifeq ($(findstring release,$(GIT_BRANCH)),release) # Push changes to Git - git push - git push $(VERSION) + git push $(GIT_REMOTE) + git tag push $(GIT_REMOTE) $(VERSION) endif .PHONY: release diff --git a/README.md b/README.md index 0529aa59ea9e..117437fc308a 100644 --- a/README.md +++ b/README.md @@ -10,20 +10,6 @@ kubectl create namespace argo kubectl apply -n argo -f https://raw.githubusercontent.com/argoproj/argo/stable/manifests/install.yaml ``` -## News - -KubeCon 2018 in Seattle was the biggest KubeCon yet with 8000 developers attending. We connected with many existing and new Argoproj users and contributions, and gave away a lot of Argo T-shirts at our booth sponsored by Intuit! - -We were also super excited to see KubeCon presentations about Argo by Argo developers, users and partners. -* [CI/CD in Light Speed with K8s and Argo CD](https://www.youtube.com/watch?v=OdzH82VpMwI&feature=youtu.be) - * How Intuit uses Argo CD. -* [Automating Research Workflows at BlackRock](https://www.youtube.com/watch?v=ZK510prml8o&t=0s&index=169&list=PLj6h78yzYM2PZf9eA7bhWnIh_mK1vyOfU) - * Why BlackRock created Argo Events and how they use it. -* [Machine Learning as Code](https://www.youtube.com/watch?v=VXrGp5er1ZE&t=0s&index=135&list=PLj6h78yzYM2PZf9eA7bhWnIh_mK1vyOfU) - * How Kubeflow uses Argo Workflows as its core workflow engine and Argo CD to declaratively deploy ML pipelines and models. - -If you actively use Argo in your organization and your organization would be interested in participating in the Argo Community, please ask a representative to contact saradhi_sreegiriraju@intuit.com for additional information. - ## What is Argoproj? Argoproj is a collection of tools for getting work done with Kubernetes. @@ -32,6 +18,9 @@ Argoproj is a collection of tools for getting work done with Kubernetes. * [Argo Events](https://github.com/argoproj/argo-events) - Event-based Dependency Manager * [Argo Rollouts](https://github.com/argoproj/argo-rollouts) - Deployment CR with support for Canary and Blue Green deployment strategies +Also argoproj-labs is a separate GitHub org that we setup for community contributions related to the Argoproj ecosystem. Repos in argoproj-labs are administered by the owners of each project. Please reach out to us on the Argo slack channel if you have a project that you would like to add to the org to make it easier to others in the Argo community to find, use, and contribute back. +* https://github.com/argoproj-labs + ## What is Argo Workflows? Argo Workflows is an open source container-native workflow engine for orchestrating parallel jobs on Kubernetes. Argo Workflows is implemented as a Kubernetes CRD (Custom Resource Definition). diff --git a/VERSION b/VERSION index 197c4d5c2d7c..437459cd94c9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.0 +2.5.0 diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 653f13d2569d..6ddc2f3ee776 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -2,7 +2,7 @@ "swagger": "2.0", "info": { "title": "Argo", - "version": "v2.4.0" + "version": "v2.5.0" }, "paths": {}, "definitions": { @@ -1201,11 +1201,11 @@ "description": "TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed", "type": "object", "properties": { - "secondsAfterCompleted": { + "secondsAfterCompletion": { "type": "integer", "format": "int32" }, - "secondsAfterFailed": { + "secondsAfterFailure": { "type": "integer", "format": "int32" }, @@ -1763,7 +1763,7 @@ "x-kubernetes-patch-strategy": "merge" }, "ttlSecondsAfterFinished": { - "description": "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution (Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be deleted after ttlSecondsAfterFinished expires. If this field is unset, ttlSecondsAfterFinished will not expire. If this field is set to zero, ttlSecondsAfterFinished expires immediately after the Workflow finishes. DEPRECATED: Use TTLStrategy.SecondsAfterCompleted instead.", + "description": "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution (Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be deleted after ttlSecondsAfterFinished expires. If this field is unset, ttlSecondsAfterFinished will not expire. If this field is set to zero, ttlSecondsAfterFinished expires immediately after the Workflow finishes. DEPRECATED: Use TTLStrategy.SecondsAfterCompletion instead.", "type": "integer", "format": "int32" }, @@ -1814,9 +1814,9 @@ "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.NodeStatus" } }, - "offloadNodeStatus": { - "description": "Whether on not node status has been offloaded to a database. If true, then Nodes and CompressedNodes will be empty.", - "type": "boolean" + "offloadNodeStatusVersion": { + "description": "Whether on not node status has been offloaded to a database. If exists, then Nodes and CompressedNodes will be empty. This will actually be populated with a hash of the offloaded data.", + "type": "string" }, "outputs": { "description": "Outputs captures output values and artifact locations produced by the workflow via global outputs", diff --git a/cmd/argo/commands/archive/delete.go b/cmd/argo/commands/archive/delete.go index e4c00fb8b0da..d779c6421462 100644 --- a/cmd/argo/commands/archive/delete.go +++ b/cmd/argo/commands/archive/delete.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflowarchive" + "github.com/argoproj/argo/server/workflowarchive" ) func NewDeleteCommand() *cobra.Command { @@ -16,7 +16,7 @@ func NewDeleteCommand() *cobra.Command { Run: func(cmd *cobra.Command, args []string) { for _, uid := range args { conn := client.GetClientConn() - ctx := client.ContextWithAuthorization() + ctx := client.GetContext() client := workflowarchive.NewArchivedWorkflowServiceClient(conn) _, err := client.DeleteArchivedWorkflow(ctx, &workflowarchive.DeleteArchivedWorkflowRequest{ Uid: uid, diff --git a/cmd/argo/commands/archive/get.go b/cmd/argo/commands/archive/get.go index 37eca0c1de9f..51421893f858 100644 --- a/cmd/argo/commands/archive/get.go +++ b/cmd/argo/commands/archive/get.go @@ -11,7 +11,7 @@ import ( "sigs.k8s.io/yaml" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflowarchive" + "github.com/argoproj/argo/server/workflowarchive" ) func NewGetCommand() *cobra.Command { @@ -27,7 +27,7 @@ func NewGetCommand() *cobra.Command { } uid := args[0] conn := client.GetClientConn() - ctx := client.ContextWithAuthorization() + ctx := client.GetContext() client := workflowarchive.NewArchivedWorkflowServiceClient(conn) wf, err := client.GetArchivedWorkflow(ctx, &workflowarchive.GetArchivedWorkflowRequest{ Uid: uid, diff --git a/cmd/argo/commands/archive/list.go b/cmd/argo/commands/archive/list.go index 488dca822c6e..2f435ccbcf24 100644 --- a/cmd/argo/commands/archive/list.go +++ b/cmd/argo/commands/archive/list.go @@ -12,7 +12,7 @@ import ( "sigs.k8s.io/yaml" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflowarchive" + "github.com/argoproj/argo/server/workflowarchive" ) func NewListCommand() *cobra.Command { @@ -24,7 +24,7 @@ func NewListCommand() *cobra.Command { Use: "list", Run: func(cmd *cobra.Command, args []string) { conn := client.GetClientConn() - ctx := client.ContextWithAuthorization() + ctx := client.GetContext() client := workflowarchive.NewArchivedWorkflowServiceClient(conn) resp, err := client.ListArchivedWorkflows(ctx, &workflowarchive.ListArchivedWorkflowsRequest{ ListOptions: &metav1.ListOptions{FieldSelector: "metadata.namespace=" + namespace}, diff --git a/cmd/argo/commands/client/conn.go b/cmd/argo/commands/client/conn.go index 5fac5f981469..6fd826e86edb 100644 --- a/cmd/argo/commands/client/conn.go +++ b/cmd/argo/commands/client/conn.go @@ -39,8 +39,12 @@ func GetClientConn() *grpc.ClientConn { return conn } -func ContextWithAuthorization() context.Context { - return metadata.NewOutgoingContext(context.Background(), metadata.Pairs("grpcgateway-authorization", "Bearer "+GetBearerToken())) +func GetContext() context.Context { + token := GetBearerToken() + if token == "" { + return context.Background() + } + return metadata.NewOutgoingContext(context.Background(), metadata.Pairs("authorization", "Bearer "+GetBearerToken())) } func GetBearerToken() string { diff --git a/cmd/argo/commands/common.go b/cmd/argo/commands/common.go index 808cb85dead5..499bed669076 100644 --- a/cmd/argo/commands/common.go +++ b/cmd/argo/commands/common.go @@ -14,10 +14,10 @@ import ( "k8s.io/client-go/rest" "github.com/argoproj/argo/cmd/argo/commands/client" - wfApiServer "github.com/argoproj/argo/cmd/server/workflow" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo/pkg/client/clientset/versioned" "github.com/argoproj/argo/pkg/client/clientset/versioned/typed/workflow/v1alpha1" + wfApiServer "github.com/argoproj/argo/server/workflow" "github.com/argoproj/argo/workflow/templateresolution" ) @@ -142,5 +142,5 @@ func (c LazyWorkflowTemplateGetter) Get(name string) (*wfv1.WorkflowTemplate, er var _ templateresolution.WorkflowTemplateNamespacedGetter = &LazyWorkflowTemplateGetter{} func GetWFApiServerGRPCClient(conn *grpc.ClientConn) (wfApiServer.WorkflowServiceClient, context.Context) { - return wfApiServer.NewWorkflowServiceClient(conn), client.ContextWithAuthorization() + return wfApiServer.NewWorkflowServiceClient(conn), client.GetContext() } diff --git a/cmd/argo/commands/delete.go b/cmd/argo/commands/delete.go index 4d37509e29dc..d332a9ddfd3c 100644 --- a/cmd/argo/commands/delete.go +++ b/cmd/argo/commands/delete.go @@ -8,7 +8,7 @@ import ( "time" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflow" + "github.com/argoproj/argo/server/workflow" argotime "github.com/argoproj/pkg/time" "github.com/spf13/cobra" diff --git a/cmd/argo/commands/get.go b/cmd/argo/commands/get.go index 32cd7a63abed..4f5c2d7361b0 100644 --- a/cmd/argo/commands/get.go +++ b/cmd/argo/commands/get.go @@ -14,8 +14,8 @@ import ( "sigs.k8s.io/yaml" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflow" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo/server/workflow" "github.com/argoproj/argo/workflow/packer" ) diff --git a/cmd/argo/commands/lint.go b/cmd/argo/commands/lint.go index 2b373126201a..8f49c66dd36c 100644 --- a/cmd/argo/commands/lint.go +++ b/cmd/argo/commands/lint.go @@ -11,8 +11,8 @@ import ( "google.golang.org/grpc" "github.com/argoproj/argo/cmd/argo/commands/client" - apiServer "github.com/argoproj/argo/cmd/server/workflow" "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + apiServer "github.com/argoproj/argo/server/workflow" cmdutil "github.com/argoproj/argo/util/cmd" "github.com/argoproj/argo/workflow/validate" ) @@ -129,7 +129,7 @@ func ServerSideLint(arg string, conn *grpc.ClientConn, strict bool) error { } func ServerLintValidation(ctx context.Context, client apiServer.WorkflowServiceClient, wf v1alpha1.Workflow, ns string) error { - wfReq := apiServer.WorkflowCreateRequest{ + wfReq := apiServer.WorkflowLintRequest{ Namespace: ns, Workflow: &wf, } diff --git a/cmd/argo/commands/list.go b/cmd/argo/commands/list.go index 2efc489fb86a..9823cf451364 100644 --- a/cmd/argo/commands/list.go +++ b/cmd/argo/commands/list.go @@ -19,9 +19,9 @@ import ( "k8s.io/apimachinery/pkg/selection" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflow" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo/pkg/client/clientset/versioned/typed/workflow/v1alpha1" + "github.com/argoproj/argo/server/workflow" "github.com/argoproj/argo/workflow/common" "github.com/argoproj/argo/workflow/packer" "github.com/argoproj/argo/workflow/util" diff --git a/cmd/argo/commands/logs.go b/cmd/argo/commands/logs.go index deebada65413..9cdc56c19f6e 100644 --- a/cmd/argo/commands/logs.go +++ b/cmd/argo/commands/logs.go @@ -27,9 +27,9 @@ import ( "github.com/argoproj/pkg/errors" "github.com/argoproj/argo/cmd/argo/commands/client" - apiv1 "github.com/argoproj/argo/cmd/server/workflow" "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" workflowv1 "github.com/argoproj/argo/pkg/client/clientset/versioned/typed/workflow/v1alpha1" + apiv1 "github.com/argoproj/argo/server/workflow" "github.com/argoproj/argo/workflow/packer" ) diff --git a/cmd/argo/commands/resubmit.go b/cmd/argo/commands/resubmit.go index 19d5dfaf915f..78269c7e5b41 100644 --- a/cmd/argo/commands/resubmit.go +++ b/cmd/argo/commands/resubmit.go @@ -9,8 +9,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflow" "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo/server/workflow" apiUtil "github.com/argoproj/argo/util/api" "github.com/argoproj/argo/workflow/util" ) diff --git a/cmd/argo/commands/resume.go b/cmd/argo/commands/resume.go index 542f5081c8c2..e309b2569d42 100644 --- a/cmd/argo/commands/resume.go +++ b/cmd/argo/commands/resume.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflow" + "github.com/argoproj/argo/server/workflow" "github.com/argoproj/argo/workflow/util" ) diff --git a/cmd/argo/commands/retry.go b/cmd/argo/commands/retry.go index 38cb59eeee0f..dae322434fbe 100644 --- a/cmd/argo/commands/retry.go +++ b/cmd/argo/commands/retry.go @@ -10,7 +10,7 @@ import ( "github.com/argoproj/pkg/errors" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflow" + "github.com/argoproj/argo/server/workflow" "github.com/argoproj/argo/workflow/packer" "github.com/argoproj/argo/workflow/util" ) diff --git a/cmd/argo/commands/server.go b/cmd/argo/commands/server.go index 828cfb9f8c3b..3f23cf960efc 100644 --- a/cmd/argo/commands/server.go +++ b/cmd/argo/commands/server.go @@ -12,8 +12,8 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/apiserver" wfclientset "github.com/argoproj/argo/pkg/client/clientset/versioned" + "github.com/argoproj/argo/server/apiserver" ) func NewServerCommand() *cobra.Command { diff --git a/cmd/argo/commands/submit.go b/cmd/argo/commands/submit.go index 48e5be70e022..48c85e1d763a 100644 --- a/cmd/argo/commands/submit.go +++ b/cmd/argo/commands/submit.go @@ -7,20 +7,21 @@ import ( "strconv" "strings" + "github.com/spf13/cobra" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apimachineryversion "k8s.io/apimachinery/pkg/version" + "github.com/argoproj/argo/cmd/argo/commands/client" "github.com/argoproj/argo/cmd/argo/commands/cron" "github.com/argoproj/argo/cmd/argo/commands/template" - apiwf "github.com/argoproj/argo/cmd/server/workflow" "github.com/argoproj/argo/pkg/apis/workflow" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + apiwf "github.com/argoproj/argo/server/workflow" apiUtil "github.com/argoproj/argo/util/api" "github.com/argoproj/argo/workflow/common" "github.com/argoproj/argo/workflow/util" "github.com/argoproj/pkg/errors" argoJson "github.com/argoproj/pkg/json" - "github.com/spf13/cobra" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - apimachineryversion "k8s.io/apimachinery/pkg/version" ) // cliSubmitOpts holds submition options specific to CLI submission (e.g. controlling output) diff --git a/cmd/argo/commands/suspend.go b/cmd/argo/commands/suspend.go index 2cf9ac6d26ce..9121d6335d7a 100644 --- a/cmd/argo/commands/suspend.go +++ b/cmd/argo/commands/suspend.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflow" + "github.com/argoproj/argo/server/workflow" "github.com/argoproj/argo/workflow/util" ) diff --git a/cmd/argo/commands/template/common.go b/cmd/argo/commands/template/common.go index d60911383612..4acafc995cab 100644 --- a/cmd/argo/commands/template/common.go +++ b/cmd/argo/commands/template/common.go @@ -9,10 +9,10 @@ import ( "k8s.io/client-go/rest" "github.com/argoproj/argo/cmd/argo/commands/client" - wftmplApiServer "github.com/argoproj/argo/cmd/server/workflowtemplate" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo/pkg/client/clientset/versioned" "github.com/argoproj/argo/pkg/client/clientset/versioned/typed/workflow/v1alpha1" + wftmplApiServer "github.com/argoproj/argo/server/workflowtemplate" "github.com/argoproj/argo/workflow/templateresolution" ) @@ -78,5 +78,5 @@ func (c LazyWorkflowTemplateGetter) Get(name string) (*wfv1.WorkflowTemplate, er var _ templateresolution.WorkflowTemplateNamespacedGetter = &LazyWorkflowTemplateGetter{} func GetWFtmplApiServerGRPCClient(conn *grpc.ClientConn) (wftmplApiServer.WorkflowTemplateServiceClient, context.Context) { - return wftmplApiServer.NewWorkflowTemplateServiceClient(conn), client.ContextWithAuthorization() + return wftmplApiServer.NewWorkflowTemplateServiceClient(conn), client.GetContext() } diff --git a/cmd/argo/commands/template/create.go b/cmd/argo/commands/template/create.go index 949f2287a87e..329eabdf7f4c 100644 --- a/cmd/argo/commands/template/create.go +++ b/cmd/argo/commands/template/create.go @@ -8,8 +8,8 @@ import ( "github.com/spf13/cobra" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflowtemplate" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo/server/workflowtemplate" "github.com/argoproj/argo/workflow/common" "github.com/argoproj/argo/workflow/templateresolution" "github.com/argoproj/argo/workflow/util" diff --git a/cmd/argo/commands/template/delete.go b/cmd/argo/commands/template/delete.go index 09e90ffc09cb..1c54ac8ac0c0 100644 --- a/cmd/argo/commands/template/delete.go +++ b/cmd/argo/commands/template/delete.go @@ -12,7 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflowtemplate" + "github.com/argoproj/argo/server/workflowtemplate" "github.com/argoproj/argo/pkg/client/clientset/versioned/typed/workflow/v1alpha1" ) diff --git a/cmd/argo/commands/template/get.go b/cmd/argo/commands/template/get.go index a420e1f8da54..dbf2d01e6c9f 100644 --- a/cmd/argo/commands/template/get.go +++ b/cmd/argo/commands/template/get.go @@ -13,8 +13,8 @@ import ( "github.com/argoproj/pkg/humanize" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflowtemplate" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo/server/workflowtemplate" ) func NewGetCommand() *cobra.Command { diff --git a/cmd/argo/commands/template/lint.go b/cmd/argo/commands/template/lint.go index 67b1ec24fd6f..ac709059cad7 100644 --- a/cmd/argo/commands/template/lint.go +++ b/cmd/argo/commands/template/lint.go @@ -11,8 +11,8 @@ import ( "google.golang.org/grpc" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflowtemplate" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo/server/workflowtemplate" cmdutil "github.com/argoproj/argo/util/cmd" "github.com/argoproj/argo/workflow/validate" ) @@ -131,7 +131,7 @@ func ServerSideLint(args []string, conn *grpc.ClientConn, strict bool) error { } func ServerLintValidation(ctx context.Context, client workflowtemplate.WorkflowTemplateServiceClient, wfTmpl wfv1.WorkflowTemplate, ns string) error { - wfTmplReq := workflowtemplate.WorkflowTemplateCreateRequest{ + wfTmplReq := workflowtemplate.WorkflowTemplateLintRequest{ Namespace: ns, Template: &wfTmpl, } diff --git a/cmd/argo/commands/template/list.go b/cmd/argo/commands/template/list.go index 9354869a3dbe..e92334408bd4 100644 --- a/cmd/argo/commands/template/list.go +++ b/cmd/argo/commands/template/list.go @@ -12,9 +12,9 @@ import ( "k8s.io/apimachinery/pkg/labels" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflowtemplate" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo/pkg/client/clientset/versioned/typed/workflow/v1alpha1" + "github.com/argoproj/argo/server/workflowtemplate" ) type listFlags struct { diff --git a/cmd/argo/commands/terminate.go b/cmd/argo/commands/terminate.go index 4b81668699bc..88c1cf77edcd 100644 --- a/cmd/argo/commands/terminate.go +++ b/cmd/argo/commands/terminate.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflow" + "github.com/argoproj/argo/server/workflow" "github.com/argoproj/argo/workflow/util" ) diff --git a/cmd/argo/commands/token.go b/cmd/argo/commands/token.go index 619ed11c06fd..5ebb8f31c94b 100644 --- a/cmd/argo/commands/token.go +++ b/cmd/argo/commands/token.go @@ -18,7 +18,7 @@ func NewTokenCommand() *cobra.Command { cmd.HelpFunc()(cmd, args) os.Exit(1) } - fmt.Println(client.GetBearerToken()) + fmt.Print(client.GetBearerToken()) }, } } diff --git a/cmd/argo/commands/wait.go b/cmd/argo/commands/wait.go index fca6bb1024c0..0bdcac7d8779 100644 --- a/cmd/argo/commands/wait.go +++ b/cmd/argo/commands/wait.go @@ -13,7 +13,7 @@ import ( "k8s.io/apimachinery/pkg/fields" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflow" + "github.com/argoproj/argo/server/workflow" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" ) diff --git a/cmd/argo/commands/watch.go b/cmd/argo/commands/watch.go index f001ba4f90e6..e8c14da4869d 100644 --- a/cmd/argo/commands/watch.go +++ b/cmd/argo/commands/watch.go @@ -6,7 +6,7 @@ import ( "time" "github.com/argoproj/argo/cmd/argo/commands/client" - "github.com/argoproj/argo/cmd/server/workflow" + "github.com/argoproj/argo/server/workflow" "github.com/argoproj/pkg/errors" "github.com/spf13/cobra" diff --git a/cmd/workflow-controller/main.go b/cmd/workflow-controller/main.go index 68dd056be7c7..f8c69159f416 100644 --- a/cmd/workflow-controller/main.go +++ b/cmd/workflow-controller/main.go @@ -33,16 +33,17 @@ const ( // NewRootCommand returns an new instance of the workflow-controller main entrypoint func NewRootCommand() *cobra.Command { var ( - clientConfig clientcmd.ClientConfig - configMap string // --configmap - executorImage string // --executor-image - executorImagePullPolicy string // --executor-image-pull-policy - logLevel string // --loglevel - glogLevel int // --gloglevel - workflowWorkers int // --workflow-workers - podWorkers int // --pod-workers - namespaced bool // --namespaced - managedNamespace string // --managed-namespace + clientConfig clientcmd.ClientConfig + configMap string // --configmap + executorImage string // --executor-image + executorImagePullPolicy string // --executor-image-pull-policy + containerRuntimeExecutor string + logLevel string // --loglevel + glogLevel int // --gloglevel + workflowWorkers int // --workflow-workers + podWorkers int // --pod-workers + namespaced bool // --namespaced + managedNamespace string // --managed-namespace ) var command = cobra.Command{ @@ -78,7 +79,7 @@ func NewRootCommand() *cobra.Command { } // start a controller on instances of our custom resource - wfController := controller.NewWorkflowController(config, kubeclientset, wfclientset, namespace, managedNamespace, executorImage, executorImagePullPolicy, configMap) + wfController := controller.NewWorkflowController(config, kubeclientset, wfclientset, namespace, managedNamespace, executorImage, executorImagePullPolicy, containerRuntimeExecutor, configMap) err = wfController.ResyncConfig() if err != nil { return err @@ -113,6 +114,7 @@ func NewRootCommand() *cobra.Command { command.Flags().StringVar(&configMap, "configmap", "workflow-controller-configmap", "Name of K8s configmap to retrieve workflow controller configuration") command.Flags().StringVar(&executorImage, "executor-image", "", "Executor image to use (overrides value in configmap)") command.Flags().StringVar(&executorImagePullPolicy, "executor-image-pull-policy", "", "Executor imagePullPolicy to use (overrides value in configmap)") + command.Flags().StringVar(&containerRuntimeExecutor, "container-runtime-executor", "", "Container runtime executor to use (overrides value in configmap)") command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error") command.Flags().IntVar(&glogLevel, "gloglevel", 0, "Set the glog logging level") command.Flags().IntVar(&workflowWorkers, "workflow-workers", 8, "Number of workflow workers") diff --git a/docs/rest-api.md b/docs/rest-api.md index 4ed829e535a9..70ba641cd8d2 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -16,10 +16,10 @@ curl -H "Authorization: Bearer $token" http://localhost:2746/api/v1/workflows/ar To view the API: 1. Open [https://editor.swagger.io/](https://editor.swagger.io/) -2. Coy and paste either: - 1. ../cmd/server/workflow/workflow.swagger.json - 2. ../cmd/server/workflowtemplate/workflow-template.swagger.json - 1. ../cmd/server/workflowarchive/archived-workflows.swagger.json +2. Copy and paste either: + 1. ../server/workflow/workflow.swagger.json + 2. ../server/workflowtemplate/workflow-template.swagger.json + 1. ../server/workflowarchive/archived-workflows.swagger.json > v2.4 and before diff --git a/docs/workflow-controller-configmap.yaml b/docs/workflow-controller-configmap.yaml index cd1eec79d339..106890943d32 100644 --- a/docs/workflow-controller-configmap.yaml +++ b/docs/workflow-controller-configmap.yaml @@ -108,7 +108,9 @@ data: - --gloglevel - "6" env: - - name: SOME_ENV_VAR + # ARGO_TRACE enables some tracing information for debugging purposes. Currently it enables + # logging of S3 request/response payloads (including auth headers) + - name: ARGO_TRACE value: "1" # metricsConfig controls the path and port for prometheus metrics @@ -133,6 +135,8 @@ data: # save completed workloads to the archived, even if disabled, you'll be able to # read from the archive archive: false + # Optional name of the cluster I'm running in. This must be unique for your cluster. + clusterName: default postgresql: host: localhost port: 5432 diff --git a/examples/README.md b/examples/README.md index 89285d6d7265..6a7059bdd039 100644 --- a/examples/README.md +++ b/examples/README.md @@ -317,7 +317,7 @@ The [FailFast](./dag-disable-failFast.yaml) flag default is `true`, if set to ` **Note:** You will need to configure an artifact repository to run this example. -[Configuring an artifact repository here](configure-artifact-repository.md). +[Configuring an artifact repository here](../docs/configure-artifact-repository.md). When running workflows, it is very common to have steps that generate or consume artifacts. Often, the output artifacts of one step may be used as input artifacts to a subsequent step. @@ -390,7 +390,7 @@ We now know enough about the basic components of a workflow spec to review its b To summarize, workflow specs are composed of a set of Argo templates where each template consists of an optional input section, an optional output section and either a container invocation or a list of steps where each step invokes another template. -Note that the controller section of the workflow spec will accept the same options as the controller section of a pod spec, including but not limited to environment variables, secrets, and volume mounts. Similarly, for volume claims and volumes. +Note that the container section of the workflow spec will accept the same options as the container section of a pod spec, including but not limited to environment variables, secrets, and volume mounts. Similarly, for volume claims and volumes. ## Secrets diff --git a/examples/gc-ttl.yaml b/examples/gc-ttl.yaml index 408524b4a930..1e425ee219f4 100644 --- a/examples/gc-ttl.yaml +++ b/examples/gc-ttl.yaml @@ -7,10 +7,10 @@ kind: Workflow metadata: generateName: gc-ttl- spec: - TTLStrategy: - secondsAfterCompleted: 10 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished - secondsAfterSuccess: 5 # Time to live after workflow is successful - secondsAfterFailed: 5 # Time to live after workflow fails + ttlStrategy: + secondsAfterCompletion: 10 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished + secondsAfterSuccess: 5 # Time to live after workflow is successful + secondsAfterFailure: 5 # Time to live after workflow fails entrypoint: whalesay templates: - name: whalesay diff --git a/gometalinter.json b/gometalinter.json deleted file mode 100644 index bded492e5654..000000000000 --- a/gometalinter.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "Vendor": true, - "DisableAll": true, - "Deadline": "8m", - "Enable": [ - "vet", - "gofmt", - "deadcode", - "errcheck", - "varcheck", - "structcheck", - "ineffassign", - "unconvert", - "misspell" - ], - "Skip": [ - "pkg/client", - "vendor/" - ], - "Exclude": [ - "pkg/client", - "vendor/", - ".*warning.*fmt.Fprint" - ] -} diff --git a/hack/auto-gen-msg.sh b/hack/auto-gen-msg.sh new file mode 100755 index 000000000000..27ed25236322 --- /dev/null +++ b/hack/auto-gen-msg.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -eu -o pipefail + +echo "# This is an auto-generated file. DO NOT EDIT" +cat \ No newline at end of file diff --git a/hack/update-manifests.sh b/hack/update-manifests.sh index 5f0035b08109..c494d98f9c1d 100755 --- a/hack/update-manifests.sh +++ b/hack/update-manifests.sh @@ -2,8 +2,6 @@ set -eu -o pipefail SRCROOT="$( CDPATH='' cd -- "$(dirname "$0")/.." && pwd -P )" -AUTOGENMSG="# This is an auto-generated file. DO NOT EDIT" - IMAGE_NAMESPACE="${IMAGE_NAMESPACE:-argoproj}" VERSION="${VERSION:-latest}" @@ -15,12 +13,14 @@ cd ${SRCROOT}/manifests/base && kustomize edit set image \ argoproj/workflow-controller=${IMAGE_NAMESPACE}/workflow-controller:${VERSION} \ argoproj/argocli=${IMAGE_NAMESPACE}/argocli:${VERSION} -echo "${AUTOGENMSG}" > "${SRCROOT}/manifests/install.yaml" -kustomize build "${SRCROOT}/manifests/cluster-install" >> "${SRCROOT}/manifests/install.yaml" +kustomize build "${SRCROOT}/manifests/cluster-install" | ${SRCROOT}/hack/auto-gen-msg.sh > "${SRCROOT}/manifests/install.yaml" sed -i.bak "s@- .*/argoexec:.*@- ${IMAGE_NAMESPACE}/argoexec:${VERSION}@" "${SRCROOT}/manifests/install.yaml" rm -f "${SRCROOT}/manifests/install.yaml.bak" -echo "${AUTOGENMSG}" > "${SRCROOT}/manifests/namespace-install.yaml" -kustomize build "${SRCROOT}/manifests/namespace-install" >> "${SRCROOT}/manifests/namespace-install.yaml" +kustomize build "${SRCROOT}/manifests/namespace-install" | ${SRCROOT}/hack/auto-gen-msg.sh > "${SRCROOT}/manifests/namespace-install.yaml" sed -i.bak "s@- .*/argoexec:.*@- ${IMAGE_NAMESPACE}/argoexec:${VERSION}@" "${SRCROOT}/manifests/namespace-install.yaml" rm -f "${SRCROOT}/manifests/namespace-install.yaml.bak" + +kustomize build ${SRCROOT}/manifests/quick-start/no-db | sed "s/:latest/:$VERSION/" | ${SRCROOT}/hack/auto-gen-msg.sh > ${SRCROOT}/manifests/quick-start-no-db.yaml +kustomize build ${SRCROOT}/manifests/quick-start/mysql | sed "s/:latest/:$VERSION/" | ${SRCROOT}/hack/auto-gen-msg.sh > ${SRCROOT}/manifests/quick-start-mysql.yaml +kustomize build ${SRCROOT}/manifests/quick-start/postgres | sed "s/:latest/:$VERSION/" | ${SRCROOT}/hack/auto-gen-msg.sh > ${SRCROOT}/manifests/quick-start-postgres.yaml diff --git a/manifests/base/argo-server/argo-server-deployment.yaml b/manifests/base/argo-server/argo-server-deployment.yaml index 920ce1cbd8eb..6a0f655b0cfa 100644 --- a/manifests/base/argo-server/argo-server-deployment.yaml +++ b/manifests/base/argo-server/argo-server-deployment.yaml @@ -15,7 +15,7 @@ spec: containers: - name: argo-server image: argoproj/argocli:latest - args: [server, --auth-mode, client] + args: [server] ports: - containerPort: 2746 readinessProbe: diff --git a/manifests/cluster-install/argo-server-rbac/argo-server-clusterole.yaml b/manifests/cluster-install/argo-server-rbac/argo-server-clusterole.yaml index b9c186e9dbfa..0620f8a71c6d 100644 --- a/manifests/cluster-install/argo-server-rbac/argo-server-clusterole.yaml +++ b/manifests/cluster-install/argo-server-rbac/argo-server-clusterole.yaml @@ -44,4 +44,6 @@ rules: - get - list - watch + - update + - patch - delete \ No newline at end of file diff --git a/manifests/cluster-install/workflow-controller-rbac/workflow-controller-clusterrole.yaml b/manifests/cluster-install/workflow-controller-rbac/workflow-controller-clusterrole.yaml index 1f447fb2e6d2..aa2f53104b40 100644 --- a/manifests/cluster-install/workflow-controller-rbac/workflow-controller-clusterrole.yaml +++ b/manifests/cluster-install/workflow-controller-rbac/workflow-controller-clusterrole.yaml @@ -72,4 +72,9 @@ rules: - update - patch - delete - - create \ No newline at end of file +- apiGroups: + - "" + resources: + - events + verbs: + - create diff --git a/manifests/install.yaml b/manifests/install.yaml index 3ee759dcdb07..c06304a3e411 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -221,6 +221,11 @@ rules: - update - patch - delete +- apiGroups: + - "" + resources: + - events + verbs: - create --- apiVersion: rbac.authorization.k8s.io/v1 @@ -269,6 +274,8 @@ rules: - get - list - watch + - update + - patch - delete --- apiVersion: rbac.authorization.k8s.io/v1 @@ -341,8 +348,6 @@ spec: containers: - args: - server - - --auth-mode - - client image: argoproj/argocli:latest name: argo-server ports: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 8d37ea106d06..eb316b68c255 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -142,6 +142,12 @@ rules: - update - patch - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -189,6 +195,8 @@ rules: - get - list - watch + - update + - patch - delete --- apiVersion: rbac.authorization.k8s.io/v1 @@ -247,8 +255,6 @@ spec: containers: - args: - server - - --auth-mode - - client - --namespaced image: argoproj/argocli:latest name: argo-server diff --git a/manifests/namespace-install/argo-server-rbac/argo-server-role.yaml b/manifests/namespace-install/argo-server-rbac/argo-server-role.yaml index 39eccf23b2d3..de0ff3a039bc 100644 --- a/manifests/namespace-install/argo-server-rbac/argo-server-role.yaml +++ b/manifests/namespace-install/argo-server-rbac/argo-server-role.yaml @@ -44,4 +44,6 @@ rules: - get - list - watch + - update + - patch - delete diff --git a/manifests/namespace-install/workflow-controller-rbac/workflow-controller-role.yaml b/manifests/namespace-install/workflow-controller-rbac/workflow-controller-role.yaml index 7f4f7fd9801b..2e1e68f8ea29 100644 --- a/manifests/namespace-install/workflow-controller-rbac/workflow-controller-role.yaml +++ b/manifests/namespace-install/workflow-controller-rbac/workflow-controller-role.yaml @@ -77,4 +77,10 @@ rules: - watch - update - patch - - delete \ No newline at end of file + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create diff --git a/manifests/quick-start-mysql.yaml b/manifests/quick-start-mysql.yaml new file mode 100644 index 000000000000..fb974d567bfb --- /dev/null +++ b/manifests/quick-start-mysql.yaml @@ -0,0 +1,494 @@ +# This is an auto-generated file. DO NOT EDIT +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cronworkflows.argoproj.io +spec: + group: argoproj.io + names: + kind: CronWorkflow + plural: cronworkflows + shortNames: + - cronwf + - cwf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflows.argoproj.io +spec: + additionalPrinterColumns: + - JSONPath: .status.phase + description: Status of the workflow + name: Status + type: string + - JSONPath: .status.startedAt + description: When the workflow was started + format: date-time + name: Age + type: date + group: argoproj.io + names: + kind: Workflow + plural: workflows + shortNames: + - wf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflowtemplates.argoproj.io +spec: + group: argoproj.io + names: + kind: WorkflowTemplate + plural: workflowtemplates + shortNames: + - wftmpl + scope: Namespaced + version: v1alpha1 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-role +rules: +- apiGroups: + - "" + resources: + - pods + - pods/exec + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - create + - delete +- apiGroups: + - argoproj.io + resources: + - workflows + - workflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete + - create +- apiGroups: + - argoproj.io + resources: + - workflowtemplates + - workflowtemplates/finalizers + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - get + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - cronworkflows + - cronworkflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-server-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - "" + resources: + - pods + - pods/exec + - pods/log + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - workflows + - workflowtemplates + - cronworkflows + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: workflow-role +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - watch + - patch +- apiGroups: + - "" + resources: + - pods/log + verbs: + - get + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-role +subjects: +- kind: ServiceAccount + name: argo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-server-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-server-role +subjects: +- kind: ServiceAccount + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: workflow-default-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: workflow-role +subjects: +- kind: ServiceAccount + name: default +--- +apiVersion: v1 +data: + config: | + artifactRepository: + archiveLogs: true + s3: + bucket: my-bucket + endpoint: minio:9000 + insecure: true + accessKeySecret: + name: my-minio-cred + key: accesskey + secretKeySecret: + name: my-minio-cred + key: secretkey + persistence: + connectionPool: + maxIdleConns: 100 + maxOpenConns: 0 + nodeStatusOffLoad: true + archive: true + mysql: + host: mysql + port: 3306 + database: argo + tableName: argo_workflows + userNameSecret: + name: argo-mysql-config + key: username + passwordSecret: + name: argo-mysql-config + key: password +kind: ConfigMap +metadata: + name: workflow-controller-configmap +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + app: mysql + name: argo-mysql-config +stringData: + password: password + username: mysql +type: Opaque +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + app: minio + name: my-minio-cred +stringData: + accesskey: admin + secretkey: password +type: Opaque +--- +apiVersion: v1 +kind: Service +metadata: + name: argo-server +spec: + ports: + - port: 2746 + targetPort: 2746 + selector: + app: argo-server +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: minio + name: minio +spec: + ports: + - port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: mysql + name: mysql +spec: + ports: + - port: 3306 + protocol: TCP + targetPort: 3306 + selector: + app: mysql +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: argo-server +spec: + selector: + matchLabels: + app: argo-server + template: + metadata: + labels: + app: argo-server + spec: + containers: + - args: + - server + - --namespaced + image: argoproj/argocli:latest + name: argo-server + ports: + - containerPort: 2746 + readinessProbe: + httpGet: + path: / + port: 2746 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 30 + serviceAccountName: argo-server +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: mysql + name: mysql +spec: + selector: + matchLabels: + app: mysql + template: + metadata: + labels: + app: mysql + name: mysql + spec: + containers: + - env: + - name: MYSQL_USER + value: mysql + - name: MYSQL_PASSWORD + value: password + - name: MYSQL_DATABASE + value: argo + - name: MYSQL_RANDOM_ROOT_PASSWORD + value: "yes" + image: mysql:8 + name: main + ports: + - containerPort: 5432 + readinessProbe: + exec: + command: + - mysql + - -u + - mysql + - -ppassword + - argo + - -e + - SELECT 1 + initialDelaySeconds: 15 + timeoutSeconds: 2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: workflow-controller +spec: + selector: + matchLabels: + app: workflow-controller + template: + metadata: + labels: + app: workflow-controller + spec: + containers: + - args: + - --configmap + - workflow-controller-configmap + - --executor-image + - argoproj/argoexec:latest + - --namespaced + command: + - workflow-controller + image: argoproj/workflow-controller:latest + name: workflow-controller + serviceAccountName: argo +--- +apiVersion: v1 +kind: Pod +metadata: + labels: + app: minio + name: minio +spec: + containers: + - command: + - minio + - server + - /data + env: + - name: MINIO_ACCESS_KEY + value: admin + - name: MINIO_SECRET_KEY + value: password + image: minio/minio:RELEASE.2019-12-17T23-16-33Z + lifecycle: + postStart: + exec: + command: + - mkdir + - -p + - /data/my-bucket + livenessProbe: + httpGet: + path: /minio/health/live + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 + name: main + ports: + - containerPort: 9000 + readinessProbe: + httpGet: + path: /minio/health/ready + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/manifests/quick-start-no-db.yaml b/manifests/quick-start-no-db.yaml new file mode 100644 index 000000000000..ed7da9cbca8e --- /dev/null +++ b/manifests/quick-start-no-db.yaml @@ -0,0 +1,409 @@ +# This is an auto-generated file. DO NOT EDIT +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cronworkflows.argoproj.io +spec: + group: argoproj.io + names: + kind: CronWorkflow + plural: cronworkflows + shortNames: + - cronwf + - cwf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflows.argoproj.io +spec: + additionalPrinterColumns: + - JSONPath: .status.phase + description: Status of the workflow + name: Status + type: string + - JSONPath: .status.startedAt + description: When the workflow was started + format: date-time + name: Age + type: date + group: argoproj.io + names: + kind: Workflow + plural: workflows + shortNames: + - wf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflowtemplates.argoproj.io +spec: + group: argoproj.io + names: + kind: WorkflowTemplate + plural: workflowtemplates + shortNames: + - wftmpl + scope: Namespaced + version: v1alpha1 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-role +rules: +- apiGroups: + - "" + resources: + - pods + - pods/exec + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - create + - delete +- apiGroups: + - argoproj.io + resources: + - workflows + - workflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete + - create +- apiGroups: + - argoproj.io + resources: + - workflowtemplates + - workflowtemplates/finalizers + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - get + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - cronworkflows + - cronworkflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-server-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - "" + resources: + - pods + - pods/exec + - pods/log + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - workflows + - workflowtemplates + - cronworkflows + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: workflow-role +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - watch + - patch +- apiGroups: + - "" + resources: + - pods/log + verbs: + - get + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-role +subjects: +- kind: ServiceAccount + name: argo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-server-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-server-role +subjects: +- kind: ServiceAccount + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: workflow-default-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: workflow-role +subjects: +- kind: ServiceAccount + name: default +--- +apiVersion: v1 +data: + config: | + artifactRepository: + archiveLogs: true + s3: + bucket: my-bucket + endpoint: minio:9000 + insecure: true + accessKeySecret: + name: my-minio-cred + key: accesskey + secretKeySecret: + name: my-minio-cred + key: secretkey +kind: ConfigMap +metadata: + name: workflow-controller-configmap +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + app: minio + name: my-minio-cred +stringData: + accesskey: admin + secretkey: password +type: Opaque +--- +apiVersion: v1 +kind: Service +metadata: + name: argo-server +spec: + ports: + - port: 2746 + targetPort: 2746 + selector: + app: argo-server +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: minio + name: minio +spec: + ports: + - port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: argo-server +spec: + selector: + matchLabels: + app: argo-server + template: + metadata: + labels: + app: argo-server + spec: + containers: + - args: + - server + - --namespaced + image: argoproj/argocli:latest + name: argo-server + ports: + - containerPort: 2746 + readinessProbe: + httpGet: + path: / + port: 2746 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 30 + serviceAccountName: argo-server +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: workflow-controller +spec: + selector: + matchLabels: + app: workflow-controller + template: + metadata: + labels: + app: workflow-controller + spec: + containers: + - args: + - --configmap + - workflow-controller-configmap + - --executor-image + - argoproj/argoexec:latest + - --namespaced + command: + - workflow-controller + image: argoproj/workflow-controller:latest + name: workflow-controller + serviceAccountName: argo +--- +apiVersion: v1 +kind: Pod +metadata: + labels: + app: minio + name: minio +spec: + containers: + - command: + - minio + - server + - /data + env: + - name: MINIO_ACCESS_KEY + value: admin + - name: MINIO_SECRET_KEY + value: password + image: minio/minio:RELEASE.2019-12-17T23-16-33Z + lifecycle: + postStart: + exec: + command: + - mkdir + - -p + - /data/my-bucket + livenessProbe: + httpGet: + path: /minio/health/live + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 + name: main + ports: + - containerPort: 9000 + readinessProbe: + httpGet: + path: /minio/health/ready + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/manifests/quick-start-postgres.yaml b/manifests/quick-start-postgres.yaml new file mode 100644 index 000000000000..ad390f20226e --- /dev/null +++ b/manifests/quick-start-postgres.yaml @@ -0,0 +1,486 @@ +# This is an auto-generated file. DO NOT EDIT +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cronworkflows.argoproj.io +spec: + group: argoproj.io + names: + kind: CronWorkflow + plural: cronworkflows + shortNames: + - cronwf + - cwf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflows.argoproj.io +spec: + additionalPrinterColumns: + - JSONPath: .status.phase + description: Status of the workflow + name: Status + type: string + - JSONPath: .status.startedAt + description: When the workflow was started + format: date-time + name: Age + type: date + group: argoproj.io + names: + kind: Workflow + plural: workflows + shortNames: + - wf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflowtemplates.argoproj.io +spec: + group: argoproj.io + names: + kind: WorkflowTemplate + plural: workflowtemplates + shortNames: + - wftmpl + scope: Namespaced + version: v1alpha1 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-role +rules: +- apiGroups: + - "" + resources: + - pods + - pods/exec + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - create + - delete +- apiGroups: + - argoproj.io + resources: + - workflows + - workflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete + - create +- apiGroups: + - argoproj.io + resources: + - workflowtemplates + - workflowtemplates/finalizers + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - get + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - cronworkflows + - cronworkflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-server-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - "" + resources: + - pods + - pods/exec + - pods/log + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - workflows + - workflowtemplates + - cronworkflows + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: workflow-role +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - watch + - patch +- apiGroups: + - "" + resources: + - pods/log + verbs: + - get + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-role +subjects: +- kind: ServiceAccount + name: argo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-server-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-server-role +subjects: +- kind: ServiceAccount + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: workflow-default-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: workflow-role +subjects: +- kind: ServiceAccount + name: default +--- +apiVersion: v1 +data: + config: | + artifactRepository: + archiveLogs: true + s3: + bucket: my-bucket + endpoint: minio:9000 + insecure: true + accessKeySecret: + name: my-minio-cred + key: accesskey + secretKeySecret: + name: my-minio-cred + key: secretkey + persistence: + connectionPool: + maxIdleConns: 100 + maxOpenConns: 0 + nodeStatusOffLoad: true + archive: true + postgresql: + host: postgres + port: 5432 + database: postgres + tableName: argo_workflows + userNameSecret: + name: argo-postgres-config + key: username + passwordSecret: + name: argo-postgres-config + key: password +kind: ConfigMap +metadata: + name: workflow-controller-configmap +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + app: postgres + name: argo-postgres-config +stringData: + password: password + username: postgres +type: Opaque +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + app: minio + name: my-minio-cred +stringData: + accesskey: admin + secretkey: password +type: Opaque +--- +apiVersion: v1 +kind: Service +metadata: + name: argo-server +spec: + ports: + - port: 2746 + targetPort: 2746 + selector: + app: argo-server +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: minio + name: minio +spec: + ports: + - port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: postgres + name: postgres +spec: + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + app: postgres +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: argo-server +spec: + selector: + matchLabels: + app: argo-server + template: + metadata: + labels: + app: argo-server + spec: + containers: + - args: + - server + - --namespaced + image: argoproj/argocli:latest + name: argo-server + ports: + - containerPort: 2746 + readinessProbe: + httpGet: + path: / + port: 2746 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 30 + serviceAccountName: argo-server +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: postgres + name: postgres +spec: + selector: + matchLabels: + app: postgres + template: + metadata: + labels: + app: postgres + name: postgres + spec: + containers: + - env: + - name: POSTGRES_PASSWORD + value: password + image: postgres:12-alpine + name: main + ports: + - containerPort: 5432 + readinessProbe: + exec: + command: + - psql + - -U + - postgres + - -c + - SELECT 1 + initialDelaySeconds: 15 + timeoutSeconds: 2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: workflow-controller +spec: + selector: + matchLabels: + app: workflow-controller + template: + metadata: + labels: + app: workflow-controller + spec: + containers: + - args: + - --configmap + - workflow-controller-configmap + - --executor-image + - argoproj/argoexec:latest + - --namespaced + command: + - workflow-controller + image: argoproj/workflow-controller:latest + name: workflow-controller + serviceAccountName: argo +--- +apiVersion: v1 +kind: Pod +metadata: + labels: + app: minio + name: minio +spec: + containers: + - command: + - minio + - server + - /data + env: + - name: MINIO_ACCESS_KEY + value: admin + - name: MINIO_SECRET_KEY + value: password + image: minio/minio:RELEASE.2019-12-17T23-16-33Z + lifecycle: + postStart: + exec: + command: + - mkdir + - -p + - /data/my-bucket + livenessProbe: + httpGet: + path: /minio/health/live + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 + name: main + ports: + - containerPort: 9000 + readinessProbe: + httpGet: + path: /minio/health/ready + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/manifests/quick-start/base/minio/minio-pod.yaml b/manifests/quick-start/base/minio/minio-pod.yaml index 6fb8d9f6257a..707fea3835aa 100644 --- a/manifests/quick-start/base/minio/minio-pod.yaml +++ b/manifests/quick-start/base/minio/minio-pod.yaml @@ -7,7 +7,7 @@ metadata: spec: containers: - name: main - image: minio/minio + image: minio/minio:RELEASE.2019-12-17T23-16-33Z env: - name: MINIO_ACCESS_KEY value: admin diff --git a/manifests/quick-start/mysql/mysql-deployment.yaml b/manifests/quick-start/mysql/mysql-deployment.yaml index df8c6cd8c46c..7d4e9ec23379 100644 --- a/manifests/quick-start/mysql/mysql-deployment.yaml +++ b/manifests/quick-start/mysql/mysql-deployment.yaml @@ -27,4 +27,9 @@ spec: - name: MYSQL_RANDOM_ROOT_PASSWORD value: "yes" ports: - - containerPort: 5432 \ No newline at end of file + - containerPort: 5432 + readinessProbe: + exec: + command: ["mysql", "-u", "mysql", "-ppassword", "argo", "-e", "SELECT 1"] + initialDelaySeconds: 15 + timeoutSeconds: 2 \ No newline at end of file diff --git a/manifests/quick-start/no-db/kustomization.yaml b/manifests/quick-start/no-db/kustomization.yaml new file mode 100644 index 000000000000..76f15e3feea7 --- /dev/null +++ b/manifests/quick-start/no-db/kustomization.yaml @@ -0,0 +1,8 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +bases: + - ../base + +patchesStrategicMerge: + - overlays/workflow-controller-configmap.yaml \ No newline at end of file diff --git a/manifests/quick-start/no-db/overlays/workflow-controller-configmap.yaml b/manifests/quick-start/no-db/overlays/workflow-controller-configmap.yaml new file mode 100644 index 000000000000..e0cb4679606e --- /dev/null +++ b/manifests/quick-start/no-db/overlays/workflow-controller-configmap.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +data: + config: | + artifactRepository: + archiveLogs: true + s3: + bucket: my-bucket + endpoint: minio:9000 + insecure: true + accessKeySecret: + name: my-minio-cred + key: accesskey + secretKeySecret: + name: my-minio-cred + key: secretkey +kind: ConfigMap +metadata: + name: workflow-controller-configmap \ No newline at end of file diff --git a/manifests/quick-start/postgres/postgres-deployment.yaml b/manifests/quick-start/postgres/postgres-deployment.yaml index 7b52541c5604..bc770295b759 100644 --- a/manifests/quick-start/postgres/postgres-deployment.yaml +++ b/manifests/quick-start/postgres/postgres-deployment.yaml @@ -21,4 +21,9 @@ spec: - name: POSTGRES_PASSWORD value: password ports: - - containerPort: 5432 \ No newline at end of file + - containerPort: 5432 + readinessProbe: + exec: + command: ["psql", "-U", "postgres", "-c", "SELECT 1"] + initialDelaySeconds: 15 + timeoutSeconds: 2 \ No newline at end of file diff --git a/persist/sqldb/ansi_sql_change.go b/persist/sqldb/ansi_sql_change.go new file mode 100644 index 000000000000..50682fd1ad3e --- /dev/null +++ b/persist/sqldb/ansi_sql_change.go @@ -0,0 +1,11 @@ +package sqldb + +import "upper.io/db.v3/lib/sqlbuilder" + +// represent a straight forward change that is compatible with all database providers +type ansiSQLChange string + +func (s ansiSQLChange) apply(session sqlbuilder.Database) error { + _, err := session.Exec(string(s)) + return err +} diff --git a/persist/sqldb/backfill_cluster_name.go b/persist/sqldb/backfill_cluster_name.go new file mode 100644 index 000000000000..7b6fd2c35ab7 --- /dev/null +++ b/persist/sqldb/backfill_cluster_name.go @@ -0,0 +1,56 @@ +package sqldb + +import ( + "fmt" + + log "github.com/sirupsen/logrus" + "upper.io/db.v3" + "upper.io/db.v3/lib/sqlbuilder" +) + +type backfillClusterName struct { + clusterName string + tableName string +} + +func (s backfillClusterName) String() string { + return fmt.Sprintf("backfillClusterName{%s,%s}", s.clusterName, s.tableName) +} + +func (s backfillClusterName) apply(session sqlbuilder.Database) error { + log.WithField("clustername", s.clusterName).Info("Back-filling cluster name") + rs, err := session. + Select("uid"). + From(s.tableName). + Where(db.Cond{"clustername": nil}). + Query() + if err != nil { + return err + } + for rs.Next() { + uid := "" + err := rs.Scan(&uid) + if err != nil { + return err + } + logCtx := log.WithFields(log.Fields{"clustername": s.clusterName, "uid": uid}) + logCtx.Info("Back-filling cluster name") + res, err := session. + Update(s.tableName). + Set("clustername", s.clusterName). + Where(db.Cond{"clustername": nil}). + And(db.Cond{"uuid": uid}). + Exec() + if err != nil { + return err + } + rowsAffected, err := res.RowsAffected() + if err != nil { + return err + } + if rowsAffected != 1 { + logCtx.WithField("rowsAffected", rowsAffected).Warn("Expected exactly one row affected") + } + } + return nil +} diff --git a/persist/sqldb/backfill_nodes.go b/persist/sqldb/backfill_nodes.go new file mode 100644 index 000000000000..741c9e796872 --- /dev/null +++ b/persist/sqldb/backfill_nodes.go @@ -0,0 +1,66 @@ +package sqldb + +import ( + "encoding/json" + "fmt" + + log "github.com/sirupsen/logrus" + "upper.io/db.v3" + "upper.io/db.v3/lib/sqlbuilder" + + wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" +) + +type backfillNodes struct { + tableName string +} + +func (s backfillNodes) String() string { + return fmt.Sprintf("backfillNodes{%s}", s.tableName) +} + +func (s backfillNodes) apply(session sqlbuilder.Database) error { + log.Info("Backfill node status") + rs, err := session.SelectFrom(s.tableName). + Columns("workflow"). + Where(db.Cond{"version": nil}). + Query() + if err != nil { + return err + } + for rs.Next() { + workflow := "" + err := rs.Scan(&workflow) + if err != nil { + return err + } + var wf *wfv1.Workflow + err = json.Unmarshal([]byte(workflow), &wf) + if err != nil { + return err + } + marshalled, version, err := nodeStatusVersion(wf.Status.Nodes) + if err != nil { + return err + } + logCtx := log.WithFields(log.Fields{"name": wf.Name, "namespace": wf.Namespace, "version": version}) + logCtx.Info("Back-filling node status") + res, err := session.Update(archiveTableName). + Set("version", wf.ResourceVersion). + Set("nodes", marshalled). + Where(db.Cond{"name": wf.Name}). + And(db.Cond{"namespace": wf.Namespace}). + Exec() + if err != nil { + return err + } + rowsAffected, err := res.RowsAffected() + if err != nil { + return err + } + if rowsAffected != 1 { + logCtx.WithField("rowsAffected", rowsAffected).Warn("Expected exactly one row affected") + } + } + return nil +} diff --git a/persist/sqldb/explosive_offload_node_status_repo.go b/persist/sqldb/explosive_offload_node_status_repo.go index 7660444297da..42652927e119 100644 --- a/persist/sqldb/explosive_offload_node_status_repo.go +++ b/persist/sqldb/explosive_offload_node_status_repo.go @@ -3,10 +3,11 @@ package sqldb import ( "fmt" - "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" ) -var ExplosiveOffloadNodeStatusRepo = &explosiveOffloadNodeStatusRepo{} +var ExplosiveOffloadNodeStatusRepo OffloadNodeStatusRepo = &explosiveOffloadNodeStatusRepo{} +var notSupportedError = fmt.Errorf("offload node status is not supported") type explosiveOffloadNodeStatusRepo struct { } @@ -15,18 +16,22 @@ func (n *explosiveOffloadNodeStatusRepo) IsEnabled() bool { return false } -func (n *explosiveOffloadNodeStatusRepo) Save(*v1alpha1.Workflow) error { - return fmt.Errorf("offload node status not supported") +func (n *explosiveOffloadNodeStatusRepo) Save(string, string, wfv1.Nodes) (string, error) { + return "", notSupportedError } -func (n *explosiveOffloadNodeStatusRepo) Get(string, string) (*v1alpha1.Workflow, error) { - return nil, fmt.Errorf("offload node status not supported") +func (n *explosiveOffloadNodeStatusRepo) Get(string, string) (wfv1.Nodes, error) { + return nil, notSupportedError } -func (n *explosiveOffloadNodeStatusRepo) List(string) (v1alpha1.Workflows, error) { - return nil, fmt.Errorf("offload node status not supported") +func (n *explosiveOffloadNodeStatusRepo) List(string) (map[UUIDVersion]wfv1.Nodes, error) { + return nil, notSupportedError } -func (n *explosiveOffloadNodeStatusRepo) Delete(string, string) error { - return fmt.Errorf("offload node status disabled") +func (n *explosiveOffloadNodeStatusRepo) Delete(string) error { + return notSupportedError +} + +func (n *explosiveOffloadNodeStatusRepo) ListOldUIDs(namespace string) ([]string, error) { + return nil, notSupportedError } diff --git a/persist/sqldb/mappers.go b/persist/sqldb/mappers.go deleted file mode 100644 index 78cb56ee613f..000000000000 --- a/persist/sqldb/mappers.go +++ /dev/null @@ -1,93 +0,0 @@ -package sqldb - -import ( - "encoding/json" - "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - - wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" -) - -type WorkflowMetadata struct { - Id string `db:"id"` - Name string `db:"name"` - Phase wfv1.NodePhase `db:"phase"` - Namespace string `db:"namespace"` - StartedAt time.Time `db:"startedat"` - FinishedAt time.Time `db:"finishedat"` -} - -type WorkflowOnlyRecord struct { - Workflow string `db:"workflow"` -} - -type WorkflowRecord struct { - WorkflowMetadata - WorkflowOnlyRecord -} - -func toRecord(wf *wfv1.Workflow) (*WorkflowRecord, error) { - jsonWf, err := json.Marshal(wf) - if err != nil { - return nil, err - } - startT, err := time.Parse(time.RFC3339, wf.Status.StartedAt.Format(time.RFC3339)) - if err != nil { - return nil, err - } - endT, err := time.Parse(time.RFC3339, wf.Status.FinishedAt.Format(time.RFC3339)) - if err != nil { - return nil, err - } - - return &WorkflowRecord{ - WorkflowMetadata: WorkflowMetadata{ - Id: string(wf.UID), - Name: wf.Name, - Namespace: wf.Namespace, - Phase: wf.Status.Phase, - StartedAt: startT, - FinishedAt: endT, - }, - WorkflowOnlyRecord: WorkflowOnlyRecord{Workflow: string(jsonWf)}, - }, nil -} - -func toWorkflows(workflows []WorkflowOnlyRecord) (wfv1.Workflows, error) { - wfs := make(wfv1.Workflows, len(workflows)) - for i, wf := range workflows { - wf, err := toWorkflow(&wf) - if err != nil { - return nil, err - } - wfs[i] = *wf - } - return wfs, nil -} -func toWorkflow(workflow *WorkflowOnlyRecord) (*wfv1.Workflow, error) { - var wf *wfv1.Workflow - err := json.Unmarshal([]byte(workflow.Workflow), &wf) - return wf, err -} - -func toSlimWorkflows(mds []WorkflowMetadata) wfv1.Workflows { - wfs := make(wfv1.Workflows, len(mds)) - for i, md := range mds { - wfs[i] = wfv1.Workflow{ - ObjectMeta: v1.ObjectMeta{ - Name: md.Name, - Namespace: md.Namespace, - UID: types.UID(md.Id), - CreationTimestamp: v1.Time{Time: md.StartedAt}, - }, - Status: wfv1.WorkflowStatus{ - Phase: md.Phase, - StartedAt: v1.Time{Time: md.StartedAt}, - FinishedAt: v1.Time{Time: md.FinishedAt}, - }, - } - } - return wfs -} diff --git a/persist/sqldb/migrate.go b/persist/sqldb/migrate.go index e05895638b95..e01bf84d28cd 100644 --- a/persist/sqldb/migrate.go +++ b/persist/sqldb/migrate.go @@ -1,46 +1,75 @@ package sqldb import ( + "context" + "database/sql" + + "github.com/go-sql-driver/mysql" log "github.com/sirupsen/logrus" "upper.io/db.v3/lib/sqlbuilder" ) -type migrateCfg struct { - tableName string +type Migrate interface { + Exec(ctx context.Context) error } -func migrate(cfg migrateCfg, session sqlbuilder.Database) error { - // poor mans SQL migration - _, err := session.Exec("create table if not exists schema_history(schema_version int not null)") - if err != nil { - return err - } - rs, err := session.Query("select schema_version from schema_history") - if err != nil { - return err +func NewMigrate(session sqlbuilder.Database, clusterName string, tableName string) Migrate { + return migrate{session, clusterName, tableName} +} + +type migrate struct { + session sqlbuilder.Database + clusterName string + tableName string +} + +type change interface { + apply(session sqlbuilder.Database) error +} + +func ternary(condition bool, left, right change) change { + if condition { + return left + } else { + return right } - schemaVersion := -1 - if rs.Next() { - err := rs.Scan(&schemaVersion) +} + +func (m migrate) Exec(ctx context.Context) error { + { + // poor mans SQL migration + _, err := m.session.Exec("create table if not exists schema_history(schema_version int not null)") if err != nil { return err } - } else { - _, err := session.Exec("insert into schema_history values(-1)") + rs, err := m.session.Query("select schema_version from schema_history") + if err != nil { + return err + } + if !rs.Next() { + _, err := m.session.Exec("insert into schema_history values(-1)") + if err != nil { + return err + } + } + err = rs.Close() if err != nil { return err } } - err = rs.Close() - if err != nil { - return err + dbType := "postgres" + switch m.session.Driver().(*sql.DB).Driver().(type) { + case *mysql.MySQLDriver: + dbType = "mysql" } - log.WithField("schemaVersion", schemaVersion).Info("Migrating database schema") + + log.WithFields(log.Fields{"clusterName": m.clusterName, "dbType": dbType}).Info("Migrating database schema") // try and make changes idempotent, as it is possible for the change to apply, but the archive update to fail // and therefore try and apply again next try - for changeSchemaVersion, change := range []string{ - `create table if not exists ` + cfg.tableName + ` ( + + for changeSchemaVersion, change := range []change{ + ansiSQLChange(`create table if not exists ` + m.tableName + ` ( id varchar(128) , name varchar(256), phase varchar(25), @@ -49,9 +78,9 @@ func migrate(cfg migrateCfg, session sqlbuilder.Database) error { startedat timestamp, finishedat timestamp, primary key (id, namespace) -)`, - `create unique index idx_name on ` + cfg.tableName + ` (name)`, - `create table if not exists argo_workflow_history ( +)`), + ansiSQLChange(`create unique index idx_name on ` + m.tableName + ` (name)`), + ansiSQLChange(`create table if not exists argo_workflow_history ( id varchar(128) , name varchar(256), phase varchar(25), @@ -60,29 +89,139 @@ func migrate(cfg migrateCfg, session sqlbuilder.Database) error { startedat timestamp, finishedat timestamp, primary key (id, namespace) -)`, - `alter table argo_workflow_history rename to argo_archived_workflows`, - `drop index idx_name`, - `create unique index idx_name on ` + cfg.tableName + `(name, namespace)`, - `alter table ` + cfg.tableName + ` drop constraint ` + cfg.tableName + `_pkey`, - `alter table ` + cfg.tableName + ` add primary key(name,namespace)`, - `drop index idx_name`, - // huh - why does the pkey not have the same name as the table - history! - `alter table argo_archived_workflows drop constraint argo_workflow_history_pkey`, - `alter table argo_archived_workflows add primary key(id)`, +)`), + ansiSQLChange(`alter table argo_workflow_history rename to argo_archived_workflows`), + ternary(dbType == "mysql", + ansiSQLChange(`drop index idx_name on `+m.tableName), + ansiSQLChange(`drop index idx_name`), + ), + ansiSQLChange(`create unique index idx_name on ` + m.tableName + `(name, namespace)`), + ternary(dbType == "mysql", + ansiSQLChange(`alter table `+m.tableName+` drop primary key`), + ansiSQLChange(`alter table `+m.tableName+` drop constraint `+m.tableName+`_pkey`), + ), + ansiSQLChange(`alter table ` + m.tableName + ` add primary key(name,namespace)`), + // huh - why does the pkey not have the same name as the table - history + ternary(dbType == "mysql", + ansiSQLChange(`alter table argo_archived_workflows drop primary key`), + ansiSQLChange(`alter table argo_archived_workflows drop constraint argo_workflow_history_pkey`), + ), + ansiSQLChange(`alter table argo_archived_workflows add primary key(id)`), + // *** + // THE CHANGES ABOVE THIS LINE MAY BE IN PER-PRODUCTION SYSTEMS - DO NOT CHANGE THEM + // *** + ansiSQLChange(`alter table argo_archived_workflows rename column id to uid`), + ternary(dbType == "mysql", + ansiSQLChange(`alter table argo_archived_workflows modify column uid varchar(128) not null`), + ansiSQLChange(`alter table argo_archived_workflows alter column uid set not null`), + ), + ternary(dbType == "mysql", + ansiSQLChange(`alter table argo_archived_workflows modify column phase varchar(25) not null`), + ansiSQLChange(`alter table argo_archived_workflows alter column phase set not null`), + ), + ternary(dbType == "mysql", + ansiSQLChange(`alter table argo_archived_workflows modify column namespace varchar(256) not null`), + ansiSQLChange(`alter table argo_archived_workflows alter column namespace set not null`), + ), + ternary(dbType == "mysql", + ansiSQLChange(`alter table argo_archived_workflows modify column workflow text not null`), + ansiSQLChange(`alter table argo_archived_workflows alter column workflow set not null`), + ), + ternary(dbType == "mysql", + ansiSQLChange(`alter table argo_archived_workflows modify column startedat timestamp not null`), + ansiSQLChange(`alter table argo_archived_workflows alter column startedat set not null`), + ), + ternary(dbType == "mysql", + ansiSQLChange(`alter table argo_archived_workflows modify column finishedat timestamp not null`), + ansiSQLChange(`alter table argo_archived_workflows alter column finishedat set not null`), + ), + ansiSQLChange(`alter table argo_archived_workflows add clustername varchar(64)`), // DNS entry can only be max 63 bytes + backfillClusterName{clusterName: m.clusterName, tableName: "argo_archived_workflows"}, + ternary(dbType == "mysql", + ansiSQLChange(`alter table argo_archived_workflows modify column clustername varchar(64) not null`), + ansiSQLChange(`alter table argo_archived_workflows alter column clustername set not null`), + ), + ternary(dbType == "mysql", + ansiSQLChange(`alter table argo_archived_workflows drop primary key`), + ansiSQLChange(`alter table argo_archived_workflows drop constraint argo_archived_workflows_pkey`), + ), + ansiSQLChange(`alter table argo_archived_workflows add primary key(clustername,uid)`), + ansiSQLChange(`create index argo_archived_workflows_i1 on argo_archived_workflows (clustername,namespace)`), + // argo_archived_workflows now looks like: + // clustername(not null) uid(not null) | phase(not null) | namespace(not null) | workflow(not null) | startedat(not null) | finishedat(not null) + // remove unused columns + ansiSQLChange(`alter table ` + m.tableName + ` drop column phase`), + ansiSQLChange(`alter table ` + m.tableName + ` drop column startedat`), + ansiSQLChange(`alter table ` + m.tableName + ` drop column finishedat`), + ansiSQLChange(`alter table ` + m.tableName + ` rename column id to uid`), + ternary(dbType == "mysql", + ansiSQLChange(`alter table `+m.tableName+` modify column uid varchar(128) not null`), + ansiSQLChange(`alter table `+m.tableName+` alter column uid set not null`), + ), + ternary(dbType == "mysql", + ansiSQLChange(`alter table `+m.tableName+` modify column namespace varchar(256) not null`), + ansiSQLChange(`alter table `+m.tableName+` alter column namespace set not null`), + ), + ansiSQLChange(`alter table ` + m.tableName + ` add column clustername varchar(64)`), // DNS cannot be longer than 64 bytes + backfillClusterName{m.clusterName, m.tableName}, + ternary(dbType == "mysql", + ansiSQLChange(`alter table `+m.tableName+` modify column clustername varchar(64) not null`), + ansiSQLChange(`alter table `+m.tableName+` alter column clustername set not null`), + ), + ansiSQLChange(`alter table ` + m.tableName + ` add column version varchar(64)`), + ansiSQLChange(`alter table ` + m.tableName + ` add column nodes text`), + backfillNodes{tableName: m.tableName}, + ternary(dbType == "mysql", + ansiSQLChange(`alter table `+m.tableName+` modify column nodes text not null`), + ansiSQLChange(`alter table `+m.tableName+` alter column nodes set not null`), + ), + ansiSQLChange(`alter table ` + m.tableName + ` drop column workflow`), + // add a timestamp column to indicate updated time + ansiSQLChange(`alter table ` + m.tableName + ` add column updatedat timestamp not null default current_timestamp`), + // remove the old primary key and add a new one + ternary(dbType == "mysql", + ansiSQLChange(`alter table `+m.tableName+` drop primary key`), + ansiSQLChange(`alter table `+m.tableName+` drop constraint `+m.tableName+`_pkey`), + ), + ternary(dbType == "mysql", + ansiSQLChange(`drop index idx_name on `+m.tableName), + ansiSQLChange(`drop index idx_name`), + ), + ansiSQLChange(`alter table ` + m.tableName + ` drop column name`), + ansiSQLChange(`alter table ` + m.tableName + ` add primary key(clustername,uid,version)`), + ansiSQLChange(`create index ` + m.tableName + `_i1 on ` + m.tableName + ` (clustername,namespace)`), + // argo_workflows now looks like: + // clustername(not null) | uid(not null) | namespace(not null) | version(not null) | nodes(not null) | updatedat(not null) } { - if changeSchemaVersion > schemaVersion { - log.WithFields(log.Fields{"changeSchemaVersion": changeSchemaVersion, "change": change}).Info("Applying database change") - _, err := session.Exec(change) - if err != nil { - return err - } - _, err = session.Exec("update schema_history set schema_version=?", changeSchemaVersion) - if err != nil { - return err - } + err := m.applyChange(ctx, changeSchemaVersion, change) + if err != nil { + return err } } return nil } + +func (m migrate) applyChange(ctx context.Context, changeSchemaVersion int, c change) error { + tx, err := m.session.NewTx(ctx) + if err != nil { + return err + } + defer func() { _ = tx.Rollback() }() + rs, err := tx.Exec("update schema_history set schema_version = ? where schema_version = ?", changeSchemaVersion, changeSchemaVersion-1) + if err != nil { + return err + } + rowsAffected, err := rs.RowsAffected() + if err != nil { + return err + } + if rowsAffected == 1 { + log.WithFields(log.Fields{"changeSchemaVersion": changeSchemaVersion, "change": c}).Info("applying database change") + err := c.apply(m.session) + if err != nil { + return err + } + } + return tx.Commit() +} diff --git a/persist/sqldb/mocks/DBRepository.go b/persist/sqldb/mocks/DBRepository.go deleted file mode 100644 index 6ee44f46e6ef..000000000000 --- a/persist/sqldb/mocks/DBRepository.go +++ /dev/null @@ -1,153 +0,0 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. - -package mocks - -import db "upper.io/db.v3" -import mock "github.com/stretchr/testify/mock" - -import v1alpha1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" - -// DBRepository is an autogenerated mock type for the DBRepository type -type DBRepository struct { - mock.Mock -} - -// Delete provides a mock function with given fields: condition -func (_m *DBRepository) Delete(condition db.Cond) error { - ret := _m.Called(condition) - - var r0 error - if rf, ok := ret.Get(0).(func(db.Cond) error); ok { - r0 = rf(condition) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Get provides a mock function with given fields: uid -func (_m *DBRepository) Get(uid string) (*v1alpha1.Workflow, error) { - ret := _m.Called(uid) - - var r0 *v1alpha1.Workflow - if rf, ok := ret.Get(0).(func(string) *v1alpha1.Workflow); ok { - r0 = rf(uid) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*v1alpha1.Workflow) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(uid) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// IsNodeStatusOffload provides a mock function with given fields: -func (_m *DBRepository) IsNodeStatusOffload() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// List provides a mock function with given fields: orderBy -func (_m *DBRepository) List(orderBy string) (*v1alpha1.WorkflowList, error) { - ret := _m.Called(orderBy) - - var r0 *v1alpha1.WorkflowList - if rf, ok := ret.Get(0).(func(string) *v1alpha1.WorkflowList); ok { - r0 = rf(orderBy) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*v1alpha1.WorkflowList) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(orderBy) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Query provides a mock function with given fields: condition, orderBy -func (_m *DBRepository) Query(condition db.Cond, orderBy ...interface{}) ([]v1alpha1.Workflow, error) { - var _ca []interface{} - _ca = append(_ca, condition) - _ca = append(_ca, orderBy...) - ret := _m.Called(_ca...) - - var r0 []v1alpha1.Workflow - if rf, ok := ret.Get(0).(func(db.Cond, ...interface{}) []v1alpha1.Workflow); ok { - r0 = rf(condition, orderBy...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]v1alpha1.Workflow) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(db.Cond, ...interface{}) error); ok { - r1 = rf(condition, orderBy...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// QueryWithPagination provides a mock function with given fields: condition, pageSize, lastID, orderBy -func (_m *DBRepository) QueryWithPagination(condition db.Cond, pageSize uint, lastID string, orderBy ...interface{}) (*v1alpha1.WorkflowList, error) { - var _ca []interface{} - _ca = append(_ca, condition, pageSize, lastID) - _ca = append(_ca, orderBy...) - ret := _m.Called(_ca...) - - var r0 *v1alpha1.WorkflowList - if rf, ok := ret.Get(0).(func(db.Cond, uint, string, ...interface{}) *v1alpha1.WorkflowList); ok { - r0 = rf(condition, pageSize, lastID, orderBy...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*v1alpha1.WorkflowList) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(db.Cond, uint, string, ...interface{}) error); ok { - r1 = rf(condition, pageSize, lastID, orderBy...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Save provides a mock function with given fields: wf -func (_m *DBRepository) Save(wf *v1alpha1.Workflow) error { - ret := _m.Called(wf) - - var r0 error - if rf, ok := ret.Get(0).(func(*v1alpha1.Workflow) error); ok { - r0 = rf(wf) - } else { - r0 = ret.Error(0) - } - - return r0 -} diff --git a/persist/sqldb/mocks/OffloadNodeStatusRepo.go b/persist/sqldb/mocks/OffloadNodeStatusRepo.go index 7369274f71d4..9418f093a49d 100644 --- a/persist/sqldb/mocks/OffloadNodeStatusRepo.go +++ b/persist/sqldb/mocks/OffloadNodeStatusRepo.go @@ -2,22 +2,25 @@ package mocks -import mock "github.com/stretchr/testify/mock" +import ( + sqldb "github.com/argoproj/argo/persist/sqldb" + mock "github.com/stretchr/testify/mock" -import v1alpha1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + v1alpha1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" +) // OffloadNodeStatusRepo is an autogenerated mock type for the OffloadNodeStatusRepo type type OffloadNodeStatusRepo struct { mock.Mock } -// Delete provides a mock function with given fields: name, namespace -func (_m *OffloadNodeStatusRepo) Delete(name string, namespace string) error { - ret := _m.Called(name, namespace) +// Delete provides a mock function with given fields: uid +func (_m *OffloadNodeStatusRepo) Delete(uid string) error { + ret := _m.Called(uid) var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(name, namespace) + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(uid) } else { r0 = ret.Error(0) } @@ -25,22 +28,22 @@ func (_m *OffloadNodeStatusRepo) Delete(name string, namespace string) error { return r0 } -// Get provides a mock function with given fields: name, namespace -func (_m *OffloadNodeStatusRepo) Get(name string, namespace string) (*v1alpha1.Workflow, error) { - ret := _m.Called(name, namespace) +// Get provides a mock function with given fields: uid, version +func (_m *OffloadNodeStatusRepo) Get(uid string, version string) (v1alpha1.Nodes, error) { + ret := _m.Called(uid, version) - var r0 *v1alpha1.Workflow - if rf, ok := ret.Get(0).(func(string, string) *v1alpha1.Workflow); ok { - r0 = rf(name, namespace) + var r0 v1alpha1.Nodes + if rf, ok := ret.Get(0).(func(string, string) v1alpha1.Nodes); ok { + r0 = rf(uid, version) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*v1alpha1.Workflow) + r0 = ret.Get(0).(v1alpha1.Nodes) } } var r1 error if rf, ok := ret.Get(1).(func(string, string) error); ok { - r1 = rf(name, namespace) + r1 = rf(uid, version) } else { r1 = ret.Error(1) } @@ -63,15 +66,15 @@ func (_m *OffloadNodeStatusRepo) IsEnabled() bool { } // List provides a mock function with given fields: namespace -func (_m *OffloadNodeStatusRepo) List(namespace string) (v1alpha1.Workflows, error) { +func (_m *OffloadNodeStatusRepo) List(namespace string) (map[sqldb.UUIDVersion]v1alpha1.Nodes, error) { ret := _m.Called(namespace) - var r0 v1alpha1.Workflows - if rf, ok := ret.Get(0).(func(string) v1alpha1.Workflows); ok { + var r0 map[sqldb.UUIDVersion]v1alpha1.Nodes + if rf, ok := ret.Get(0).(func(string) map[sqldb.UUIDVersion]v1alpha1.Nodes); ok { r0 = rf(namespace) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(v1alpha1.Workflows) + r0 = ret.Get(0).(map[sqldb.UUIDVersion]v1alpha1.Nodes) } } @@ -85,16 +88,46 @@ func (_m *OffloadNodeStatusRepo) List(namespace string) (v1alpha1.Workflows, err return r0, r1 } -// Save provides a mock function with given fields: wf -func (_m *OffloadNodeStatusRepo) Save(wf *v1alpha1.Workflow) error { - ret := _m.Called(wf) +// ListOldUIDs provides a mock function with given fields: namespace +func (_m *OffloadNodeStatusRepo) ListOldUIDs(namespace string) ([]string, error) { + ret := _m.Called(namespace) - var r0 error - if rf, ok := ret.Get(0).(func(*v1alpha1.Workflow) error); ok { - r0 = rf(wf) + var r0 []string + if rf, ok := ret.Get(0).(func(string) []string); ok { + r0 = rf(namespace) } else { - r0 = ret.Error(0) + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } } - return r0 + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(namespace) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Save provides a mock function with given fields: uid, namespace, nodes +func (_m *OffloadNodeStatusRepo) Save(uid string, namespace string, nodes v1alpha1.Nodes) (string, error) { + ret := _m.Called(uid, namespace, nodes) + + var r0 string + if rf, ok := ret.Get(0).(func(string, string, v1alpha1.Nodes) string); ok { + r0 = rf(uid, namespace, nodes) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, string, v1alpha1.Nodes) error); ok { + r1 = rf(uid, namespace, nodes) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } diff --git a/persist/sqldb/null_workflow_archive.go b/persist/sqldb/null_workflow_archive.go index 81852ce3156f..20ac0cab37d0 100644 --- a/persist/sqldb/null_workflow_archive.go +++ b/persist/sqldb/null_workflow_archive.go @@ -6,7 +6,7 @@ import ( wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" ) -var NullWorkflowArchive = &nullWorkflowArchive{} +var NullWorkflowArchive WorkflowArchive = &nullWorkflowArchive{} type nullWorkflowArchive struct { } diff --git a/persist/sqldb/offload_node_status_repo.go b/persist/sqldb/offload_node_status_repo.go index 06ac7a8ee48f..32d4e7617871 100644 --- a/persist/sqldb/offload_node_status_repo.go +++ b/persist/sqldb/offload_node_status_repo.go @@ -1,151 +1,205 @@ package sqldb import ( - "context" + "encoding/json" + "fmt" + "hash/fnv" "strings" log "github.com/sirupsen/logrus" "upper.io/db.v3" "upper.io/db.v3/lib/sqlbuilder" - "github.com/argoproj/argo/errors" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" ) +type UUIDVersion struct { + UID, Version string +} + type OffloadNodeStatusRepo interface { - Save(wf *wfv1.Workflow) error - Get(name, namespace string) (*wfv1.Workflow, error) - List(namespace string) (wfv1.Workflows, error) - Delete(name, namespace string) error + Save(uid, namespace string, nodes wfv1.Nodes) (string, error) + Get(uid, version string) (wfv1.Nodes, error) + List(namespace string) (map[UUIDVersion]wfv1.Nodes, error) + ListOldUIDs(namespace string) ([]string, error) + Delete(uid string) error IsEnabled() bool } -func NewOffloadNodeStatusRepo(tableName string, session sqlbuilder.Database) OffloadNodeStatusRepo { - return &nodeOffloadRepo{tableName, session} +func NewOffloadNodeStatusRepo(session sqlbuilder.Database, clusterName, tableName string) OffloadNodeStatusRepo { + return &nodeOffloadRepo{session: session, clusterName: clusterName, tableName: tableName} +} + +type nodesRecord struct { + ClusterName string `db:"clustername"` + UID string `db:"uid"` + Version string `db:"version"` + Namespace string `db:"namespace"` + Nodes string `db:"nodes"` } type nodeOffloadRepo struct { - tableName string - session sqlbuilder.Database + session sqlbuilder.Database + clusterName string + tableName string } func (wdc *nodeOffloadRepo) IsEnabled() bool { return true } -// Save will upsert the workflow -func (wdc *nodeOffloadRepo) Save(wf *wfv1.Workflow) error { - log.WithFields(log.Fields{"name": wf.Name, "namespace": wf.Namespace}).Debug("Saving offloaded workflow") - wfdb, err := toRecord(wf) +func nodeStatusVersion(s wfv1.Nodes) (string, string, error) { + marshalled, err := json.Marshal(s) if err != nil { - return err + return "", "", err } - err = wdc.update(wfdb) - if err != nil { - if errors.IsCode(CodeDBUpdateRowNotFound, err) { - return wdc.insert(wfdb) - } else { - log.Warn(err) - return errors.InternalErrorf("Error in inserting workflow in persistence. %v", err) - } - } - - log.Info("Workflow update successfully into persistence") - return nil + h := fnv.New32() + _, _ = h.Write(marshalled) + return string(marshalled), fmt.Sprintf("fnv:%v", h.Sum32()), nil } -func (wdc *nodeOffloadRepo) insert(wfDB *WorkflowRecord) error { - tx, err := wdc.session.NewTx(context.TODO()) +func (wdc *nodeOffloadRepo) Save(uid, namespace string, nodes wfv1.Nodes) (string, error) { + + marshalled, version, err := nodeStatusVersion(nodes) if err != nil { - return errors.InternalErrorf("Error in creating transaction. %v", err) + return "", err } - defer func() { - if tx != nil { - err := tx.Close() - if err != nil { - log.Warnf("Transaction failed to close") - } - } - }() + record := &nodesRecord{ + ClusterName: wdc.clusterName, + UID: uid, + Version: version, + Namespace: namespace, + Nodes: marshalled, + } - _, err = tx.Collection(wdc.tableName).Insert(wfDB) + logCtx := log.WithFields(log.Fields{"uid": uid, "version": version}) + logCtx.Debug("Offloading nodes") + _, err = wdc.session.Collection(wdc.tableName).Insert(record) if err != nil { - return errors.InternalErrorf("Error in inserting workflow in persistence. %v", err) + // if we have a duplicate, then it must have the same clustername+uid+version, which MUST mean that we + // have already written this record + if !isDuplicateKeyError(err) { + return "", err + } + logCtx.WithField("err", err).Info("Ignoring duplicate key error") } - err = tx.Commit() + logCtx.Info("Nodes offloaded, cleaning up old offloads") + + // This might fail, which kind of fine (maybe a bug). + // It might not delete all records, which is also fine, as we always key on resource version. + // We also want to keep enough around so that we can service watches. + rs, err := wdc.session. + DeleteFrom(wdc.tableName). + Where(db.Cond{"clustername": wdc.clusterName}). + And(db.Cond{"uid": uid}). + And(db.Cond{"version <>": version}). + And("updatedat < current_timestamp - interval '5' minute"). + Exec() if err != nil { - return errors.InternalErrorf("Error in Committing workflow insert in persistence. %v", err) + return "", err } - - return nil -} - -func (wdc *nodeOffloadRepo) update(wfDB *WorkflowRecord) error { - tx, err := wdc.session.NewTx(context.TODO()) + rowsAffected, err := rs.RowsAffected() if err != nil { - return errors.InternalErrorf("Error in creating transaction. %v", err) + return "", err } + logCtx.WithField("rowsAffected", rowsAffected).Debug("Deleted offloaded nodes") + return version, nil +} - defer func() { - if tx != nil { - err := tx.Close() - if err != nil { - log.Warnf("Transaction failed to close") - } - } - }() +func isDuplicateKeyError(err error) bool { + // postgres + if strings.Contains(err.Error(), "duplicate key") { + return true + } + // mysql + if strings.Contains(err.Error(), "Duplicate entry") { + return true + } + return false +} - err = tx.Collection(wdc.tableName).UpdateReturning(wfDB) +func (wdc *nodeOffloadRepo) Get(uid, version string) (wfv1.Nodes, error) { + log.WithFields(log.Fields{"uid": uid, "version": version}).Debug("Getting offloaded nodes") + r := &nodesRecord{} + err := wdc.session. + SelectFrom(wdc.tableName). + Where(db.Cond{"clustername": wdc.clusterName}). + And(db.Cond{"uid": uid}). + And(db.Cond{"version": version}). + One(r) if err != nil { - if strings.Contains(err.Error(), "upper: no more rows in this result set") { - return DBUpdateNoRowFoundError(err) - } - return errors.InternalErrorf("Error in updating workflow in persistence %v", err) + return nil, err } - - err = tx.Commit() + nodes := &wfv1.Nodes{} + err = json.Unmarshal([]byte(r.Nodes), nodes) if err != nil { - return errors.InternalErrorf("Error in Committing workflow update in persistence %v", err) + return nil, err } - - return nil + return *nodes, nil } -func (wdc *nodeOffloadRepo) Get(name, namespace string) (*wfv1.Workflow, error) { - log.WithFields(log.Fields{"name": name, "namespace": namespace}).Debug("Getting offloaded workflow") - wf := &WorkflowOnlyRecord{} +func (wdc *nodeOffloadRepo) List(namespace string) (map[UUIDVersion]wfv1.Nodes, error) { + log.WithFields(log.Fields{"namespace": namespace}).Debug("Listing offloaded nodes") + var records []nodesRecord err := wdc.session. - Select("workflow"). - From(wdc.tableName). - Where(db.Cond{"name": name}). - And(db.Cond{"namespace": namespace}). - One(wf) + SelectFrom(wdc.tableName). + Where(db.Cond{"clustername": wdc.clusterName}). + And(namespaceEqual(namespace)). + All(&records) if err != nil { return nil, err } - return toWorkflow(wf) + res := make(map[UUIDVersion]wfv1.Nodes) + for _, r := range records { + nodes := &wfv1.Nodes{} + err = json.Unmarshal([]byte(r.Nodes), nodes) + if err != nil { + return nil, err + } + res[UUIDVersion{UID: r.UID, Version: r.Version}] = *nodes + } + + return res, nil } -func (wdc *nodeOffloadRepo) List(namespace string) (wfv1.Workflows, error) { - var wfDBs []WorkflowOnlyRecord - err := wdc.session. - Select("workflow"). - From(tableName). - Where(namespaceEqual(namespace)). - OrderBy("-startedat"). - All(&wfDBs) +func (wdc *nodeOffloadRepo) ListOldUIDs(namespace string) ([]string, error) { + log.WithFields(log.Fields{"namespace": namespace}).Debug("Listing old offloaded nodes") + row, err := wdc.session. + Query("select distinct uid from "+wdc.tableName+" where clustername = ? and namespace = ? and updatedat < current_timestamp - interval '5' minute", wdc.clusterName, namespace) if err != nil { return nil, err } - - return toWorkflows(wfDBs) + var uids []string + for row.Next() { + uid := "" + err := row.Scan(&uid) + if err != nil { + return nil, err + } + uids = append(uids, uid) + } + return uids, nil } -func (wdc *nodeOffloadRepo) Delete(name, namespace string) error { - log.WithFields(log.Fields{"name": name, "namespace": namespace}).Debug("Deleting offloaded workflow") - return wdc.session.Collection(wdc.tableName).Find(db.Cond{"name": name}).And(db.Cond{"namespace": namespace}).Delete() +func (wdc *nodeOffloadRepo) Delete(uid string) error { + logCtx := log.WithFields(log.Fields{"uid": uid}) + logCtx.Debug("Deleting offloaded nodes") + rs, err := wdc.session. + DeleteFrom(wdc.tableName). + Where(db.Cond{"clustername": wdc.clusterName}). + And(db.Cond{"uid": uid}). + Exec() + if err != nil { + return err + } + rowsAffected, err := rs.RowsAffected() + if err != nil { + return err + } + logCtx.WithField("rowsAffected", rowsAffected).Debug("Deleted offloaded nodes") + return nil } diff --git a/persist/sqldb/offload_node_status_repo_test.go b/persist/sqldb/offload_node_status_repo_test.go new file mode 100644 index 000000000000..73ab69c85f01 --- /dev/null +++ b/persist/sqldb/offload_node_status_repo_test.go @@ -0,0 +1,26 @@ +package sqldb + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" +) + +func Test_nodeStatusVersion(t *testing.T) { + t.Run("Empty", func(t *testing.T) { + marshalled, version, err := nodeStatusVersion(nil) + if assert.NoError(t, err) { + assert.NotEmpty(t, marshalled) + assert.Equal(t, "fnv:784127654", version) + } + }) + t.Run("NonEmpty", func(t *testing.T) { + marshalled, version, err := nodeStatusVersion(wfv1.Nodes{"my-node": wfv1.NodeStatus{}}) + if assert.NoError(t, err) { + assert.NotEmpty(t, marshalled) + assert.Equal(t, "fnv:3097886412", version) + } + }) +} diff --git a/persist/sqldb/sqldb.go b/persist/sqldb/sqldb.go index ec189cefab05..99b8fff5d2dc 100644 --- a/persist/sqldb/sqldb.go +++ b/persist/sqldb/sqldb.go @@ -3,6 +3,7 @@ package sqldb import ( "fmt" + log "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" "upper.io/db.v3/lib/sqlbuilder" "upper.io/db.v3/mysql" @@ -13,26 +14,19 @@ import ( "github.com/argoproj/argo/workflow/config" ) -const ( - CodeDBUpdateRowNotFound = "ERR_DB_UPDATE_ROW_NOT_FOUND" -) - -func DBUpdateNoRowFoundError(err error) error { - return errors.Wrap(err, CodeDBUpdateRowNotFound, err.Error()) -} - // CreateDBSession creates the dB session func CreateDBSession(kubectlConfig kubernetes.Interface, namespace string, persistConfig *config.PersistConfig) (sqlbuilder.Database, string, error) { if persistConfig == nil { return nil, "", errors.InternalError("Persistence config is not found") } + log.Info("Creating DB session") + if persistConfig.PostgreSQL != nil { return CreatePostGresDBSession(kubectlConfig, namespace, persistConfig.PostgreSQL, persistConfig.ConnectionPool) } else if persistConfig.MySQL != nil { return CreateMySQLDBSession(kubectlConfig, namespace, persistConfig.MySQL, persistConfig.ConnectionPool) } - return nil, "", fmt.Errorf("no databases are configured") } @@ -74,14 +68,7 @@ func CreatePostGresDBSession(kubectlConfig kubernetes.Interface, namespace strin session.SetMaxOpenConns(persistPool.MaxOpenConns) session.SetMaxIdleConns(persistPool.MaxIdleConns) } - - err = migrate(migrateCfg{cfg.TableName}, session) - if err != nil { - return nil, "", err - } - return session, cfg.TableName, nil - } // CreateMySQLDBSession creates Mysql DB session @@ -114,12 +101,14 @@ func CreateMySQLDBSession(kubectlConfig kubernetes.Interface, namespace string, session.SetMaxOpenConns(persistPool.MaxOpenConns) session.SetMaxIdleConns(persistPool.MaxIdleConns) } - - err = migrate(migrateCfg{cfg.TableName}, session) + // this is needed to make MySQL run in a Golang-compatible UTF-8 character set. + _, err = session.Exec("SET NAMES 'utf8mb4'") + if err != nil { + return nil, "", err + } + _, err = session.Exec("SET CHARACTER SET utf8mb4") if err != nil { return nil, "", err } - return session, cfg.TableName, nil - } diff --git a/persist/sqldb/workflow_archive.go b/persist/sqldb/workflow_archive.go index a227ad8dfc8c..41060cd303cb 100644 --- a/persist/sqldb/workflow_archive.go +++ b/persist/sqldb/workflow_archive.go @@ -1,14 +1,35 @@ package sqldb import ( + "encoding/json" + "strings" + "time" + + log "github.com/sirupsen/logrus" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "upper.io/db.v3" "upper.io/db.v3/lib/sqlbuilder" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" ) -const tableName = "argo_archived_workflows" +const archiveTableName = "argo_archived_workflows" + +type archivedWorkflowMetadata struct { + ClusterName string `db:"clustername"` + UID string `db:"uid"` + Name string `db:"name"` + Namespace string `db:"namespace"` + Phase wfv1.NodePhase `db:"phase"` + StartedAt time.Time `db:"startedat"` + FinishedAt time.Time `db:"finishedat"` +} +type archivedWorkflowRecord struct { + archivedWorkflowMetadata + Workflow string `db:"workflow"` +} type WorkflowArchive interface { ArchiveWorkflow(wf *wfv1.Workflow) error ListWorkflows(namespace string, limit, offset int) (wfv1.Workflows, error) @@ -17,40 +38,96 @@ type WorkflowArchive interface { } type workflowArchive struct { - sqlbuilder.Database + session sqlbuilder.Database + clusterName string } -func NewWorkflowArchive(database sqlbuilder.Database) WorkflowArchive { - return &workflowArchive{Database: database} +func NewWorkflowArchive(session sqlbuilder.Database, clusterName string) WorkflowArchive { + return &workflowArchive{session: session, clusterName: clusterName} } func (r *workflowArchive) ArchiveWorkflow(wf *wfv1.Workflow) error { - err := r.DeleteWorkflow(string(wf.UID)) + logCtx := log.WithField("uid", wf.UID) + log.Debug("Archiving workflow") + workflow, err := json.Marshal(wf) if err != nil { return err } - wfDB, err := toRecord(wf) + // We assume that we're much more likely to be inserting rows that updating them, so we try and insert, + // and if that fails, then we update. + // There is no check for race condition here, last writer wins. + _, err = r.session.Collection(archiveTableName). + Insert(&archivedWorkflowRecord{ + archivedWorkflowMetadata: archivedWorkflowMetadata{ + ClusterName: r.clusterName, + UID: string(wf.UID), + Name: wf.Name, + Namespace: wf.Namespace, + Phase: wf.Status.Phase, + StartedAt: wf.Status.StartedAt.Time, + FinishedAt: wf.Status.FinishedAt.Time, + }, + Workflow: string(workflow), + }) if err != nil { - return err + if isDuplicateKeyError(err) { + res, err := r.session. + Update(archiveTableName). + Set("workflow", string(workflow)). + Set("phase", wf.Status.Phase). + Set("startedat", wf.Status.StartedAt.Time). + Set("finishedat", wf.Status.FinishedAt.Time). + Where(db.Cond{"clustername": r.clusterName}). + And(db.Cond{"uuid": wf.UID}). + Exec() + if err != nil { + return err + } + rowsAffected, err := res.RowsAffected() + if err != nil { + return err + } + if rowsAffected != 1 { + logCtx.WithField("rowsAffected", rowsAffected).Warn("Expected exactly one row affected") + } + } else { + return err + } } - _, err = r.Collection(tableName).Insert(wfDB) - return err + + return nil } func (r *workflowArchive) ListWorkflows(namespace string, limit int, offset int) (wfv1.Workflows, error) { - var wfMDs []WorkflowMetadata - err := r. - Select("name", "namespace", "id", "phase", "startedat", "finishedat"). - From(tableName). - Where(namespaceEqual(namespace)). + var archivedWfs []archivedWorkflowMetadata + err := r.session. + Select("name", "namespace", "uid", "phase", "startedat", "finishedat"). + From(archiveTableName). + Where(db.Cond{"clustername": r.clusterName}). + And(namespaceEqual(namespace)). OrderBy("-startedat"). Limit(limit). Offset(offset). - All(&wfMDs) + All(&archivedWfs) if err != nil { return nil, err } - wfs := toSlimWorkflows(wfMDs) + wfs := make(wfv1.Workflows, len(archivedWfs)) + for i, md := range archivedWfs { + wfs[i] = wfv1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: md.Name, + Namespace: md.Namespace, + UID: types.UID(md.UID), + CreationTimestamp: v1.Time{Time: md.StartedAt}, + }, + Status: wfv1.WorkflowStatus{ + Phase: md.Phase, + StartedAt: v1.Time{Time: md.StartedAt}, + FinishedAt: v1.Time{Time: md.FinishedAt}, + }, + } + } return wfs, nil } @@ -63,27 +140,40 @@ func namespaceEqual(namespace string) db.Cond { } func (r *workflowArchive) GetWorkflow(uid string) (*wfv1.Workflow, error) { - rs := r.Collection(tableName). - Find(). - Where(db.Cond{"id": uid}) - exists, err := rs.Exists() + archivedWf := &archivedWorkflowRecord{} + err := r.session. + Select("workflow"). + From(archiveTableName). + Where(db.Cond{"clustername": r.clusterName}). + And(db.Cond{"uid": uid}). + One(archivedWf) if err != nil { + if strings.Contains(err.Error(), "no more rows") { + return nil, nil + } return nil, err } - if !exists { - return nil, nil - } - workflow := &WorkflowOnlyRecord{} - err = rs.One(workflow) + var wf *wfv1.Workflow + err = json.Unmarshal([]byte(archivedWf.Workflow), &wf) if err != nil { return nil, err } - return toWorkflow(workflow) + return wf, nil } func (r *workflowArchive) DeleteWorkflow(uid string) error { - return r.Collection(tableName). - Find(). - Where(db.Cond{"id": uid}). - Delete() + rs, err := r.session. + DeleteFrom(archiveTableName). + Where(db.Cond{"clustername": r.clusterName}). + And(db.Cond{"uid": uid}). + Exec() + if err != nil { + return err + } + rowsAffected, err := rs.RowsAffected() + if err != nil { + return err + } + log.WithFields(log.Fields{"uid": uid, "rowsAffected": rowsAffected}).Debug("Deleted archived workflow") + return nil } diff --git a/pkg/apis/workflow/v1alpha1/generated.pb.go b/pkg/apis/workflow/v1alpha1/generated.pb.go index 07ee0c134a3f..f4c357dccf95 100644 --- a/pkg/apis/workflow/v1alpha1/generated.pb.go +++ b/pkg/apis/workflow/v1alpha1/generated.pb.go @@ -1585,332 +1585,332 @@ func init() { } var fileDescriptor_c23edafa7e7ea072 = []byte{ - // 5190 bytes of a gzipped FileDescriptorProto + // 5187 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7c, 0x4d, 0x6c, 0x1c, 0xc9, 0x75, 0xbf, 0x86, 0xe4, 0x0c, 0x67, 0xde, 0x90, 0x22, 0x55, 0xa2, 0xa4, 0x59, 0x5a, 0xcb, 0x91, 0x7b, 0xff, 0xde, 0xbf, 0x9c, 0xec, 0x0e, 0xbd, 0x92, 0x9d, 0xac, 0xd7, 0xd9, 0x5d, 0x73, 0x48, 0x51, 0xa2, 0x24, 0x52, 0xcc, 0x1b, 0x4a, 0x8a, 0xb3, 0x0b, 0x3b, 0xcd, 0xee, 0x9a, 0x99, 0x16, 0x67, 0xba, 0x7b, 0xbb, 0x7a, 0xc4, 0x65, 0x36, 0x40, 0x36, 0x41, 0x82, 0x24, 0x08, 0x0c, 0xd8, - 0x17, 0xc7, 0x80, 0x2f, 0x41, 0x0e, 0x09, 0x10, 0xe4, 0x12, 0x20, 0xa7, 0x1c, 0x7c, 0x30, 0x72, - 0x58, 0xf8, 0x92, 0x45, 0x2e, 0xd9, 0x43, 0x40, 0x78, 0x19, 0x20, 0x08, 0x90, 0x00, 0x41, 0x72, - 0x09, 0xa2, 0x53, 0x50, 0x1f, 0x5d, 0xfd, 0x31, 0x4d, 0xad, 0x34, 0x43, 0x29, 0x09, 0xec, 0x13, - 0xa7, 0xdf, 0x7b, 0xf5, 0x7b, 0xf5, 0xf9, 0xaa, 0xde, 0xab, 0x57, 0x84, 0xd5, 0x8e, 0x13, 0x76, - 0x07, 0xbb, 0x0d, 0xcb, 0xeb, 0x2f, 0x9b, 0x41, 0xc7, 0xf3, 0x03, 0xef, 0x81, 0xf8, 0xb1, 0xec, - 0xef, 0x75, 0x96, 0x4d, 0xdf, 0x61, 0xcb, 0xfb, 0x5e, 0xb0, 0xd7, 0xee, 0x79, 0xfb, 0xcb, 0x0f, - 0x5f, 0x33, 0x7b, 0x7e, 0xd7, 0x7c, 0x6d, 0xb9, 0x43, 0x5d, 0x1a, 0x98, 0x21, 0xb5, 0x1b, 0x7e, - 0xe0, 0x85, 0x1e, 0xb9, 0x1a, 0x83, 0x34, 0x22, 0x10, 0xf1, 0xa3, 0xe1, 0xef, 0x75, 0x1a, 0x1c, - 0xa4, 0x11, 0x81, 0x34, 0x22, 0x90, 0xc5, 0x57, 0x13, 0x9a, 0x3b, 0x1e, 0x57, 0xc8, 0xb1, 0x76, - 0x07, 0x6d, 0xf1, 0x25, 0x3e, 0xc4, 0x2f, 0xa9, 0x63, 0xd1, 0xd8, 0x7b, 0x9d, 0x35, 0x1c, 0x8f, - 0x57, 0x69, 0xd9, 0xf2, 0x02, 0xba, 0xfc, 0x70, 0xa8, 0x1e, 0x8b, 0x5f, 0x8e, 0x65, 0xfa, 0xa6, - 0xd5, 0x75, 0x5c, 0x1a, 0x1c, 0xc4, 0xed, 0xe8, 0xd3, 0xd0, 0xcc, 0x2b, 0xb5, 0x7c, 0x5c, 0xa9, - 0x60, 0xe0, 0x86, 0x4e, 0x9f, 0x0e, 0x15, 0xf8, 0x85, 0xcf, 0x2a, 0xc0, 0xac, 0x2e, 0xed, 0x9b, - 0xd9, 0x72, 0xc6, 0xdf, 0x16, 0x60, 0x6e, 0x25, 0xb0, 0xba, 0xce, 0x43, 0xda, 0x0a, 0x39, 0xa3, - 0x73, 0x40, 0xde, 0x81, 0xc9, 0xd0, 0x0c, 0x6a, 0x85, 0x4b, 0x85, 0xcb, 0xd5, 0x2b, 0x5f, 0x6f, - 0x8c, 0xd0, 0x91, 0x8d, 0x1d, 0x33, 0x88, 0xe0, 0x9a, 0xd3, 0x47, 0x87, 0xf5, 0xc9, 0x1d, 0x33, - 0x40, 0x8e, 0x4a, 0xbe, 0x05, 0x53, 0xae, 0xe7, 0xd2, 0xda, 0x84, 0x40, 0x5f, 0x19, 0x09, 0x7d, - 0xcb, 0x73, 0x75, 0x6d, 0x9b, 0xe5, 0xa3, 0xc3, 0xfa, 0x14, 0xa7, 0xa0, 0x00, 0x36, 0xfe, 0xad, - 0x00, 0x95, 0x95, 0xa0, 0x33, 0xe8, 0x53, 0x37, 0x64, 0x24, 0x00, 0xf0, 0xcd, 0xc0, 0xec, 0xd3, - 0x90, 0x06, 0xac, 0x56, 0xb8, 0x34, 0x79, 0xb9, 0x7a, 0xe5, 0xad, 0x91, 0x94, 0x6e, 0x47, 0x30, - 0x4d, 0xf2, 0xd1, 0x61, 0xfd, 0xd4, 0xd1, 0x61, 0x1d, 0x34, 0x89, 0x61, 0x42, 0x0b, 0x71, 0xa1, - 0x62, 0x06, 0xa1, 0xd3, 0x36, 0xad, 0x90, 0xd5, 0x26, 0x84, 0xca, 0x37, 0x47, 0x52, 0xb9, 0xa2, - 0x50, 0x9a, 0x67, 0x94, 0xc6, 0x4a, 0x44, 0x61, 0x18, 0xab, 0x30, 0xfe, 0x65, 0x12, 0xca, 0x11, - 0x83, 0x5c, 0x82, 0x29, 0xd7, 0xec, 0x53, 0x31, 0x7a, 0x95, 0xe6, 0x8c, 0x2a, 0x38, 0xb5, 0x65, - 0xf6, 0x79, 0x07, 0x99, 0x7d, 0xca, 0x25, 0x7c, 0x33, 0xec, 0x8a, 0x11, 0x48, 0x48, 0x6c, 0x9b, - 0x61, 0x17, 0x05, 0x87, 0x5c, 0x84, 0xa9, 0xbe, 0x67, 0xd3, 0xda, 0xe4, 0xa5, 0xc2, 0xe5, 0xa2, - 0xec, 0xe0, 0x4d, 0xcf, 0xa6, 0x28, 0xa8, 0xbc, 0x7c, 0x3b, 0xf0, 0xfa, 0xb5, 0xa9, 0x74, 0xf9, - 0xf5, 0xc0, 0xeb, 0xa3, 0xe0, 0x90, 0x3f, 0x2c, 0xc0, 0x7c, 0x54, 0xbd, 0xdb, 0x9e, 0x65, 0x86, - 0x8e, 0xe7, 0xd6, 0x8a, 0x62, 0xc0, 0xaf, 0x8d, 0xd5, 0x11, 0x11, 0x58, 0xb3, 0xa6, 0xb4, 0xce, - 0x67, 0x39, 0x38, 0xa4, 0x98, 0x5c, 0x01, 0xe8, 0xf4, 0xbc, 0x5d, 0xb3, 0xc7, 0xfb, 0xa0, 0x56, - 0x12, 0xb5, 0xd6, 0x43, 0x78, 0x5d, 0x73, 0x30, 0x21, 0x45, 0xf6, 0x60, 0xda, 0x94, 0xab, 0xa2, - 0x36, 0x2d, 0xea, 0xbd, 0x36, 0x62, 0xbd, 0x53, 0x2b, 0xab, 0x59, 0x3d, 0x3a, 0xac, 0x4f, 0x2b, - 0x22, 0x46, 0x1a, 0xc8, 0x2b, 0x50, 0xf6, 0x7c, 0x5e, 0x55, 0xb3, 0x57, 0x2b, 0x5f, 0x2a, 0x5c, - 0x2e, 0x37, 0xe7, 0x55, 0xf5, 0xca, 0x77, 0x14, 0x1d, 0xb5, 0x84, 0xf1, 0x47, 0x45, 0x18, 0x6a, - 0x35, 0x79, 0x0d, 0xaa, 0x0a, 0xed, 0xb6, 0xd7, 0x61, 0x62, 0xf0, 0xcb, 0xcd, 0xb9, 0xa3, 0xc3, - 0x7a, 0x75, 0x25, 0x26, 0x63, 0x52, 0x86, 0xdc, 0x87, 0x09, 0x76, 0x55, 0x2d, 0xc3, 0xb7, 0x47, - 0x6a, 0x5d, 0xeb, 0xaa, 0x9e, 0xa0, 0xa5, 0xa3, 0xc3, 0xfa, 0x44, 0xeb, 0x2a, 0x4e, 0xb0, 0xab, - 0xdc, 0x7c, 0x74, 0x9c, 0x50, 0x4c, 0x9e, 0x51, 0xcd, 0xc7, 0x75, 0x27, 0xd4, 0xd0, 0xc2, 0x7c, - 0x5c, 0x77, 0x42, 0xe4, 0xa8, 0xdc, 0x7c, 0x74, 0xc3, 0xd0, 0x17, 0x93, 0x6f, 0x54, 0xf3, 0x71, - 0x63, 0x67, 0x67, 0x5b, 0xc3, 0x8b, 0xd9, 0xcd, 0x29, 0x28, 0x80, 0xc9, 0x07, 0xbc, 0x27, 0x25, - 0xcf, 0x0b, 0x0e, 0xd4, 0xac, 0xbd, 0x31, 0xd6, 0xac, 0xf5, 0x82, 0x03, 0xad, 0x4e, 0x8d, 0x89, - 0x66, 0x60, 0x52, 0x9b, 0x68, 0x9d, 0xdd, 0x66, 0x62, 0x92, 0x8e, 0xdc, 0xba, 0xb5, 0xf5, 0x56, - 0xa6, 0x75, 0x6b, 0xeb, 0x2d, 0x14, 0xc0, 0x7c, 0x6c, 0x02, 0x73, 0x5f, 0xcd, 0xe9, 0xd1, 0xc6, - 0x06, 0xcd, 0xfd, 0xf4, 0xd8, 0xa0, 0xb9, 0x8f, 0x1c, 0xd5, 0xe8, 0xc0, 0xb9, 0x88, 0x83, 0xd4, - 0xf7, 0x98, 0x23, 0x1a, 0x48, 0xdb, 0x64, 0x19, 0x2a, 0x96, 0xe7, 0xb6, 0x9d, 0xce, 0xa6, 0xe9, - 0x2b, 0xc3, 0xa4, 0x2d, 0xda, 0x6a, 0xc4, 0xc0, 0x58, 0x86, 0xbc, 0x08, 0x93, 0x7b, 0xf4, 0x40, - 0x59, 0xa8, 0xaa, 0x12, 0x9d, 0xbc, 0x45, 0x0f, 0x90, 0xd3, 0x8d, 0x1f, 0x16, 0xe0, 0x6c, 0x4e, - 0xe7, 0xf2, 0x62, 0x83, 0xa0, 0xa7, 0x34, 0xe8, 0x62, 0x77, 0xf1, 0x36, 0x72, 0x3a, 0xf9, 0xbd, - 0x02, 0xcc, 0x25, 0x7a, 0x7b, 0x65, 0xa0, 0x8c, 0xe0, 0xe8, 0xab, 0x3b, 0x85, 0xd5, 0xbc, 0xa0, - 0x34, 0xce, 0x65, 0x18, 0x98, 0xd5, 0x6a, 0xfc, 0xbd, 0xd8, 0x75, 0x53, 0x34, 0x62, 0xc2, 0xe9, - 0x01, 0xa3, 0x01, 0x37, 0xd1, 0x2d, 0x6a, 0x05, 0x34, 0x54, 0x1b, 0xf0, 0x17, 0x1a, 0x72, 0x6b, - 0xe7, 0xb5, 0x68, 0xf0, 0x53, 0x46, 0xe3, 0xe1, 0x6b, 0x0d, 0x29, 0x71, 0x8b, 0x1e, 0xb4, 0x68, - 0x8f, 0x72, 0x8c, 0x26, 0x39, 0x3a, 0xac, 0x9f, 0xbe, 0x9b, 0x02, 0xc0, 0x0c, 0x20, 0x57, 0xe1, - 0x9b, 0x8c, 0xed, 0x7b, 0x81, 0xad, 0x54, 0x4c, 0x3c, 0xb5, 0x8a, 0xed, 0x14, 0x00, 0x66, 0x00, - 0x8d, 0xef, 0x15, 0x60, 0xba, 0x69, 0x5a, 0x7b, 0x5e, 0xbb, 0xcd, 0xed, 0x9a, 0x3d, 0x08, 0xa4, - 0xf5, 0x97, 0x63, 0xa2, 0xed, 0xda, 0x9a, 0xa2, 0xa3, 0x96, 0x20, 0x2f, 0x43, 0x49, 0x76, 0x87, - 0xa8, 0x54, 0xb1, 0x79, 0x5a, 0xc9, 0x96, 0xd6, 0x05, 0x15, 0x15, 0x97, 0x7c, 0x05, 0xaa, 0x7d, - 0xf3, 0xfd, 0x08, 0x40, 0x98, 0x99, 0x4a, 0xf3, 0xac, 0x12, 0xae, 0x6e, 0xc6, 0x2c, 0x4c, 0xca, - 0x19, 0xdf, 0x00, 0x58, 0xf5, 0xdc, 0xd0, 0x71, 0x07, 0xf4, 0x8e, 0x4b, 0x5e, 0x82, 0x22, 0x0d, - 0x02, 0x2f, 0x50, 0x96, 0x72, 0x56, 0x15, 0x2f, 0x5e, 0xe3, 0x44, 0x94, 0x3c, 0x59, 0x23, 0xa7, - 0x47, 0x6d, 0x51, 0xa3, 0x72, 0xb2, 0x46, 0x9c, 0x8a, 0x8a, 0x6b, 0xfc, 0x78, 0x02, 0x66, 0x56, - 0x03, 0xcf, 0xbd, 0xaf, 0x66, 0x08, 0xf9, 0x35, 0x28, 0xf3, 0x83, 0x9d, 0x6d, 0x86, 0xa6, 0x1a, - 0xc4, 0x2f, 0x25, 0x7a, 0x58, 0x9f, 0xcf, 0xe2, 0xb9, 0xc5, 0xa5, 0x79, 0x9f, 0xdf, 0xd9, 0x7d, - 0x40, 0xad, 0x70, 0x93, 0x86, 0x66, 0xbc, 0x43, 0xc5, 0x34, 0xd4, 0xa8, 0xa4, 0x03, 0x53, 0xcc, - 0xa7, 0x96, 0x1a, 0xbf, 0xd1, 0x36, 0xd5, 0x64, 0x95, 0x5b, 0x3e, 0xb5, 0xe2, 0xad, 0x9c, 0x7f, - 0xa1, 0x50, 0x40, 0x3c, 0x28, 0xb1, 0xd0, 0x0c, 0x07, 0x4c, 0xd9, 0xf3, 0xeb, 0xe3, 0xab, 0x12, - 0x70, 0x71, 0x67, 0xca, 0x6f, 0x54, 0x6a, 0x8c, 0x4f, 0x0a, 0x30, 0x9f, 0x14, 0xbf, 0xed, 0xb0, - 0x90, 0xbc, 0x3b, 0xd4, 0xa1, 0x8d, 0x27, 0xeb, 0x50, 0x5e, 0x5a, 0x74, 0xa7, 0x9e, 0x79, 0x11, - 0x25, 0xd1, 0x99, 0x6d, 0x28, 0x3a, 0x21, 0xed, 0x47, 0x67, 0xb5, 0x95, 0xb1, 0x9b, 0x18, 0xcf, - 0xa7, 0x0d, 0x8e, 0x8b, 0x12, 0xde, 0xf8, 0x4e, 0x31, 0xdd, 0x34, 0xde, 0xcd, 0xfc, 0xac, 0x34, - 0xb3, 0x9f, 0x20, 0xa8, 0xf6, 0x8d, 0x56, 0x89, 0xd4, 0x70, 0xfe, 0x3f, 0x55, 0x89, 0x99, 0x24, - 0xf5, 0x51, 0xe6, 0x1b, 0x53, 0xca, 0xf9, 0x92, 0xe5, 0x8e, 0x82, 0x3d, 0xe8, 0x51, 0x65, 0x7d, - 0x75, 0xc7, 0xb5, 0x14, 0x1d, 0xb5, 0x04, 0x79, 0x17, 0xce, 0x58, 0x9e, 0x6b, 0x0d, 0x82, 0x80, - 0xba, 0xd6, 0xc1, 0xb6, 0xd7, 0x73, 0xac, 0x03, 0xb5, 0x20, 0x1b, 0xaa, 0xd8, 0x99, 0xd5, 0xac, - 0xc0, 0xa3, 0x3c, 0x22, 0x0e, 0x03, 0x91, 0x2f, 0xc2, 0x34, 0x1b, 0x30, 0x9f, 0xba, 0xb6, 0xd8, - 0xed, 0xcb, 0xcd, 0x39, 0x85, 0x39, 0xdd, 0x92, 0x64, 0x8c, 0xf8, 0xe4, 0x2e, 0x5c, 0x60, 0x21, - 0x37, 0xb2, 0x6e, 0x67, 0x8d, 0x9a, 0x76, 0xcf, 0x71, 0xb9, 0xc9, 0xf3, 0x5c, 0x9b, 0x89, 0x0d, - 0x7c, 0xb2, 0xf9, 0xb9, 0xa3, 0xc3, 0xfa, 0x85, 0x56, 0xbe, 0x08, 0x1e, 0x57, 0x96, 0x7c, 0x13, - 0x16, 0xd9, 0xc0, 0xb2, 0x28, 0x63, 0xed, 0x41, 0xef, 0xa6, 0xb7, 0xcb, 0x6e, 0x38, 0x8c, 0xdb, - 0xeb, 0xdb, 0x4e, 0xdf, 0x09, 0xc5, 0x26, 0x5d, 0x6c, 0x2e, 0x1d, 0x1d, 0xd6, 0x17, 0x5b, 0xc7, - 0x4a, 0xe1, 0x63, 0x10, 0x08, 0xc2, 0x79, 0x69, 0x42, 0x86, 0xb0, 0xa7, 0x05, 0xf6, 0xe2, 0xd1, - 0x61, 0xfd, 0xfc, 0x7a, 0xae, 0x04, 0x1e, 0x53, 0x92, 0x8f, 0x20, 0xf7, 0xf7, 0x7e, 0x9d, 0xfb, - 0x58, 0xe5, 0xf4, 0x08, 0xee, 0x28, 0x3a, 0x6a, 0x09, 0xe3, 0xef, 0x0a, 0x40, 0x86, 0x17, 0x27, - 0xb9, 0x05, 0x25, 0xd3, 0x0a, 0xf9, 0xe9, 0x57, 0x7a, 0x4c, 0x2f, 0xe5, 0x6d, 0x10, 0xd2, 0x30, - 0x21, 0x6d, 0x53, 0x3e, 0x6a, 0x34, 0x5e, 0xd1, 0x2b, 0xa2, 0x28, 0x2a, 0x08, 0xe2, 0xc1, 0x99, - 0x9e, 0xc9, 0xc2, 0x68, 0xfe, 0xd8, 0xbc, 0x1a, 0xca, 0x70, 0xfd, 0xdc, 0x93, 0xad, 0x62, 0x5e, - 0xa2, 0x79, 0x8e, 0xcf, 0xa6, 0xdb, 0x59, 0x20, 0x1c, 0xc6, 0x36, 0x7e, 0x54, 0x82, 0xe9, 0xb5, - 0x95, 0xeb, 0x3b, 0x26, 0xdb, 0x7b, 0x02, 0x77, 0x88, 0x77, 0x18, 0xed, 0xfb, 0x3d, 0x33, 0x1c, - 0x9a, 0xf2, 0x3b, 0x8a, 0x8e, 0x5a, 0x82, 0x78, 0xdc, 0xb7, 0x53, 0xce, 0xa5, 0x32, 0x89, 0x6f, - 0x8d, 0x78, 0x78, 0x50, 0x28, 0x49, 0xe7, 0x4e, 0x91, 0x30, 0xd6, 0x41, 0x18, 0x54, 0x23, 0xe5, - 0x48, 0xdb, 0xea, 0xdc, 0x3b, 0xa2, 0x53, 0x1e, 0xe3, 0xc8, 0x73, 0x68, 0x82, 0x80, 0x49, 0x2d, - 0xe4, 0xcb, 0x30, 0x63, 0x53, 0xbe, 0xb2, 0xa8, 0x6b, 0x39, 0x94, 0x2f, 0xa2, 0x49, 0xde, 0x2f, - 0xdc, 0x98, 0xac, 0x25, 0xe8, 0x98, 0x92, 0x22, 0x0f, 0xa0, 0xb2, 0xef, 0x84, 0x5d, 0x61, 0xf3, - 0x6a, 0x25, 0x31, 0x71, 0xbe, 0x3a, 0x52, 0x45, 0x39, 0x42, 0xdc, 0x2d, 0xf7, 0x23, 0x4c, 0x8c, - 0xe1, 0xf9, 0x91, 0x92, 0x7f, 0x08, 0x0f, 0x5c, 0xac, 0x96, 0x4a, 0xba, 0x80, 0x60, 0x60, 0x2c, - 0x43, 0x18, 0xcc, 0xf0, 0x8f, 0x16, 0x7d, 0x6f, 0xc0, 0x67, 0xab, 0x58, 0x1b, 0xa3, 0xfa, 0xe5, - 0x11, 0x88, 0xec, 0x91, 0xfb, 0x09, 0x58, 0x4c, 0x29, 0xe1, 0xb3, 0x6f, 0xbf, 0x4b, 0xdd, 0x5a, - 0x25, 0x3d, 0xfb, 0xee, 0x77, 0xa9, 0x8b, 0x82, 0x43, 0x3c, 0x00, 0x4b, 0x1f, 0x4b, 0x6a, 0x30, - 0x86, 0x37, 0x16, 0x9f, 0x6e, 0x9a, 0xa7, 0xf9, 0xb9, 0x21, 0xfe, 0xc6, 0x84, 0x0a, 0x7e, 0xa8, - 0xf1, 0xdc, 0x6b, 0xef, 0x3b, 0x61, 0xad, 0x2a, 0x2a, 0xa5, 0x57, 0xed, 0x1d, 0x41, 0x45, 0xc5, - 0x35, 0x7e, 0x54, 0x80, 0x2a, 0x5f, 0x44, 0xd1, 0xc4, 0x7f, 0x19, 0x4a, 0xa1, 0x19, 0x74, 0xd4, - 0xb1, 0x34, 0x51, 0x6e, 0x47, 0x50, 0x51, 0x71, 0x89, 0x09, 0xc5, 0xd0, 0x64, 0x7b, 0xd1, 0x66, - 0xfa, 0x4b, 0x23, 0xb5, 0x45, 0xad, 0xde, 0x78, 0x1f, 0xe5, 0x5f, 0x0c, 0x25, 0x32, 0xb9, 0x0c, - 0x65, 0x6e, 0xfc, 0xd6, 0x4d, 0x26, 0xbd, 0xcc, 0x72, 0x73, 0x86, 0xaf, 0xd6, 0x75, 0x45, 0x43, - 0xcd, 0x35, 0xde, 0x85, 0xd3, 0xd7, 0xde, 0xa7, 0xd6, 0x20, 0xf4, 0x02, 0xe9, 0x67, 0x90, 0x9b, - 0x40, 0x18, 0x0d, 0x1e, 0x3a, 0x16, 0x5d, 0xb1, 0x2c, 0x6f, 0xe0, 0x86, 0x5b, 0xb1, 0x75, 0x58, - 0x54, 0xda, 0x48, 0x6b, 0x48, 0x02, 0x73, 0x4a, 0x19, 0x7f, 0x31, 0x05, 0xd5, 0x84, 0xa7, 0xca, - 0x47, 0x3b, 0xa0, 0xbe, 0x97, 0xb5, 0x35, 0xdc, 0x17, 0x42, 0xc1, 0xe1, 0xb6, 0x26, 0xa0, 0x0f, - 0x1d, 0xc6, 0x0f, 0xae, 0x19, 0x5b, 0x83, 0x8a, 0x8e, 0x5a, 0x82, 0xd4, 0xa1, 0x68, 0x53, 0x3f, - 0xec, 0x8a, 0x46, 0x4e, 0x35, 0x2b, 0xbc, 0x23, 0xd6, 0x38, 0x01, 0x25, 0x9d, 0x0b, 0xb4, 0x69, - 0x68, 0x75, 0x6b, 0x53, 0x62, 0x7d, 0x0a, 0x81, 0x75, 0x4e, 0x40, 0x49, 0xcf, 0xf1, 0x29, 0x8a, - 0xcf, 0xde, 0xa7, 0x28, 0x9d, 0xb0, 0x4f, 0x41, 0x7c, 0x38, 0xcb, 0x58, 0x77, 0x3b, 0x70, 0x1e, - 0x9a, 0x21, 0x15, 0x85, 0x85, 0x9e, 0xe9, 0xa7, 0xd1, 0x73, 0xe1, 0xe8, 0xb0, 0x7e, 0xb6, 0xd5, - 0xba, 0x91, 0x45, 0xc1, 0x3c, 0x68, 0xd2, 0x82, 0x73, 0x8e, 0xcb, 0xa8, 0x35, 0x08, 0xe8, 0x46, - 0xc7, 0xf5, 0x02, 0x7a, 0xc3, 0x63, 0x1c, 0x4e, 0x85, 0x67, 0x5e, 0x54, 0x83, 0x76, 0x6e, 0x23, - 0x4f, 0x08, 0xf3, 0xcb, 0x1a, 0x3f, 0x2e, 0xc0, 0x4c, 0xd2, 0x39, 0x27, 0x0c, 0xa0, 0xbb, 0xb6, - 0xde, 0x92, 0x33, 0x53, 0x9d, 0xfb, 0xde, 0x1e, 0xd9, 0xe7, 0x97, 0x30, 0xb1, 0xdf, 0x10, 0xd3, - 0x30, 0xa1, 0xe6, 0x09, 0xa2, 0x7f, 0x2f, 0x41, 0xb1, 0xed, 0x05, 0x16, 0x55, 0x6b, 0x4b, 0xaf, - 0xc1, 0x75, 0x4e, 0x44, 0xc9, 0x33, 0xfe, 0xb9, 0x00, 0x09, 0x0d, 0xe4, 0x37, 0x61, 0x96, 0xeb, - 0xb8, 0x15, 0xec, 0xa6, 0x5a, 0xd3, 0x1c, 0xb9, 0x35, 0x1a, 0xa9, 0x79, 0x4e, 0xe9, 0x9f, 0x4d, - 0x91, 0x31, 0xad, 0x8f, 0xfc, 0x3c, 0x54, 0x4c, 0xdb, 0x0e, 0x28, 0x63, 0x54, 0x9a, 0x9e, 0x4a, - 0x73, 0x56, 0xec, 0xa9, 0x11, 0x11, 0x63, 0x3e, 0x5f, 0x86, 0x5d, 0xbb, 0xcd, 0xf8, 0xcc, 0x56, - 0xc7, 0x55, 0xbd, 0x0c, 0xb9, 0x12, 0x4e, 0x47, 0x2d, 0x61, 0x7c, 0x7b, 0x0a, 0xd2, 0xba, 0x89, - 0x0d, 0x73, 0x7b, 0xc1, 0xee, 0xea, 0xaa, 0x69, 0x75, 0x47, 0xf2, 0xd5, 0xcf, 0x1e, 0x1d, 0xd6, - 0xe7, 0x6e, 0xa5, 0x11, 0x30, 0x0b, 0xa9, 0xb4, 0xdc, 0xa2, 0x07, 0xa1, 0xb9, 0x3b, 0x8a, 0xbb, - 0x1e, 0x69, 0x49, 0x22, 0x60, 0x16, 0x92, 0xbb, 0xd3, 0x7b, 0xc1, 0x6e, 0xb4, 0xc8, 0xb3, 0xee, - 0xf4, 0xad, 0x98, 0x85, 0x49, 0x39, 0xde, 0x85, 0x7b, 0xc1, 0x2e, 0x52, 0xb3, 0x17, 0x05, 0x82, - 0x75, 0x17, 0xde, 0x52, 0x74, 0xd4, 0x12, 0xc4, 0x07, 0xb2, 0x17, 0xf5, 0x9e, 0x0e, 0xf8, 0x28, - 0x5b, 0x74, 0x39, 0xaf, 0x35, 0x5a, 0x28, 0xd9, 0xa0, 0xf3, 0xdc, 0x36, 0xdf, 0x1a, 0xc2, 0xc1, - 0x1c, 0x6c, 0xf2, 0x0d, 0xb8, 0xb0, 0x17, 0xec, 0x2a, 0x43, 0xbe, 0x1d, 0x38, 0xae, 0xe5, 0xf8, - 0xa9, 0x08, 0x70, 0x5d, 0x55, 0xf7, 0xc2, 0xad, 0x7c, 0x31, 0x3c, 0xae, 0xbc, 0xf1, 0x2a, 0xcc, - 0x24, 0x23, 0x88, 0x9f, 0x11, 0x75, 0x32, 0xfe, 0xb5, 0x00, 0xa5, 0x0d, 0xd7, 0x1f, 0xfc, 0x94, - 0x5c, 0x46, 0xfc, 0xc9, 0x14, 0x4c, 0xf1, 0x23, 0x1a, 0xb9, 0x0c, 0x53, 0xe1, 0x81, 0x2f, 0xf7, - 0xd6, 0xc9, 0xe6, 0x42, 0x64, 0x68, 0x76, 0x0e, 0x7c, 0xfa, 0x48, 0xfd, 0x45, 0x21, 0x41, 0xde, - 0x82, 0x92, 0x3b, 0xe8, 0xdf, 0x33, 0x7b, 0xca, 0x28, 0xbd, 0x1c, 0x1d, 0x2d, 0xb6, 0x04, 0xf5, - 0xd1, 0x61, 0x7d, 0x81, 0xba, 0x96, 0x67, 0x3b, 0x6e, 0x67, 0xf9, 0x01, 0xf3, 0xdc, 0xc6, 0xd6, - 0xa0, 0xbf, 0x4b, 0x03, 0x54, 0xa5, 0xb8, 0xa3, 0xb8, 0xeb, 0x79, 0x3d, 0x0e, 0x30, 0x99, 0x76, - 0x14, 0x9b, 0x92, 0x8c, 0x11, 0x9f, 0x9f, 0x62, 0x58, 0x18, 0x70, 0xc9, 0xa9, 0xf4, 0x29, 0xa6, - 0x25, 0xa8, 0xa8, 0xb8, 0xa4, 0x0f, 0xa5, 0xbe, 0xe9, 0x73, 0xb9, 0xa2, 0xe8, 0xb2, 0x6b, 0x23, - 0x9f, 0x63, 0x1b, 0x9b, 0x02, 0xe7, 0x9a, 0x1b, 0x06, 0x07, 0xb1, 0x3a, 0x49, 0x44, 0xa5, 0x84, - 0x38, 0x30, 0xdd, 0x73, 0x58, 0xc8, 0xf5, 0x95, 0xc6, 0x98, 0x15, 0x5c, 0xdf, 0x3d, 0xb3, 0x37, - 0xa0, 0x71, 0x0f, 0xdc, 0x96, 0xb0, 0x18, 0xe1, 0x2f, 0x1e, 0x40, 0x35, 0x51, 0x23, 0x32, 0x2f, - 0x23, 0xad, 0x62, 0xf2, 0x8a, 0xe0, 0x2a, 0xd9, 0x81, 0xe2, 0x43, 0x8e, 0xa1, 0x8c, 0xcd, 0x98, - 0x35, 0x41, 0x09, 0xf6, 0xc6, 0xc4, 0xeb, 0x85, 0x37, 0xca, 0xdf, 0xff, 0xe3, 0xfa, 0xa9, 0x0f, - 0xff, 0xe1, 0xd2, 0x29, 0xe3, 0x6f, 0x26, 0xa1, 0xa2, 0x45, 0xfe, 0x6f, 0xcf, 0x94, 0x20, 0x33, - 0x53, 0x6e, 0x8e, 0xd7, 0x5f, 0x4f, 0x34, 0x5d, 0x56, 0xd2, 0xd3, 0x65, 0xa6, 0xf9, 0xff, 0x13, - 0x43, 0xfd, 0xe8, 0xb0, 0x5e, 0x4b, 0x77, 0x02, 0x9a, 0xfb, 0x9b, 0x94, 0x31, 0xb3, 0x43, 0xe3, - 0x69, 0xf0, 0xd5, 0xcf, 0x9a, 0x06, 0x0b, 0xc9, 0x69, 0x50, 0xc9, 0x1f, 0xc6, 0x0f, 0x27, 0xa1, - 0xbc, 0x19, 0x45, 0xd1, 0x7e, 0xb7, 0x00, 0x55, 0xd3, 0x75, 0xbd, 0x50, 0xc4, 0x5b, 0x23, 0xf3, - 0xb6, 0x35, 0x52, 0x77, 0x44, 0xa0, 0x8d, 0x95, 0x18, 0x50, 0x76, 0x89, 0xde, 0x99, 0x12, 0x1c, - 0x4c, 0xea, 0x25, 0xef, 0x41, 0xa9, 0x67, 0xee, 0xd2, 0x5e, 0x64, 0xed, 0x36, 0xc6, 0xab, 0xc1, - 0x6d, 0x81, 0x95, 0x19, 0x0f, 0x49, 0x44, 0xa5, 0x68, 0xf1, 0x2d, 0x98, 0xcf, 0x56, 0xf4, 0x69, - 0x7a, 0x94, 0x0f, 0x46, 0x42, 0xcd, 0xd3, 0x14, 0x35, 0xfe, 0xab, 0x02, 0xb0, 0xe5, 0xd9, 0x54, - 0x05, 0x6e, 0x16, 0x61, 0xc2, 0xb1, 0xd5, 0x56, 0x04, 0xaa, 0xb6, 0x13, 0x1b, 0x6b, 0x38, 0xe1, - 0xd8, 0x3a, 0x14, 0x32, 0x71, 0x6c, 0x28, 0xe4, 0x2b, 0x50, 0xb5, 0x1d, 0xe6, 0xf7, 0xcc, 0x83, - 0xad, 0x9c, 0xb3, 0xc0, 0x5a, 0xcc, 0xc2, 0xa4, 0x1c, 0x79, 0x45, 0xad, 0x5f, 0xb9, 0x50, 0x6a, - 0x99, 0xf5, 0x5b, 0xe6, 0xd5, 0x4b, 0xac, 0xe1, 0xd7, 0x61, 0x26, 0x0a, 0x35, 0x08, 0x2d, 0x45, - 0x51, 0x2a, 0x5a, 0xf5, 0x33, 0x3b, 0x09, 0x1e, 0xa6, 0x24, 0xb3, 0xa1, 0x90, 0xd2, 0x73, 0x09, - 0x85, 0xac, 0xc1, 0x3c, 0x0b, 0xbd, 0x80, 0xda, 0x91, 0xc4, 0xc6, 0x5a, 0x8d, 0xa4, 0x1a, 0x3a, - 0xdf, 0xca, 0xf0, 0x71, 0xa8, 0x04, 0xd9, 0x86, 0x85, 0xa8, 0x12, 0xc9, 0x06, 0xd6, 0xce, 0x0a, - 0xa4, 0x8b, 0x0a, 0x69, 0xe1, 0x7e, 0x8e, 0x0c, 0xe6, 0x96, 0x24, 0x5f, 0x83, 0xd9, 0xa8, 0x9a, - 0x2d, 0xcb, 0xf3, 0x69, 0x6d, 0x41, 0x40, 0xe9, 0xd3, 0xf2, 0x4e, 0x92, 0x89, 0x69, 0x59, 0xf2, - 0x25, 0x28, 0xfa, 0x5d, 0x93, 0x51, 0x15, 0x39, 0x89, 0x1c, 0xdf, 0xe2, 0x36, 0x27, 0x3e, 0x3a, - 0xac, 0x57, 0xf8, 0x98, 0x89, 0x0f, 0x94, 0x82, 0xe4, 0x0a, 0xc0, 0xae, 0x37, 0x70, 0x6d, 0x33, - 0x38, 0xd8, 0x58, 0x53, 0x81, 0x45, 0x7d, 0xf4, 0x68, 0x6a, 0x0e, 0x26, 0xa4, 0xb8, 0xb5, 0xed, - 0x4b, 0xbb, 0xa3, 0x02, 0x20, 0xda, 0xda, 0x6a, 0x73, 0xa4, 0xf8, 0xe4, 0x1d, 0xa8, 0x88, 0x20, - 0x2c, 0xb5, 0x57, 0x42, 0x15, 0x05, 0x79, 0x9a, 0xd8, 0xa0, 0x3e, 0x92, 0xb4, 0x22, 0x10, 0x8c, - 0xf1, 0xc8, 0x37, 0x01, 0xda, 0x8e, 0xeb, 0xb0, 0xae, 0x40, 0xaf, 0x3e, 0x35, 0xba, 0x6e, 0xe7, - 0xba, 0x46, 0xc1, 0x04, 0x22, 0x77, 0x98, 0x7c, 0xcf, 0xde, 0xd8, 0xae, 0xcd, 0x88, 0x56, 0x6a, - 0x87, 0x69, 0x9b, 0x13, 0x51, 0xf2, 0xc8, 0x65, 0x28, 0xdb, 0x26, 0xed, 0x7b, 0x2e, 0xb5, 0x6b, - 0xb3, 0x71, 0xd0, 0x62, 0x4d, 0xd1, 0x50, 0x73, 0xc9, 0xb7, 0xa0, 0xe4, 0x88, 0xf3, 0x62, 0xed, - 0xb4, 0xa8, 0xea, 0xd7, 0x46, 0xdb, 0x51, 0x04, 0x44, 0x13, 0xb8, 0xb9, 0x92, 0xbf, 0x51, 0xc1, - 0x12, 0x0b, 0xa6, 0xbd, 0x41, 0x28, 0x34, 0xcc, 0x09, 0x0d, 0xa3, 0x05, 0x69, 0xee, 0x48, 0x0c, - 0x99, 0xd4, 0xa0, 0x3e, 0x30, 0x42, 0xe6, 0xed, 0xb5, 0xba, 0x4e, 0xcf, 0x0e, 0xa8, 0x5b, 0x9b, - 0x17, 0xfe, 0x98, 0x68, 0xef, 0xaa, 0xa2, 0xa1, 0xe6, 0x92, 0x5f, 0x84, 0x59, 0x6f, 0x10, 0x8a, - 0x79, 0xc3, 0xa7, 0x1d, 0xab, 0x9d, 0x11, 0xe2, 0x67, 0xf8, 0x2c, 0xbe, 0x93, 0x64, 0x60, 0x5a, - 0xce, 0x38, 0x0d, 0x33, 0xc9, 0x4c, 0x20, 0xe3, 0xbb, 0x13, 0x10, 0xd5, 0xe3, 0xa7, 0xe1, 0xa8, - 0x4d, 0x0c, 0x28, 0x05, 0x94, 0x0d, 0x7a, 0xa1, 0xb2, 0xd4, 0x62, 0xac, 0x51, 0x50, 0x50, 0x71, - 0x8c, 0x7d, 0x98, 0xe5, 0xb5, 0xed, 0xf5, 0x68, 0xaf, 0x15, 0x52, 0x9f, 0x91, 0x36, 0x14, 0x19, - 0xff, 0xa1, 0xfa, 0x64, 0xcc, 0x7b, 0xa6, 0x90, 0xfa, 0xf1, 0x7c, 0x17, 0x0a, 0x50, 0xc2, 0x1b, - 0xdf, 0x9b, 0x80, 0x8a, 0xee, 0xa7, 0x27, 0x08, 0xc3, 0x7f, 0x01, 0xa6, 0x6d, 0xda, 0x36, 0x79, - 0x6b, 0xd4, 0xb5, 0x3f, 0x9f, 0x56, 0x6b, 0x92, 0x84, 0x11, 0x8f, 0xd4, 0xa3, 0x9d, 0x50, 0x36, - 0x59, 0x84, 0xbc, 0x92, 0x07, 0x4d, 0xb2, 0x07, 0x15, 0xf1, 0x63, 0x3d, 0x4a, 0x51, 0x1a, 0x75, - 0xdc, 0xef, 0x45, 0x28, 0x32, 0x90, 0xa0, 0x3f, 0x31, 0xc6, 0xcf, 0xa4, 0x16, 0x15, 0x9f, 0x24, - 0xb5, 0xc8, 0x58, 0x07, 0x6e, 0x18, 0xae, 0xaf, 0x92, 0x37, 0xa1, 0xcc, 0xd4, 0xd4, 0x55, 0xfd, - 0xf2, 0x79, 0x7d, 0xd7, 0xa6, 0xe8, 0x8f, 0x0e, 0xeb, 0xb3, 0x42, 0x38, 0x22, 0xa0, 0x2e, 0x62, - 0x2c, 0x43, 0x35, 0x91, 0x8a, 0xc1, 0x7b, 0x58, 0x5f, 0x8f, 0x26, 0x7a, 0x78, 0xcd, 0x0c, 0x4d, - 0x14, 0x1c, 0xe3, 0xd1, 0x04, 0xcc, 0x23, 0x65, 0xde, 0x20, 0xb0, 0x68, 0x32, 0xac, 0x6b, 0x5a, - 0x89, 0x1b, 0xfa, 0xd4, 0x25, 0x8e, 0xe7, 0xa2, 0xe2, 0xf2, 0xed, 0xa6, 0x4f, 0x83, 0x8e, 0x5e, - 0x6c, 0x6a, 0x90, 0xf4, 0x76, 0xb3, 0x99, 0x64, 0x62, 0x5a, 0x96, 0xbc, 0x02, 0xe5, 0xbe, 0xe9, - 0x3a, 0x6d, 0xca, 0xc2, 0x6c, 0xbc, 0x65, 0x53, 0xd1, 0x51, 0x4b, 0x90, 0xeb, 0x70, 0x86, 0xd1, - 0xf0, 0xce, 0xbe, 0x4b, 0x03, 0x7d, 0xb9, 0xa4, 0x6e, 0x00, 0x5f, 0x88, 0x6e, 0x15, 0x5b, 0x59, - 0x01, 0x1c, 0x2e, 0x23, 0xb6, 0x6e, 0x79, 0xf9, 0xb6, 0xea, 0xb9, 0xb6, 0xa3, 0xb3, 0xd0, 0x92, - 0x5b, 0x77, 0x86, 0x8f, 0x43, 0x25, 0x38, 0x4a, 0xdb, 0x74, 0x7a, 0x83, 0x80, 0xc6, 0x28, 0xa5, - 0x34, 0xca, 0x7a, 0x86, 0x8f, 0x43, 0x25, 0x8c, 0x7f, 0x2a, 0xc0, 0x2c, 0xd2, 0x30, 0x38, 0xd0, - 0x9d, 0x52, 0x87, 0x62, 0x4f, 0xdc, 0xf5, 0x15, 0xc4, 0x5d, 0x9f, 0x98, 0xc9, 0xf2, 0x6a, 0x4f, - 0xd2, 0xc9, 0x1a, 0x54, 0x03, 0x5e, 0x42, 0xdd, 0xab, 0xca, 0x0e, 0x37, 0xa2, 0xd3, 0x18, 0xc6, - 0xac, 0x47, 0xe9, 0x4f, 0x4c, 0x16, 0x23, 0x2e, 0x4c, 0xef, 0xca, 0x7c, 0x0c, 0x75, 0x5d, 0x35, - 0x9a, 0xb1, 0x57, 0x39, 0x1d, 0x22, 0x06, 0x13, 0x25, 0x78, 0x3c, 0x8a, 0x7f, 0x62, 0xa4, 0xc4, - 0xf8, 0x7e, 0x01, 0x20, 0x4e, 0x0c, 0x23, 0x7b, 0x50, 0x66, 0x57, 0x9b, 0x03, 0x6b, 0x4f, 0xc7, - 0xc8, 0x46, 0xbc, 0x72, 0x51, 0x20, 0x89, 0xfb, 0x68, 0x45, 0x41, 0xad, 0xe0, 0xb3, 0xd2, 0x86, - 0xfe, 0x72, 0x12, 0x74, 0x29, 0x3e, 0x27, 0xa9, 0x6b, 0xfb, 0x9e, 0xe3, 0x86, 0xd9, 0xe4, 0x94, - 0x6b, 0x8a, 0x8e, 0x5a, 0x82, 0x2f, 0x93, 0x5d, 0xd9, 0x88, 0x89, 0xf4, 0x32, 0x51, 0x75, 0x50, - 0x5c, 0x2e, 0x17, 0xd0, 0x4e, 0x9c, 0x97, 0xa2, 0xe5, 0x50, 0x50, 0x51, 0x71, 0xf9, 0xee, 0x18, - 0x05, 0x89, 0xd5, 0xd4, 0x16, 0xbb, 0x63, 0x14, 0x4f, 0x46, 0xcd, 0x25, 0x5d, 0x98, 0x33, 0xc5, - 0x8c, 0x8c, 0x03, 0xdf, 0x4f, 0x15, 0xc3, 0x8f, 0x93, 0x92, 0xd2, 0x28, 0x98, 0x85, 0xe5, 0x9a, - 0x58, 0x5c, 0xfc, 0xe9, 0x43, 0xf9, 0x5a, 0x53, 0x2b, 0x8d, 0x82, 0x59, 0x58, 0x7e, 0x30, 0x0c, - 0xbc, 0x1e, 0x5d, 0xc1, 0x2d, 0x75, 0x00, 0xd5, 0x07, 0x43, 0x94, 0x64, 0x8c, 0xf8, 0xc6, 0xef, - 0x17, 0xe0, 0x74, 0xcb, 0x0a, 0x1c, 0x3f, 0xd4, 0x26, 0x6b, 0x4b, 0x64, 0x93, 0x85, 0x26, 0x3f, - 0xb2, 0xa9, 0x39, 0xf5, 0xe2, 0x31, 0x31, 0x44, 0x29, 0x94, 0x4a, 0x36, 0x93, 0x24, 0x8c, 0x21, - 0x84, 0xa7, 0x2f, 0x8c, 0x62, 0x76, 0x6c, 0x5b, 0x82, 0x8a, 0x8a, 0x6b, 0xfc, 0xa0, 0x00, 0x65, - 0x7d, 0xb3, 0xf7, 0x12, 0x14, 0xc5, 0x45, 0x90, 0x9a, 0x3b, 0x7a, 0x0f, 0x5c, 0xe5, 0x44, 0x94, - 0x3c, 0x2e, 0x24, 0x4e, 0xa1, 0x0a, 0x38, 0xb1, 0x51, 0x9a, 0x41, 0x88, 0x92, 0xc7, 0x27, 0x2d, - 0x75, 0x6d, 0x35, 0x5f, 0xf4, 0xa4, 0xbd, 0xe6, 0xda, 0xc8, 0xe9, 0x22, 0x09, 0xc9, 0x0b, 0xfa, - 0x66, 0x98, 0x8d, 0x43, 0xac, 0x0b, 0x2a, 0x2a, 0xae, 0xf1, 0x36, 0xcc, 0xa9, 0xb4, 0x08, 0xdd, - 0x51, 0x4f, 0x95, 0x7f, 0x65, 0xfc, 0x7b, 0x01, 0xaa, 0x3b, 0x3b, 0xb7, 0xb5, 0x7d, 0xba, 0x03, - 0xe7, 0x98, 0xcc, 0x83, 0x58, 0x69, 0x87, 0x34, 0x58, 0xf5, 0xfa, 0x7e, 0x8f, 0x86, 0xd4, 0x56, - 0xf6, 0xea, 0x85, 0xa3, 0xc3, 0xfa, 0xb9, 0x56, 0x9e, 0x00, 0xe6, 0x97, 0x23, 0x1b, 0x70, 0x36, - 0xc9, 0x50, 0xa6, 0x57, 0x65, 0x7b, 0xc9, 0xfb, 0x99, 0x61, 0x36, 0xe6, 0x95, 0x21, 0xeb, 0x40, - 0x92, 0x64, 0x99, 0x22, 0xa1, 0xd2, 0x95, 0xcf, 0xcb, 0x1b, 0xbc, 0x2c, 0x17, 0x73, 0x4a, 0x18, - 0xb3, 0x50, 0x4d, 0x64, 0xaa, 0x1b, 0xff, 0x71, 0x01, 0xf4, 0x9d, 0xff, 0xcf, 0x32, 0x07, 0x46, - 0x72, 0x97, 0x2d, 0xed, 0xbc, 0x14, 0xc7, 0x77, 0x5e, 0xf4, 0x5c, 0xcf, 0x38, 0x30, 0x9d, 0xd8, - 0x81, 0x29, 0x9d, 0x80, 0x03, 0xa3, 0xad, 0xcf, 0x90, 0x13, 0xf3, 0x07, 0x05, 0x98, 0x71, 0x3d, - 0x9b, 0x46, 0x36, 0xae, 0x36, 0x2d, 0x0e, 0xcd, 0x77, 0xc6, 0xea, 0xc4, 0xc6, 0x56, 0x02, 0x51, - 0x06, 0x96, 0x74, 0xf4, 0x23, 0xc9, 0xc2, 0x94, 0x6a, 0xb2, 0x0e, 0x65, 0xb3, 0xcd, 0xbd, 0xce, - 0xf0, 0x40, 0x25, 0x2f, 0x5c, 0xcc, 0xb3, 0x7a, 0x2b, 0x4a, 0x46, 0x6e, 0x28, 0xd1, 0x17, 0xea, - 0xb2, 0x7c, 0x47, 0xd6, 0xb9, 0x74, 0x95, 0x31, 0x76, 0xe4, 0x28, 0x42, 0x96, 0x38, 0xcb, 0x29, - 0x4a, 0x22, 0xb5, 0xce, 0x80, 0x92, 0xf4, 0x6b, 0x85, 0x53, 0x5f, 0x96, 0x2e, 0x8a, 0xf4, 0x79, - 0x51, 0x71, 0x48, 0x27, 0xf2, 0x48, 0xaa, 0xa2, 0x73, 0x9b, 0x23, 0x7b, 0x69, 0xda, 0xc9, 0xc9, - 0x77, 0x49, 0xc8, 0xcd, 0xe4, 0xc6, 0x31, 0xf3, 0x24, 0x1b, 0xc7, 0xec, 0xb1, 0x9b, 0x46, 0x07, - 0x4a, 0x4c, 0x6c, 0x4b, 0xc2, 0x99, 0xaf, 0x5e, 0x59, 0x1d, 0xed, 0x54, 0x93, 0xda, 0xd9, 0x64, - 0xef, 0x48, 0x1a, 0x2a, 0x78, 0xe2, 0x41, 0x39, 0x50, 0x87, 0x76, 0x15, 0x0f, 0x18, 0xed, 0x2e, - 0x22, 0x7b, 0xf2, 0x97, 0xf3, 0x23, 0xa2, 0xa2, 0x56, 0x42, 0xde, 0x81, 0x49, 0xdb, 0xec, 0xa8, - 0xc8, 0xc0, 0xd7, 0x47, 0x4e, 0xdf, 0x88, 0xd4, 0x88, 0x14, 0xf1, 0xb5, 0x95, 0xeb, 0xc8, 0x51, - 0xc9, 0x5e, 0x9c, 0xd3, 0x37, 0x3f, 0x46, 0xe6, 0x75, 0x66, 0xa7, 0x93, 0xbe, 0xe2, 0x50, 0x56, - 0xe0, 0x35, 0x98, 0x7e, 0xe8, 0xf5, 0x06, 0x7d, 0x15, 0x52, 0xa8, 0x5e, 0x59, 0xcc, 0x1b, 0xed, - 0x7b, 0x42, 0x24, 0x36, 0x02, 0xf2, 0x9b, 0x61, 0x54, 0x96, 0xfc, 0x76, 0x01, 0x4e, 0xf3, 0xa5, - 0xa3, 0xe7, 0x01, 0xab, 0x91, 0x31, 0x66, 0xea, 0x5d, 0xc6, 0x37, 0xc5, 0x68, 0x86, 0x9d, 0x57, - 0x6a, 0x4f, 0x6f, 0xa4, 0x34, 0x60, 0x46, 0x23, 0xf1, 0xa1, 0xcc, 0x1c, 0x9b, 0x5a, 0x66, 0xc0, - 0x6a, 0x67, 0x4f, 0x4c, 0x7b, 0x7c, 0x98, 0x56, 0xd8, 0xa8, 0xb5, 0x90, 0xdf, 0x11, 0xd9, 0xf2, - 0xea, 0xbd, 0x88, 0x7a, 0xc3, 0xb3, 0x70, 0x92, 0x6f, 0x78, 0xce, 0xca, 0x54, 0xf9, 0x94, 0x06, - 0xcc, 0xaa, 0xe4, 0xc7, 0x10, 0x99, 0x47, 0x98, 0x4d, 0xec, 0x3c, 0x27, 0x6e, 0x8b, 0xc4, 0x31, - 0x64, 0x25, 0x4f, 0x00, 0xf3, 0xcb, 0x91, 0x0f, 0x60, 0x36, 0x48, 0x3a, 0x62, 0xb5, 0xf3, 0x63, - 0xa4, 0x2a, 0xa4, 0x5c, 0x3a, 0x19, 0xb2, 0x4a, 0x91, 0x30, 0xad, 0x8b, 0xbc, 0x06, 0x55, 0x5f, - 0x59, 0x2a, 0x87, 0xf5, 0x6b, 0x17, 0x44, 0x1b, 0xc4, 0x8e, 0xba, 0x1d, 0x93, 0x31, 0x29, 0x43, - 0xee, 0x42, 0x35, 0xf4, 0x7a, 0x34, 0x50, 0xd7, 0x2a, 0x35, 0x31, 0xf8, 0x4b, 0x79, 0x33, 0x79, - 0x47, 0x8b, 0xc5, 0x41, 0xfb, 0x98, 0xc6, 0x30, 0x89, 0xc3, 0x1d, 0xfa, 0x28, 0x8f, 0x37, 0x10, - 0xd1, 0x8b, 0x17, 0xd2, 0x0e, 0x7d, 0x2b, 0xc9, 0xc4, 0xb4, 0x2c, 0x77, 0xd1, 0xfd, 0xc0, 0xf1, - 0x02, 0x27, 0x3c, 0x58, 0xed, 0x99, 0x8c, 0x09, 0x80, 0x45, 0x01, 0xa0, 0x5d, 0xf4, 0xed, 0xac, - 0x00, 0x0e, 0x97, 0xe1, 0x7e, 0x50, 0x44, 0xac, 0x7d, 0x4e, 0x1c, 0xdf, 0x84, 0x59, 0x8a, 0xca, - 0xa2, 0xe6, 0x1e, 0x93, 0xb8, 0x75, 0x71, 0x94, 0xc4, 0x2d, 0x62, 0xc3, 0x45, 0x73, 0x10, 0x7a, - 0x7d, 0x4e, 0x48, 0x17, 0xd9, 0xf1, 0xf6, 0xa8, 0x5b, 0xbb, 0x24, 0xf6, 0xaa, 0x4b, 0x47, 0x87, - 0xf5, 0x8b, 0x2b, 0x8f, 0x91, 0xc3, 0xc7, 0xa2, 0x90, 0x3e, 0x94, 0xa9, 0x4a, 0x3e, 0xab, 0x7d, - 0x7e, 0x8c, 0x4d, 0x22, 0x9d, 0xc1, 0x26, 0x3b, 0x28, 0xa2, 0xa1, 0x56, 0x41, 0x76, 0xa0, 0xda, - 0xf5, 0x58, 0xb8, 0xd2, 0x73, 0x4c, 0x46, 0x59, 0xed, 0x45, 0x31, 0x4f, 0x72, 0xf7, 0xb7, 0x1b, - 0x91, 0x58, 0x3c, 0x4d, 0x6e, 0xc4, 0x25, 0x31, 0x09, 0x43, 0xa8, 0x70, 0x0a, 0x07, 0x62, 0xd4, - 0x3c, 0x37, 0xa4, 0xef, 0x87, 0xb5, 0x25, 0xd1, 0x96, 0x97, 0xf3, 0x90, 0xb7, 0x3d, 0xbb, 0x95, - 0x96, 0x96, 0xab, 0x3c, 0x43, 0xc4, 0x2c, 0x26, 0x79, 0x1d, 0x66, 0x7c, 0xcf, 0x6e, 0xf9, 0xd4, - 0xda, 0x36, 0x43, 0xab, 0x5b, 0xab, 0xa7, 0x2f, 0x85, 0xb6, 0x13, 0x3c, 0x4c, 0x49, 0x2e, 0xbe, - 0x0d, 0x67, 0x86, 0xce, 0x53, 0x4f, 0x75, 0x83, 0xf6, 0xa7, 0xdc, 0xef, 0x49, 0x9c, 0x60, 0x4f, - 0xfa, 0xdc, 0x7f, 0x1d, 0xce, 0xa8, 0x37, 0xb8, 0x7c, 0xb3, 0xed, 0x0d, 0xf4, 0xab, 0x95, 0x44, - 0x38, 0x0b, 0xb3, 0x02, 0x38, 0x5c, 0xc6, 0xf8, 0xb3, 0x02, 0xcc, 0xa6, 0xcc, 0xf7, 0x89, 0x7b, - 0xc2, 0xeb, 0x40, 0xfa, 0x4e, 0x10, 0x78, 0x81, 0xdc, 0x03, 0x37, 0xf9, 0x5c, 0x66, 0xea, 0xf1, - 0x8b, 0x70, 0xab, 0x36, 0x87, 0xb8, 0x98, 0x53, 0xc2, 0xf8, 0xeb, 0x02, 0xc4, 0xf1, 0x52, 0x9d, - 0x71, 0x56, 0x38, 0x36, 0xe3, 0xec, 0x15, 0x28, 0x3f, 0x60, 0x9e, 0xbb, 0x1d, 0xe7, 0xa5, 0xe9, - 0x0e, 0xbd, 0xd9, 0xba, 0xb3, 0x25, 0x24, 0xb5, 0x84, 0x90, 0x7e, 0x6f, 0xdd, 0xe9, 0x85, 0xc3, - 0xd9, 0x5b, 0x37, 0x7f, 0x59, 0xd2, 0x51, 0x4b, 0x90, 0x65, 0xa8, 0xe8, 0x10, 0xbd, 0x72, 0xa1, - 0x75, 0x27, 0xe8, 0xf8, 0x34, 0xc6, 0x32, 0xc6, 0x0f, 0x27, 0xa0, 0xfc, 0x1c, 0x5f, 0xf2, 0x58, - 0xa9, 0x97, 0x3c, 0x27, 0xf0, 0xec, 0x23, 0xef, 0x15, 0xcf, 0x5e, 0xe6, 0x15, 0xcf, 0xea, 0x98, - 0x51, 0xff, 0xc7, 0xbe, 0xe0, 0xf9, 0xb8, 0x00, 0x33, 0xcf, 0xf1, 0xf5, 0xce, 0x6e, 0xfa, 0xf5, - 0xce, 0x9b, 0x63, 0x35, 0xed, 0x98, 0x97, 0x3b, 0x7f, 0xb5, 0x00, 0xa9, 0x57, 0x33, 0xc4, 0x85, - 0x4a, 0xb4, 0xc0, 0xa3, 0x9b, 0x94, 0x37, 0xc7, 0x72, 0x0a, 0xe3, 0x49, 0x19, 0x51, 0x18, 0xc6, - 0x2a, 0xc8, 0x15, 0x00, 0xca, 0x2d, 0x9b, 0x8c, 0x57, 0x4e, 0xa4, 0x2f, 0x1a, 0xae, 0x69, 0x0e, - 0x26, 0xa4, 0x9e, 0x7f, 0xc0, 0x21, 0x7f, 0x8b, 0x9e, 0x7a, 0x26, 0x5b, 0xf4, 0xc5, 0x13, 0xdf, - 0xa2, 0x5f, 0x7c, 0xf6, 0x5b, 0x74, 0xc2, 0x21, 0x29, 0x8e, 0xe1, 0x90, 0x7c, 0x00, 0x0b, 0xf2, - 0xe7, 0x6a, 0xcf, 0x74, 0xfa, 0x7a, 0xbe, 0xa8, 0xd4, 0xb1, 0x2f, 0xe6, 0x6e, 0xcc, 0x34, 0x60, - 0x0e, 0x0b, 0xa9, 0x1b, 0xde, 0x8b, 0x4b, 0xc6, 0x79, 0x07, 0xf7, 0x72, 0xe0, 0x30, 0x57, 0x49, - 0xf6, 0x04, 0x3b, 0xfd, 0x04, 0x27, 0xd8, 0x1f, 0x14, 0xe0, 0x9c, 0x99, 0xf7, 0x30, 0x58, 0xc5, - 0x31, 0x6e, 0x8e, 0xe5, 0x4f, 0xa4, 0x10, 0x95, 0x3f, 0x90, 0xc7, 0xc2, 0xfc, 0x3a, 0x90, 0x2f, - 0xc4, 0x2e, 0x69, 0x45, 0x4c, 0xaa, 0x7c, 0x67, 0xf2, 0xdb, 0xd9, 0x50, 0x10, 0x88, 0xde, 0x6e, - 0x8d, 0x6d, 0xb0, 0x4f, 0x20, 0x1c, 0x54, 0x1d, 0x23, 0x1c, 0x94, 0x71, 0x2f, 0x66, 0x4e, 0xc8, - 0xbd, 0x70, 0x61, 0xde, 0xe9, 0x9b, 0x1d, 0xba, 0x3d, 0xe8, 0xf5, 0x64, 0xd4, 0x9f, 0xd5, 0x66, - 0x05, 0x76, 0x6e, 0xbe, 0x2f, 0x77, 0xf7, 0x7a, 0xd9, 0x07, 0x65, 0xfa, 0x7e, 0x6d, 0x23, 0x83, - 0x84, 0x43, 0xd8, 0x7c, 0x5a, 0xf2, 0x63, 0xeb, 0x16, 0x0d, 0x79, 0x6f, 0x8b, 0x48, 0x89, 0xfa, - 0x07, 0x08, 0x37, 0x62, 0x32, 0x26, 0x65, 0xc8, 0x2d, 0xa8, 0xd8, 0x2e, 0x53, 0xb7, 0x6b, 0x73, - 0xc2, 0x4a, 0xbd, 0xca, 0x6d, 0xdb, 0xda, 0x56, 0x4b, 0xdf, 0xab, 0x5d, 0x1c, 0xfe, 0x0f, 0x2f, - 0x0d, 0xcd, 0xc7, 0xb8, 0x3c, 0xd9, 0x14, 0x60, 0x2a, 0xf9, 0x5d, 0x86, 0x36, 0x2e, 0x1d, 0x73, - 0x42, 0x5e, 0xdb, 0x8a, 0x72, 0xf5, 0x67, 0x95, 0x3a, 0x95, 0xd2, 0x1e, 0x23, 0x24, 0x5e, 0xe9, - 0x9c, 0x79, 0xdc, 0x2b, 0x1d, 0x72, 0x17, 0x2e, 0x84, 0x61, 0x2f, 0x15, 0xed, 0x56, 0x79, 0x29, - 0x22, 0x49, 0xa9, 0x28, 0x1f, 0x3e, 0xee, 0xec, 0xdc, 0xce, 0x13, 0xc1, 0xe3, 0xca, 0x8a, 0xd0, - 0x71, 0xd8, 0xd3, 0x1e, 0xf2, 0xd2, 0x38, 0xa1, 0xe3, 0xf8, 0x4a, 0x41, 0x85, 0x8e, 0x63, 0x02, - 0x26, 0xb5, 0x1c, 0xef, 0xe9, 0x9f, 0x1d, 0xd1, 0xd3, 0x4f, 0x3a, 0x97, 0x0b, 0x8f, 0x75, 0x2e, - 0x87, 0x9c, 0xe1, 0x73, 0x4f, 0xe1, 0x0c, 0xbf, 0x23, 0xd2, 0x7f, 0xae, 0xaf, 0xaa, 0x40, 0xc2, - 0x1b, 0xa3, 0xc5, 0x2f, 0x39, 0x82, 0xbc, 0x04, 0x16, 0x3f, 0x51, 0x62, 0x92, 0x6d, 0x58, 0xf0, - 0x3d, 0x7b, 0xc8, 0x97, 0x16, 0x91, 0x83, 0x44, 0xe2, 0xd8, 0x76, 0x8e, 0x0c, 0xe6, 0x96, 0x14, - 0x06, 0x3c, 0xa6, 0xd7, 0x6a, 0xa2, 0x63, 0xa4, 0x01, 0x8f, 0xc9, 0x98, 0x94, 0xc9, 0xba, 0x96, - 0x2f, 0x3c, 0x33, 0xd7, 0x72, 0xf1, 0x39, 0xb8, 0x96, 0x9f, 0x7b, 0x7e, 0xae, 0xe5, 0x9f, 0x57, - 0xe0, 0x74, 0xe6, 0x65, 0xad, 0xce, 0xbc, 0x2b, 0x3c, 0x69, 0xe6, 0x5d, 0x2a, 0x35, 0x6e, 0xe2, - 0x99, 0xa6, 0xc6, 0x4d, 0x9e, 0x78, 0x6a, 0x5c, 0x22, 0x05, 0x70, 0xea, 0x33, 0x52, 0x00, 0x57, - 0x60, 0xce, 0xf2, 0xfa, 0xbe, 0x78, 0xa2, 0xa3, 0x12, 0xc1, 0x64, 0xb2, 0x86, 0xbe, 0x57, 0x5e, - 0x4d, 0xb3, 0x31, 0x2b, 0x4f, 0x7e, 0x03, 0x8a, 0xae, 0x28, 0x58, 0x1a, 0x23, 0xf7, 0x38, 0x3d, - 0x60, 0x62, 0x77, 0x56, 0xe9, 0xbf, 0x51, 0xac, 0xb6, 0x28, 0x68, 0x8f, 0xa2, 0x1f, 0x28, 0x95, - 0x72, 0x47, 0xdf, 0x6b, 0xb7, 0x7b, 0x9e, 0x69, 0xc7, 0x09, 0xb9, 0xea, 0xda, 0x43, 0x3b, 0xfa, - 0x77, 0xb2, 0x02, 0x38, 0x5c, 0x86, 0x9f, 0x97, 0xe6, 0xd2, 0x19, 0xa4, 0xac, 0x56, 0x11, 0x2d, - 0xfa, 0x95, 0x93, 0x68, 0x51, 0x3a, 0x5d, 0x55, 0xb5, 0x2d, 0xbe, 0xbc, 0x4f, 0x73, 0x31, 0x5b, - 0x13, 0x12, 0xc0, 0x79, 0x3f, 0xef, 0x34, 0xc9, 0xd4, 0xe5, 0xd8, 0xe3, 0xce, 0xb4, 0x4b, 0x4a, - 0xcb, 0xf9, 0xdc, 0xf3, 0x28, 0xc3, 0x63, 0x90, 0x93, 0x19, 0x8b, 0xe5, 0x67, 0x95, 0xb1, 0xb8, - 0x78, 0x20, 0x33, 0xa9, 0x8f, 0x4d, 0xc2, 0xbe, 0x9b, 0x7e, 0x18, 0xf1, 0xf6, 0x88, 0xff, 0xba, - 0x4c, 0x8f, 0x7c, 0x22, 0x01, 0xfc, 0xb7, 0x0a, 0xb0, 0x90, 0x37, 0x2c, 0x39, 0xb5, 0x68, 0xa5, - 0x6b, 0x31, 0x9e, 0xd7, 0x99, 0x34, 0x56, 0xdf, 0x2d, 0x25, 0x7c, 0xdc, 0x90, 0xfa, 0x3f, 0xbb, - 0x00, 0x1f, 0xe9, 0x02, 0x3c, 0xf5, 0x08, 0xbe, 0xf8, 0x1c, 0x1f, 0xc1, 0x97, 0x46, 0x78, 0x04, - 0x3f, 0xfd, 0x3c, 0x1f, 0xc1, 0x97, 0x9f, 0xf0, 0x11, 0x7c, 0xe5, 0x7f, 0xcf, 0x23, 0xf8, 0x4f, - 0x0b, 0x30, 0x9f, 0xcd, 0xc9, 0x7f, 0x0e, 0x31, 0xc1, 0xbd, 0x54, 0x4c, 0x70, 0x63, 0x2c, 0xa3, - 0xaf, 0xdf, 0x01, 0x1c, 0x13, 0x1b, 0x34, 0x7e, 0x52, 0x80, 0xa1, 0x77, 0x07, 0xcf, 0x21, 0x6c, - 0xf7, 0x20, 0x1d, 0xb6, 0xbb, 0x76, 0x22, 0x8d, 0x3c, 0x26, 0x7c, 0xf7, 0x9f, 0x39, 0x4d, 0xfc, - 0x1f, 0x09, 0xe3, 0xa5, 0x4c, 0xe0, 0xc4, 0xb3, 0x37, 0x81, 0xcd, 0xc6, 0x47, 0x9f, 0x2e, 0x9d, - 0xfa, 0xf8, 0xd3, 0xa5, 0x53, 0x9f, 0x7c, 0xba, 0x74, 0xea, 0xc3, 0xa3, 0xa5, 0xc2, 0x47, 0x47, - 0x4b, 0x85, 0x8f, 0x8f, 0x96, 0x0a, 0x9f, 0x1c, 0x2d, 0x15, 0x7e, 0x72, 0xb4, 0x54, 0xf8, 0xce, - 0x3f, 0x2e, 0x9d, 0xfa, 0xd5, 0x72, 0x84, 0xfb, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbb, 0x06, - 0x64, 0xef, 0x7b, 0x55, 0x00, 0x00, + 0x17, 0xc7, 0x80, 0x2f, 0x41, 0x0e, 0xc9, 0x25, 0x97, 0x00, 0x39, 0xe5, 0xe0, 0x00, 0x46, 0x0e, + 0x0b, 0x5f, 0xb2, 0xc8, 0x25, 0x7b, 0x08, 0x08, 0x2f, 0x03, 0x04, 0x01, 0x12, 0x20, 0x40, 0x2e, + 0x46, 0x74, 0x0a, 0xea, 0xa3, 0xab, 0x3f, 0xa6, 0xa9, 0x95, 0x66, 0x28, 0x25, 0x81, 0x7d, 0xe2, + 0xf4, 0x7b, 0xaf, 0x7e, 0xaf, 0x3e, 0x5f, 0xd5, 0x7b, 0xf5, 0x8a, 0xb0, 0xda, 0x71, 0xc2, 0xee, + 0x60, 0xb7, 0x61, 0x79, 0xfd, 0x65, 0x33, 0xe8, 0x78, 0x7e, 0xe0, 0x3d, 0x10, 0x3f, 0x96, 0xfd, + 0xbd, 0xce, 0xb2, 0xe9, 0x3b, 0x6c, 0x79, 0xdf, 0x0b, 0xf6, 0xda, 0x3d, 0x6f, 0x7f, 0xf9, 0xe1, + 0x6b, 0x66, 0xcf, 0xef, 0x9a, 0xaf, 0x2d, 0x77, 0xa8, 0x4b, 0x03, 0x33, 0xa4, 0x76, 0xc3, 0x0f, + 0xbc, 0xd0, 0x23, 0x57, 0x63, 0x90, 0x46, 0x04, 0x22, 0x7e, 0x34, 0xfc, 0xbd, 0x4e, 0x83, 0x83, + 0x34, 0x22, 0x90, 0x46, 0x04, 0xb2, 0xf8, 0x6a, 0x42, 0x73, 0xc7, 0xe3, 0x0a, 0x39, 0xd6, 0xee, + 0xa0, 0x2d, 0xbe, 0xc4, 0x87, 0xf8, 0x25, 0x75, 0x2c, 0x1a, 0x7b, 0xaf, 0xb3, 0x86, 0xe3, 0xf1, + 0x2a, 0x2d, 0x5b, 0x5e, 0x40, 0x97, 0x1f, 0x0e, 0xd5, 0x63, 0xf1, 0xcb, 0xb1, 0x4c, 0xdf, 0xb4, + 0xba, 0x8e, 0x4b, 0x83, 0x83, 0xb8, 0x1d, 0x7d, 0x1a, 0x9a, 0x79, 0xa5, 0x96, 0x8f, 0x2b, 0x15, + 0x0c, 0xdc, 0xd0, 0xe9, 0xd3, 0xa1, 0x02, 0xbf, 0xf4, 0x59, 0x05, 0x98, 0xd5, 0xa5, 0x7d, 0x33, + 0x5b, 0xce, 0xf8, 0xfb, 0x02, 0xcc, 0xad, 0x04, 0x56, 0xd7, 0x79, 0x48, 0x5b, 0x21, 0x67, 0x74, + 0x0e, 0xc8, 0x3b, 0x30, 0x19, 0x9a, 0x41, 0xad, 0x70, 0xa9, 0x70, 0xb9, 0x7a, 0xe5, 0xeb, 0x8d, + 0x11, 0x3a, 0xb2, 0xb1, 0x63, 0x06, 0x11, 0x5c, 0x73, 0xfa, 0xe8, 0xb0, 0x3e, 0xb9, 0x63, 0x06, + 0xc8, 0x51, 0xc9, 0xb7, 0x60, 0xca, 0xf5, 0x5c, 0x5a, 0x9b, 0x10, 0xe8, 0x2b, 0x23, 0xa1, 0x6f, + 0x79, 0xae, 0xae, 0x6d, 0xb3, 0x7c, 0x74, 0x58, 0x9f, 0xe2, 0x14, 0x14, 0xc0, 0xc6, 0x7f, 0x14, + 0xa0, 0xb2, 0x12, 0x74, 0x06, 0x7d, 0xea, 0x86, 0x8c, 0x04, 0x00, 0xbe, 0x19, 0x98, 0x7d, 0x1a, + 0xd2, 0x80, 0xd5, 0x0a, 0x97, 0x26, 0x2f, 0x57, 0xaf, 0xbc, 0x35, 0x92, 0xd2, 0xed, 0x08, 0xa6, + 0x49, 0x3e, 0x3a, 0xac, 0x9f, 0x3a, 0x3a, 0xac, 0x83, 0x26, 0x31, 0x4c, 0x68, 0x21, 0x2e, 0x54, + 0xcc, 0x20, 0x74, 0xda, 0xa6, 0x15, 0xb2, 0xda, 0x84, 0x50, 0xf9, 0xe6, 0x48, 0x2a, 0x57, 0x14, + 0x4a, 0xf3, 0x8c, 0xd2, 0x58, 0x89, 0x28, 0x0c, 0x63, 0x15, 0xc6, 0xbf, 0x4d, 0x42, 0x39, 0x62, + 0x90, 0x4b, 0x30, 0xe5, 0x9a, 0x7d, 0x2a, 0x46, 0xaf, 0xd2, 0x9c, 0x51, 0x05, 0xa7, 0xb6, 0xcc, + 0x3e, 0xef, 0x20, 0xb3, 0x4f, 0xb9, 0x84, 0x6f, 0x86, 0x5d, 0x31, 0x02, 0x09, 0x89, 0x6d, 0x33, + 0xec, 0xa2, 0xe0, 0x90, 0x8b, 0x30, 0xd5, 0xf7, 0x6c, 0x5a, 0x9b, 0xbc, 0x54, 0xb8, 0x5c, 0x94, + 0x1d, 0xbc, 0xe9, 0xd9, 0x14, 0x05, 0x95, 0x97, 0x6f, 0x07, 0x5e, 0xbf, 0x36, 0x95, 0x2e, 0xbf, + 0x1e, 0x78, 0x7d, 0x14, 0x1c, 0xf2, 0xc7, 0x05, 0x98, 0x8f, 0xaa, 0x77, 0xdb, 0xb3, 0xcc, 0xd0, + 0xf1, 0xdc, 0x5a, 0x51, 0x0c, 0xf8, 0xb5, 0xb1, 0x3a, 0x22, 0x02, 0x6b, 0xd6, 0x94, 0xd6, 0xf9, + 0x2c, 0x07, 0x87, 0x14, 0x93, 0x2b, 0x00, 0x9d, 0x9e, 0xb7, 0x6b, 0xf6, 0x78, 0x1f, 0xd4, 0x4a, + 0xa2, 0xd6, 0x7a, 0x08, 0xaf, 0x6b, 0x0e, 0x26, 0xa4, 0xc8, 0x1e, 0x4c, 0x9b, 0x72, 0x55, 0xd4, + 0xa6, 0x45, 0xbd, 0xd7, 0x46, 0xac, 0x77, 0x6a, 0x65, 0x35, 0xab, 0x47, 0x87, 0xf5, 0x69, 0x45, + 0xc4, 0x48, 0x03, 0x79, 0x05, 0xca, 0x9e, 0xcf, 0xab, 0x6a, 0xf6, 0x6a, 0xe5, 0x4b, 0x85, 0xcb, + 0xe5, 0xe6, 0xbc, 0xaa, 0x5e, 0xf9, 0x8e, 0xa2, 0xa3, 0x96, 0x30, 0xfe, 0xa4, 0x08, 0x43, 0xad, + 0x26, 0xaf, 0x41, 0x55, 0xa1, 0xdd, 0xf6, 0x3a, 0x4c, 0x0c, 0x7e, 0xb9, 0x39, 0x77, 0x74, 0x58, + 0xaf, 0xae, 0xc4, 0x64, 0x4c, 0xca, 0x90, 0xfb, 0x30, 0xc1, 0xae, 0xaa, 0x65, 0xf8, 0xf6, 0x48, + 0xad, 0x6b, 0x5d, 0xd5, 0x13, 0xb4, 0x74, 0x74, 0x58, 0x9f, 0x68, 0x5d, 0xc5, 0x09, 0x76, 0x95, + 0x9b, 0x8f, 0x8e, 0x13, 0x8a, 0xc9, 0x33, 0xaa, 0xf9, 0xb8, 0xee, 0x84, 0x1a, 0x5a, 0x98, 0x8f, + 0xeb, 0x4e, 0x88, 0x1c, 0x95, 0x9b, 0x8f, 0x6e, 0x18, 0xfa, 0x62, 0xf2, 0x8d, 0x6a, 0x3e, 0x6e, + 0xec, 0xec, 0x6c, 0x6b, 0x78, 0x31, 0xbb, 0x39, 0x05, 0x05, 0x30, 0xf9, 0x80, 0xf7, 0xa4, 0xe4, + 0x79, 0xc1, 0x81, 0x9a, 0xb5, 0x37, 0xc6, 0x9a, 0xb5, 0x5e, 0x70, 0xa0, 0xd5, 0xa9, 0x31, 0xd1, + 0x0c, 0x4c, 0x6a, 0x13, 0xad, 0xb3, 0xdb, 0x4c, 0x4c, 0xd2, 0x91, 0x5b, 0xb7, 0xb6, 0xde, 0xca, + 0xb4, 0x6e, 0x6d, 0xbd, 0x85, 0x02, 0x98, 0x8f, 0x4d, 0x60, 0xee, 0xab, 0x39, 0x3d, 0xda, 0xd8, + 0xa0, 0xb9, 0x9f, 0x1e, 0x1b, 0x34, 0xf7, 0x91, 0xa3, 0x1a, 0x1d, 0x38, 0x17, 0x71, 0x90, 0xfa, + 0x1e, 0x73, 0x44, 0x03, 0x69, 0x9b, 0x2c, 0x43, 0xc5, 0xf2, 0xdc, 0xb6, 0xd3, 0xd9, 0x34, 0x7d, + 0x65, 0x98, 0xb4, 0x45, 0x5b, 0x8d, 0x18, 0x18, 0xcb, 0x90, 0x17, 0x61, 0x72, 0x8f, 0x1e, 0x28, + 0x0b, 0x55, 0x55, 0xa2, 0x93, 0xb7, 0xe8, 0x01, 0x72, 0xba, 0xf1, 0xc3, 0x02, 0x9c, 0xcd, 0xe9, + 0x5c, 0x5e, 0x6c, 0x10, 0xf4, 0x94, 0x06, 0x5d, 0xec, 0x2e, 0xde, 0x46, 0x4e, 0x27, 0x7f, 0x50, + 0x80, 0xb9, 0x44, 0x6f, 0xaf, 0x0c, 0x94, 0x11, 0x1c, 0x7d, 0x75, 0xa7, 0xb0, 0x9a, 0x17, 0x94, + 0xc6, 0xb9, 0x0c, 0x03, 0xb3, 0x5a, 0x8d, 0x7f, 0x14, 0xbb, 0x6e, 0x8a, 0x46, 0x4c, 0x38, 0x3d, + 0x60, 0x34, 0xe0, 0x26, 0xba, 0x45, 0xad, 0x80, 0x86, 0x6a, 0x03, 0xfe, 0x42, 0x43, 0x6e, 0xed, + 0xbc, 0x16, 0x0d, 0x7e, 0xca, 0x68, 0x3c, 0x7c, 0xad, 0x21, 0x25, 0x6e, 0xd1, 0x83, 0x16, 0xed, + 0x51, 0x8e, 0xd1, 0x24, 0x47, 0x87, 0xf5, 0xd3, 0x77, 0x53, 0x00, 0x98, 0x01, 0xe4, 0x2a, 0x7c, + 0x93, 0xb1, 0x7d, 0x2f, 0xb0, 0x95, 0x8a, 0x89, 0xa7, 0x56, 0xb1, 0x9d, 0x02, 0xc0, 0x0c, 0xa0, + 0xf1, 0xbd, 0x02, 0x4c, 0x37, 0x4d, 0x6b, 0xcf, 0x6b, 0xb7, 0xb9, 0x5d, 0xb3, 0x07, 0x81, 0xb4, + 0xfe, 0x72, 0x4c, 0xb4, 0x5d, 0x5b, 0x53, 0x74, 0xd4, 0x12, 0xe4, 0x65, 0x28, 0xc9, 0xee, 0x10, + 0x95, 0x2a, 0x36, 0x4f, 0x2b, 0xd9, 0xd2, 0xba, 0xa0, 0xa2, 0xe2, 0x92, 0xaf, 0x40, 0xb5, 0x6f, + 0xbe, 0x1f, 0x01, 0x08, 0x33, 0x53, 0x69, 0x9e, 0x55, 0xc2, 0xd5, 0xcd, 0x98, 0x85, 0x49, 0x39, + 0xe3, 0x1b, 0x00, 0xab, 0x9e, 0x1b, 0x3a, 0xee, 0x80, 0xde, 0x71, 0xc9, 0x4b, 0x50, 0xa4, 0x41, + 0xe0, 0x05, 0xca, 0x52, 0xce, 0xaa, 0xe2, 0xc5, 0x6b, 0x9c, 0x88, 0x92, 0x27, 0x6b, 0xe4, 0xf4, + 0xa8, 0x2d, 0x6a, 0x54, 0x4e, 0xd6, 0x88, 0x53, 0x51, 0x71, 0x8d, 0x1f, 0x4f, 0xc0, 0xcc, 0x6a, + 0xe0, 0xb9, 0xf7, 0xd5, 0x0c, 0x21, 0xbf, 0x01, 0x65, 0x7e, 0xb0, 0xb3, 0xcd, 0xd0, 0x54, 0x83, + 0xf8, 0xa5, 0x44, 0x0f, 0xeb, 0xf3, 0x59, 0x3c, 0xb7, 0xb8, 0x34, 0xef, 0xf3, 0x3b, 0xbb, 0x0f, + 0xa8, 0x15, 0x6e, 0xd2, 0xd0, 0x8c, 0x77, 0xa8, 0x98, 0x86, 0x1a, 0x95, 0x74, 0x60, 0x8a, 0xf9, + 0xd4, 0x52, 0xe3, 0x37, 0xda, 0xa6, 0x9a, 0xac, 0x72, 0xcb, 0xa7, 0x56, 0xbc, 0x95, 0xf3, 0x2f, + 0x14, 0x0a, 0x88, 0x07, 0x25, 0x16, 0x9a, 0xe1, 0x80, 0x29, 0x7b, 0x7e, 0x7d, 0x7c, 0x55, 0x02, + 0x2e, 0xee, 0x4c, 0xf9, 0x8d, 0x4a, 0x8d, 0xf1, 0x49, 0x01, 0xe6, 0x93, 0xe2, 0xb7, 0x1d, 0x16, + 0x92, 0x77, 0x87, 0x3a, 0xb4, 0xf1, 0x64, 0x1d, 0xca, 0x4b, 0x8b, 0xee, 0xd4, 0x33, 0x2f, 0xa2, + 0x24, 0x3a, 0xb3, 0x0d, 0x45, 0x27, 0xa4, 0xfd, 0xe8, 0xac, 0xb6, 0x32, 0x76, 0x13, 0xe3, 0xf9, + 0xb4, 0xc1, 0x71, 0x51, 0xc2, 0x1b, 0xdf, 0x29, 0xa6, 0x9b, 0xc6, 0xbb, 0x99, 0x9f, 0x95, 0x66, + 0xf6, 0x13, 0x04, 0xd5, 0xbe, 0xd1, 0x2a, 0x91, 0x1a, 0xce, 0xff, 0xa7, 0x2a, 0x31, 0x93, 0xa4, + 0x3e, 0xca, 0x7c, 0x63, 0x4a, 0x39, 0x5f, 0xb2, 0xdc, 0x51, 0xb0, 0x07, 0x3d, 0xaa, 0xac, 0xaf, + 0xee, 0xb8, 0x96, 0xa2, 0xa3, 0x96, 0x20, 0xef, 0xc2, 0x19, 0xcb, 0x73, 0xad, 0x41, 0x10, 0x50, + 0xd7, 0x3a, 0xd8, 0xf6, 0x7a, 0x8e, 0x75, 0xa0, 0x16, 0x64, 0x43, 0x15, 0x3b, 0xb3, 0x9a, 0x15, + 0x78, 0x94, 0x47, 0xc4, 0x61, 0x20, 0xf2, 0x45, 0x98, 0x66, 0x03, 0xe6, 0x53, 0xd7, 0x16, 0xbb, + 0x7d, 0xb9, 0x39, 0xa7, 0x30, 0xa7, 0x5b, 0x92, 0x8c, 0x11, 0x9f, 0xdc, 0x85, 0x0b, 0x2c, 0xe4, + 0x46, 0xd6, 0xed, 0xac, 0x51, 0xd3, 0xee, 0x39, 0x2e, 0x37, 0x79, 0x9e, 0x6b, 0x33, 0xb1, 0x81, + 0x4f, 0x36, 0x3f, 0x77, 0x74, 0x58, 0xbf, 0xd0, 0xca, 0x17, 0xc1, 0xe3, 0xca, 0x92, 0x6f, 0xc2, + 0x22, 0x1b, 0x58, 0x16, 0x65, 0xac, 0x3d, 0xe8, 0xdd, 0xf4, 0x76, 0xd9, 0x0d, 0x87, 0x71, 0x7b, + 0x7d, 0xdb, 0xe9, 0x3b, 0xa1, 0xd8, 0xa4, 0x8b, 0xcd, 0xa5, 0xa3, 0xc3, 0xfa, 0x62, 0xeb, 0x58, + 0x29, 0x7c, 0x0c, 0x02, 0x41, 0x38, 0x2f, 0x4d, 0xc8, 0x10, 0xf6, 0xb4, 0xc0, 0x5e, 0x3c, 0x3a, + 0xac, 0x9f, 0x5f, 0xcf, 0x95, 0xc0, 0x63, 0x4a, 0xf2, 0x11, 0xe4, 0xfe, 0xde, 0x6f, 0x72, 0x1f, + 0xab, 0x9c, 0x1e, 0xc1, 0x1d, 0x45, 0x47, 0x2d, 0x61, 0xfc, 0x43, 0x01, 0xc8, 0xf0, 0xe2, 0x24, + 0xb7, 0xa0, 0x64, 0x5a, 0x21, 0x3f, 0xfd, 0x4a, 0x8f, 0xe9, 0xa5, 0xbc, 0x0d, 0x42, 0x1a, 0x26, + 0xa4, 0x6d, 0xca, 0x47, 0x8d, 0xc6, 0x2b, 0x7a, 0x45, 0x14, 0x45, 0x05, 0x41, 0x3c, 0x38, 0xd3, + 0x33, 0x59, 0x18, 0xcd, 0x1f, 0x9b, 0x57, 0x43, 0x19, 0xae, 0x5f, 0x78, 0xb2, 0x55, 0xcc, 0x4b, + 0x34, 0xcf, 0xf1, 0xd9, 0x74, 0x3b, 0x0b, 0x84, 0xc3, 0xd8, 0xc6, 0x8f, 0x4a, 0x30, 0xbd, 0xb6, + 0x72, 0x7d, 0xc7, 0x64, 0x7b, 0x4f, 0xe0, 0x0e, 0xf1, 0x0e, 0xa3, 0x7d, 0xbf, 0x67, 0x86, 0x43, + 0x53, 0x7e, 0x47, 0xd1, 0x51, 0x4b, 0x10, 0x8f, 0xfb, 0x76, 0xca, 0xb9, 0x54, 0x26, 0xf1, 0xad, + 0x11, 0x0f, 0x0f, 0x0a, 0x25, 0xe9, 0xdc, 0x29, 0x12, 0xc6, 0x3a, 0x08, 0x83, 0x6a, 0xa4, 0x1c, + 0x69, 0x5b, 0x9d, 0x7b, 0x47, 0x74, 0xca, 0x63, 0x1c, 0x79, 0x0e, 0x4d, 0x10, 0x30, 0xa9, 0x85, + 0x7c, 0x19, 0x66, 0x6c, 0xca, 0x57, 0x16, 0x75, 0x2d, 0x87, 0xf2, 0x45, 0x34, 0xc9, 0xfb, 0x85, + 0x1b, 0x93, 0xb5, 0x04, 0x1d, 0x53, 0x52, 0xe4, 0x01, 0x54, 0xf6, 0x9d, 0xb0, 0x2b, 0x6c, 0x5e, + 0xad, 0x24, 0x26, 0xce, 0x57, 0x47, 0xaa, 0x28, 0x47, 0x88, 0xbb, 0xe5, 0x7e, 0x84, 0x89, 0x31, + 0x3c, 0x3f, 0x52, 0xf2, 0x0f, 0xe1, 0x81, 0x8b, 0xd5, 0x52, 0x49, 0x17, 0x10, 0x0c, 0x8c, 0x65, + 0x08, 0x83, 0x19, 0xfe, 0xd1, 0xa2, 0xef, 0x0d, 0xf8, 0x6c, 0x15, 0x6b, 0x63, 0x54, 0xbf, 0x3c, + 0x02, 0x91, 0x3d, 0x72, 0x3f, 0x01, 0x8b, 0x29, 0x25, 0x7c, 0xf6, 0xed, 0x77, 0xa9, 0x5b, 0xab, + 0xa4, 0x67, 0xdf, 0xfd, 0x2e, 0x75, 0x51, 0x70, 0x88, 0x07, 0x60, 0xe9, 0x63, 0x49, 0x0d, 0xc6, + 0xf0, 0xc6, 0xe2, 0xd3, 0x4d, 0xf3, 0x34, 0x3f, 0x37, 0xc4, 0xdf, 0x98, 0x50, 0xc1, 0x0f, 0x35, + 0x9e, 0x7b, 0xed, 0x7d, 0x27, 0xac, 0x55, 0x45, 0xa5, 0xf4, 0xaa, 0xbd, 0x23, 0xa8, 0xa8, 0xb8, + 0xc6, 0x8f, 0x0a, 0x50, 0xe5, 0x8b, 0x28, 0x9a, 0xf8, 0x2f, 0x43, 0x29, 0x34, 0x83, 0x8e, 0x3a, + 0x96, 0x26, 0xca, 0xed, 0x08, 0x2a, 0x2a, 0x2e, 0x31, 0xa1, 0x18, 0x9a, 0x6c, 0x2f, 0xda, 0x4c, + 0x7f, 0x65, 0xa4, 0xb6, 0xa8, 0xd5, 0x1b, 0xef, 0xa3, 0xfc, 0x8b, 0xa1, 0x44, 0x26, 0x97, 0xa1, + 0xcc, 0x8d, 0xdf, 0xba, 0xc9, 0xa4, 0x97, 0x59, 0x6e, 0xce, 0xf0, 0xd5, 0xba, 0xae, 0x68, 0xa8, + 0xb9, 0xc6, 0xbb, 0x70, 0xfa, 0xda, 0xfb, 0xd4, 0x1a, 0x84, 0x5e, 0x20, 0xfd, 0x0c, 0x72, 0x13, + 0x08, 0xa3, 0xc1, 0x43, 0xc7, 0xa2, 0x2b, 0x96, 0xe5, 0x0d, 0xdc, 0x70, 0x2b, 0xb6, 0x0e, 0x8b, + 0x4a, 0x1b, 0x69, 0x0d, 0x49, 0x60, 0x4e, 0x29, 0xe3, 0x2f, 0xa7, 0xa0, 0x9a, 0xf0, 0x54, 0xf9, + 0x68, 0x07, 0xd4, 0xf7, 0xb2, 0xb6, 0x86, 0xfb, 0x42, 0x28, 0x38, 0xdc, 0xd6, 0x04, 0xf4, 0xa1, + 0xc3, 0xf8, 0xc1, 0x35, 0x63, 0x6b, 0x50, 0xd1, 0x51, 0x4b, 0x90, 0x3a, 0x14, 0x6d, 0xea, 0x87, + 0x5d, 0xd1, 0xc8, 0xa9, 0x66, 0x85, 0x77, 0xc4, 0x1a, 0x27, 0xa0, 0xa4, 0x73, 0x81, 0x36, 0x0d, + 0xad, 0x6e, 0x6d, 0x4a, 0xac, 0x4f, 0x21, 0xb0, 0xce, 0x09, 0x28, 0xe9, 0x39, 0x3e, 0x45, 0xf1, + 0xd9, 0xfb, 0x14, 0xa5, 0x13, 0xf6, 0x29, 0x88, 0x0f, 0x67, 0x19, 0xeb, 0x6e, 0x07, 0xce, 0x43, + 0x33, 0xa4, 0xa2, 0xb0, 0xd0, 0x33, 0xfd, 0x34, 0x7a, 0x2e, 0x1c, 0x1d, 0xd6, 0xcf, 0xb6, 0x5a, + 0x37, 0xb2, 0x28, 0x98, 0x07, 0x4d, 0x5a, 0x70, 0xce, 0x71, 0x19, 0xb5, 0x06, 0x01, 0xdd, 0xe8, + 0xb8, 0x5e, 0x40, 0x6f, 0x78, 0x8c, 0xc3, 0xa9, 0xf0, 0xcc, 0x8b, 0x6a, 0xd0, 0xce, 0x6d, 0xe4, + 0x09, 0x61, 0x7e, 0x59, 0xe3, 0xc7, 0x05, 0x98, 0x49, 0x3a, 0xe7, 0x84, 0x01, 0x74, 0xd7, 0xd6, + 0x5b, 0x72, 0x66, 0xaa, 0x73, 0xdf, 0xdb, 0x23, 0xfb, 0xfc, 0x12, 0x26, 0xf6, 0x1b, 0x62, 0x1a, + 0x26, 0xd4, 0x3c, 0x41, 0xf4, 0xef, 0x25, 0x28, 0xb6, 0xbd, 0xc0, 0xa2, 0x6a, 0x6d, 0xe9, 0x35, + 0xb8, 0xce, 0x89, 0x28, 0x79, 0xc6, 0xbf, 0x16, 0x20, 0xa1, 0x81, 0xfc, 0x36, 0xcc, 0x72, 0x1d, + 0xb7, 0x82, 0xdd, 0x54, 0x6b, 0x9a, 0x23, 0xb7, 0x46, 0x23, 0x35, 0xcf, 0x29, 0xfd, 0xb3, 0x29, + 0x32, 0xa6, 0xf5, 0x91, 0x5f, 0x84, 0x8a, 0x69, 0xdb, 0x01, 0x65, 0x8c, 0x4a, 0xd3, 0x53, 0x69, + 0xce, 0x8a, 0x3d, 0x35, 0x22, 0x62, 0xcc, 0xe7, 0xcb, 0xb0, 0x6b, 0xb7, 0x19, 0x9f, 0xd9, 0xea, + 0xb8, 0xaa, 0x97, 0x21, 0x57, 0xc2, 0xe9, 0xa8, 0x25, 0x8c, 0x6f, 0x4f, 0x41, 0x5a, 0x37, 0xb1, + 0x61, 0x6e, 0x2f, 0xd8, 0x5d, 0x5d, 0x35, 0xad, 0xee, 0x48, 0xbe, 0xfa, 0xd9, 0xa3, 0xc3, 0xfa, + 0xdc, 0xad, 0x34, 0x02, 0x66, 0x21, 0x95, 0x96, 0x5b, 0xf4, 0x20, 0x34, 0x77, 0x47, 0x71, 0xd7, + 0x23, 0x2d, 0x49, 0x04, 0xcc, 0x42, 0x72, 0x77, 0x7a, 0x2f, 0xd8, 0x8d, 0x16, 0x79, 0xd6, 0x9d, + 0xbe, 0x15, 0xb3, 0x30, 0x29, 0xc7, 0xbb, 0x70, 0x2f, 0xd8, 0x45, 0x6a, 0xf6, 0xa2, 0x40, 0xb0, + 0xee, 0xc2, 0x5b, 0x8a, 0x8e, 0x5a, 0x82, 0xf8, 0x40, 0xf6, 0xa2, 0xde, 0xd3, 0x01, 0x1f, 0x65, + 0x8b, 0x2e, 0xe7, 0xb5, 0x46, 0x0b, 0x25, 0x1b, 0x74, 0x9e, 0xdb, 0xe6, 0x5b, 0x43, 0x38, 0x98, + 0x83, 0x4d, 0xbe, 0x01, 0x17, 0xf6, 0x82, 0x5d, 0x65, 0xc8, 0xb7, 0x03, 0xc7, 0xb5, 0x1c, 0x3f, + 0x15, 0x01, 0xae, 0xab, 0xea, 0x5e, 0xb8, 0x95, 0x2f, 0x86, 0xc7, 0x95, 0x37, 0x5e, 0x85, 0x99, + 0x64, 0x04, 0xf1, 0x33, 0xa2, 0x4e, 0xc6, 0xbf, 0x17, 0xa0, 0xb4, 0xe1, 0xfa, 0x83, 0x9f, 0x91, + 0xcb, 0x88, 0x3f, 0x9b, 0x82, 0x29, 0x7e, 0x44, 0x23, 0x97, 0x61, 0x2a, 0x3c, 0xf0, 0xe5, 0xde, + 0x3a, 0xd9, 0x5c, 0x88, 0x0c, 0xcd, 0xce, 0x81, 0x4f, 0x1f, 0xa9, 0xbf, 0x28, 0x24, 0xc8, 0x5b, + 0x50, 0x72, 0x07, 0xfd, 0x7b, 0x66, 0x4f, 0x19, 0xa5, 0x97, 0xa3, 0xa3, 0xc5, 0x96, 0xa0, 0x3e, + 0x3a, 0xac, 0x2f, 0x50, 0xd7, 0xf2, 0x6c, 0xc7, 0xed, 0x2c, 0x3f, 0x60, 0x9e, 0xdb, 0xd8, 0x1a, + 0xf4, 0x77, 0x69, 0x80, 0xaa, 0x14, 0x77, 0x14, 0x77, 0x3d, 0xaf, 0xc7, 0x01, 0x26, 0xd3, 0x8e, + 0x62, 0x53, 0x92, 0x31, 0xe2, 0xf3, 0x53, 0x0c, 0x0b, 0x03, 0x2e, 0x39, 0x95, 0x3e, 0xc5, 0xb4, + 0x04, 0x15, 0x15, 0x97, 0xf4, 0xa1, 0xd4, 0x37, 0x7d, 0x2e, 0x57, 0x14, 0x5d, 0x76, 0x6d, 0xe4, + 0x73, 0x6c, 0x63, 0x53, 0xe0, 0x5c, 0x73, 0xc3, 0xe0, 0x20, 0x56, 0x27, 0x89, 0xa8, 0x94, 0x10, + 0x07, 0xa6, 0x7b, 0x0e, 0x0b, 0xb9, 0xbe, 0xd2, 0x18, 0xb3, 0x82, 0xeb, 0xbb, 0x67, 0xf6, 0x06, + 0x34, 0xee, 0x81, 0xdb, 0x12, 0x16, 0x23, 0xfc, 0xc5, 0x03, 0xa8, 0x26, 0x6a, 0x44, 0xe6, 0x65, + 0xa4, 0x55, 0x4c, 0x5e, 0x11, 0x5c, 0x25, 0x3b, 0x50, 0x7c, 0xc8, 0x31, 0x94, 0xb1, 0x19, 0xb3, + 0x26, 0x28, 0xc1, 0xde, 0x98, 0x78, 0xbd, 0xf0, 0x46, 0xf9, 0xfb, 0x7f, 0x5a, 0x3f, 0xf5, 0xe1, + 0x3f, 0x5d, 0x3a, 0x65, 0xfc, 0xdd, 0x24, 0x54, 0xb4, 0xc8, 0xff, 0xed, 0x99, 0x12, 0x64, 0x66, + 0xca, 0xcd, 0xf1, 0xfa, 0xeb, 0x89, 0xa6, 0xcb, 0x4a, 0x7a, 0xba, 0xcc, 0x34, 0xff, 0x7f, 0x62, + 0xa8, 0x1f, 0x1d, 0xd6, 0x6b, 0xe9, 0x4e, 0x40, 0x73, 0x7f, 0x93, 0x32, 0x66, 0x76, 0x68, 0x3c, + 0x0d, 0xbe, 0xfa, 0x59, 0xd3, 0x60, 0x21, 0x39, 0x0d, 0x2a, 0xf9, 0xc3, 0xf8, 0xe1, 0x24, 0x94, + 0x37, 0xa3, 0x28, 0xda, 0xef, 0x17, 0xa0, 0x6a, 0xba, 0xae, 0x17, 0x8a, 0x78, 0x6b, 0x64, 0xde, + 0xb6, 0x46, 0xea, 0x8e, 0x08, 0xb4, 0xb1, 0x12, 0x03, 0xca, 0x2e, 0xd1, 0x3b, 0x53, 0x82, 0x83, + 0x49, 0xbd, 0xe4, 0x3d, 0x28, 0xf5, 0xcc, 0x5d, 0xda, 0x8b, 0xac, 0xdd, 0xc6, 0x78, 0x35, 0xb8, + 0x2d, 0xb0, 0x32, 0xe3, 0x21, 0x89, 0xa8, 0x14, 0x2d, 0xbe, 0x05, 0xf3, 0xd9, 0x8a, 0x3e, 0x4d, + 0x8f, 0xf2, 0xc1, 0x48, 0xa8, 0x79, 0x9a, 0xa2, 0xc6, 0x7f, 0x55, 0x00, 0xb6, 0x3c, 0x9b, 0xaa, + 0xc0, 0xcd, 0x22, 0x4c, 0x38, 0xb6, 0xda, 0x8a, 0x40, 0xd5, 0x76, 0x62, 0x63, 0x0d, 0x27, 0x1c, + 0x5b, 0x87, 0x42, 0x26, 0x8e, 0x0d, 0x85, 0x7c, 0x05, 0xaa, 0xb6, 0xc3, 0xfc, 0x9e, 0x79, 0xb0, + 0x95, 0x73, 0x16, 0x58, 0x8b, 0x59, 0x98, 0x94, 0x23, 0xaf, 0xa8, 0xf5, 0x2b, 0x17, 0x4a, 0x2d, + 0xb3, 0x7e, 0xcb, 0xbc, 0x7a, 0x89, 0x35, 0xfc, 0x3a, 0xcc, 0x44, 0xa1, 0x06, 0xa1, 0xa5, 0x28, + 0x4a, 0x45, 0xab, 0x7e, 0x66, 0x27, 0xc1, 0xc3, 0x94, 0x64, 0x36, 0x14, 0x52, 0x7a, 0x2e, 0xa1, + 0x90, 0x35, 0x98, 0x67, 0xa1, 0x17, 0x50, 0x3b, 0x92, 0xd8, 0x58, 0xab, 0x91, 0x54, 0x43, 0xe7, + 0x5b, 0x19, 0x3e, 0x0e, 0x95, 0x20, 0xdb, 0xb0, 0x10, 0x55, 0x22, 0xd9, 0xc0, 0xda, 0x59, 0x81, + 0x74, 0x51, 0x21, 0x2d, 0xdc, 0xcf, 0x91, 0xc1, 0xdc, 0x92, 0xe4, 0x6b, 0x30, 0x1b, 0x55, 0xb3, + 0x65, 0x79, 0x3e, 0xad, 0x2d, 0x08, 0x28, 0x7d, 0x5a, 0xde, 0x49, 0x32, 0x31, 0x2d, 0x4b, 0xbe, + 0x04, 0x45, 0xbf, 0x6b, 0x32, 0xaa, 0x22, 0x27, 0x91, 0xe3, 0x5b, 0xdc, 0xe6, 0xc4, 0x47, 0x87, + 0xf5, 0x0a, 0x1f, 0x33, 0xf1, 0x81, 0x52, 0x90, 0x5c, 0x01, 0xd8, 0xf5, 0x06, 0xae, 0x6d, 0x06, + 0x07, 0x1b, 0x6b, 0x2a, 0xb0, 0xa8, 0x8f, 0x1e, 0x4d, 0xcd, 0xc1, 0x84, 0x14, 0xb7, 0xb6, 0x7d, + 0x69, 0x77, 0x54, 0x00, 0x44, 0x5b, 0x5b, 0x6d, 0x8e, 0x14, 0x9f, 0xbc, 0x03, 0x15, 0x11, 0x84, + 0xa5, 0xf6, 0x4a, 0xa8, 0xa2, 0x20, 0x4f, 0x13, 0x1b, 0xd4, 0x47, 0x92, 0x56, 0x04, 0x82, 0x31, + 0x1e, 0xf9, 0x26, 0x40, 0xdb, 0x71, 0x1d, 0xd6, 0x15, 0xe8, 0xd5, 0xa7, 0x46, 0xd7, 0xed, 0x5c, + 0xd7, 0x28, 0x98, 0x40, 0xe4, 0x0e, 0x93, 0xef, 0xd9, 0x1b, 0xdb, 0xb5, 0x19, 0xd1, 0x4a, 0xed, + 0x30, 0x6d, 0x73, 0x22, 0x4a, 0x1e, 0xb9, 0x0c, 0x65, 0xdb, 0xa4, 0x7d, 0xcf, 0xa5, 0x76, 0x6d, + 0x36, 0x0e, 0x5a, 0xac, 0x29, 0x1a, 0x6a, 0x2e, 0xf9, 0x16, 0x94, 0x1c, 0x71, 0x5e, 0xac, 0x9d, + 0x16, 0x55, 0xfd, 0xda, 0x68, 0x3b, 0x8a, 0x80, 0x68, 0x02, 0x37, 0x57, 0xf2, 0x37, 0x2a, 0x58, + 0x62, 0xc1, 0xb4, 0x37, 0x08, 0x85, 0x86, 0x39, 0xa1, 0x61, 0xb4, 0x20, 0xcd, 0x1d, 0x89, 0x21, + 0x93, 0x1a, 0xd4, 0x07, 0x46, 0xc8, 0xbc, 0xbd, 0x56, 0xd7, 0xe9, 0xd9, 0x01, 0x75, 0x6b, 0xf3, + 0xc2, 0x1f, 0x13, 0xed, 0x5d, 0x55, 0x34, 0xd4, 0x5c, 0xf2, 0xcb, 0x30, 0xeb, 0x0d, 0x42, 0x31, + 0x6f, 0xf8, 0xb4, 0x63, 0xb5, 0x33, 0x42, 0xfc, 0x0c, 0x9f, 0xc5, 0x77, 0x92, 0x0c, 0x4c, 0xcb, + 0x19, 0xa7, 0x61, 0x26, 0x99, 0x09, 0x64, 0x7c, 0x77, 0x02, 0xa2, 0x7a, 0xfc, 0x2c, 0x1c, 0xb5, + 0x89, 0x01, 0xa5, 0x80, 0xb2, 0x41, 0x2f, 0x54, 0x96, 0x5a, 0x8c, 0x35, 0x0a, 0x0a, 0x2a, 0x8e, + 0xb1, 0x0f, 0xb3, 0xbc, 0xb6, 0xbd, 0x1e, 0xed, 0xb5, 0x42, 0xea, 0x33, 0xd2, 0x86, 0x22, 0xe3, + 0x3f, 0x54, 0x9f, 0x8c, 0x79, 0xcf, 0x14, 0x52, 0x3f, 0x9e, 0xef, 0x42, 0x01, 0x4a, 0x78, 0xe3, + 0x7b, 0x13, 0x50, 0xd1, 0xfd, 0xf4, 0x04, 0x61, 0xf8, 0x2f, 0xc0, 0xb4, 0x4d, 0xdb, 0x26, 0x6f, + 0x8d, 0xba, 0xf6, 0xe7, 0xd3, 0x6a, 0x4d, 0x92, 0x30, 0xe2, 0x91, 0x7a, 0xb4, 0x13, 0xca, 0x26, + 0x8b, 0x90, 0x57, 0xf2, 0xa0, 0x49, 0xf6, 0xa0, 0x22, 0x7e, 0xac, 0x47, 0x29, 0x4a, 0xa3, 0x8e, + 0xfb, 0xbd, 0x08, 0x45, 0x06, 0x12, 0xf4, 0x27, 0xc6, 0xf8, 0x99, 0xd4, 0xa2, 0xe2, 0x93, 0xa4, + 0x16, 0x19, 0xeb, 0xc0, 0x0d, 0xc3, 0xf5, 0x55, 0xf2, 0x26, 0x94, 0x99, 0x9a, 0xba, 0xaa, 0x5f, + 0x3e, 0xaf, 0xef, 0xda, 0x14, 0xfd, 0xd1, 0x61, 0x7d, 0x56, 0x08, 0x47, 0x04, 0xd4, 0x45, 0x8c, + 0x65, 0xa8, 0x26, 0x52, 0x31, 0x78, 0x0f, 0xeb, 0xeb, 0xd1, 0x44, 0x0f, 0xaf, 0x99, 0xa1, 0x89, + 0x82, 0x63, 0x3c, 0x9a, 0x80, 0x79, 0xa4, 0xcc, 0x1b, 0x04, 0x16, 0x4d, 0x86, 0x75, 0x4d, 0x2b, + 0x71, 0x43, 0x9f, 0xba, 0xc4, 0xf1, 0x5c, 0x54, 0x5c, 0xbe, 0xdd, 0xf4, 0x69, 0xd0, 0xd1, 0x8b, + 0x4d, 0x0d, 0x92, 0xde, 0x6e, 0x36, 0x93, 0x4c, 0x4c, 0xcb, 0x92, 0x57, 0xa0, 0xdc, 0x37, 0x5d, + 0xa7, 0x4d, 0x59, 0x98, 0x8d, 0xb7, 0x6c, 0x2a, 0x3a, 0x6a, 0x09, 0x72, 0x1d, 0xce, 0x30, 0x1a, + 0xde, 0xd9, 0x77, 0x69, 0xa0, 0x2f, 0x97, 0xd4, 0x0d, 0xe0, 0x0b, 0xd1, 0xad, 0x62, 0x2b, 0x2b, + 0x80, 0xc3, 0x65, 0xc4, 0xd6, 0x2d, 0x2f, 0xdf, 0x56, 0x3d, 0xd7, 0x76, 0x74, 0x16, 0x5a, 0x72, + 0xeb, 0xce, 0xf0, 0x71, 0xa8, 0x04, 0x47, 0x69, 0x9b, 0x4e, 0x6f, 0x10, 0xd0, 0x18, 0xa5, 0x94, + 0x46, 0x59, 0xcf, 0xf0, 0x71, 0xa8, 0x84, 0xf1, 0x2f, 0x05, 0x98, 0x45, 0x1a, 0x06, 0x07, 0xba, + 0x53, 0xea, 0x50, 0xec, 0x89, 0xbb, 0xbe, 0x82, 0xb8, 0xeb, 0x13, 0x33, 0x59, 0x5e, 0xed, 0x49, + 0x3a, 0x59, 0x83, 0x6a, 0xc0, 0x4b, 0xa8, 0x7b, 0x55, 0xd9, 0xe1, 0x46, 0x74, 0x1a, 0xc3, 0x98, + 0xf5, 0x28, 0xfd, 0x89, 0xc9, 0x62, 0xc4, 0x85, 0xe9, 0x5d, 0x99, 0x8f, 0xa1, 0xae, 0xab, 0x46, + 0x33, 0xf6, 0x2a, 0xa7, 0x43, 0xc4, 0x60, 0xa2, 0x04, 0x8f, 0x47, 0xf1, 0x4f, 0x8c, 0x94, 0x18, + 0xdf, 0x2f, 0x00, 0xc4, 0x89, 0x61, 0x64, 0x0f, 0xca, 0xec, 0x6a, 0x73, 0x60, 0xed, 0xe9, 0x18, + 0xd9, 0x88, 0x57, 0x2e, 0x0a, 0x24, 0x71, 0x1f, 0xad, 0x28, 0xa8, 0x15, 0x7c, 0x56, 0xda, 0xd0, + 0x5f, 0x4d, 0x82, 0x2e, 0xc5, 0xe7, 0x24, 0x75, 0x6d, 0xdf, 0x73, 0xdc, 0x30, 0x9b, 0x9c, 0x72, + 0x4d, 0xd1, 0x51, 0x4b, 0xf0, 0x65, 0xb2, 0x2b, 0x1b, 0x31, 0x91, 0x5e, 0x26, 0xaa, 0x0e, 0x8a, + 0xcb, 0xe5, 0x02, 0xda, 0x89, 0xf3, 0x52, 0xb4, 0x1c, 0x0a, 0x2a, 0x2a, 0x2e, 0xdf, 0x1d, 0xa3, + 0x20, 0xb1, 0x9a, 0xda, 0x62, 0x77, 0x8c, 0xe2, 0xc9, 0xa8, 0xb9, 0xa4, 0x0b, 0x73, 0xa6, 0x98, + 0x91, 0x71, 0xe0, 0xfb, 0xa9, 0x62, 0xf8, 0x71, 0x52, 0x52, 0x1a, 0x05, 0xb3, 0xb0, 0x5c, 0x13, + 0x8b, 0x8b, 0x3f, 0x7d, 0x28, 0x5f, 0x6b, 0x6a, 0xa5, 0x51, 0x30, 0x0b, 0xcb, 0x0f, 0x86, 0x81, + 0xd7, 0xa3, 0x2b, 0xb8, 0xa5, 0x0e, 0xa0, 0xfa, 0x60, 0x88, 0x92, 0x8c, 0x11, 0xdf, 0xf8, 0xc3, + 0x02, 0x9c, 0x6e, 0x59, 0x81, 0xe3, 0x87, 0xda, 0x64, 0x6d, 0x89, 0x6c, 0xb2, 0xd0, 0xe4, 0x47, + 0x36, 0x35, 0xa7, 0x5e, 0x3c, 0x26, 0x86, 0x28, 0x85, 0x52, 0xc9, 0x66, 0x92, 0x84, 0x31, 0x84, + 0xf0, 0xf4, 0x85, 0x51, 0xcc, 0x8e, 0x6d, 0x4b, 0x50, 0x51, 0x71, 0x8d, 0x1f, 0x14, 0xa0, 0xac, + 0x6f, 0xf6, 0x5e, 0x82, 0xa2, 0xb8, 0x08, 0x52, 0x73, 0x47, 0xef, 0x81, 0xab, 0x9c, 0x88, 0x92, + 0xc7, 0x85, 0xc4, 0x29, 0x54, 0x01, 0x27, 0x36, 0x4a, 0x33, 0x08, 0x51, 0xf2, 0xf8, 0xa4, 0xa5, + 0xae, 0xad, 0xe6, 0x8b, 0x9e, 0xb4, 0xd7, 0x5c, 0x1b, 0x39, 0x5d, 0x24, 0x21, 0x79, 0x41, 0xdf, + 0x0c, 0xb3, 0x71, 0x88, 0x75, 0x41, 0x45, 0xc5, 0x35, 0xde, 0x86, 0x39, 0x95, 0x16, 0xa1, 0x3b, + 0xea, 0xa9, 0xf2, 0xaf, 0x8c, 0x9f, 0x16, 0xa0, 0xba, 0xb3, 0x73, 0x5b, 0xdb, 0x27, 0x84, 0xf3, + 0x4c, 0xe6, 0x41, 0xac, 0xb4, 0x43, 0x1a, 0xac, 0x7a, 0x7d, 0xbf, 0x47, 0x35, 0x96, 0x4a, 0x4e, + 0x68, 0xe5, 0x4a, 0xe0, 0x31, 0x25, 0xc9, 0x06, 0x9c, 0x4d, 0x72, 0x94, 0xf5, 0x55, 0x09, 0x5f, + 0xf2, 0x8a, 0x66, 0x98, 0x8d, 0x79, 0x65, 0xb2, 0x50, 0xca, 0x04, 0xab, 0x94, 0xe5, 0x21, 0x28, + 0xc5, 0xc6, 0xbc, 0x32, 0xc6, 0x2c, 0x54, 0x13, 0xf9, 0xea, 0xc6, 0x7f, 0x5e, 0x00, 0x7d, 0xf3, + 0xff, 0xf3, 0xfc, 0x81, 0x91, 0x9c, 0x66, 0x4b, 0xbb, 0x30, 0xc5, 0xf1, 0x5d, 0x18, 0x3d, 0xe3, + 0x33, 0x6e, 0x4c, 0x27, 0x76, 0x63, 0x4a, 0x27, 0xe0, 0xc6, 0x68, 0x1b, 0x34, 0xe4, 0xca, 0xfc, + 0x51, 0x01, 0x66, 0x5c, 0xcf, 0xa6, 0x91, 0xa5, 0xab, 0x4d, 0x8b, 0xa3, 0xf3, 0x9d, 0xb1, 0x3a, + 0xb1, 0xb1, 0x95, 0x40, 0x94, 0xe1, 0x25, 0x1d, 0x03, 0x49, 0xb2, 0x30, 0xa5, 0x9a, 0xac, 0x43, + 0xd9, 0x6c, 0x73, 0xdf, 0x33, 0x3c, 0x50, 0x29, 0x0c, 0x17, 0xf3, 0x6c, 0xdf, 0x8a, 0x92, 0x91, + 0xdb, 0x4a, 0xf4, 0x85, 0xba, 0x2c, 0xdf, 0x97, 0x75, 0x46, 0x5d, 0x65, 0x8c, 0x7d, 0x39, 0x8a, + 0x93, 0x25, 0x4e, 0x74, 0x8a, 0x92, 0x48, 0xb0, 0x33, 0xa0, 0x24, 0xbd, 0x5b, 0xe1, 0xda, 0x97, + 0xa5, 0xa3, 0x22, 0x3d, 0x5f, 0x54, 0x1c, 0xd2, 0x89, 0xfc, 0x92, 0xaa, 0xe8, 0xdc, 0xe6, 0xc8, + 0xbe, 0x9a, 0x76, 0x75, 0xf2, 0x1d, 0x13, 0x72, 0x33, 0xb9, 0x7d, 0xcc, 0x3c, 0xc9, 0xf6, 0x31, + 0x7b, 0xec, 0xd6, 0xd1, 0x81, 0x12, 0x13, 0x9b, 0x93, 0x70, 0xe9, 0xab, 0x57, 0x56, 0x47, 0x3b, + 0xdb, 0xa4, 0xf6, 0x37, 0xd9, 0x3b, 0x92, 0x86, 0x0a, 0x9e, 0x78, 0x50, 0x0e, 0xd4, 0xd1, 0x5d, + 0x45, 0x05, 0x46, 0xbb, 0x91, 0xc8, 0x9e, 0xff, 0xe5, 0xfc, 0x88, 0xa8, 0xa8, 0x95, 0x90, 0x77, + 0x60, 0xd2, 0x36, 0x3b, 0x2a, 0x3e, 0xf0, 0xf5, 0x91, 0x93, 0x38, 0x22, 0x35, 0x22, 0x51, 0x7c, + 0x6d, 0xe5, 0x3a, 0x72, 0x54, 0xb2, 0x17, 0x67, 0xf6, 0xcd, 0x8f, 0x91, 0x7f, 0x9d, 0xd9, 0xef, + 0xa4, 0xc7, 0x38, 0x94, 0x1b, 0x78, 0x0d, 0xa6, 0x1f, 0x7a, 0xbd, 0x41, 0x5f, 0x05, 0x16, 0xaa, + 0x57, 0x16, 0xf3, 0x46, 0xfb, 0x9e, 0x10, 0x89, 0x8d, 0x80, 0xfc, 0x66, 0x18, 0x95, 0x25, 0xbf, + 0x5b, 0x80, 0xd3, 0x7c, 0xe9, 0xe8, 0x79, 0xc0, 0x6a, 0x64, 0x8c, 0x99, 0x7a, 0x97, 0xf1, 0x8d, + 0x31, 0x9a, 0x61, 0xe7, 0x95, 0xda, 0xd3, 0x1b, 0x29, 0x0d, 0x98, 0xd1, 0x48, 0x7c, 0x28, 0x33, + 0xc7, 0xa6, 0x96, 0x19, 0xb0, 0xda, 0xd9, 0x13, 0xd3, 0x1e, 0x1f, 0xa9, 0x15, 0x36, 0x6a, 0x2d, + 0xe4, 0xf7, 0x44, 0xce, 0xbc, 0x7a, 0x35, 0xa2, 0x5e, 0xf2, 0x2c, 0x9c, 0xe4, 0x4b, 0x9e, 0xb3, + 0x32, 0x61, 0x3e, 0xa5, 0x01, 0xb3, 0x2a, 0xc9, 0x1d, 0x38, 0x27, 0xb3, 0x09, 0xb3, 0xe9, 0x9d, + 0xe7, 0xc4, 0x9d, 0xd1, 0x0b, 0x47, 0x87, 0xf5, 0x73, 0x2b, 0x79, 0x02, 0x98, 0x5f, 0x8e, 0x7c, + 0x00, 0xb3, 0x41, 0xd2, 0x1d, 0xab, 0x9d, 0x1f, 0x23, 0x61, 0x21, 0xe5, 0xd8, 0xc9, 0xc0, 0x55, + 0x8a, 0x84, 0x69, 0x5d, 0xe4, 0x35, 0xa8, 0xfa, 0xca, 0x52, 0x39, 0xac, 0x5f, 0xbb, 0x20, 0xda, + 0x20, 0x76, 0xd4, 0xed, 0x98, 0x8c, 0x49, 0x19, 0x72, 0x17, 0xaa, 0xa1, 0xd7, 0xa3, 0x81, 0xba, + 0x5c, 0xa9, 0x89, 0xc1, 0x5f, 0xca, 0x9b, 0xc9, 0x3b, 0x5a, 0x2c, 0x0e, 0xdd, 0xc7, 0x34, 0x86, + 0x49, 0x1c, 0xee, 0xd6, 0x47, 0xd9, 0xbc, 0x81, 0x88, 0x61, 0xbc, 0x90, 0x76, 0xeb, 0x5b, 0x49, + 0x26, 0xa6, 0x65, 0xb9, 0xa3, 0xee, 0x07, 0x8e, 0x17, 0x38, 0xe1, 0xc1, 0x6a, 0xcf, 0x64, 0x4c, + 0x00, 0x2c, 0x0a, 0x00, 0xed, 0xa8, 0x6f, 0x67, 0x05, 0x70, 0xb8, 0x0c, 0xf7, 0x86, 0x22, 0x62, + 0xed, 0x73, 0xe2, 0x00, 0x27, 0xcc, 0x52, 0x54, 0x16, 0x35, 0xf7, 0x98, 0xf4, 0xad, 0x8b, 0xa3, + 0xa4, 0x6f, 0x11, 0x1b, 0x2e, 0x9a, 0x83, 0xd0, 0xeb, 0x73, 0x42, 0xba, 0xc8, 0x8e, 0xb7, 0x47, + 0xdd, 0xda, 0x25, 0xb1, 0x57, 0x5d, 0x3a, 0x3a, 0xac, 0x5f, 0x5c, 0x79, 0x8c, 0x1c, 0x3e, 0x16, + 0x85, 0xf4, 0xa1, 0x4c, 0x55, 0x0a, 0x5a, 0xed, 0xf3, 0x63, 0x6c, 0x12, 0xe9, 0x3c, 0x36, 0xd9, + 0x41, 0x11, 0x0d, 0xb5, 0x0a, 0xb2, 0x03, 0xd5, 0xae, 0xc7, 0xc2, 0x95, 0x9e, 0x63, 0x32, 0xca, + 0x6a, 0x2f, 0x8a, 0x79, 0x92, 0xbb, 0xbf, 0xdd, 0x88, 0xc4, 0xe2, 0x69, 0x72, 0x23, 0x2e, 0x89, + 0x49, 0x18, 0x42, 0x85, 0x6b, 0x38, 0x10, 0xa3, 0xe6, 0xb9, 0x21, 0x7d, 0x3f, 0xac, 0x2d, 0x89, + 0xb6, 0xbc, 0x9c, 0x87, 0xbc, 0xed, 0xd9, 0xad, 0xb4, 0xb4, 0x5c, 0xe5, 0x19, 0x22, 0x66, 0x31, + 0xc9, 0xeb, 0x30, 0xe3, 0x7b, 0x76, 0xcb, 0xa7, 0xd6, 0xb6, 0x19, 0x5a, 0xdd, 0x5a, 0x3d, 0x7d, + 0x35, 0xb4, 0x9d, 0xe0, 0x61, 0x4a, 0x72, 0xf1, 0x6d, 0x38, 0x33, 0x74, 0x9e, 0x7a, 0xaa, 0x7b, + 0xb4, 0x3f, 0xe7, 0xde, 0x4f, 0xe2, 0x04, 0x7b, 0xd2, 0xe7, 0xfe, 0xeb, 0x70, 0x46, 0xbd, 0xc4, + 0xe5, 0x9b, 0x6d, 0x6f, 0xa0, 0xdf, 0xae, 0x24, 0x82, 0x5a, 0x98, 0x15, 0xc0, 0xe1, 0x32, 0xc6, + 0x5f, 0x14, 0x60, 0x36, 0x65, 0xbe, 0x4f, 0xdc, 0x1f, 0x5e, 0x07, 0xd2, 0x77, 0x82, 0xc0, 0x0b, + 0xe4, 0x1e, 0xb8, 0xc9, 0xe7, 0x32, 0x53, 0x4f, 0x60, 0x44, 0x0a, 0xce, 0xe6, 0x10, 0x17, 0x73, + 0x4a, 0x18, 0x7f, 0x53, 0x80, 0x38, 0x6a, 0xaa, 0xf3, 0xce, 0x0a, 0xc7, 0xe6, 0x9d, 0xbd, 0x02, + 0xe5, 0x07, 0xcc, 0x73, 0xb7, 0xe3, 0xec, 0x34, 0xdd, 0xa1, 0x37, 0x5b, 0x77, 0xb6, 0x84, 0xa4, + 0x96, 0x10, 0xd2, 0xef, 0xad, 0x3b, 0xbd, 0x70, 0x38, 0x87, 0xeb, 0xe6, 0xaf, 0x4a, 0x3a, 0x6a, + 0x09, 0xb2, 0x0c, 0x15, 0x1d, 0xa8, 0x57, 0x8e, 0xb4, 0xee, 0x04, 0x1d, 0xa5, 0xc6, 0x58, 0xc6, + 0xf8, 0xe1, 0x04, 0x94, 0x9f, 0xe3, 0x7b, 0x1e, 0x2b, 0xf5, 0x9e, 0xe7, 0x04, 0x1e, 0x7f, 0xe4, + 0xbd, 0xe5, 0xd9, 0xcb, 0xbc, 0xe5, 0x59, 0x1d, 0x33, 0xf6, 0xff, 0xd8, 0x77, 0x3c, 0x1f, 0x17, + 0x60, 0xe6, 0x39, 0xbe, 0xe1, 0xd9, 0x4d, 0xbf, 0xe1, 0x79, 0x73, 0xac, 0xa6, 0x1d, 0xf3, 0x7e, + 0xe7, 0xaf, 0x17, 0x20, 0xf5, 0x76, 0x86, 0xb8, 0x50, 0x89, 0x16, 0x78, 0x74, 0x9f, 0xf2, 0xe6, + 0x58, 0x4e, 0x61, 0x3c, 0x29, 0x23, 0x0a, 0xc3, 0x58, 0x05, 0xb9, 0x02, 0x40, 0xb9, 0x65, 0x93, + 0x51, 0xcb, 0x89, 0xf4, 0x75, 0xc3, 0x35, 0xcd, 0xc1, 0x84, 0xd4, 0xf3, 0x0f, 0x38, 0xe4, 0x6f, + 0xd1, 0x53, 0xcf, 0x64, 0x8b, 0xbe, 0x78, 0xe2, 0x5b, 0xf4, 0x8b, 0xcf, 0x7e, 0x8b, 0x4e, 0x38, + 0x24, 0xc5, 0x31, 0x1c, 0x92, 0x0f, 0x60, 0x41, 0xfe, 0x5c, 0xed, 0x99, 0x4e, 0x5f, 0xcf, 0x17, + 0x95, 0x40, 0xf6, 0xc5, 0xdc, 0x8d, 0x99, 0x06, 0xcc, 0x61, 0x21, 0x75, 0xc3, 0x7b, 0x71, 0xc9, + 0x38, 0xfb, 0xe0, 0x5e, 0x0e, 0x1c, 0xe6, 0x2a, 0xc9, 0x9e, 0x60, 0xa7, 0x9f, 0xe0, 0x04, 0xfb, + 0x83, 0x02, 0x9c, 0x33, 0xf3, 0x9e, 0x07, 0xab, 0x38, 0xc6, 0xcd, 0xb1, 0xfc, 0x89, 0x14, 0xa2, + 0xf2, 0x07, 0xf2, 0x58, 0x98, 0x5f, 0x07, 0xf2, 0x85, 0xd8, 0x25, 0xad, 0x88, 0x49, 0x95, 0xef, + 0x4c, 0x7e, 0x3b, 0x1b, 0x0a, 0x02, 0xd1, 0xdb, 0xad, 0xb1, 0x0d, 0xf6, 0x09, 0x84, 0x83, 0xaa, + 0x63, 0x84, 0x83, 0x32, 0xee, 0xc5, 0xcc, 0x09, 0xb9, 0x17, 0x2e, 0xcc, 0x3b, 0x7d, 0xb3, 0x43, + 0xb7, 0x07, 0xbd, 0x9e, 0x8c, 0xfd, 0xb3, 0xda, 0xac, 0xc0, 0xce, 0xcd, 0xfa, 0xe5, 0xee, 0x5e, + 0x2f, 0xfb, 0xac, 0x4c, 0xdf, 0xb2, 0x6d, 0x64, 0x90, 0x70, 0x08, 0x9b, 0x4f, 0x4b, 0x7e, 0x6c, + 0xdd, 0xa2, 0x21, 0xef, 0x6d, 0x11, 0x29, 0x51, 0xff, 0x06, 0xe1, 0x46, 0x4c, 0xc6, 0xa4, 0x0c, + 0xb9, 0x05, 0x15, 0xdb, 0x65, 0xea, 0x8e, 0x6d, 0x4e, 0x58, 0xa9, 0x57, 0xb9, 0x6d, 0x5b, 0xdb, + 0x6a, 0xe9, 0xdb, 0xb5, 0x8b, 0xc3, 0xff, 0xe7, 0xa5, 0xa1, 0xf9, 0x18, 0x97, 0x27, 0x9b, 0x02, + 0x4c, 0xa5, 0xc0, 0xcb, 0xd0, 0xc6, 0xa5, 0x63, 0x4e, 0xc8, 0x6b, 0x5b, 0x51, 0xc6, 0xfe, 0xac, + 0x52, 0xa7, 0x12, 0xdb, 0x63, 0x84, 0xc4, 0x5b, 0x9d, 0x33, 0x8f, 0x7b, 0xab, 0x43, 0xee, 0xc2, + 0x85, 0x30, 0xec, 0xa5, 0xe2, 0xdd, 0x2a, 0x3b, 0x45, 0xa4, 0x2a, 0x15, 0xe5, 0xf3, 0xc7, 0x9d, + 0x9d, 0xdb, 0x79, 0x22, 0x78, 0x5c, 0x59, 0x11, 0x3a, 0x0e, 0x7b, 0xda, 0x43, 0x5e, 0x1a, 0x27, + 0x74, 0x1c, 0x5f, 0x2c, 0xa8, 0xd0, 0x71, 0x4c, 0xc0, 0xa4, 0x96, 0xe3, 0x3d, 0xfd, 0xb3, 0x23, + 0x7a, 0xfa, 0x49, 0xe7, 0x72, 0xe1, 0xb1, 0xce, 0xe5, 0x90, 0x33, 0x7c, 0xee, 0x29, 0x9c, 0xe1, + 0x77, 0x44, 0x12, 0xd0, 0xf5, 0x55, 0x15, 0x48, 0x78, 0x63, 0xb4, 0xf8, 0x25, 0x47, 0x90, 0x57, + 0xc1, 0xe2, 0x27, 0x4a, 0x4c, 0xb2, 0x0d, 0x0b, 0xbe, 0x67, 0x0f, 0xf9, 0xd2, 0x22, 0x72, 0x90, + 0x48, 0x1f, 0xdb, 0xce, 0x91, 0xc1, 0xdc, 0x92, 0xc2, 0x80, 0xc7, 0xf4, 0x5a, 0x4d, 0x74, 0x8c, + 0x34, 0xe0, 0x31, 0x19, 0x93, 0x32, 0x59, 0xd7, 0xf2, 0x85, 0x67, 0xe6, 0x5a, 0x2e, 0x3e, 0x07, + 0xd7, 0xf2, 0x73, 0xcf, 0xcf, 0xb5, 0xfc, 0xdb, 0x0a, 0x9c, 0xce, 0xbc, 0xaf, 0xd5, 0xf9, 0x77, + 0x85, 0x27, 0xcd, 0xbf, 0x4b, 0x25, 0xc8, 0x4d, 0x3c, 0xd3, 0x04, 0xb9, 0xc9, 0x13, 0x4f, 0x90, + 0x4b, 0x24, 0x02, 0x4e, 0x7d, 0x46, 0x22, 0xe0, 0x0a, 0xcc, 0x59, 0x5e, 0xdf, 0x17, 0x0f, 0x75, + 0x54, 0x3a, 0x98, 0x4c, 0xd9, 0xd0, 0xb7, 0xcb, 0xab, 0x69, 0x36, 0x66, 0xe5, 0xc9, 0x6f, 0x41, + 0xd1, 0x15, 0x05, 0x4b, 0x63, 0x64, 0x20, 0xa7, 0x07, 0x4c, 0xec, 0xce, 0x2a, 0x09, 0x38, 0x8a, + 0xd5, 0x16, 0x05, 0xed, 0x51, 0xf4, 0x03, 0xa5, 0x52, 0xf2, 0x2e, 0xd4, 0xbc, 0x76, 0xbb, 0xe7, + 0x99, 0x76, 0x9c, 0x96, 0x7b, 0x8f, 0x9f, 0xbb, 0xd4, 0xed, 0x47, 0xa5, 0x79, 0x49, 0x01, 0xd4, + 0xee, 0x1c, 0x23, 0x87, 0xc7, 0x22, 0xf0, 0x43, 0xd4, 0x5c, 0x3a, 0xb9, 0x94, 0xd5, 0x2a, 0xa2, + 0x99, 0xbf, 0x76, 0x12, 0xcd, 0x4c, 0x67, 0xb2, 0xaa, 0x06, 0xc7, 0xf7, 0xfa, 0x69, 0x2e, 0x66, + 0x6b, 0x42, 0x02, 0x38, 0xef, 0xe7, 0x1d, 0x31, 0x99, 0xba, 0x31, 0x7b, 0xdc, 0x41, 0x77, 0x49, + 0x69, 0x39, 0x9f, 0x7b, 0x48, 0x65, 0x78, 0x0c, 0x72, 0x32, 0x99, 0xb1, 0xfc, 0xac, 0x92, 0x19, + 0x17, 0x0f, 0x64, 0x92, 0xf5, 0xb1, 0xf9, 0xd9, 0x77, 0xd3, 0x6f, 0x26, 0xde, 0x1e, 0xf1, 0xbf, + 0x9a, 0x45, 0xa3, 0x9d, 0xcc, 0x0d, 0xff, 0x9d, 0x02, 0x2c, 0xe4, 0x0d, 0x4b, 0x4e, 0x2d, 0x5a, + 0xe9, 0x5a, 0x8c, 0xe7, 0x8a, 0x26, 0x2d, 0xd8, 0x77, 0x4b, 0x09, 0xc7, 0x37, 0xa4, 0xfe, 0xcf, + 0x6f, 0xc5, 0x47, 0xba, 0x15, 0x4f, 0xbd, 0x8f, 0x2f, 0x3e, 0xc7, 0xf7, 0xf1, 0xa5, 0x11, 0xde, + 0xc7, 0x4f, 0x3f, 0xcf, 0xf7, 0xf1, 0xe5, 0x27, 0x7c, 0x1f, 0x5f, 0xf9, 0xdf, 0xf3, 0x3e, 0xfe, + 0xd3, 0x02, 0xcc, 0x67, 0xd3, 0xf5, 0x9f, 0x43, 0xa0, 0x70, 0x2f, 0x15, 0x28, 0xdc, 0x18, 0xcb, + 0xe8, 0xeb, 0x27, 0x02, 0xc7, 0x04, 0x0c, 0x8d, 0x9f, 0x14, 0x60, 0xe8, 0x49, 0xc2, 0x73, 0x88, + 0xe5, 0x3d, 0x48, 0xc7, 0xf2, 0xae, 0x9d, 0x48, 0x23, 0x8f, 0x89, 0xe9, 0xfd, 0x34, 0xa7, 0x89, + 0xff, 0x23, 0xb1, 0xbd, 0xe7, 0x6d, 0x02, 0x9b, 0x8d, 0x8f, 0x3e, 0x5d, 0x3a, 0xf5, 0xf1, 0xa7, + 0x4b, 0xa7, 0x3e, 0xf9, 0x74, 0xe9, 0xd4, 0x87, 0x47, 0x4b, 0x85, 0x8f, 0x8e, 0x96, 0x0a, 0x1f, + 0x1f, 0x2d, 0x15, 0x3e, 0x39, 0x5a, 0x2a, 0xfc, 0xe4, 0x68, 0xa9, 0xf0, 0x9d, 0x7f, 0x5e, 0x3a, + 0xf5, 0xeb, 0xe5, 0x08, 0xf7, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x21, 0xdc, 0xa7, 0x02, 0x96, + 0x55, 0x00, 0x00, } func (m *ArchiveStrategy) Marshal() (dAtA []byte, err error) { @@ -4127,8 +4127,8 @@ func (m *TTLStrategy) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.SecondsAfterFailed != nil { - i = encodeVarintGenerated(dAtA, i, uint64(*m.SecondsAfterFailed)) + if m.SecondsAfterFailure != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.SecondsAfterFailure)) i-- dAtA[i] = 0x18 } @@ -4137,8 +4137,8 @@ func (m *TTLStrategy) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x10 } - if m.SecondsAfterCompleted != nil { - i = encodeVarintGenerated(dAtA, i, uint64(*m.SecondsAfterCompleted)) + if m.SecondsAfterCompletion != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.SecondsAfterCompletion)) i-- dAtA[i] = 0x8 } @@ -5166,14 +5166,11 @@ func (m *WorkflowStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + i -= len(m.OffloadNodeStatusVersion) + copy(dAtA[i:], m.OffloadNodeStatusVersion) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.OffloadNodeStatusVersion))) i-- - if m.OffloadNodeStatus { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x50 + dAtA[i] = 0x52 if len(m.StoredTemplates) > 0 { keysForStoredTemplates := make([]string, 0, len(m.StoredTemplates)) for k := range m.StoredTemplates { @@ -5523,7 +5520,7 @@ func (m *WorkflowTemplateSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenerated(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a if len(m.Templates) > 0 { for iNdEx := len(m.Templates) - 1; iNdEx >= 0; iNdEx-- { { @@ -6368,14 +6365,14 @@ func (m *TTLStrategy) Size() (n int) { } var l int _ = l - if m.SecondsAfterCompleted != nil { - n += 1 + sovGenerated(uint64(*m.SecondsAfterCompleted)) + if m.SecondsAfterCompletion != nil { + n += 1 + sovGenerated(uint64(*m.SecondsAfterCompletion)) } if m.SecondsAfterSuccess != nil { n += 1 + sovGenerated(uint64(*m.SecondsAfterSuccess)) } - if m.SecondsAfterFailed != nil { - n += 1 + sovGenerated(uint64(*m.SecondsAfterFailed)) + if m.SecondsAfterFailure != nil { + n += 1 + sovGenerated(uint64(*m.SecondsAfterFailure)) } return n } @@ -6765,7 +6762,8 @@ func (m *WorkflowStatus) Size() (n int) { n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) } } - n += 2 + l = len(m.OffloadNodeStatusVersion) + n += 1 + l + sovGenerated(uint64(l)) return n } @@ -7415,9 +7413,9 @@ func (this *TTLStrategy) String() string { return "nil" } s := strings.Join([]string{`&TTLStrategy{`, - `SecondsAfterCompleted:` + valueToStringGenerated(this.SecondsAfterCompleted) + `,`, + `SecondsAfterCompletion:` + valueToStringGenerated(this.SecondsAfterCompletion) + `,`, `SecondsAfterSuccess:` + valueToStringGenerated(this.SecondsAfterSuccess) + `,`, - `SecondsAfterFailed:` + valueToStringGenerated(this.SecondsAfterFailed) + `,`, + `SecondsAfterFailure:` + valueToStringGenerated(this.SecondsAfterFailure) + `,`, `}`, }, "") return s @@ -7695,7 +7693,7 @@ func (this *WorkflowStatus) String() string { `PersistentVolumeClaims:` + repeatedStringForPersistentVolumeClaims + `,`, `Outputs:` + strings.Replace(this.Outputs.String(), "Outputs", "Outputs", 1) + `,`, `StoredTemplates:` + mapStringForStoredTemplates + `,`, - `OffloadNodeStatus:` + fmt.Sprintf("%v", this.OffloadNodeStatus) + `,`, + `OffloadNodeStatusVersion:` + fmt.Sprintf("%v", this.OffloadNodeStatusVersion) + `,`, `}`, }, "") return s @@ -15035,7 +15033,7 @@ func (m *TTLStrategy) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field SecondsAfterCompleted", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SecondsAfterCompletion", wireType) } var v int32 for shift := uint(0); ; shift += 7 { @@ -15052,7 +15050,7 @@ func (m *TTLStrategy) Unmarshal(dAtA []byte) error { break } } - m.SecondsAfterCompleted = &v + m.SecondsAfterCompletion = &v case 2: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field SecondsAfterSuccess", wireType) @@ -15075,7 +15073,7 @@ func (m *TTLStrategy) Unmarshal(dAtA []byte) error { m.SecondsAfterSuccess = &v case 3: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field SecondsAfterFailed", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SecondsAfterFailure", wireType) } var v int32 for shift := uint(0); ; shift += 7 { @@ -15092,7 +15090,7 @@ func (m *TTLStrategy) Unmarshal(dAtA []byte) error { break } } - m.SecondsAfterFailed = &v + m.SecondsAfterFailure = &v default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -18650,10 +18648,10 @@ func (m *WorkflowStatus) Unmarshal(dAtA []byte) error { m.StoredTemplates[mapkey] = *mapvalue iNdEx = postIndex case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OffloadNodeStatus", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OffloadNodeStatusVersion", wireType) } - var v int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -18663,12 +18661,24 @@ func (m *WorkflowStatus) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - m.OffloadNodeStatus = bool(v != 0) + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OffloadNodeStatusVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -19383,7 +19393,7 @@ func (m *WorkflowTemplateSpec) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 2: + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Arguments", wireType) } diff --git a/pkg/apis/workflow/v1alpha1/generated.proto b/pkg/apis/workflow/v1alpha1/generated.proto index d90a5c9b9f39..a303e5ba6fc8 100644 --- a/pkg/apis/workflow/v1alpha1/generated.proto +++ b/pkg/apis/workflow/v1alpha1/generated.proto @@ -628,11 +628,11 @@ message SuspendTemplate { // TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed message TTLStrategy { - optional int32 secondsAfterCompleted = 1; + optional int32 secondsAfterCompletion = 1; optional int32 secondsAfterSuccess = 2; - optional int32 secondsAfterFailed = 3; + optional int32 secondsAfterFailure = 3; } // TarStrategy will tar and gzip the file or directory when saving @@ -921,7 +921,7 @@ message WorkflowSpec { // deleted after ttlSecondsAfterFinished expires. If this field is unset, // ttlSecondsAfterFinished will not expire. If this field is set to zero, // ttlSecondsAfterFinished expires immediately after the Workflow finishes. - // DEPRECATED: Use TTLStrategy.SecondsAfterCompleted instead. + // DEPRECATED: Use TTLStrategy.SecondsAfterCompletion instead. optional int32 ttlSecondsAfterFinished = 18; // TTLStrategy limits the lifetime of a Workflow that has finished execution depending on if it @@ -988,8 +988,9 @@ message WorkflowStatus { // Nodes is a mapping between a node ID and the node's status. map nodes = 6; - // Whether on not node status has been offloaded to a database. If true, then Nodes and CompressedNodes will be empty. - optional bool offloadNodeStatus = 10; + // Whether on not node status has been offloaded to a database. If exists, then Nodes and CompressedNodes will be empty. + // This will actually be populated with a hash of the offloaded data. + optional string offloadNodeStatusVersion = 10; // StoredTemplates is a mapping between a template ref and the node's status. map storedTemplates = 9; @@ -1063,6 +1064,6 @@ message WorkflowTemplateSpec { repeated Template templates = 1; // Arguments hold arguments to the template. - optional Arguments arguments = 2; + optional Arguments arguments = 3; } diff --git a/pkg/apis/workflow/v1alpha1/openapi_generated.go b/pkg/apis/workflow/v1alpha1/openapi_generated.go index e2d6a21bd9c4..0310ed984581 100644 --- a/pkg/apis/workflow/v1alpha1/openapi_generated.go +++ b/pkg/apis/workflow/v1alpha1/openapi_generated.go @@ -2195,7 +2195,7 @@ func schema_pkg_apis_workflow_v1alpha1_TTLStrategy(ref common.ReferenceCallback) Description: "TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "secondsAfterCompleted": { + "secondsAfterCompletion": { SchemaProps: spec.SchemaProps{ Type: []string{"integer"}, Format: "int32", @@ -2207,7 +2207,7 @@ func schema_pkg_apis_workflow_v1alpha1_TTLStrategy(ref common.ReferenceCallback) Format: "int32", }, }, - "secondsAfterFailed": { + "secondsAfterFailure": { SchemaProps: spec.SchemaProps{ Type: []string{"integer"}, Format: "int32", @@ -3152,7 +3152,7 @@ func schema_pkg_apis_workflow_v1alpha1_WorkflowSpec(ref common.ReferenceCallback }, "ttlSecondsAfterFinished": { SchemaProps: spec.SchemaProps{ - Description: "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution (Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be deleted after ttlSecondsAfterFinished expires. If this field is unset, ttlSecondsAfterFinished will not expire. If this field is set to zero, ttlSecondsAfterFinished expires immediately after the Workflow finishes. DEPRECATED: Use TTLStrategy.SecondsAfterCompleted instead.", + Description: "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution (Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be deleted after ttlSecondsAfterFinished expires. If this field is unset, ttlSecondsAfterFinished will not expire. If this field is set to zero, ttlSecondsAfterFinished expires immediately after the Workflow finishes. DEPRECATED: Use TTLStrategy.SecondsAfterCompletion instead.", Type: []string{"integer"}, Format: "int32", }, @@ -3298,10 +3298,10 @@ func schema_pkg_apis_workflow_v1alpha1_WorkflowStatus(ref common.ReferenceCallba }, }, }, - "offloadNodeStatus": { + "offloadNodeStatusVersion": { SchemaProps: spec.SchemaProps{ - Description: "Whether on not node status has been offloaded to a database. If true, then Nodes and CompressedNodes will be empty.", - Type: []string{"boolean"}, + Description: "Whether on not node status has been offloaded to a database. If exists, then Nodes and CompressedNodes will be empty. This will actually be populated with a hash of the offloaded data.", + Type: []string{"string"}, Format: "", }, }, diff --git a/pkg/apis/workflow/v1alpha1/register.go b/pkg/apis/workflow/v1alpha1/register.go index 06e5f8d6a807..588a7901072a 100644 --- a/pkg/apis/workflow/v1alpha1/register.go +++ b/pkg/apis/workflow/v1alpha1/register.go @@ -10,7 +10,8 @@ import ( // SchemeGroupVersion is group version used to register these objects var ( - SchemeGroupVersion = schema.GroupVersion{Group: workflow.Group, Version: "v1alpha1"} + SchemeGroupVersion = schema.GroupVersion{Group: workflow.Group, Version: "v1alpha1"} + WorkflowSchemaGroupVersionKind = schema.GroupVersionKind{Group: workflow.Group, Version: "v1alpha1", Kind: workflow.WorkflowKind} ) // Kind takes an unqualified kind and returns back a Group qualified GroupKind diff --git a/pkg/apis/workflow/v1alpha1/workflow_template_types.go b/pkg/apis/workflow/v1alpha1/workflow_template_types.go index 5be428945179..34372d5f6c63 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_template_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_template_types.go @@ -45,7 +45,7 @@ type WorkflowTemplateSpec struct { // Templates is a list of workflow templates. Templates []Template `json:"templates" protobuf:"bytes,1,rep,name=templates"` // Arguments hold arguments to the template. - Arguments Arguments `json:"arguments,omitempty" protobuf:"bytes,2,opt,name=arguments"` + Arguments Arguments `json:"arguments,omitempty" protobuf:"bytes,3,opt,name=arguments"` } // GetTemplateByName retrieves a defined template by its name diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 3ffb2a4a0637..24c5386099ad 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -131,9 +131,9 @@ var _ TemplateStorage = &Workflow{} // TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed type TTLStrategy struct { - SecondsAfterCompleted *int32 `json:"secondsAfterCompleted,omitempty" protobuf:"bytes,1,opt,name=secondsAfterCompleted"` - SecondsAfterSuccess *int32 `json:"secondsAfterSuccess,omitempty" protobuf:"bytes,2,opt,name=secondsAfterSuccess"` - SecondsAfterFailed *int32 `json:"secondsAfterFailed,omitempty" protobuf:"bytes,3,opt,name=secondsAfterFailed"` + SecondsAfterCompletion *int32 `json:"secondsAfterCompletion,omitempty" protobuf:"bytes,1,opt,name=secondsAfterCompletion"` + SecondsAfterSuccess *int32 `json:"secondsAfterSuccess,omitempty" protobuf:"bytes,2,opt,name=secondsAfterSuccess"` + SecondsAfterFailure *int32 `json:"secondsAfterFailure,omitempty" protobuf:"bytes,3,opt,name=secondsAfterFailure"` } // WorkflowSpec is the specification of a Workflow. @@ -229,7 +229,7 @@ type WorkflowSpec struct { // deleted after ttlSecondsAfterFinished expires. If this field is unset, // ttlSecondsAfterFinished will not expire. If this field is set to zero, // ttlSecondsAfterFinished expires immediately after the Workflow finishes. - // DEPRECATED: Use TTLStrategy.SecondsAfterCompleted instead. + // DEPRECATED: Use TTLStrategy.SecondsAfterCompletion instead. TTLSecondsAfterFinished *int32 `json:"ttlSecondsAfterFinished,omitempty" protobuf:"bytes,18,opt,name=ttlSecondsAfterFinished"` // TTLStrategy limits the lifetime of a Workflow that has finished execution depending on if it @@ -776,8 +776,9 @@ type WorkflowStatus struct { // Nodes is a mapping between a node ID and the node's status. Nodes Nodes `json:"nodes,omitempty" protobuf:"bytes,6,rep,name=nodes"` - // Whether on not node status has been offloaded to a database. If true, then Nodes and CompressedNodes will be empty. - OffloadNodeStatus bool `json:"offloadNodeStatus,omitempty" protobuf:"bytes,10,rep,name=offloadNodeStatus"` + // Whether on not node status has been offloaded to a database. If exists, then Nodes and CompressedNodes will be empty. + // This will actually be populated with a hash of the offloaded data. + OffloadNodeStatusVersion string `json:"offloadNodeStatusVersion,omitempty" protobuf:"bytes,10,rep,name=offloadNodeStatusVersion"` // StoredTemplates is a mapping between a template ref and the node's status. StoredTemplates map[string]Template `json:"storedTemplates,omitempty" protobuf:"bytes,9,rep,name=storedTemplates"` @@ -790,6 +791,18 @@ type WorkflowStatus struct { Outputs *Outputs `json:"outputs,omitempty" protobuf:"bytes,8,opt,name=outputs"` } +func (ws *WorkflowStatus) IsOffloadNodeStatus() bool { + return ws.OffloadNodeStatusVersion != "" +} + +func (ws *WorkflowStatus) GetOffloadNodeStatusVersion() string { + return ws.OffloadNodeStatusVersion +} + +func (wf *Workflow) GetOffloadNodeStatusVersion() string { + return wf.Status.GetOffloadNodeStatusVersion() +} + type RetryPolicy string const ( diff --git a/pkg/apis/workflow/v1alpha1/workflow_types_test.go b/pkg/apis/workflow/v1alpha1/workflow_types_test.go index 74a0595c7eb0..53ae49f72523 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types_test.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/stretchr/testify/assert" - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func TestWorkflows(t *testing.T) { diff --git a/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go index d529011aed96..8ffc99fe7982 100644 --- a/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go @@ -1036,8 +1036,8 @@ func (in *SuspendTemplate) DeepCopy() *SuspendTemplate { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TTLStrategy) DeepCopyInto(out *TTLStrategy) { *out = *in - if in.SecondsAfterCompleted != nil { - in, out := &in.SecondsAfterCompleted, &out.SecondsAfterCompleted + if in.SecondsAfterCompletion != nil { + in, out := &in.SecondsAfterCompletion, &out.SecondsAfterCompletion *out = new(int32) **out = **in } @@ -1046,8 +1046,8 @@ func (in *TTLStrategy) DeepCopyInto(out *TTLStrategy) { *out = new(int32) **out = **in } - if in.SecondsAfterFailed != nil { - in, out := &in.SecondsAfterFailed, &out.SecondsAfterFailed + if in.SecondsAfterFailure != nil { + in, out := &in.SecondsAfterFailure, &out.SecondsAfterFailure *out = new(int32) **out = **in } diff --git a/cmd/server/.gitignore b/server/.gitignore similarity index 100% rename from cmd/server/.gitignore rename to server/.gitignore diff --git a/cmd/server/apiserver/argoserver.go b/server/apiserver/argoserver.go similarity index 89% rename from cmd/server/apiserver/argoserver.go rename to server/apiserver/argoserver.go index 05611196c58d..9262c8ccea2c 100644 --- a/cmd/server/apiserver/argoserver.go +++ b/server/apiserver/argoserver.go @@ -6,6 +6,15 @@ import ( "net/http" "time" + "github.com/argoproj/argo/server/artifacts" + "github.com/argoproj/argo/server/auth" + "github.com/argoproj/argo/server/cronworkflow" + "github.com/argoproj/argo/server/info" + "github.com/argoproj/argo/server/static" + "github.com/argoproj/argo/server/workflow" + "github.com/argoproj/argo/server/workflowarchive" + "github.com/argoproj/argo/server/workflowtemplate" + grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" "github.com/grpc-ecosystem/grpc-gateway/runtime" @@ -20,14 +29,6 @@ import ( "k8s.io/client-go/rest" "sigs.k8s.io/yaml" - "github.com/argoproj/argo/cmd/server/artifacts" - "github.com/argoproj/argo/cmd/server/auth" - "github.com/argoproj/argo/cmd/server/cronworkflow" - "github.com/argoproj/argo/cmd/server/info" - "github.com/argoproj/argo/cmd/server/static" - "github.com/argoproj/argo/cmd/server/workflow" - "github.com/argoproj/argo/cmd/server/workflowarchive" - "github.com/argoproj/argo/cmd/server/workflowtemplate" "github.com/argoproj/argo/errors" "github.com/argoproj/argo/persist/sqldb" "github.com/argoproj/argo/pkg/apiclient" @@ -99,18 +100,21 @@ func (as *argoServer) Run(ctx context.Context, port int) { // TODO: this currently returns an error every time log.Errorf("Error marshalling config map: %s", err) } - var offloadRepo sqldb.OffloadNodeStatusRepo = sqldb.ExplosiveOffloadNodeStatusRepo - var wfArchive sqldb.WorkflowArchive = sqldb.NullWorkflowArchive - if configMap != nil && configMap.Persistence != nil { - session, tableName, err := sqldb.CreateDBSession(as.kubeClientset, as.namespace, configMap.Persistence) - if err != nil { - log.Fatal(err) - } - log.WithField("nodeStatusOffload", configMap.Persistence.NodeStatusOffload).Info("Offload node status") - if configMap.Persistence.NodeStatusOffload { - offloadRepo = sqldb.NewOffloadNodeStatusRepo(tableName, session) + var offloadRepo = sqldb.ExplosiveOffloadNodeStatusRepo + var wfArchive = sqldb.NullWorkflowArchive + if configMap != nil { + persistence := configMap.Persistence + if persistence != nil { + session, tableName, err := sqldb.CreateDBSession(as.kubeClientset, as.namespace, persistence) + if err != nil { + log.Fatal(err) + } + log.WithField("nodeStatusOffload", persistence.NodeStatusOffload).Info("Offload node status") + if persistence.NodeStatusOffload { + offloadRepo = sqldb.NewOffloadNodeStatusRepo(session, persistence.GetClusterName(), tableName) + } + wfArchive = sqldb.NewWorkflowArchive(session, persistence.GetClusterName()) } - wfArchive = sqldb.NewWorkflowArchive(session) } artifactServer := artifacts.NewArtifactServer(as.authenticator, offloadRepo, wfArchive) grpcServer := as.newGRPCServer(offloadRepo, wfArchive) diff --git a/cmd/server/artifacts/artifact_server.go b/server/artifacts/artifact_server.go similarity index 90% rename from cmd/server/artifacts/artifact_server.go rename to server/artifacts/artifact_server.go index 1e6f4dd6d03c..e97831a09860 100644 --- a/cmd/server/artifacts/artifact_server.go +++ b/server/artifacts/artifact_server.go @@ -14,9 +14,9 @@ import ( "google.golang.org/grpc/status" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/argoproj/argo/cmd/server/auth" "github.com/argoproj/argo/persist/sqldb" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo/server/auth" artifact "github.com/argoproj/argo/workflow/artifacts" "github.com/argoproj/argo/workflow/packer" ) @@ -91,9 +91,15 @@ func (a *ArtifactServer) GetArtifactByUID(w http.ResponseWriter, r *http.Request a.ok(w, data) } func (a *ArtifactServer) gateKeeping(r *http.Request) (context.Context, error) { - // TODO - we should not put the token in the URL - OSWAP obvs - authHeader := r.URL.Query().Get("Authorization") - ctx := metadata.NewIncomingContext(r.Context(), metadata.MD{"grpcgateway-authorization": []string{authHeader}}) + token := r.Header.Get("Authorization") + if token == "" { + cookie, err := r.Cookie("authorization") + if err != nil { + return nil, err + } + token = cookie.Value + } + ctx := metadata.NewIncomingContext(r.Context(), metadata.MD{"authorization": []string{token}}) return a.authN.Context(ctx) } @@ -157,12 +163,12 @@ func (a *ArtifactServer) getWorkflow(ctx context.Context, namespace string, work if err != nil { return nil, err } - if wf.Status.OffloadNodeStatus { - offloadedWf, err := a.offloadNodeStatusRepo.Get(workflowName, namespace) + if wf.Status.IsOffloadNodeStatus() { + offloadedNodes, err := a.offloadNodeStatusRepo.Get(string(wf.UID), wf.GetOffloadNodeStatusVersion()) if err != nil { return nil, err } - wf.Status.Nodes = offloadedWf.Status.Nodes + wf.Status.Nodes = offloadedNodes } return wf, nil } diff --git a/cmd/server/artifacts/resources.go b/server/artifacts/resources.go similarity index 100% rename from cmd/server/artifacts/resources.go rename to server/artifacts/resources.go diff --git a/cmd/server/auth/authorizer.go b/server/auth/authorizer.go similarity index 80% rename from cmd/server/auth/authorizer.go rename to server/auth/authorizer.go index e039d094cb49..bee70ab2d97c 100644 --- a/cmd/server/auth/authorizer.go +++ b/server/auth/authorizer.go @@ -4,11 +4,14 @@ import ( "context" "sort" + log "github.com/sirupsen/logrus" authorizationv1 "k8s.io/api/authorization/v1" ) func CanI(ctx context.Context, verb, resource, namespace, name string) (bool, error) { kubeClientset := GetKubeClient(ctx) + logCtx := log.WithFields(log.Fields{"verb": verb, "resource": resource, "namespace": namespace, "name": name}) + logCtx.Debug("CanI") review, err := kubeClientset.AuthorizationV1().SelfSubjectAccessReviews().Create(&authorizationv1.SelfSubjectAccessReview{ Spec: authorizationv1.SelfSubjectAccessReviewSpec{ ResourceAttributes: &authorizationv1.ResourceAttributes{ @@ -23,6 +26,7 @@ func CanI(ctx context.Context, verb, resource, namespace, name string) (bool, er if err != nil { return false, err } + logCtx.WithField("status", review.Status).Debug("CanI") return review.Status.Allowed, nil } @@ -32,6 +36,7 @@ type Authorizer struct { } func (a Authorizer) CanI(verb, resource, namespace, name string) (bool, error) { + logCtx := log.WithFields(log.Fields{"verb": verb, "resource": resource, "namespace": namespace, "name": name}) _, ok := a.status[namespace] if !ok { kubeClientset := GetKubeClient(a.ctx) @@ -46,9 +51,11 @@ func (a Authorizer) CanI(verb, resource, namespace, name string) (bool, error) { allowed(rule.Resources, resource) && allowed(rule.APIGroups, "argoproj.io") && allowed(rule.ResourceNames, name) { + logCtx.WithField("allowed", true).Debug("CanI") return true, nil } } + logCtx.WithField("allowed", false).Debug("CanI") return false, nil } diff --git a/cmd/server/auth/authorizer_test.go b/server/auth/authorizer_test.go similarity index 100% rename from cmd/server/auth/authorizer_test.go rename to server/auth/authorizer_test.go diff --git a/cmd/server/auth/gatekeeper.go b/server/auth/gatekeeper.go similarity index 82% rename from cmd/server/auth/gatekeeper.go rename to server/auth/gatekeeper.go index 306c5abfbfdf..f9f4f2f22aad 100644 --- a/cmd/server/auth/gatekeeper.go +++ b/server/auth/gatekeeper.go @@ -2,6 +2,7 @@ package auth import ( "context" + "net/http" "strings" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" @@ -85,15 +86,34 @@ func (s Gatekeeper) useHybridAuth() bool { return s.authType == Hybrid } -func (s Gatekeeper) useClientAuth(md metadata.MD) (bool, error) { - if s.authType == Client && len(md.Get("grpcgateway-authorization")) == 0 { - return false, status.Error(codes.Unauthenticated, "Auth Token is not found") +func (s Gatekeeper) useClientAuth(token string) bool { + if s.authType == Client { + return true } - if s.useHybridAuth() && len(md.Get("grpcgateway-authorization")) > 0 { - return true, nil + if s.useHybridAuth() && token != "" { + return true } - return true, nil + return false } + +func getToken(md metadata.MD) string { + // looks for the HTTP header `Authorization: Bearer ...` + for _, t := range md.Get("authorization") { + return strings.TrimPrefix(t, "Bearer ") + } + // check the HTTP cookie + for _, t := range md.Get("grpcgateway-cookie") { + header := http.Header{} + header.Add("Cookie", t) + request := http.Request{Header: header} + token, err := request.Cookie("authorization") + if err == nil { + return strings.TrimPrefix(token.Value, "Bearer ") + } + } + return "" +} + func (s Gatekeeper) getClients(ctx context.Context) (versioned.Interface, kubernetes.Interface, error) { if s.useServerAuth() { @@ -106,17 +126,13 @@ func (s Gatekeeper) getClients(ctx context.Context) (versioned.Interface, kubern } return nil, nil, status.Error(codes.Unauthenticated, "unable to get metadata from incoming context") } - useClientAuth, err := s.useClientAuth(md) - if err != nil { - return nil, nil, status.Errorf(codes.Unauthenticated, "auth token is not present in the request: %v", err) - } - if !useClientAuth { + + token := getToken(md) + + if !s.useClientAuth(token) { return s.wfClient, s.kubeClient, nil } - authorization := md.Get("grpcgateway-authorization") - token := strings.TrimPrefix(authorization[0], "Bearer ") - restConfig, err := kubeconfig.GetRestConfig(token) if err != nil { return nil, nil, status.Errorf(codes.Unauthenticated, "failed to create REST config: %v", err) diff --git a/cmd/server/auth/gatekeeper_test.go b/server/auth/gatekeeper_test.go similarity index 67% rename from cmd/server/auth/gatekeeper_test.go rename to server/auth/gatekeeper_test.go index 6dbb1ea28fb2..b7843765e8f7 100644 --- a/cmd/server/auth/gatekeeper_test.go +++ b/server/auth/gatekeeper_test.go @@ -29,17 +29,26 @@ func TestServer_GetWFClient(t *testing.T) { t.Run("ClientAuth", func(t *testing.T) { t.SkipNow() // TODO s := NewGatekeeper("client", wfClient, kubeClient, restConfig) - ctx, err := authAndHandle(s, metadata.NewIncomingContext(context.Background(), metadata.Pairs("grpcgateway-authorization", "v0:"+base64.StdEncoding.EncodeToString([]byte("anything"))))) - if assert.NoError(t, err) { - assert.NotEqual(t, wfClient, GetWfClient(*ctx)) - assert.NotEqual(t, kubeClient, GetKubeClient(*ctx)) - } + t.Run("AuthorizationHeader", func(t *testing.T) { + ctx, err := authAndHandle(s, metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", base64.StdEncoding.EncodeToString([]byte("anything"))))) + if assert.NoError(t, err) { + assert.NotEqual(t, wfClient, GetWfClient(*ctx)) + assert.NotEqual(t, kubeClient, GetKubeClient(*ctx)) + } + }) + t.Run("Cookie", func(t *testing.T) { + ctx, err := authAndHandle(s, metadata.NewIncomingContext(context.Background(), metadata.Pairs("grpcgateway-cookie", "authorization="+base64.StdEncoding.EncodeToString([]byte("anything"))))) + if assert.NoError(t, err) { + assert.NotEqual(t, wfClient, GetWfClient(*ctx)) + assert.NotEqual(t, kubeClient, GetKubeClient(*ctx)) + } + }) }) t.Run("HybridAuth", func(t *testing.T) { t.SkipNow() // TODO s := NewGatekeeper("hybrid", wfClient, kubeClient, restConfig) t.Run("clientAuth", func(t *testing.T) { - ctx, err := authAndHandle(s, metadata.NewIncomingContext(context.Background(), metadata.Pairs("grpcgateway-authorization", "v0:"+base64.StdEncoding.EncodeToString([]byte("{anything}"))))) + ctx, err := authAndHandle(s, metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", base64.StdEncoding.EncodeToString([]byte("{anything}"))))) if assert.NoError(t, err) { assert.NotEqual(t, wfClient, GetWfClient(*ctx)) assert.NotEqual(t, kubeClient, GetKubeClient(*ctx)) diff --git a/cmd/server/cronworkflow/cron-workflow.pb.go b/server/cronworkflow/cron-workflow.pb.go similarity index 89% rename from cmd/server/cronworkflow/cron-workflow.pb.go rename to server/cronworkflow/cron-workflow.pb.go index fdc5ab9f2bc0..7cad62d06db9 100644 --- a/cmd/server/cronworkflow/cron-workflow.pb.go +++ b/server/cronworkflow/cron-workflow.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cmd/server/cronworkflow/cron-workflow.proto +// source: server/cronworkflow/cron-workflow.proto package cronworkflow @@ -44,7 +44,7 @@ func (m *CreateCronWorkflowRequest) Reset() { *m = CreateCronWorkflowReq func (m *CreateCronWorkflowRequest) String() string { return proto.CompactTextString(m) } func (*CreateCronWorkflowRequest) ProtoMessage() {} func (*CreateCronWorkflowRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_e71e06cfb78f032a, []int{0} + return fileDescriptor_02ecfb52b8f4ca0d, []int{0} } func (m *CreateCronWorkflowRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -106,7 +106,7 @@ func (m *ListCronWorkflowsRequest) Reset() { *m = ListCronWorkflowsReque func (m *ListCronWorkflowsRequest) String() string { return proto.CompactTextString(m) } func (*ListCronWorkflowsRequest) ProtoMessage() {} func (*ListCronWorkflowsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_e71e06cfb78f032a, []int{1} + return fileDescriptor_02ecfb52b8f4ca0d, []int{1} } func (m *ListCronWorkflowsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -150,7 +150,7 @@ func (m *ListCronWorkflowsRequest) GetListOptions() *v1.ListOptions { } type GetCronWorkflowRequest struct { - CronWorkflowName string `protobuf:"bytes,1,opt,name=cronWorkflowName,proto3" json:"cronWorkflowName,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` GetOptions *v1.GetOptions `protobuf:"bytes,3,opt,name=getOptions,proto3" json:"getOptions,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -162,7 +162,7 @@ func (m *GetCronWorkflowRequest) Reset() { *m = GetCronWorkflowRequest{} func (m *GetCronWorkflowRequest) String() string { return proto.CompactTextString(m) } func (*GetCronWorkflowRequest) ProtoMessage() {} func (*GetCronWorkflowRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_e71e06cfb78f032a, []int{2} + return fileDescriptor_02ecfb52b8f4ca0d, []int{2} } func (m *GetCronWorkflowRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -191,9 +191,9 @@ func (m *GetCronWorkflowRequest) XXX_DiscardUnknown() { var xxx_messageInfo_GetCronWorkflowRequest proto.InternalMessageInfo -func (m *GetCronWorkflowRequest) GetCronWorkflowName() string { +func (m *GetCronWorkflowRequest) GetName() string { if m != nil { - return m.CronWorkflowName + return m.Name } return "" } @@ -213,7 +213,7 @@ func (m *GetCronWorkflowRequest) GetGetOptions() *v1.GetOptions { } type UpdateCronWorkflowRequest struct { - CronWorkflowName string `protobuf:"bytes,1,opt,name=cronWorkflowName,proto3" json:"cronWorkflowName,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` CronWorkflow *v1alpha1.CronWorkflow `protobuf:"bytes,3,opt,name=cronWorkflow,proto3" json:"cronWorkflow,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -225,7 +225,7 @@ func (m *UpdateCronWorkflowRequest) Reset() { *m = UpdateCronWorkflowReq func (m *UpdateCronWorkflowRequest) String() string { return proto.CompactTextString(m) } func (*UpdateCronWorkflowRequest) ProtoMessage() {} func (*UpdateCronWorkflowRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_e71e06cfb78f032a, []int{3} + return fileDescriptor_02ecfb52b8f4ca0d, []int{3} } func (m *UpdateCronWorkflowRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -254,9 +254,9 @@ func (m *UpdateCronWorkflowRequest) XXX_DiscardUnknown() { var xxx_messageInfo_UpdateCronWorkflowRequest proto.InternalMessageInfo -func (m *UpdateCronWorkflowRequest) GetCronWorkflowName() string { +func (m *UpdateCronWorkflowRequest) GetName() string { if m != nil { - return m.CronWorkflowName + return m.Name } return "" } @@ -276,7 +276,7 @@ func (m *UpdateCronWorkflowRequest) GetCronWorkflow() *v1alpha1.CronWorkflow { } type DeleteCronWorkflowRequest struct { - CronWorkflowName string `protobuf:"bytes,1,opt,name=cronWorkflowName,proto3" json:"cronWorkflowName,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` DeleteOptions *v1.DeleteOptions `protobuf:"bytes,3,opt,name=deleteOptions,proto3" json:"deleteOptions,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -288,7 +288,7 @@ func (m *DeleteCronWorkflowRequest) Reset() { *m = DeleteCronWorkflowReq func (m *DeleteCronWorkflowRequest) String() string { return proto.CompactTextString(m) } func (*DeleteCronWorkflowRequest) ProtoMessage() {} func (*DeleteCronWorkflowRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_e71e06cfb78f032a, []int{4} + return fileDescriptor_02ecfb52b8f4ca0d, []int{4} } func (m *DeleteCronWorkflowRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -317,9 +317,9 @@ func (m *DeleteCronWorkflowRequest) XXX_DiscardUnknown() { var xxx_messageInfo_DeleteCronWorkflowRequest proto.InternalMessageInfo -func (m *DeleteCronWorkflowRequest) GetCronWorkflowName() string { +func (m *DeleteCronWorkflowRequest) GetName() string { if m != nil { - return m.CronWorkflowName + return m.Name } return "" } @@ -348,7 +348,7 @@ func (m *CronWorkflowDeletedResponse) Reset() { *m = CronWorkflowDeleted func (m *CronWorkflowDeletedResponse) String() string { return proto.CompactTextString(m) } func (*CronWorkflowDeletedResponse) ProtoMessage() {} func (*CronWorkflowDeletedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_e71e06cfb78f032a, []int{5} + return fileDescriptor_02ecfb52b8f4ca0d, []int{5} } func (m *CronWorkflowDeletedResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -387,52 +387,51 @@ func init() { } func init() { - proto.RegisterFile("cmd/server/cronworkflow/cron-workflow.proto", fileDescriptor_e71e06cfb78f032a) -} - -var fileDescriptor_e71e06cfb78f032a = []byte{ - // 648 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x96, 0xcf, 0x4f, 0xd4, 0x40, - 0x14, 0xc7, 0x33, 0x90, 0x68, 0x18, 0x24, 0xea, 0x68, 0xcc, 0xb2, 0x22, 0x21, 0x0d, 0x11, 0x5c, - 0xc3, 0x0c, 0x0b, 0x1a, 0x0d, 0x89, 0x46, 0x05, 0xc3, 0x85, 0xa8, 0x29, 0x31, 0x06, 0x6f, 0x43, - 0xf7, 0x59, 0xea, 0x6e, 0x3b, 0x75, 0x66, 0x28, 0x31, 0x84, 0x8b, 0x77, 0x4f, 0xfe, 0x09, 0x1e, - 0xbc, 0xe9, 0xc5, 0x8b, 0x37, 0xe3, 0xc9, 0x83, 0x07, 0x13, 0xff, 0x01, 0x43, 0xfc, 0x2f, 0xbc, - 0x98, 0xce, 0xd2, 0xed, 0x2f, 0x1a, 0x37, 0xb0, 0xdc, 0xa6, 0x33, 0xf3, 0xde, 0xfb, 0xbc, 0x6f, - 0xdf, 0x7b, 0x2d, 0xbe, 0xee, 0xf8, 0x2d, 0xa6, 0x40, 0x46, 0x20, 0x99, 0x23, 0x45, 0xb0, 0x23, - 0x64, 0xfb, 0x45, 0x47, 0xec, 0x98, 0x87, 0xb9, 0xe4, 0x89, 0x86, 0x52, 0x68, 0x41, 0xce, 0x64, - 0x6f, 0xd4, 0x2f, 0xba, 0xc2, 0x15, 0xe6, 0x80, 0xc5, 0xab, 0xee, 0x9d, 0xfa, 0x84, 0x2b, 0x84, - 0xdb, 0x01, 0xc6, 0x43, 0x8f, 0xf1, 0x20, 0x10, 0x9a, 0x6b, 0x4f, 0x04, 0xea, 0xe0, 0xf4, 0x46, - 0xfb, 0xb6, 0xa2, 0x9e, 0x88, 0x4f, 0x7d, 0xee, 0x6c, 0x79, 0x01, 0xc8, 0xd7, 0x2c, 0x6c, 0xbb, - 0xf1, 0x86, 0x62, 0x3e, 0x68, 0xce, 0xa2, 0x26, 0x73, 0x21, 0x00, 0xc9, 0x35, 0xb4, 0x0e, 0xac, - 0x96, 0x5d, 0x4f, 0x6f, 0x6d, 0x6f, 0x52, 0x47, 0xf8, 0x8c, 0x4b, 0x13, 0xf4, 0xa5, 0x59, 0xa4, - 0xa6, 0x3d, 0xee, 0xa8, 0xc9, 0x3b, 0xe1, 0x16, 0x2f, 0x3b, 0xb1, 0xd2, 0xd0, 0xcc, 0x11, 0x12, - 0x0e, 0x09, 0x64, 0xfd, 0x45, 0x78, 0x7c, 0x59, 0x02, 0xd7, 0xb0, 0x2c, 0x45, 0xf0, 0xec, 0xc0, - 0xa7, 0x0d, 0xaf, 0xb6, 0x41, 0x69, 0x32, 0x81, 0x47, 0x02, 0xee, 0x83, 0x0a, 0xb9, 0x03, 0x35, - 0x34, 0x85, 0x66, 0x47, 0xec, 0x74, 0x83, 0x00, 0x36, 0xf2, 0x24, 0x46, 0xb5, 0xa1, 0x29, 0x34, - 0x3b, 0xba, 0x70, 0x9f, 0xa6, 0xec, 0x34, 0x61, 0x37, 0x0b, 0x1a, 0xb6, 0x5d, 0x1a, 0xb3, 0xd3, - 0x9e, 0xca, 0x09, 0x3b, 0xcd, 0x45, 0xcf, 0xb9, 0x25, 0x1b, 0x78, 0xcc, 0x31, 0x84, 0x8f, 0x43, - 0x23, 0x6c, 0x6d, 0xd8, 0xc4, 0x59, 0xa4, 0xdd, 0xf4, 0x68, 0x56, 0xd9, 0x34, 0x44, 0xac, 0x2c, - 0x8d, 0x62, 0xc7, 0x19, 0x53, 0x3b, 0xef, 0xc9, 0x7a, 0x8b, 0x70, 0x6d, 0xcd, 0x53, 0x3a, 0x1b, - 0x5d, 0xf5, 0x97, 0xfc, 0x3a, 0x1e, 0xed, 0x78, 0x4a, 0x27, 0x4c, 0xdd, 0xdc, 0x9b, 0xfd, 0x31, - 0xad, 0xa5, 0x86, 0x76, 0xd6, 0x8b, 0xf5, 0x19, 0xe1, 0x4b, 0xab, 0xa0, 0x0f, 0x7b, 0x15, 0x0d, - 0x7c, 0x2e, 0xab, 0xca, 0x23, 0xee, 0x27, 0x50, 0xa5, 0xfd, 0x3c, 0xf9, 0x50, 0x91, 0xfc, 0x09, - 0xc6, 0x2e, 0xe8, 0xbc, 0x98, 0xf3, 0xfd, 0x81, 0xaf, 0xf6, 0xec, 0xec, 0x8c, 0x0f, 0xeb, 0x07, - 0xc2, 0xe3, 0x4f, 0xc3, 0x56, 0x45, 0x11, 0x0d, 0x8e, 0xbc, 0x58, 0x70, 0xc3, 0x27, 0x52, 0x70, - 0xd6, 0x57, 0x84, 0xc7, 0x57, 0xa0, 0x03, 0x27, 0x9d, 0xce, 0x06, 0x1e, 0x6b, 0x99, 0x30, 0x47, - 0x2a, 0xec, 0x95, 0xac, 0xa9, 0x9d, 0xf7, 0x64, 0x5d, 0xc1, 0x97, 0xb3, 0xec, 0xdd, 0xbb, 0x2d, - 0x1b, 0x54, 0x28, 0x02, 0x05, 0x0b, 0xef, 0x4f, 0xe3, 0x0b, 0xd9, 0xf3, 0x75, 0x90, 0x91, 0xe7, - 0x00, 0xf9, 0x84, 0x30, 0x29, 0x4f, 0x03, 0x32, 0x43, 0xb3, 0x63, 0x90, 0x56, 0xce, 0x8b, 0xfa, - 0xf1, 0x5f, 0x85, 0x35, 0xf7, 0xe6, 0xd7, 0x9f, 0x77, 0x43, 0x33, 0x96, 0x65, 0xc6, 0x56, 0xd4, - 0xcc, 0x8f, 0x65, 0xc5, 0x76, 0x7b, 0xfa, 0xed, 0x2d, 0xa1, 0x06, 0xf9, 0x88, 0xf0, 0xf9, 0x52, - 0x07, 0x93, 0xab, 0x79, 0xe0, 0xaa, 0x16, 0xaf, 0x3f, 0x3c, 0x36, 0x6f, 0xec, 0xda, 0x6a, 0x18, - 0xe6, 0x69, 0xd2, 0x07, 0x33, 0xf9, 0x82, 0xf0, 0xd9, 0x42, 0x8b, 0x93, 0xe9, 0x3c, 0xee, 0xe1, - 0x13, 0x60, 0x10, 0xe2, 0xde, 0x31, 0xa0, 0xb7, 0xc8, 0xcd, 0xff, 0x83, 0xb2, 0xdd, 0x62, 0x35, - 0xef, 0x91, 0x6f, 0x08, 0x93, 0x72, 0x9f, 0x17, 0xcb, 0xa3, 0x72, 0x12, 0x0c, 0x22, 0x83, 0x7b, - 0x26, 0x83, 0xa5, 0xfa, 0xd1, 0x32, 0x88, 0x2b, 0xe6, 0x03, 0xc2, 0xa4, 0xdc, 0xdd, 0xc5, 0x24, - 0x2a, 0xfb, 0xbf, 0x7e, 0xad, 0xd8, 0x0c, 0x95, 0x6d, 0x96, 0xc8, 0xdd, 0x38, 0x1a, 0xec, 0x83, - 0xbb, 0xdf, 0xf7, 0x27, 0xd1, 0xcf, 0xfd, 0x49, 0xf4, 0x7b, 0x7f, 0x12, 0x3d, 0x9f, 0xaf, 0xfc, - 0x25, 0xa8, 0xf8, 0xa1, 0xd9, 0x3c, 0x65, 0x3e, 0xf1, 0x8b, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, - 0x3e, 0x1e, 0x3b, 0x95, 0xf2, 0x08, 0x00, 0x00, + proto.RegisterFile("server/cronworkflow/cron-workflow.proto", fileDescriptor_02ecfb52b8f4ca0d) +} + +var fileDescriptor_02ecfb52b8f4ca0d = []byte{ + // 632 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x96, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0xc6, 0xb5, 0x2d, 0xaa, 0xd4, 0x2d, 0x15, 0x62, 0x41, 0x28, 0x35, 0x25, 0xaa, 0xac, 0x8a, + 0xb4, 0x81, 0xae, 0x49, 0xdb, 0x03, 0xea, 0x0d, 0x52, 0xd4, 0x4b, 0x25, 0x90, 0x2b, 0x84, 0xca, + 0x6d, 0xeb, 0x0c, 0x8e, 0x49, 0xe2, 0x35, 0xbb, 0x5b, 0x57, 0x08, 0xf5, 0xc2, 0x9d, 0x13, 0x47, + 0x78, 0x00, 0x2e, 0xc0, 0x05, 0xf1, 0x0c, 0x1c, 0x91, 0x78, 0x01, 0x14, 0xf1, 0x16, 0x1c, 0x40, + 0xde, 0xc4, 0xf1, 0x9f, 0xc4, 0xc2, 0xd0, 0x70, 0x1b, 0x7b, 0x77, 0x66, 0x7e, 0xfb, 0x65, 0xbe, + 0x75, 0x70, 0x4d, 0x82, 0x08, 0x41, 0x58, 0x8e, 0xe0, 0xfe, 0x09, 0x17, 0x9d, 0x27, 0x5d, 0x7e, + 0xa2, 0x1f, 0x36, 0xe2, 0x27, 0x1a, 0x08, 0xae, 0x38, 0x39, 0x9f, 0xde, 0x61, 0x5c, 0x76, 0xb9, + 0xcb, 0xf5, 0x82, 0x15, 0x45, 0x83, 0x3d, 0xc6, 0xb2, 0xcb, 0xb9, 0xdb, 0x05, 0x8b, 0x05, 0x9e, + 0xc5, 0x7c, 0x9f, 0x2b, 0xa6, 0x3c, 0xee, 0xcb, 0xe1, 0xea, 0x76, 0xe7, 0xb6, 0xa4, 0x1e, 0x8f, + 0x56, 0x7b, 0xcc, 0x69, 0x7b, 0x3e, 0x88, 0xe7, 0x56, 0xd0, 0x71, 0xa3, 0x17, 0xd2, 0xea, 0x81, + 0x62, 0x56, 0xd8, 0xb0, 0x5c, 0xf0, 0x41, 0x30, 0x05, 0xad, 0x61, 0x56, 0xd3, 0xf5, 0x54, 0xfb, + 0xf8, 0x88, 0x3a, 0xbc, 0x67, 0x31, 0xa1, 0x9b, 0x3e, 0xd5, 0x41, 0x92, 0x3a, 0xe2, 0x0e, 0x1b, + 0xac, 0x1b, 0xb4, 0xd9, 0x78, 0x11, 0x33, 0x69, 0x6d, 0x39, 0x5c, 0xc0, 0x84, 0x46, 0xe6, 0x4f, + 0x84, 0x97, 0x9a, 0x02, 0x98, 0x82, 0xa6, 0xe0, 0xfe, 0xa3, 0x61, 0x4d, 0x1b, 0x9e, 0x1d, 0x83, + 0x54, 0x64, 0x19, 0xcf, 0xfb, 0xac, 0x07, 0x32, 0x60, 0x0e, 0x54, 0xd0, 0x0a, 0x5a, 0x9b, 0xb7, + 0x93, 0x17, 0x04, 0xb0, 0x96, 0x27, 0x4e, 0xaa, 0xcc, 0xac, 0xa0, 0xb5, 0x85, 0xcd, 0x3b, 0x34, + 0x61, 0xa7, 0x31, 0xbb, 0x0e, 0x68, 0xd0, 0x71, 0x69, 0xc4, 0x4e, 0x47, 0x2a, 0xc7, 0xec, 0x34, + 0xd3, 0x3d, 0x53, 0x96, 0x1c, 0xe2, 0x45, 0x47, 0x13, 0xde, 0x0f, 0xb4, 0xb0, 0x95, 0x59, 0xdd, + 0x67, 0x8b, 0x0e, 0x8e, 0x47, 0xd3, 0xca, 0x26, 0x2d, 0x22, 0x65, 0x69, 0x18, 0x15, 0x4e, 0xa5, + 0xda, 0xd9, 0x4a, 0xe6, 0x2b, 0x84, 0x2b, 0xfb, 0x9e, 0x54, 0xe9, 0xee, 0xb2, 0xdc, 0xe1, 0x0f, + 0xf0, 0x42, 0xd7, 0x93, 0x2a, 0x66, 0x1a, 0x9c, 0xbd, 0x51, 0x8e, 0x69, 0x3f, 0x49, 0xb4, 0xd3, + 0x55, 0xcc, 0xb7, 0x08, 0x5f, 0xd9, 0x03, 0x35, 0xe9, 0xa7, 0x20, 0xf8, 0x5c, 0xd4, 0x7c, 0x08, + 0xa2, 0xe3, 0x2c, 0xe1, 0x4c, 0x9e, 0xf0, 0x01, 0xc6, 0x2e, 0xa8, 0xac, 0x68, 0xb7, 0xca, 0x01, + 0xee, 0x8d, 0xf2, 0xec, 0x54, 0x0d, 0xf3, 0x13, 0xc2, 0x4b, 0x0f, 0x83, 0x56, 0xc1, 0xb0, 0xfc, + 0x3d, 0x61, 0x7e, 0x80, 0x66, 0xff, 0xcb, 0x00, 0x99, 0xef, 0x10, 0x5e, 0xda, 0x85, 0x2e, 0x4c, + 0x0b, 0xfb, 0x10, 0x2f, 0xb6, 0x74, 0xb9, 0x7f, 0x1a, 0xc8, 0xdd, 0x74, 0xaa, 0x9d, 0xad, 0x64, + 0x5e, 0xc3, 0x57, 0xd3, 0x8c, 0x83, 0xbd, 0x2d, 0x1b, 0x64, 0xc0, 0x7d, 0x09, 0x9b, 0xbf, 0xe6, + 0xf0, 0xa5, 0xf4, 0xfa, 0x01, 0x88, 0xd0, 0x73, 0x80, 0x7c, 0x44, 0x98, 0x8c, 0xbb, 0x98, 0xd4, + 0x68, 0xfa, 0xfa, 0xa2, 0x85, 0x3e, 0x37, 0xce, 0x2e, 0xb9, 0xb9, 0xf1, 0xf2, 0xdb, 0x8f, 0xd7, + 0x33, 0x35, 0xd3, 0xd4, 0xd7, 0x4d, 0xd8, 0xc8, 0x5e, 0xa7, 0xd2, 0x7a, 0x31, 0xd2, 0xef, 0x74, + 0x07, 0xd5, 0xc9, 0x07, 0x84, 0x2f, 0x8e, 0x39, 0x8f, 0x5c, 0xcf, 0x02, 0x17, 0x59, 0xd3, 0xb8, + 0x77, 0x66, 0xde, 0xa8, 0xb4, 0x59, 0xd7, 0xcc, 0xab, 0xa4, 0x04, 0x33, 0x79, 0x8f, 0xf0, 0x85, + 0x9c, 0x35, 0xc9, 0x6a, 0x16, 0x77, 0xb2, 0x73, 0xa7, 0x21, 0x6e, 0x43, 0x83, 0xde, 0x20, 0xeb, + 0x7f, 0x06, 0x1d, 0xc4, 0xa7, 0xe4, 0x33, 0xc2, 0x64, 0xdc, 0xab, 0xf9, 0x91, 0x28, 0x74, 0xf3, + 0x34, 0xa8, 0xb7, 0x35, 0x35, 0x35, 0xca, 0x53, 0x47, 0x93, 0xf1, 0x06, 0x61, 0x32, 0xee, 0xd6, + 0x3c, 0x78, 0xa1, 0x9f, 0x8d, 0xf5, 0xfc, 0xd0, 0x17, 0xda, 0x29, 0x96, 0xb5, 0x5e, 0x1e, 0xf0, + 0xee, 0xce, 0x97, 0x7e, 0x15, 0x7d, 0xed, 0x57, 0xd1, 0xf7, 0x7e, 0x15, 0x3d, 0xbe, 0x59, 0xf8, + 0x99, 0x9e, 0xf0, 0x07, 0xe3, 0x68, 0x4e, 0x7f, 0x72, 0xb7, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, + 0x95, 0xe2, 0x7d, 0x1a, 0x7e, 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -656,7 +655,7 @@ var _CronWorkflowService_serviceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "cmd/server/cronworkflow/cron-workflow.proto", + Metadata: "server/cronworkflow/cron-workflow.proto", } func (m *CreateCronWorkflowRequest) Marshal() (dAtA []byte, err error) { @@ -806,10 +805,10 @@ func (m *GetCronWorkflowRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) i-- dAtA[i] = 0x12 } - if len(m.CronWorkflowName) > 0 { - i -= len(m.CronWorkflowName) - copy(dAtA[i:], m.CronWorkflowName) - i = encodeVarintCronWorkflow(dAtA, i, uint64(len(m.CronWorkflowName))) + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintCronWorkflow(dAtA, i, uint64(len(m.Name))) i-- dAtA[i] = 0xa } @@ -859,10 +858,10 @@ func (m *UpdateCronWorkflowRequest) MarshalToSizedBuffer(dAtA []byte) (int, erro i-- dAtA[i] = 0x12 } - if len(m.CronWorkflowName) > 0 { - i -= len(m.CronWorkflowName) - copy(dAtA[i:], m.CronWorkflowName) - i = encodeVarintCronWorkflow(dAtA, i, uint64(len(m.CronWorkflowName))) + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintCronWorkflow(dAtA, i, uint64(len(m.Name))) i-- dAtA[i] = 0xa } @@ -912,10 +911,10 @@ func (m *DeleteCronWorkflowRequest) MarshalToSizedBuffer(dAtA []byte) (int, erro i-- dAtA[i] = 0x12 } - if len(m.CronWorkflowName) > 0 { - i -= len(m.CronWorkflowName) - copy(dAtA[i:], m.CronWorkflowName) - i = encodeVarintCronWorkflow(dAtA, i, uint64(len(m.CronWorkflowName))) + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintCronWorkflow(dAtA, i, uint64(len(m.Name))) i-- dAtA[i] = 0xa } @@ -1010,7 +1009,7 @@ func (m *GetCronWorkflowRequest) Size() (n int) { } var l int _ = l - l = len(m.CronWorkflowName) + l = len(m.Name) if l > 0 { n += 1 + l + sovCronWorkflow(uint64(l)) } @@ -1034,7 +1033,7 @@ func (m *UpdateCronWorkflowRequest) Size() (n int) { } var l int _ = l - l = len(m.CronWorkflowName) + l = len(m.Name) if l > 0 { n += 1 + l + sovCronWorkflow(uint64(l)) } @@ -1058,7 +1057,7 @@ func (m *DeleteCronWorkflowRequest) Size() (n int) { } var l int _ = l - l = len(m.CronWorkflowName) + l = len(m.Name) if l > 0 { n += 1 + l + sovCronWorkflow(uint64(l)) } @@ -1405,7 +1404,7 @@ func (m *GetCronWorkflowRequest) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CronWorkflowName", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1433,7 +1432,7 @@ func (m *GetCronWorkflowRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CronWorkflowName = string(dAtA[iNdEx:postIndex]) + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -1559,7 +1558,7 @@ func (m *UpdateCronWorkflowRequest) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CronWorkflowName", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1587,7 +1586,7 @@ func (m *UpdateCronWorkflowRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CronWorkflowName = string(dAtA[iNdEx:postIndex]) + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -1713,7 +1712,7 @@ func (m *DeleteCronWorkflowRequest) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CronWorkflowName", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1741,7 +1740,7 @@ func (m *DeleteCronWorkflowRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CronWorkflowName = string(dAtA[iNdEx:postIndex]) + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { diff --git a/cmd/server/cronworkflow/cron-workflow.pb.gw.go b/server/cronworkflow/cron-workflow.pb.gw.go similarity index 93% rename from cmd/server/cronworkflow/cron-workflow.pb.gw.go rename to server/cronworkflow/cron-workflow.pb.gw.go index c077b1946eb8..05545936878f 100644 --- a/cmd/server/cronworkflow/cron-workflow.pb.gw.go +++ b/server/cronworkflow/cron-workflow.pb.gw.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: cmd/server/cronworkflow/cron-workflow.proto +// source: server/cronworkflow/cron-workflow.proto /* Package cronworkflow is a reverse proxy. @@ -171,7 +171,7 @@ func local_request_CronWorkflowService_ListCronWorkflows_0(ctx context.Context, } var ( - filter_CronWorkflowService_GetCronWorkflow_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0, "cronWorkflowName": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} + filter_CronWorkflowService_GetCronWorkflow_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0, "name": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} ) func request_CronWorkflowService_GetCronWorkflow_0(ctx context.Context, marshaler runtime.Marshaler, client CronWorkflowServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -196,15 +196,15 @@ func request_CronWorkflowService_GetCronWorkflow_0(ctx context.Context, marshale return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) } - val, ok = pathParams["cronWorkflowName"] + val, ok = pathParams["name"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cronWorkflowName") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") } - protoReq.CronWorkflowName, err = runtime.String(val) + protoReq.Name, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cronWorkflowName", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } if err := req.ParseForm(); err != nil { @@ -241,15 +241,15 @@ func local_request_CronWorkflowService_GetCronWorkflow_0(ctx context.Context, ma return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) } - val, ok = pathParams["cronWorkflowName"] + val, ok = pathParams["name"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cronWorkflowName") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") } - protoReq.CronWorkflowName, err = runtime.String(val) + protoReq.Name, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cronWorkflowName", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_CronWorkflowService_GetCronWorkflow_0); err != nil { @@ -291,15 +291,15 @@ func request_CronWorkflowService_UpdateCronWorkflow_0(ctx context.Context, marsh return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) } - val, ok = pathParams["cronWorkflowName"] + val, ok = pathParams["name"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cronWorkflowName") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") } - protoReq.CronWorkflowName, err = runtime.String(val) + protoReq.Name, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cronWorkflowName", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } msg, err := client.UpdateCronWorkflow(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -337,15 +337,15 @@ func local_request_CronWorkflowService_UpdateCronWorkflow_0(ctx context.Context, return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) } - val, ok = pathParams["cronWorkflowName"] + val, ok = pathParams["name"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cronWorkflowName") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") } - protoReq.CronWorkflowName, err = runtime.String(val) + protoReq.Name, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cronWorkflowName", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } msg, err := server.UpdateCronWorkflow(ctx, &protoReq) @@ -354,7 +354,7 @@ func local_request_CronWorkflowService_UpdateCronWorkflow_0(ctx context.Context, } var ( - filter_CronWorkflowService_DeleteCronWorkflow_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0, "cronWorkflowName": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} + filter_CronWorkflowService_DeleteCronWorkflow_0 = &utilities.DoubleArray{Encoding: map[string]int{"namespace": 0, "name": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} ) func request_CronWorkflowService_DeleteCronWorkflow_0(ctx context.Context, marshaler runtime.Marshaler, client CronWorkflowServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -379,15 +379,15 @@ func request_CronWorkflowService_DeleteCronWorkflow_0(ctx context.Context, marsh return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) } - val, ok = pathParams["cronWorkflowName"] + val, ok = pathParams["name"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cronWorkflowName") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") } - protoReq.CronWorkflowName, err = runtime.String(val) + protoReq.Name, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cronWorkflowName", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } if err := req.ParseForm(); err != nil { @@ -424,15 +424,15 @@ func local_request_CronWorkflowService_DeleteCronWorkflow_0(ctx context.Context, return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) } - val, ok = pathParams["cronWorkflowName"] + val, ok = pathParams["name"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cronWorkflowName") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") } - protoReq.CronWorkflowName, err = runtime.String(val) + protoReq.Name, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cronWorkflowName", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_CronWorkflowService_DeleteCronWorkflow_0); err != nil { @@ -698,11 +698,11 @@ var ( pattern_CronWorkflowService_ListCronWorkflows_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "cron-workflows", "namespace"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_CronWorkflowService_GetCronWorkflow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "v1", "cron-workflows", "namespace", "cronWorkflowName"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_CronWorkflowService_GetCronWorkflow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "v1", "cron-workflows", "namespace", "name"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_CronWorkflowService_UpdateCronWorkflow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "v1", "cron-workflows", "namespace", "cronWorkflowName"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_CronWorkflowService_UpdateCronWorkflow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "v1", "cron-workflows", "namespace", "name"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_CronWorkflowService_DeleteCronWorkflow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "v1", "cron-workflows", "namespace", "cronWorkflowName"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_CronWorkflowService_DeleteCronWorkflow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"api", "v1", "cron-workflows", "namespace", "name"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( diff --git a/cmd/server/cronworkflow/cron-workflow.proto b/server/cronworkflow/cron-workflow.proto similarity index 87% rename from cmd/server/cronworkflow/cron-workflow.proto rename to server/cronworkflow/cron-workflow.proto index 2825b40ba942..c602d7f0126b 100644 --- a/cmd/server/cronworkflow/cron-workflow.proto +++ b/server/cronworkflow/cron-workflow.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -option go_package = "github.com/argoproj/argo/cmd/server/cronworkflow"; +option go_package = "github.com/argoproj/argo/server/cronworkflow"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; @@ -19,17 +19,17 @@ message ListCronWorkflowsRequest { k8s.io.apimachinery.pkg.apis.meta.v1.ListOptions listOptions = 2; } message GetCronWorkflowRequest { - string cronWorkflowName = 1; + string name = 1; string namespace = 2; k8s.io.apimachinery.pkg.apis.meta.v1.GetOptions getOptions = 3; } message UpdateCronWorkflowRequest { - string cronWorkflowName = 1; + string name = 1; string namespace = 2; github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.CronWorkflow cronWorkflow = 3; } message DeleteCronWorkflowRequest { - string cronWorkflowName = 1; + string name = 1; string namespace = 2; k8s.io.apimachinery.pkg.apis.meta.v1.DeleteOptions deleteOptions = 3; } @@ -49,17 +49,17 @@ service CronWorkflowService { } rpc GetCronWorkflow (GetCronWorkflowRequest) returns (github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.CronWorkflow) { - option (google.api.http).get = "/api/v1/cron-workflows/{namespace}/{cronWorkflowName}"; + option (google.api.http).get = "/api/v1/cron-workflows/{namespace}/{name}"; } rpc UpdateCronWorkflow (UpdateCronWorkflowRequest) returns (github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.CronWorkflow) { option (google.api.http) = { - put: "/api/v1/cron-workflows/{namespace}/{cronWorkflowName}" + put: "/api/v1/cron-workflows/{namespace}/{name}" body: "*" }; } rpc DeleteCronWorkflow (DeleteCronWorkflowRequest) returns (CronWorkflowDeletedResponse) { - option (google.api.http).delete = "/api/v1/cron-workflows/{namespace}/{cronWorkflowName}"; + option (google.api.http).delete = "/api/v1/cron-workflows/{namespace}/{name}"; } } \ No newline at end of file diff --git a/cmd/server/cronworkflow/cron-workflow.swagger.json b/server/cronworkflow/cron-workflow.swagger.json similarity index 99% rename from cmd/server/cronworkflow/cron-workflow.swagger.json rename to server/cronworkflow/cron-workflow.swagger.json index 39a8e718a1a8..0c6a80cac71e 100644 --- a/cmd/server/cronworkflow/cron-workflow.swagger.json +++ b/server/cronworkflow/cron-workflow.swagger.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "cmd/server/cronworkflow/cron-workflow.proto", + "title": "server/cronworkflow/cron-workflow.proto", "version": "version not set" }, "consumes": [ @@ -125,7 +125,7 @@ ] } }, - "/api/v1/cron-workflows/{namespace}/{cronWorkflowName}": { + "/api/v1/cron-workflows/{namespace}/{name}": { "get": { "operationId": "GetCronWorkflow", "responses": { @@ -144,7 +144,7 @@ "type": "string" }, { - "name": "cronWorkflowName", + "name": "name", "in": "path", "required": true, "type": "string" @@ -179,7 +179,7 @@ "type": "string" }, { - "name": "cronWorkflowName", + "name": "name", "in": "path", "required": true, "type": "string" @@ -255,7 +255,7 @@ "type": "string" }, { - "name": "cronWorkflowName", + "name": "name", "in": "path", "required": true, "type": "string" @@ -310,7 +310,7 @@ "cronworkflowUpdateCronWorkflowRequest": { "type": "object", "properties": { - "cronWorkflowName": { + "name": { "type": "string" }, "namespace": { @@ -3598,7 +3598,7 @@ "v1alpha1TTLStrategy": { "type": "object", "properties": { - "secondsAfterCompleted": { + "secondsAfterCompletion": { "type": "integer", "format": "int32" }, @@ -3606,7 +3606,7 @@ "type": "integer", "format": "int32" }, - "secondsAfterFailed": { + "secondsAfterFailure": { "type": "integer", "format": "int32" } @@ -3940,7 +3940,7 @@ "ttlSecondsAfterFinished": { "type": "integer", "format": "int32", - "description": "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution\n(Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be\ndeleted after ttlSecondsAfterFinished expires. If this field is unset,\nttlSecondsAfterFinished will not expire. If this field is set to zero,\nttlSecondsAfterFinished expires immediately after the Workflow finishes.\nDEPRECATED: Use TTLStrategy.SecondsAfterCompleted instead." + "description": "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution\n(Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be\ndeleted after ttlSecondsAfterFinished expires. If this field is unset,\nttlSecondsAfterFinished will not expire. If this field is set to zero,\nttlSecondsAfterFinished expires immediately after the Workflow finishes.\nDEPRECATED: Use TTLStrategy.SecondsAfterCompletion instead." }, "ttlStrategy": { "$ref": "#/definitions/v1alpha1TTLStrategy", diff --git a/cmd/server/cronworkflow/cron_workflow_server.go b/server/cronworkflow/cron_workflow_server.go similarity index 91% rename from cmd/server/cronworkflow/cron_workflow_server.go rename to server/cronworkflow/cron_workflow_server.go index a89af6d4e8f6..93b0b427318f 100644 --- a/cmd/server/cronworkflow/cron_workflow_server.go +++ b/server/cronworkflow/cron_workflow_server.go @@ -5,8 +5,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/argoproj/argo/cmd/server/auth" "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo/server/auth" ) type cronWorkflowServiceServer struct { @@ -33,7 +33,7 @@ func (c *cronWorkflowServiceServer) GetCronWorkflow(ctx context.Context, req *Ge if req.GetOptions != nil { options = *req.GetOptions } - return auth.GetWfClient(ctx).ArgoprojV1alpha1().CronWorkflows(req.Namespace).Get(req.CronWorkflowName, options) + return auth.GetWfClient(ctx).ArgoprojV1alpha1().CronWorkflows(req.Namespace).Get(req.Name, options) } func (c *cronWorkflowServiceServer) UpdateCronWorkflow(ctx context.Context, req *UpdateCronWorkflowRequest) (*v1alpha1.CronWorkflow, error) { @@ -45,7 +45,7 @@ func (c *cronWorkflowServiceServer) UpdateCronWorkflow(ctx context.Context, req } func (c *cronWorkflowServiceServer) DeleteCronWorkflow(ctx context.Context, req *DeleteCronWorkflowRequest) (*CronWorkflowDeletedResponse, error) { - err := auth.GetWfClient(ctx).ArgoprojV1alpha1().CronWorkflows(req.Namespace).Delete(req.CronWorkflowName, req.DeleteOptions) + err := auth.GetWfClient(ctx).ArgoprojV1alpha1().CronWorkflows(req.Namespace).Delete(req.Name, req.DeleteOptions) if err != nil { return nil, err } diff --git a/cmd/server/cronworkflow/cron_workflow_server_test.go b/server/cronworkflow/cron_workflow_server_test.go similarity index 84% rename from cmd/server/cronworkflow/cron_workflow_server_test.go rename to server/cronworkflow/cron_workflow_server_test.go index d9dd7b99db7f..1dbf4f37e4a9 100644 --- a/cmd/server/cronworkflow/cron_workflow_server_test.go +++ b/server/cronworkflow/cron_workflow_server_test.go @@ -4,10 +4,11 @@ import ( "context" "testing" + "github.com/argoproj/argo/server/auth" + "github.com/stretchr/testify/assert" - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/argoproj/argo/cmd/server/auth" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" wftFake "github.com/argoproj/argo/pkg/client/clientset/versioned/fake" ) @@ -36,19 +37,19 @@ func Test_cronWorkflowServiceServer(t *testing.T) { } }) t.Run("GetCronWorkflow", func(t *testing.T) { - cronWf, err := server.GetCronWorkflow(ctx, &GetCronWorkflowRequest{Namespace: "my-ns", CronWorkflowName: "my-name"}) + cronWf, err := server.GetCronWorkflow(ctx, &GetCronWorkflowRequest{Namespace: "my-ns", Name: "my-name"}) if assert.NoError(t, err) { assert.NotNil(t, cronWf) } }) t.Run("UpdateCronWorkflow", func(t *testing.T) { - cronWf, err := server.UpdateCronWorkflow(ctx, &UpdateCronWorkflowRequest{Namespace: "my-ns", CronWorkflowName: "my-name", CronWorkflow: cronWf}) + cronWf, err := server.UpdateCronWorkflow(ctx, &UpdateCronWorkflowRequest{Namespace: "my-ns", Name: "my-name", CronWorkflow: cronWf}) if assert.NoError(t, err) { assert.NotNil(t, cronWf) } }) t.Run("DeleteCronWorkflow", func(t *testing.T) { - _, err := server.DeleteCronWorkflow(ctx, &DeleteCronWorkflowRequest{CronWorkflowName: "my-name", Namespace: "my-ns"}) + _, err := server.DeleteCronWorkflow(ctx, &DeleteCronWorkflowRequest{Name: "my-name", Namespace: "my-ns"}) assert.NoError(t, err) }) } diff --git a/cmd/server/info/info.pb.go b/server/info/info.pb.go similarity index 85% rename from cmd/server/info/info.pb.go rename to server/info/info.pb.go index 91e924d566b8..5001edcd3d89 100644 --- a/cmd/server/info/info.pb.go +++ b/server/info/info.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cmd/server/info/info.proto +// source: server/info/info.proto package info @@ -41,7 +41,7 @@ func (m *GetInfoRequest) Reset() { *m = GetInfoRequest{} } func (m *GetInfoRequest) String() string { return proto.CompactTextString(m) } func (*GetInfoRequest) ProtoMessage() {} func (*GetInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8b893c3550e6e6df, []int{0} + return fileDescriptor_bc6e4252b6544a4e, []int{0} } func (m *GetInfoRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -81,7 +81,7 @@ func (m *InfoResponse) Reset() { *m = InfoResponse{} } func (m *InfoResponse) String() string { return proto.CompactTextString(m) } func (*InfoResponse) ProtoMessage() {} func (*InfoResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8b893c3550e6e6df, []int{1} + return fileDescriptor_bc6e4252b6544a4e, []int{1} } func (m *InfoResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -122,30 +122,30 @@ func init() { proto.RegisterType((*InfoResponse)(nil), "info.InfoResponse") } -func init() { proto.RegisterFile("cmd/server/info/info.proto", fileDescriptor_8b893c3550e6e6df) } - -var fileDescriptor_8b893c3550e6e6df = []byte{ - // 312 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xc1, 0x4a, 0x3b, 0x31, - 0x10, 0xc6, 0xd9, 0x3f, 0x7f, 0x14, 0xd7, 0x52, 0xca, 0xd2, 0x83, 0x2c, 0x52, 0x64, 0x4f, 0xc5, - 0xc3, 0x0e, 0x55, 0x11, 0xf1, 0xa8, 0x07, 0xe9, 0xc5, 0x43, 0xbd, 0x88, 0xb7, 0xe9, 0x76, 0x9a, - 0xc6, 0x36, 0x99, 0x98, 0xa4, 0x5b, 0xbc, 0xfa, 0x0a, 0xbe, 0x94, 0x47, 0xc1, 0x17, 0x90, 0xe2, - 0x83, 0xc8, 0xa6, 0x0b, 0x55, 0xab, 0x97, 0x30, 0xf9, 0x3e, 0xbe, 0xf9, 0x25, 0x33, 0x71, 0x5a, - 0xa8, 0x11, 0x38, 0xb2, 0x25, 0x59, 0x90, 0x7a, 0xcc, 0xe1, 0xc8, 0x8d, 0x65, 0xcf, 0xc9, 0xff, - 0xaa, 0x4e, 0xdb, 0x82, 0x05, 0x07, 0x01, 0xaa, 0x6a, 0xe5, 0xa5, 0xfb, 0x82, 0x59, 0xcc, 0x08, - 0xd0, 0x48, 0x40, 0xad, 0xd9, 0xa3, 0x97, 0xac, 0x5d, 0xed, 0x9e, 0x4c, 0xcf, 0x5c, 0x2e, 0xb9, - 0x72, 0x15, 0x16, 0x13, 0xa9, 0xc9, 0x3e, 0x82, 0x99, 0x8a, 0x4a, 0x70, 0xa0, 0xc8, 0x23, 0x94, - 0x3d, 0x10, 0xa4, 0xc9, 0xa2, 0xa7, 0x51, 0x9d, 0xba, 0x14, 0xd2, 0x4f, 0xe6, 0xc3, 0xbc, 0x60, - 0x05, 0x68, 0x03, 0xf4, 0x3e, 0x14, 0xeb, 0xe8, 0x82, 0xed, 0x74, 0x3c, 0xe3, 0x05, 0x94, 0x3d, - 0x9c, 0x99, 0x09, 0x6e, 0x36, 0xc9, 0xd6, 0x68, 0x28, 0xd8, 0xd2, 0x2f, 0xa0, 0xac, 0x15, 0x37, - 0xaf, 0xc8, 0xf7, 0xf5, 0x98, 0x07, 0xf4, 0x30, 0x27, 0xe7, 0xb3, 0xf3, 0xb8, 0xb1, 0xba, 0x3a, - 0xc3, 0xda, 0x51, 0x72, 0x18, 0xb7, 0x14, 0x6a, 0x14, 0x34, 0xba, 0x46, 0x45, 0xce, 0x60, 0x41, - 0x7b, 0xd1, 0x41, 0xd4, 0xdd, 0x19, 0x6c, 0xe8, 0x47, 0xb7, 0xf1, 0x6e, 0x95, 0xbd, 0x21, 0x5b, - 0xca, 0x82, 0x92, 0x7e, 0xbc, 0x5d, 0x37, 0x4f, 0xda, 0x79, 0x98, 0xe6, 0x77, 0x56, 0x9a, 0xac, - 0xd4, 0xaf, 0xbc, 0xac, 0xfd, 0xf4, 0xf6, 0xf1, 0xfc, 0xaf, 0x99, 0x34, 0xc2, 0xbb, 0xcb, 0x5e, - 0x58, 0xc3, 0xc5, 0xe9, 0xcb, 0xb2, 0x13, 0xbd, 0x2e, 0x3b, 0xd1, 0xfb, 0xb2, 0x13, 0xdd, 0x75, - 0xff, 0x1c, 0xcf, 0x8f, 0x1d, 0x0e, 0xb7, 0xc2, 0x37, 0x8f, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, - 0x05, 0xce, 0x15, 0x70, 0xdd, 0x01, 0x00, 0x00, +func init() { proto.RegisterFile("server/info/info.proto", fileDescriptor_bc6e4252b6544a4e) } + +var fileDescriptor_bc6e4252b6544a4e = []byte{ + // 308 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xc1, 0x4a, 0x03, 0x31, + 0x10, 0x86, 0x59, 0x11, 0xc5, 0x58, 0x4a, 0x09, 0x45, 0xa4, 0x48, 0x91, 0xc5, 0x83, 0x78, 0xd8, + 0xd0, 0xea, 0x41, 0x3c, 0xea, 0x41, 0x7a, 0xf1, 0x50, 0x2f, 0xe2, 0x6d, 0xba, 0x9d, 0xa6, 0xb1, + 0xdd, 0x4c, 0x4c, 0xd2, 0x2d, 0x5e, 0x7d, 0x05, 0x5f, 0xca, 0xa3, 0xe0, 0x0b, 0xc8, 0xe2, 0x83, + 0xc8, 0x66, 0x17, 0x5a, 0xa9, 0x5e, 0xc2, 0xe4, 0xff, 0xf9, 0xe7, 0x4b, 0x66, 0xd8, 0x81, 0x43, + 0x9b, 0xa3, 0x15, 0x4a, 0x4f, 0x28, 0x1c, 0x89, 0xb1, 0xe4, 0x89, 0x6f, 0x97, 0x75, 0xa7, 0x2d, + 0x49, 0x52, 0x10, 0x44, 0x59, 0x55, 0x5e, 0xe7, 0x48, 0x12, 0xc9, 0x39, 0x0a, 0x30, 0x4a, 0x80, + 0xd6, 0xe4, 0xc1, 0x2b, 0xd2, 0xae, 0x76, 0x2f, 0x66, 0x97, 0x2e, 0x51, 0x54, 0xba, 0x19, 0xa4, + 0x53, 0xa5, 0xd1, 0xbe, 0x08, 0x33, 0x93, 0xa5, 0xe0, 0x44, 0x86, 0x1e, 0x44, 0xde, 0x13, 0x12, + 0x35, 0x5a, 0xf0, 0x38, 0xae, 0x53, 0x37, 0x52, 0xf9, 0xe9, 0x62, 0x94, 0xa4, 0x94, 0x09, 0xb0, + 0x01, 0xfa, 0x14, 0x8a, 0x55, 0x74, 0x49, 0x76, 0x36, 0x99, 0xd3, 0x52, 0xe4, 0x3d, 0x98, 0x9b, + 0x29, 0x6c, 0x36, 0x89, 0x57, 0x68, 0x91, 0x92, 0xc5, 0x3f, 0x40, 0x71, 0x8b, 0x35, 0x6f, 0xd1, + 0x0f, 0xf4, 0x84, 0x86, 0xf8, 0xbc, 0x40, 0xe7, 0xe3, 0x2b, 0xd6, 0xa8, 0xae, 0xce, 0x90, 0x76, + 0xc8, 0xcf, 0x58, 0x2b, 0x03, 0x0d, 0x12, 0xc7, 0x77, 0x90, 0xa1, 0x33, 0x90, 0xe2, 0x61, 0x74, + 0x1c, 0x9d, 0xee, 0x0d, 0x37, 0xf4, 0xfe, 0x03, 0xdb, 0x2f, 0xb3, 0xf7, 0x68, 0x73, 0x95, 0x22, + 0x1f, 0xb0, 0xdd, 0xba, 0x39, 0x6f, 0x27, 0x61, 0x9a, 0xbf, 0x59, 0x1d, 0x5e, 0xa9, 0xeb, 0xbc, + 0xb8, 0xfd, 0xfa, 0xf9, 0xfd, 0xb6, 0xd5, 0xe4, 0x8d, 0xf0, 0xee, 0xbc, 0x17, 0xd6, 0x70, 0xdd, + 0x7f, 0x2f, 0xba, 0xd1, 0x47, 0xd1, 0x8d, 0xbe, 0x8a, 0x6e, 0xf4, 0x78, 0xf2, 0xef, 0x78, 0xd6, + 0xf6, 0x37, 0xda, 0x09, 0x5f, 0x3c, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x1e, 0xdc, 0xbc, 0xc6, + 0xd5, 0x01, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -225,7 +225,7 @@ var _InfoService_serviceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "cmd/server/info/info.proto", + Metadata: "server/info/info.proto", } func (m *GetInfoRequest) Marshal() (dAtA []byte, err error) { diff --git a/cmd/server/info/info.pb.gw.go b/server/info/info.pb.gw.go similarity index 99% rename from cmd/server/info/info.pb.gw.go rename to server/info/info.pb.gw.go index f1ac742bd078..3f7eb316976f 100644 --- a/cmd/server/info/info.pb.gw.go +++ b/server/info/info.pb.gw.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: cmd/server/info/info.proto +// source: server/info/info.proto /* Package info is a reverse proxy. diff --git a/cmd/server/info/info.proto b/server/info/info.proto similarity index 89% rename from cmd/server/info/info.proto rename to server/info/info.proto index c8697d88db17..cc3cc7c8687e 100644 --- a/cmd/server/info/info.proto +++ b/server/info/info.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -option go_package = "github.com/argoproj/argo/cmd/server/info"; +option go_package = "github.com/argoproj/argo/server/info"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; diff --git a/cmd/server/info/info.swagger.json b/server/info/info.swagger.json similarity index 94% rename from cmd/server/info/info.swagger.json rename to server/info/info.swagger.json index 99a3cc9a7af1..d9739808f9d1 100644 --- a/cmd/server/info/info.swagger.json +++ b/server/info/info.swagger.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "cmd/server/info/info.proto", + "title": "server/info/info.proto", "version": "version not set" }, "consumes": [ diff --git a/cmd/server/info/info_server.go b/server/info/info_server.go similarity index 100% rename from cmd/server/info/info_server.go rename to server/info/info_server.go diff --git a/cmd/server/static/static.go b/server/static/static.go similarity index 100% rename from cmd/server/static/static.go rename to server/static/static.go diff --git a/cmd/server/workflow/forwarder_overwrite.go b/server/workflow/forwarder_overwrite.go similarity index 100% rename from cmd/server/workflow/forwarder_overwrite.go rename to server/workflow/forwarder_overwrite.go diff --git a/cmd/server/workflow/workflow.pb.go b/server/workflow/workflow.pb.go similarity index 88% rename from cmd/server/workflow/workflow.pb.go rename to server/workflow/workflow.pb.go index 7fb5aa5fbd48..8fc32b9a7bfb 100644 --- a/cmd/server/workflow/workflow.pb.go +++ b/server/workflow/workflow.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cmd/server/workflow/workflow.proto +// source: server/workflow/workflow.proto // Workflow Service // @@ -50,7 +50,7 @@ func (m *WorkflowCreateRequest) Reset() { *m = WorkflowCreateRequest{} } func (m *WorkflowCreateRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowCreateRequest) ProtoMessage() {} func (*WorkflowCreateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{0} + return fileDescriptor_2af0e6384e310358, []int{0} } func (m *WorkflowCreateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -127,7 +127,7 @@ func (m *WorkflowGetRequest) Reset() { *m = WorkflowGetRequest{} } func (m *WorkflowGetRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowGetRequest) ProtoMessage() {} func (*WorkflowGetRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{1} + return fileDescriptor_2af0e6384e310358, []int{1} } func (m *WorkflowGetRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -189,7 +189,7 @@ func (m *WorkflowListRequest) Reset() { *m = WorkflowListRequest{} } func (m *WorkflowListRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowListRequest) ProtoMessage() {} func (*WorkflowListRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{2} + return fileDescriptor_2af0e6384e310358, []int{2} } func (m *WorkflowListRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -245,7 +245,7 @@ func (m *WorkflowResubmitRequest) Reset() { *m = WorkflowResubmitRequest func (m *WorkflowResubmitRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowResubmitRequest) ProtoMessage() {} func (*WorkflowResubmitRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{3} + return fileDescriptor_2af0e6384e310358, []int{3} } func (m *WorkflowResubmitRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -307,7 +307,7 @@ func (m *WorkflowRetryRequest) Reset() { *m = WorkflowRetryRequest{} } func (m *WorkflowRetryRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowRetryRequest) ProtoMessage() {} func (*WorkflowRetryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{4} + return fileDescriptor_2af0e6384e310358, []int{4} } func (m *WorkflowRetryRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -362,7 +362,7 @@ func (m *WorkflowResumeRequest) Reset() { *m = WorkflowResumeRequest{} } func (m *WorkflowResumeRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowResumeRequest) ProtoMessage() {} func (*WorkflowResumeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{5} + return fileDescriptor_2af0e6384e310358, []int{5} } func (m *WorkflowResumeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -417,7 +417,7 @@ func (m *WorkflowTerminateRequest) Reset() { *m = WorkflowTerminateReque func (m *WorkflowTerminateRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowTerminateRequest) ProtoMessage() {} func (*WorkflowTerminateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{6} + return fileDescriptor_2af0e6384e310358, []int{6} } func (m *WorkflowTerminateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -472,7 +472,7 @@ func (m *WorkflowSuspendRequest) Reset() { *m = WorkflowSuspendRequest{} func (m *WorkflowSuspendRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowSuspendRequest) ProtoMessage() {} func (*WorkflowSuspendRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{7} + return fileDescriptor_2af0e6384e310358, []int{7} } func (m *WorkflowSuspendRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -529,7 +529,7 @@ func (m *WorkflowLogRequest) Reset() { *m = WorkflowLogRequest{} } func (m *WorkflowLogRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowLogRequest) ProtoMessage() {} func (*WorkflowLogRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{8} + return fileDescriptor_2af0e6384e310358, []int{8} } func (m *WorkflowLogRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -599,7 +599,7 @@ func (m *WorkflowDeleteRequest) Reset() { *m = WorkflowDeleteRequest{} } func (m *WorkflowDeleteRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowDeleteRequest) ProtoMessage() {} func (*WorkflowDeleteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{9} + return fileDescriptor_2af0e6384e310358, []int{9} } func (m *WorkflowDeleteRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -659,7 +659,7 @@ func (m *WorkflowDeleteResponse) Reset() { *m = WorkflowDeleteResponse{} func (m *WorkflowDeleteResponse) String() string { return proto.CompactTextString(m) } func (*WorkflowDeleteResponse) ProtoMessage() {} func (*WorkflowDeleteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{10} + return fileDescriptor_2af0e6384e310358, []int{10} } func (m *WorkflowDeleteResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -700,7 +700,7 @@ func (m *WatchWorkflowsRequest) Reset() { *m = WatchWorkflowsRequest{} } func (m *WatchWorkflowsRequest) String() string { return proto.CompactTextString(m) } func (*WatchWorkflowsRequest) ProtoMessage() {} func (*WatchWorkflowsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{11} + return fileDescriptor_2af0e6384e310358, []int{11} } func (m *WatchWorkflowsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -757,7 +757,7 @@ func (m *WorkflowWatchEvent) Reset() { *m = WorkflowWatchEvent{} } func (m *WorkflowWatchEvent) String() string { return proto.CompactTextString(m) } func (*WorkflowWatchEvent) ProtoMessage() {} func (*WorkflowWatchEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{12} + return fileDescriptor_2af0e6384e310358, []int{12} } func (m *WorkflowWatchEvent) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -811,7 +811,7 @@ func (m *LogEntry) Reset() { *m = LogEntry{} } func (m *LogEntry) String() string { return proto.CompactTextString(m) } func (*LogEntry) ProtoMessage() {} func (*LogEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_192bc67c39cca05a, []int{13} + return fileDescriptor_2af0e6384e310358, []int{13} } func (m *LogEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -847,6 +847,61 @@ func (m *LogEntry) GetContent() string { return "" } +type WorkflowLintRequest struct { + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + Workflow *v1alpha1.Workflow `protobuf:"bytes,2,opt,name=workflow,proto3" json:"workflow,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WorkflowLintRequest) Reset() { *m = WorkflowLintRequest{} } +func (m *WorkflowLintRequest) String() string { return proto.CompactTextString(m) } +func (*WorkflowLintRequest) ProtoMessage() {} +func (*WorkflowLintRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_2af0e6384e310358, []int{14} +} +func (m *WorkflowLintRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WorkflowLintRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WorkflowLintRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WorkflowLintRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_WorkflowLintRequest.Merge(m, src) +} +func (m *WorkflowLintRequest) XXX_Size() int { + return m.Size() +} +func (m *WorkflowLintRequest) XXX_DiscardUnknown() { + xxx_messageInfo_WorkflowLintRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_WorkflowLintRequest proto.InternalMessageInfo + +func (m *WorkflowLintRequest) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *WorkflowLintRequest) GetWorkflow() *v1alpha1.Workflow { + if m != nil { + return m.Workflow + } + return nil +} + func init() { proto.RegisterType((*WorkflowCreateRequest)(nil), "workflow.WorkflowCreateRequest") proto.RegisterType((*WorkflowGetRequest)(nil), "workflow.WorkflowGetRequest") @@ -862,78 +917,79 @@ func init() { proto.RegisterType((*WatchWorkflowsRequest)(nil), "workflow.WatchWorkflowsRequest") proto.RegisterType((*WorkflowWatchEvent)(nil), "workflow.WorkflowWatchEvent") proto.RegisterType((*LogEntry)(nil), "workflow.LogEntry") -} - -func init() { proto.RegisterFile("cmd/server/workflow/workflow.proto", fileDescriptor_192bc67c39cca05a) } - -var fileDescriptor_192bc67c39cca05a = []byte{ - // 1042 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x97, 0x4d, 0x6f, 0xdc, 0x44, - 0x18, 0xc7, 0x35, 0x69, 0x68, 0xb7, 0x4f, 0x9a, 0x2d, 0x0c, 0x05, 0x56, 0x56, 0xba, 0x4d, 0x87, - 0x16, 0xa2, 0x34, 0xb1, 0xb3, 0x49, 0x81, 0x12, 0x89, 0x43, 0x49, 0xaa, 0x50, 0xb4, 0x82, 0xca, - 0x05, 0xa1, 0x72, 0x73, 0xbc, 0x83, 0xe3, 0x66, 0xed, 0x31, 0xf6, 0xec, 0x56, 0x4b, 0x15, 0x10, - 0x9c, 0x10, 0x57, 0x2e, 0x15, 0x12, 0x27, 0x40, 0x42, 0x42, 0x02, 0xf1, 0x2d, 0x38, 0x22, 0xf1, - 0x05, 0x50, 0xc4, 0x85, 0x6f, 0x81, 0x66, 0xec, 0x19, 0xdb, 0xd9, 0xed, 0xca, 0xac, 0x11, 0xbd, - 0xcd, 0xcb, 0xce, 0xf3, 0xff, 0xed, 0xf3, 0x32, 0xcf, 0x18, 0x88, 0x1b, 0xf4, 0xac, 0x84, 0xc6, - 0x43, 0x1a, 0x5b, 0x0f, 0x58, 0x7c, 0xf8, 0x51, 0x9f, 0x3d, 0xd0, 0x03, 0x33, 0x8a, 0x19, 0x67, - 0xb8, 0xa1, 0xe6, 0xc6, 0x05, 0x8f, 0x79, 0x4c, 0x2e, 0x5a, 0x62, 0x94, 0xee, 0x1b, 0x4b, 0x1e, - 0x63, 0x5e, 0x9f, 0x5a, 0x4e, 0xe4, 0x5b, 0x4e, 0x18, 0x32, 0xee, 0x70, 0x9f, 0x85, 0x49, 0xb6, - 0x7b, 0xfd, 0xf0, 0x46, 0x62, 0xfa, 0x4c, 0xec, 0x06, 0x8e, 0x7b, 0xe0, 0x87, 0x34, 0x1e, 0x59, - 0xd1, 0xa1, 0x27, 0x16, 0x12, 0x2b, 0xa0, 0xdc, 0xb1, 0x86, 0x1d, 0xcb, 0xa3, 0x21, 0x8d, 0x1d, - 0x4e, 0x7b, 0xd9, 0xa9, 0x1d, 0xcf, 0xe7, 0x07, 0x83, 0x7d, 0xd3, 0x65, 0x81, 0xe5, 0xc4, 0x52, - 0xf4, 0xbe, 0x1c, 0xe4, 0x47, 0x35, 0xee, 0xb0, 0xe3, 0xf4, 0xa3, 0x03, 0x67, 0xdc, 0x08, 0xc9, - 0xa5, 0x2d, 0x97, 0xc5, 0x74, 0x82, 0x10, 0xf9, 0x65, 0x0e, 0x9e, 0xfb, 0x20, 0xb3, 0xb4, 0x13, - 0x53, 0x87, 0x53, 0x9b, 0x7e, 0x3c, 0xa0, 0x09, 0xc7, 0x4b, 0x70, 0x36, 0x74, 0x02, 0x9a, 0x44, - 0x8e, 0x4b, 0x5b, 0x68, 0x19, 0xad, 0x9c, 0xb5, 0xf3, 0x05, 0x7c, 0x0f, 0xb4, 0x5b, 0x5a, 0x73, - 0xcb, 0x68, 0x65, 0x61, 0xf3, 0x0d, 0x33, 0x67, 0x36, 0x15, 0xb3, 0x1c, 0x98, 0xd1, 0xa1, 0x67, - 0x0a, 0x66, 0x53, 0x7b, 0x56, 0x31, 0x9b, 0x4a, 0xdb, 0xd6, 0xe6, 0x70, 0x1b, 0xc0, 0x0f, 0x13, - 0xee, 0x84, 0x2e, 0xbd, 0xbd, 0xdb, 0x3a, 0x25, 0x95, 0x0b, 0x2b, 0x98, 0xc0, 0xb9, 0x34, 0x62, - 0xbb, 0xf1, 0xc8, 0x1e, 0x84, 0xad, 0xf9, 0x65, 0xb4, 0xd2, 0xb0, 0x4b, 0x6b, 0xf8, 0x1e, 0x2c, - 0xba, 0xf2, 0xdf, 0xbc, 0x1b, 0xc9, 0x60, 0xb4, 0x9e, 0x92, 0x8c, 0x5b, 0x66, 0xea, 0x12, 0xb3, - 0x18, 0x8d, 0x1c, 0x4f, 0x44, 0xc3, 0x1c, 0x76, 0xcc, 0x9d, 0xe2, 0x51, 0xbb, 0x6c, 0x89, 0x3c, - 0x42, 0x80, 0x15, 0xf5, 0x1e, 0xe5, 0xca, 0x5d, 0x18, 0xe6, 0x85, 0x77, 0x32, 0x4f, 0xc9, 0x71, - 0xd9, 0x85, 0x73, 0x27, 0x5d, 0x78, 0x07, 0xc0, 0xa3, 0x5c, 0x01, 0x9e, 0x92, 0x80, 0x1b, 0xd5, - 0x00, 0xf7, 0xf4, 0x39, 0xbb, 0x60, 0x83, 0x7c, 0x89, 0xe0, 0x59, 0x85, 0xd6, 0xf5, 0x13, 0x5e, - 0x2d, 0x94, 0x77, 0x61, 0xa1, 0xef, 0x27, 0x1a, 0x24, 0x8d, 0x66, 0xa7, 0x1a, 0x48, 0x37, 0x3f, - 0x68, 0x17, 0xad, 0x10, 0x0f, 0x5e, 0xd0, 0xa1, 0xa5, 0xc9, 0x60, 0x3f, 0xf0, 0x6b, 0x78, 0xca, - 0x80, 0x46, 0x40, 0x03, 0xe6, 0x7f, 0x42, 0x7b, 0xd2, 0x4f, 0x0d, 0x5b, 0xcf, 0xc9, 0x5b, 0x70, - 0x21, 0x17, 0xe2, 0xf1, 0x68, 0x66, 0x15, 0x72, 0x3b, 0xaf, 0x04, 0x81, 0x1c, 0xd0, 0xd9, 0x4d, - 0x75, 0xa1, 0xa5, 0x4c, 0xbd, 0x47, 0xe3, 0xc0, 0x0f, 0x0b, 0x75, 0xf5, 0xef, 0xad, 0xbd, 0x0d, - 0xcf, 0x2b, 0x6b, 0x77, 0x07, 0x49, 0x44, 0xc3, 0xde, 0xec, 0xb6, 0xbe, 0x2b, 0x64, 0x6f, 0x97, - 0x79, 0xb3, 0xc7, 0xa4, 0x05, 0x67, 0x22, 0xd6, 0x7b, 0x47, 0x1c, 0x4a, 0x4b, 0x54, 0x4d, 0xf1, - 0x4d, 0x80, 0x3e, 0xf3, 0x54, 0x3a, 0xcd, 0xcb, 0x74, 0xba, 0x5c, 0x48, 0x27, 0x53, 0xdc, 0x45, - 0x22, 0x79, 0xee, 0xb0, 0x5e, 0x57, 0xff, 0xd0, 0x2e, 0x1c, 0x22, 0xdf, 0xa3, 0x3c, 0x16, 0xbb, - 0xb4, 0x4f, 0x6b, 0x78, 0x4f, 0x5c, 0x05, 0x3d, 0x69, 0xa2, 0x5c, 0x69, 0x15, 0xaf, 0x82, 0xdd, - 0xe2, 0x51, 0xbb, 0x6c, 0x89, 0xb4, 0xf2, 0xc0, 0x28, 0xca, 0x24, 0x62, 0x61, 0x42, 0xc9, 0x57, - 0xe2, 0x0f, 0x38, 0xdc, 0x3d, 0x50, 0xfb, 0xc9, 0x13, 0xac, 0xc5, 0xcf, 0xf2, 0x90, 0x4b, 0xa6, - 0x5b, 0x43, 0x1a, 0x4a, 0x4f, 0xf2, 0x51, 0xa4, 0x3d, 0x29, 0xc6, 0xf8, 0x7d, 0x38, 0xcd, 0xf6, - 0xef, 0x53, 0x97, 0xff, 0x37, 0x77, 0x7a, 0x66, 0x8c, 0x5c, 0x81, 0x46, 0x97, 0x79, 0xb7, 0x42, - 0x1e, 0x8f, 0x44, 0xde, 0xb8, 0x2c, 0xe4, 0x34, 0xe4, 0x99, 0xb2, 0x9a, 0x6e, 0xfe, 0xdd, 0x84, - 0xf3, 0x3a, 0xcf, 0x69, 0x3c, 0xf4, 0x5d, 0x8a, 0xbf, 0x41, 0xd0, 0x4c, 0x6f, 0x63, 0xb5, 0x83, - 0x2f, 0xe5, 0x8a, 0x13, 0x1b, 0x97, 0x51, 0x0f, 0x9a, 0xac, 0x7c, 0xf1, 0xc7, 0x5f, 0x5f, 0xcf, - 0x11, 0x72, 0x51, 0xf6, 0xcd, 0x61, 0x47, 0x37, 0xda, 0xc4, 0x7a, 0xa8, 0x03, 0x75, 0xb4, 0x8d, - 0x56, 0xf1, 0x23, 0x04, 0x0b, 0x7b, 0x94, 0x6b, 0xb2, 0xa5, 0x71, 0xb2, 0xbc, 0x41, 0xd4, 0xc5, - 0x5a, 0x93, 0x58, 0x2f, 0xe1, 0x2b, 0x53, 0xb1, 0xd2, 0xf1, 0x91, 0x40, 0x5b, 0x14, 0xf9, 0xa0, - 0xd3, 0x0f, 0x5f, 0x1c, 0x87, 0x2b, 0xb4, 0x08, 0xe3, 0x66, 0x2d, 0x3a, 0x61, 0x89, 0x5c, 0x95, - 0x84, 0x97, 0xf0, 0x74, 0xc7, 0xe1, 0x4f, 0xa1, 0x59, 0xae, 0x8c, 0x52, 0x44, 0x27, 0xd5, 0x8c, - 0x31, 0xc1, 0xb1, 0x79, 0x22, 0x93, 0x6b, 0x52, 0xf7, 0x2a, 0x7e, 0xf1, 0xa4, 0xee, 0x3a, 0x15, - 0xfb, 0x25, 0xf5, 0x0d, 0x84, 0x3f, 0x47, 0xd0, 0x4c, 0xab, 0x75, 0x5a, 0x4a, 0x95, 0x6e, 0x1d, - 0x63, 0xf9, 0xf1, 0x3f, 0xc8, 0x0a, 0x3e, 0x0b, 0xcf, 0x6a, 0xb5, 0xf0, 0xfc, 0x80, 0x60, 0x51, - 0x76, 0x2b, 0x8d, 0xd0, 0x1e, 0x57, 0x28, 0xb6, 0xb3, 0xba, 0xd9, 0xf3, 0x8a, 0xc4, 0xb3, 0x8c, - 0xd5, 0x2a, 0x78, 0x56, 0x2c, 0x94, 0x45, 0x86, 0xff, 0x8c, 0xe0, 0x69, 0xd5, 0xbe, 0x35, 0xea, - 0xe5, 0x49, 0xa8, 0xa5, 0x16, 0x5f, 0x97, 0xf6, 0x86, 0xa4, 0xdd, 0x34, 0xd6, 0x2b, 0xd2, 0xa6, - 0xe2, 0x02, 0xf8, 0x47, 0x04, 0xcd, 0xb4, 0x79, 0x4f, 0x0b, 0x6e, 0xa9, 0xbd, 0xd7, 0x85, 0x7d, - 0x55, 0xc2, 0x6e, 0x18, 0xd7, 0x2a, 0xc3, 0x06, 0x54, 0xa0, 0xfe, 0x84, 0xe0, 0x7c, 0xd6, 0xce, - 0x35, 0xeb, 0x84, 0x3c, 0x2b, 0x77, 0xfc, 0xba, 0xb0, 0xaf, 0x49, 0xd8, 0x8e, 0xb1, 0x56, 0x09, - 0x36, 0x49, 0xb5, 0x05, 0xed, 0xaf, 0x08, 0x9e, 0xd1, 0x4f, 0x19, 0xcd, 0x4b, 0xc6, 0x79, 0x4f, - 0xbe, 0x77, 0xea, 0x12, 0xbf, 0x2e, 0x89, 0xb7, 0x0c, 0xb3, 0x12, 0x31, 0x57, 0xea, 0x82, 0xf9, - 0x5b, 0x04, 0xe7, 0xba, 0x7e, 0xc8, 0xff, 0xb7, 0xd6, 0xb1, 0x2e, 0x59, 0x5f, 0x26, 0x64, 0x3a, - 0x6b, 0xdf, 0x0f, 0x65, 0xb2, 0x8e, 0xe0, 0x4c, 0xfa, 0x04, 0x4a, 0x26, 0xb5, 0x8e, 0xfc, 0x75, - 0x66, 0xe0, 0x7c, 0x57, 0xf5, 0x51, 0xb2, 0x2d, 0xb5, 0xae, 0xe3, 0xcd, 0x4a, 0x7e, 0x79, 0x98, - 0x3d, 0xce, 0x8e, 0xac, 0x3e, 0xf3, 0x36, 0xd0, 0x9b, 0xdb, 0xbf, 0x1d, 0xb7, 0xd1, 0xef, 0xc7, - 0x6d, 0xf4, 0xe7, 0x71, 0x1b, 0x7d, 0xb8, 0xf6, 0xd8, 0xaf, 0xcd, 0x09, 0x9f, 0xc7, 0xfb, 0xa7, - 0xe5, 0x97, 0xe3, 0xd6, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x1a, 0xf2, 0xad, 0xe1, 0x3c, 0x0f, - 0x00, 0x00, + proto.RegisterType((*WorkflowLintRequest)(nil), "workflow.WorkflowLintRequest") +} + +func init() { proto.RegisterFile("server/workflow/workflow.proto", fileDescriptor_2af0e6384e310358) } + +var fileDescriptor_2af0e6384e310358 = []byte{ + // 1052 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x97, 0x4f, 0x6f, 0xdc, 0x44, + 0x14, 0xc0, 0x35, 0x69, 0x68, 0xb7, 0x2f, 0xcd, 0x16, 0x86, 0x02, 0x2b, 0x2b, 0xdd, 0xa6, 0x43, + 0x0b, 0xab, 0xb4, 0xb1, 0xb3, 0x49, 0x29, 0xa5, 0x12, 0x87, 0x92, 0x54, 0xa1, 0x68, 0x05, 0x95, + 0x0b, 0x42, 0xe5, 0xe6, 0x78, 0x07, 0xc7, 0xcd, 0xda, 0x63, 0xec, 0xd9, 0xad, 0x96, 0x2a, 0x20, + 0x38, 0x21, 0x0e, 0x5c, 0xb8, 0x54, 0x70, 0x04, 0x24, 0x24, 0x24, 0x10, 0xdf, 0x82, 0x23, 0x12, + 0x5f, 0x00, 0x45, 0x48, 0x7c, 0x0d, 0x34, 0x63, 0xcf, 0xd8, 0xce, 0x6e, 0x57, 0x26, 0xae, 0x94, + 0xdb, 0xfc, 0xd9, 0x79, 0xef, 0xb7, 0xef, 0xbf, 0xa1, 0x9d, 0xd0, 0x78, 0x44, 0x63, 0xeb, 0x21, + 0x8b, 0xf7, 0x3e, 0x1e, 0xb0, 0x87, 0x7a, 0x61, 0x46, 0x31, 0xe3, 0x0c, 0x37, 0xd4, 0xde, 0x38, + 0xe7, 0x31, 0x8f, 0xc9, 0x43, 0x4b, 0xac, 0xd2, 0x7b, 0x63, 0xc9, 0x63, 0xcc, 0x1b, 0x50, 0xcb, + 0x89, 0x7c, 0xcb, 0x09, 0x43, 0xc6, 0x1d, 0xee, 0xb3, 0x30, 0xc9, 0x6e, 0xaf, 0xed, 0xdd, 0x48, + 0x4c, 0x9f, 0x89, 0xdb, 0xc0, 0x71, 0x77, 0xfd, 0x90, 0xc6, 0x63, 0x2b, 0xda, 0xf3, 0xc4, 0x41, + 0x62, 0x05, 0x94, 0x3b, 0xd6, 0xa8, 0x6b, 0x79, 0x34, 0xa4, 0xb1, 0xc3, 0x69, 0x3f, 0x7b, 0xb5, + 0xe9, 0xf9, 0x7c, 0x77, 0xb8, 0x63, 0xba, 0x2c, 0xb0, 0x9c, 0x58, 0x2a, 0x7d, 0x20, 0x17, 0xf9, + 0x53, 0x8d, 0x3b, 0xea, 0x3a, 0x83, 0x68, 0xd7, 0x99, 0x14, 0x42, 0x72, 0xd5, 0x96, 0xcb, 0x62, + 0x3a, 0x45, 0x11, 0xf9, 0x6d, 0x0e, 0x5e, 0xf8, 0x30, 0x93, 0xb4, 0x19, 0x53, 0x87, 0x53, 0x9b, + 0x7e, 0x32, 0xa4, 0x09, 0xc7, 0x4b, 0x70, 0x3a, 0x74, 0x02, 0x9a, 0x44, 0x8e, 0x4b, 0x5b, 0x68, + 0x19, 0x75, 0x4e, 0xdb, 0xf9, 0x01, 0xbe, 0x0f, 0xda, 0x2c, 0xad, 0xb9, 0x65, 0xd4, 0x59, 0x58, + 0x7f, 0xd3, 0xcc, 0x99, 0x4d, 0xc5, 0x2c, 0x17, 0x66, 0xb4, 0xe7, 0x99, 0x82, 0xd9, 0xd4, 0x96, + 0x55, 0xcc, 0xa6, 0xd2, 0x6d, 0x6b, 0x71, 0xb8, 0x0d, 0xe0, 0x87, 0x09, 0x77, 0x42, 0x97, 0xde, + 0xd9, 0x6a, 0x9d, 0x90, 0x9a, 0x0b, 0x27, 0x98, 0xc0, 0x99, 0xd4, 0x63, 0x5b, 0xf1, 0xd8, 0x1e, + 0x86, 0xad, 0xf9, 0x65, 0xd4, 0x69, 0xd8, 0xa5, 0x33, 0x7c, 0x1f, 0x16, 0x5d, 0xf9, 0x6f, 0xde, + 0x8b, 0xa4, 0x33, 0x5a, 0xcf, 0x48, 0xc6, 0x0d, 0x33, 0x35, 0x89, 0x59, 0xf4, 0x46, 0x8e, 0x27, + 0xbc, 0x61, 0x8e, 0xba, 0xe6, 0x66, 0xf1, 0xa9, 0x5d, 0x96, 0x44, 0x1e, 0x23, 0xc0, 0x8a, 0x7a, + 0x9b, 0x72, 0x65, 0x2e, 0x0c, 0xf3, 0xc2, 0x3a, 0x99, 0xa5, 0xe4, 0xba, 0x6c, 0xc2, 0xb9, 0xc3, + 0x26, 0xbc, 0x0b, 0xe0, 0x51, 0xae, 0x00, 0x4f, 0x48, 0xc0, 0xb5, 0x6a, 0x80, 0xdb, 0xfa, 0x9d, + 0x5d, 0x90, 0x41, 0xbe, 0x42, 0xf0, 0xbc, 0x42, 0xeb, 0xf9, 0x09, 0xaf, 0xe6, 0xca, 0x7b, 0xb0, + 0x30, 0xf0, 0x13, 0x0d, 0x92, 0x7a, 0xb3, 0x5b, 0x0d, 0xa4, 0x97, 0x3f, 0xb4, 0x8b, 0x52, 0x88, + 0x07, 0x2f, 0x69, 0xd7, 0xd2, 0x64, 0xb8, 0x13, 0xf8, 0x35, 0x2c, 0x65, 0x40, 0x23, 0xa0, 0x01, + 0xf3, 0x3f, 0xa5, 0x7d, 0x69, 0xa7, 0x86, 0xad, 0xf7, 0xe4, 0x6d, 0x38, 0x97, 0x2b, 0xe2, 0xf1, + 0xf8, 0xc8, 0x5a, 0xc8, 0x9d, 0x3c, 0x13, 0x04, 0x72, 0x40, 0x8f, 0x2e, 0xaa, 0x07, 0x2d, 0x25, + 0xea, 0x7d, 0x1a, 0x07, 0x7e, 0x58, 0xc8, 0xab, 0xff, 0x2f, 0xed, 0x1d, 0x78, 0x51, 0x49, 0xbb, + 0x37, 0x4c, 0x22, 0x1a, 0xf6, 0x8f, 0x2e, 0xeb, 0x87, 0x42, 0xf4, 0xf6, 0x98, 0x77, 0x74, 0x9f, + 0xb4, 0xe0, 0x54, 0xc4, 0xfa, 0xef, 0x8a, 0x47, 0x69, 0x8a, 0xaa, 0x2d, 0xbe, 0x05, 0x30, 0x60, + 0x9e, 0x0a, 0xa7, 0x79, 0x19, 0x4e, 0x17, 0x0b, 0xe1, 0x64, 0x8a, 0x5a, 0x24, 0x82, 0xe7, 0x2e, + 0xeb, 0xf7, 0xf4, 0x0f, 0xed, 0xc2, 0x23, 0xf2, 0x23, 0xca, 0x7d, 0xb1, 0x45, 0x07, 0xb4, 0x86, + 0xf5, 0x44, 0x29, 0xe8, 0x4b, 0x11, 0xe5, 0x4c, 0xab, 0x58, 0x0a, 0xb6, 0x8a, 0x4f, 0xed, 0xb2, + 0x24, 0xd2, 0xca, 0x1d, 0xa3, 0x28, 0x93, 0x88, 0x85, 0x09, 0x25, 0x5f, 0x8b, 0x3f, 0xe0, 0x70, + 0x77, 0x57, 0xdd, 0x27, 0xc7, 0x98, 0x8b, 0x9f, 0xe7, 0x2e, 0x97, 0x4c, 0xb7, 0x47, 0x34, 0x94, + 0x96, 0xe4, 0xe3, 0x48, 0x5b, 0x52, 0xac, 0xf1, 0x07, 0x70, 0x92, 0xed, 0x3c, 0xa0, 0x2e, 0x7f, + 0x3a, 0x35, 0x3d, 0x13, 0x46, 0x2e, 0x41, 0xa3, 0xc7, 0xbc, 0xdb, 0x21, 0x8f, 0xc7, 0x22, 0x6e, + 0x5c, 0x16, 0x72, 0x1a, 0xf2, 0x4c, 0xb3, 0xda, 0x92, 0x6f, 0x4a, 0xd5, 0x2b, 0xe4, 0xc7, 0xdd, + 0x88, 0xd6, 0xff, 0x6d, 0xc2, 0x59, 0x9d, 0x78, 0x34, 0x1e, 0xf9, 0x2e, 0xc5, 0xdf, 0x21, 0x68, + 0xa6, 0xed, 0x41, 0xdd, 0xe0, 0x0b, 0xb9, 0xb4, 0xa9, 0x9d, 0xd4, 0xa8, 0x07, 0x44, 0x3a, 0x5f, + 0xfe, 0xf5, 0xcf, 0xb7, 0x73, 0x84, 0x9c, 0x97, 0x8d, 0x7c, 0xd4, 0xd5, 0x9d, 0x3f, 0xb1, 0x1e, + 0x69, 0x3b, 0xec, 0xdf, 0x44, 0x2b, 0xf8, 0x31, 0x82, 0x85, 0x6d, 0xca, 0x35, 0xd9, 0xd2, 0x24, + 0x59, 0xde, 0xb1, 0xea, 0x62, 0x5d, 0x95, 0x58, 0xaf, 0xe0, 0x4b, 0x33, 0xb1, 0xd2, 0xf5, 0xbe, + 0x40, 0x5b, 0x14, 0x01, 0xaa, 0xf3, 0x01, 0x9f, 0x9f, 0x84, 0x2b, 0xf4, 0x2c, 0xe3, 0x56, 0x2d, + 0x3a, 0x21, 0x89, 0x5c, 0x96, 0x84, 0x17, 0xf0, 0x6c, 0xc3, 0xe1, 0xcf, 0xa0, 0x59, 0x4e, 0xd5, + 0x92, 0x47, 0xa7, 0x25, 0xb1, 0x31, 0xc5, 0xb0, 0x79, 0x66, 0x91, 0x2b, 0x52, 0xef, 0x65, 0xfc, + 0xf2, 0x61, 0xbd, 0xab, 0x54, 0xdc, 0x97, 0xb4, 0xaf, 0x21, 0xfc, 0x05, 0x82, 0x66, 0x5a, 0x3e, + 0x66, 0x85, 0x54, 0xa9, 0x0c, 0x1a, 0xcb, 0x4f, 0xfe, 0x41, 0x56, 0x81, 0x32, 0xf7, 0xac, 0x54, + 0x73, 0xcf, 0x4f, 0x08, 0x16, 0x65, 0xfb, 0xd4, 0x08, 0xed, 0x49, 0x0d, 0xc5, 0xfe, 0x5a, 0x37, + 0x7a, 0x5e, 0x93, 0x78, 0x96, 0xb1, 0x52, 0x05, 0xcf, 0x8a, 0x85, 0x66, 0x11, 0xe1, 0xbf, 0x22, + 0x78, 0x56, 0xcd, 0x13, 0x1a, 0xf5, 0xe2, 0x34, 0xd4, 0xd2, 0xcc, 0x51, 0x97, 0xf6, 0x86, 0xa4, + 0x5d, 0x37, 0x56, 0x2b, 0xd2, 0xa6, 0xca, 0x05, 0xf0, 0xcf, 0x08, 0x9a, 0xe9, 0x34, 0x31, 0xcb, + 0xb9, 0xa5, 0x79, 0xa3, 0x2e, 0xec, 0x75, 0x09, 0xbb, 0x66, 0x5c, 0xa9, 0x0c, 0x1b, 0x50, 0x81, + 0xfa, 0x0b, 0x82, 0xb3, 0xd9, 0x7c, 0xa1, 0x59, 0xa7, 0xc4, 0x59, 0x79, 0x04, 0xa9, 0x0b, 0xfb, + 0xba, 0x84, 0xed, 0x1a, 0x57, 0x2b, 0xc1, 0x26, 0xa9, 0x6e, 0x41, 0xfb, 0x3b, 0x82, 0xe7, 0xf4, + 0x6c, 0xa5, 0x79, 0xc9, 0x24, 0xef, 0xe1, 0x01, 0xac, 0x2e, 0xf1, 0x1b, 0x92, 0x78, 0xc3, 0x30, + 0x2b, 0x11, 0x73, 0xa5, 0x5d, 0x30, 0x7f, 0x8f, 0xe0, 0x8c, 0xe8, 0x6c, 0x1a, 0x77, 0x6a, 0x0d, + 0x0c, 0x9f, 0x56, 0xd4, 0xae, 0x4a, 0xd2, 0x57, 0x09, 0x99, 0x4d, 0x3a, 0xf0, 0x43, 0x19, 0xaa, + 0x63, 0x38, 0x95, 0x4e, 0x64, 0xc9, 0xb4, 0xc6, 0x91, 0x0f, 0x8b, 0x06, 0xce, 0x6f, 0x55, 0x5b, + 0x27, 0x37, 0xa5, 0xae, 0x6b, 0x78, 0xbd, 0x92, 0x55, 0x1e, 0x65, 0xb3, 0xe2, 0xbe, 0x35, 0x60, + 0xde, 0x1a, 0x7a, 0xeb, 0xfa, 0x1f, 0x07, 0x6d, 0xf4, 0xe7, 0x41, 0x1b, 0xfd, 0x7d, 0xd0, 0x46, + 0x1f, 0x75, 0x9e, 0xf8, 0xf1, 0x7b, 0xe8, 0x4b, 0x7d, 0xe7, 0xa4, 0xfc, 0x88, 0xdd, 0xf8, 0x2f, + 0x00, 0x00, 0xff, 0xff, 0x02, 0xf6, 0x61, 0x76, 0xc3, 0x0f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -958,7 +1014,7 @@ type WorkflowServiceClient interface { ResumeWorkflow(ctx context.Context, in *WorkflowResumeRequest, opts ...grpc.CallOption) (*v1alpha1.Workflow, error) SuspendWorkflow(ctx context.Context, in *WorkflowSuspendRequest, opts ...grpc.CallOption) (*v1alpha1.Workflow, error) TerminateWorkflow(ctx context.Context, in *WorkflowTerminateRequest, opts ...grpc.CallOption) (*v1alpha1.Workflow, error) - LintWorkflow(ctx context.Context, in *WorkflowCreateRequest, opts ...grpc.CallOption) (*v1alpha1.Workflow, error) + LintWorkflow(ctx context.Context, in *WorkflowLintRequest, opts ...grpc.CallOption) (*v1alpha1.Workflow, error) PodLogs(ctx context.Context, in *WorkflowLogRequest, opts ...grpc.CallOption) (WorkflowService_PodLogsClient, error) } @@ -1083,7 +1139,7 @@ func (c *workflowServiceClient) TerminateWorkflow(ctx context.Context, in *Workf return out, nil } -func (c *workflowServiceClient) LintWorkflow(ctx context.Context, in *WorkflowCreateRequest, opts ...grpc.CallOption) (*v1alpha1.Workflow, error) { +func (c *workflowServiceClient) LintWorkflow(ctx context.Context, in *WorkflowLintRequest, opts ...grpc.CallOption) (*v1alpha1.Workflow, error) { out := new(v1alpha1.Workflow) err := c.cc.Invoke(ctx, "/workflow.WorkflowService/LintWorkflow", in, out, opts...) if err != nil { @@ -1136,7 +1192,7 @@ type WorkflowServiceServer interface { ResumeWorkflow(context.Context, *WorkflowResumeRequest) (*v1alpha1.Workflow, error) SuspendWorkflow(context.Context, *WorkflowSuspendRequest) (*v1alpha1.Workflow, error) TerminateWorkflow(context.Context, *WorkflowTerminateRequest) (*v1alpha1.Workflow, error) - LintWorkflow(context.Context, *WorkflowCreateRequest) (*v1alpha1.Workflow, error) + LintWorkflow(context.Context, *WorkflowLintRequest) (*v1alpha1.Workflow, error) PodLogs(*WorkflowLogRequest, WorkflowService_PodLogsServer) error } @@ -1174,7 +1230,7 @@ func (*UnimplementedWorkflowServiceServer) SuspendWorkflow(ctx context.Context, func (*UnimplementedWorkflowServiceServer) TerminateWorkflow(ctx context.Context, req *WorkflowTerminateRequest) (*v1alpha1.Workflow, error) { return nil, status.Errorf(codes.Unimplemented, "method TerminateWorkflow not implemented") } -func (*UnimplementedWorkflowServiceServer) LintWorkflow(ctx context.Context, req *WorkflowCreateRequest) (*v1alpha1.Workflow, error) { +func (*UnimplementedWorkflowServiceServer) LintWorkflow(ctx context.Context, req *WorkflowLintRequest) (*v1alpha1.Workflow, error) { return nil, status.Errorf(codes.Unimplemented, "method LintWorkflow not implemented") } func (*UnimplementedWorkflowServiceServer) PodLogs(req *WorkflowLogRequest, srv WorkflowService_PodLogsServer) error { @@ -1369,7 +1425,7 @@ func _WorkflowService_TerminateWorkflow_Handler(srv interface{}, ctx context.Con } func _WorkflowService_LintWorkflow_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(WorkflowCreateRequest) + in := new(WorkflowLintRequest) if err := dec(in); err != nil { return nil, err } @@ -1381,7 +1437,7 @@ func _WorkflowService_LintWorkflow_Handler(srv interface{}, ctx context.Context, FullMethod: "/workflow.WorkflowService/LintWorkflow", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(WorkflowServiceServer).LintWorkflow(ctx, req.(*WorkflowCreateRequest)) + return srv.(WorkflowServiceServer).LintWorkflow(ctx, req.(*WorkflowLintRequest)) } return interceptor(ctx, in, info, handler) } @@ -1464,7 +1520,7 @@ var _WorkflowService_serviceDesc = grpc.ServiceDesc{ ServerStreams: true, }, }, - Metadata: "cmd/server/workflow/workflow.proto", + Metadata: "server/workflow/workflow.proto", } func (m *WorkflowCreateRequest) Marshal() (dAtA []byte, err error) { @@ -2122,6 +2178,52 @@ func (m *LogEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *WorkflowLintRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *WorkflowLintRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WorkflowLintRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Workflow != nil { + { + size, err := m.Workflow.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintWorkflow(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintWorkflow(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintWorkflow(dAtA []byte, offset int, v uint64) int { offset -= sovWorkflow(v) base := offset @@ -2431,6 +2533,26 @@ func (m *LogEntry) Size() (n int) { return n } +func (m *WorkflowLintRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovWorkflow(uint64(l)) + } + if m.Workflow != nil { + l = m.Workflow.Size() + n += 1 + l + sovWorkflow(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func sovWorkflow(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -4257,6 +4379,128 @@ func (m *LogEntry) Unmarshal(dAtA []byte) error { } return nil } +func (m *WorkflowLintRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: WorkflowLintRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WorkflowLintRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthWorkflow + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthWorkflow + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Workflow", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthWorkflow + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthWorkflow + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Workflow == nil { + m.Workflow = &v1alpha1.Workflow{} + } + if err := m.Workflow.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipWorkflow(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthWorkflow + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthWorkflow + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipWorkflow(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/cmd/server/workflow/workflow.pb.gw.go b/server/workflow/workflow.pb.gw.go similarity index 99% rename from cmd/server/workflow/workflow.pb.gw.go rename to server/workflow/workflow.pb.gw.go index f1be95884fec..6058c4b0e5e2 100644 --- a/cmd/server/workflow/workflow.pb.gw.go +++ b/server/workflow/workflow.pb.gw.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: cmd/server/workflow/workflow.proto +// source: server/workflow/workflow.proto /* Package workflow is a reverse proxy. @@ -859,7 +859,7 @@ func local_request_WorkflowService_TerminateWorkflow_0(ctx context.Context, mars } func request_WorkflowService_LintWorkflow_0(ctx context.Context, marshaler runtime.Marshaler, client WorkflowServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq WorkflowCreateRequest + var protoReq WorkflowLintRequest var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -894,7 +894,7 @@ func request_WorkflowService_LintWorkflow_0(ctx context.Context, marshaler runti } func local_request_WorkflowService_LintWorkflow_0(ctx context.Context, marshaler runtime.Marshaler, server WorkflowServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq WorkflowCreateRequest + var protoReq WorkflowLintRequest var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) diff --git a/cmd/server/workflow/workflow.proto b/server/workflow/workflow.proto similarity index 93% rename from cmd/server/workflow/workflow.proto rename to server/workflow/workflow.proto index 1b847310fb65..471980b0e800 100644 --- a/cmd/server/workflow/workflow.proto +++ b/server/workflow/workflow.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -option go_package = "github.com/argoproj/argo/cmd/server/workflow"; +option go_package = "github.com/argoproj/argo/server/workflow"; import "gogoproto/gogo.proto"; @@ -21,7 +21,6 @@ message WorkflowCreateRequest { bool serverDryRun = 4; k8s.io.apimachinery.pkg.apis.meta.v1.CreateOptions createOptions = 5; } - message WorkflowGetRequest { string name = 1; string namespace = 2; @@ -90,6 +89,11 @@ message LogEntry { string content = 1; } +message WorkflowLintRequest { + string namespace = 1; + github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.Workflow workflow = 2; +} + service WorkflowService { rpc CreateWorkflow (WorkflowCreateRequest) returns (github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.Workflow) { option (google.api.http) = { @@ -149,7 +153,7 @@ service WorkflowService { }; } - rpc LintWorkflow (WorkflowCreateRequest) returns (github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.Workflow) { + rpc LintWorkflow (WorkflowLintRequest) returns (github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.Workflow) { option (google.api.http) = { post: "/api/v1/workflows/{namespace}/lint" body: "*" diff --git a/cmd/server/workflow/workflow.swagger.json b/server/workflow/workflow.swagger.json similarity index 99% rename from cmd/server/workflow/workflow.swagger.json rename to server/workflow/workflow.swagger.json index 8693decd3156..29b7a6c1dffe 100644 --- a/cmd/server/workflow/workflow.swagger.json +++ b/server/workflow/workflow.swagger.json @@ -233,7 +233,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/workflowWorkflowCreateRequest" + "$ref": "#/definitions/workflowWorkflowLintRequest" } } ], @@ -3905,7 +3905,7 @@ "v1alpha1TTLStrategy": { "type": "object", "properties": { - "secondsAfterCompleted": { + "secondsAfterCompletion": { "type": "integer", "format": "int32" }, @@ -3913,7 +3913,7 @@ "type": "integer", "format": "int32" }, - "secondsAfterFailed": { + "secondsAfterFailure": { "type": "integer", "format": "int32" } @@ -4277,7 +4277,7 @@ "ttlSecondsAfterFinished": { "type": "integer", "format": "int32", - "description": "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution\n(Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be\ndeleted after ttlSecondsAfterFinished expires. If this field is unset,\nttlSecondsAfterFinished will not expire. If this field is set to zero,\nttlSecondsAfterFinished expires immediately after the Workflow finishes.\nDEPRECATED: Use TTLStrategy.SecondsAfterCompleted instead." + "description": "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution\n(Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be\ndeleted after ttlSecondsAfterFinished expires. If this field is unset,\nttlSecondsAfterFinished will not expire. If this field is set to zero,\nttlSecondsAfterFinished expires immediately after the Workflow finishes.\nDEPRECATED: Use TTLStrategy.SecondsAfterCompletion instead." }, "ttlStrategy": { "$ref": "#/definitions/v1alpha1TTLStrategy", @@ -4358,10 +4358,9 @@ }, "description": "Nodes is a mapping between a node ID and the node's status." }, - "offloadNodeStatus": { - "type": "boolean", - "format": "boolean", - "description": "Whether on not node status has been offloaded to a database. If true, then Nodes and CompressedNodes will be empty." + "offloadNodeStatusVersion": { + "type": "string", + "description": "Whether on not node status has been offloaded to a database. If exists, then Nodes and CompressedNodes will be empty.\nThis will actually be populated with a hash of the offloaded data." }, "storedTemplates": { "type": "object", @@ -4465,6 +4464,17 @@ "workflowWorkflowDeleteResponse": { "type": "object" }, + "workflowWorkflowLintRequest": { + "type": "object", + "properties": { + "namespace": { + "type": "string" + }, + "workflow": { + "$ref": "#/definitions/v1alpha1Workflow" + } + } + }, "workflowWorkflowResubmitRequest": { "type": "object", "properties": { diff --git a/cmd/server/workflow/workflow_server.go b/server/workflow/workflow_server.go similarity index 88% rename from cmd/server/workflow/workflow_server.go rename to server/workflow/workflow_server.go index 48bd5c8ccacb..cd74d55ba8ed 100644 --- a/cmd/server/workflow/workflow_server.go +++ b/server/workflow/workflow_server.go @@ -4,11 +4,12 @@ import ( "bufio" "fmt" + "github.com/argoproj/argo/server/auth" + log "github.com/sirupsen/logrus" "golang.org/x/net/context" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/argoproj/argo/cmd/server/auth" "github.com/argoproj/argo/persist/sqldb" "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo/workflow/common" @@ -81,13 +82,12 @@ func (s *workflowServer) GetWorkflow(ctx context.Context, req *WorkflowGetReques return nil, err } - if wf.Status.OffloadNodeStatus { - offloaded, err := s.offloadNodeStatusRepo.Get(req.Name, req.Namespace) + if wf.Status.IsOffloadNodeStatus() && s.offloadNodeStatusRepo.IsEnabled() { + offloadedNodes, err := s.offloadNodeStatusRepo.Get(string(wf.UID), wf.GetOffloadNodeStatusVersion()) if err != nil { return nil, err } - wf.Status.Nodes = offloaded.Status.Nodes - wf.Status.CompressedNodes = offloaded.Status.CompressedNodes + wf.Status.Nodes = offloadedNodes } err = packer.DecompressWorkflow(wf) if err != nil { @@ -108,8 +108,19 @@ func (s *workflowServer) ListWorkflows(ctx context.Context, req *WorkflowListReq if err != nil { return nil, err } + if s.offloadNodeStatusRepo.IsEnabled() { + offloadedNodes, err := s.offloadNodeStatusRepo.List(req.Namespace) + if err != nil { + return nil, err + } + for i, wf := range wfList.Items { + if wf.Status.IsOffloadNodeStatus() { + wfList.Items[i].Status.Nodes = offloadedNodes[sqldb.UUIDVersion{UID: string(wf.UID), Version: wf.GetOffloadNodeStatusVersion()}] + } + } + } - return wfList, nil + return &v1alpha1.WorkflowList{Items: wfList.Items}, nil } func (s *workflowServer) WatchWorkflows(req *WatchWorkflowsRequest, ws WorkflowService_WatchWorkflowsServer) error { @@ -144,12 +155,12 @@ func (s *workflowServer) WatchWorkflows(req *WatchWorkflowsRequest, ws WorkflowS if err != nil { return err } - if wf.Status.OffloadNodeStatus { - offloaded, err := s.offloadNodeStatusRepo.Get(wf.Name, wf.Namespace) + if wf.Status.IsOffloadNodeStatus() && s.offloadNodeStatusRepo.IsEnabled() { + offloadedNodes, err := s.offloadNodeStatusRepo.Get(string(wf.UID), wf.GetOffloadNodeStatusVersion()) if err != nil { return err } - wf.Status.Nodes = offloaded.Status.Nodes + wf.Status.Nodes = offloadedNodes } logCtx.Debug("Sending event") err = ws.Send(&WorkflowWatchEvent{Type: string(next.Type), Object: wf}) @@ -165,18 +176,7 @@ func (s *workflowServer) WatchWorkflows(req *WatchWorkflowsRequest, ws WorkflowS func (s *workflowServer) DeleteWorkflow(ctx context.Context, req *WorkflowDeleteRequest) (*WorkflowDeleteResponse, error) { wfClient := auth.GetWfClient(ctx) - wf, err := wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Get(req.Name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - - if wf.Status.OffloadNodeStatus { - err = s.offloadNodeStatusRepo.Delete(req.Name, req.Namespace) - if err != nil { - return nil, err - } - } - err = wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Delete(req.Name, &metav1.DeleteOptions{}) + err := wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Delete(req.Name, &metav1.DeleteOptions{}) if err != nil { return nil, err } @@ -263,7 +263,7 @@ func (s *workflowServer) TerminateWorkflow(ctx context.Context, req *WorkflowTer return wf, nil } -func (s *workflowServer) LintWorkflow(ctx context.Context, req *WorkflowCreateRequest) (*v1alpha1.Workflow, error) { +func (s *workflowServer) LintWorkflow(ctx context.Context, req *WorkflowLintRequest) (*v1alpha1.Workflow, error) { wfClient := auth.GetWfClient(ctx) wftmplGetter := templateresolution.WrapWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().WorkflowTemplates(req.Namespace)) diff --git a/cmd/server/workflow/workflow_server_test.go b/server/workflow/workflow_server_test.go similarity index 96% rename from cmd/server/workflow/workflow_server_test.go rename to server/workflow/workflow_server_test.go index 502894dc32c0..5ed56c9a998f 100644 --- a/cmd/server/workflow/workflow_server_test.go +++ b/server/workflow/workflow_server_test.go @@ -7,14 +7,17 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/kubernetes/fake" ktesting "k8s.io/client-go/testing" - "github.com/argoproj/argo/cmd/server/auth" + "github.com/argoproj/argo/persist/sqldb" + "github.com/argoproj/argo/persist/sqldb/mocks" "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" v1alpha "github.com/argoproj/argo/pkg/client/clientset/versioned/fake" + "github.com/argoproj/argo/server/auth" ) const wf1 = ` @@ -361,7 +364,10 @@ func getWorkflowServer() (WorkflowServiceServer, context.Context) { _ = json.Unmarshal([]byte(wf3), &wfObj3) _ = json.Unmarshal([]byte(wf4), &wfObj4) _ = json.Unmarshal([]byte(wf5), &wfObj5) - server := NewWorkflowServer(nil) + offloadNodeStatusRepo := &mocks.OffloadNodeStatusRepo{} + offloadNodeStatusRepo.On("IsEnabled", mock.Anything).Return(true) + offloadNodeStatusRepo.On("List", mock.Anything).Return(map[sqldb.UUIDVersion]v1alpha1.Nodes{}, nil) + server := NewWorkflowServer(offloadNodeStatusRepo) kubeClientSet := fake.NewSimpleClientset() wfClientset := v1alpha.NewSimpleClientset(&wfObj1, &wfObj2, &wfObj3, &wfObj4, &wfObj5) wfClientset.PrependReactor("create", "workflows", generateNameReactor) @@ -390,10 +396,7 @@ func getWorkflow(ctx context.Context, server WorkflowServiceServer, namespace st } func getWorkflowList(ctx context.Context, server WorkflowServiceServer, namespace string) (*v1alpha1.WorkflowList, error) { - req := WorkflowListRequest{ - Namespace: namespace, - } - return server.ListWorkflows(ctx, &req) + return server.ListWorkflows(ctx, &WorkflowListRequest{Namespace: namespace}) } diff --git a/cmd/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go similarity index 83% rename from cmd/server/workflowarchive/archived_workflow_server.go rename to server/workflowarchive/archived_workflow_server.go index 44b0b96aa7cf..652159714d28 100644 --- a/cmd/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -11,17 +11,17 @@ import ( "google.golang.org/grpc/status" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/argoproj/argo/cmd/server/auth" "github.com/argoproj/argo/persist/sqldb" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo/server/auth" ) type archivedWorkflowServer struct { - repo sqldb.WorkflowArchive + wfArchive sqldb.WorkflowArchive } -func NewWorkflowArchiveServer(repo sqldb.WorkflowArchive) ArchivedWorkflowServiceServer { - return &archivedWorkflowServer{repo: repo} +func NewWorkflowArchiveServer(wfArchive sqldb.WorkflowArchive) ArchivedWorkflowServiceServer { + return &archivedWorkflowServer{wfArchive: wfArchive} } func (w *archivedWorkflowServer) ListArchivedWorkflows(ctx context.Context, req *ListArchivedWorkflowsRequest) (*wfv1.WorkflowList, error) { @@ -52,7 +52,7 @@ func (w *archivedWorkflowServer) ListArchivedWorkflows(ctx context.Context, req authorizer := auth.NewAuthorizer(ctx) // keep trying until we have enough for len(items) < limit { - moreItems, err := w.repo.ListWorkflows(namespace, limit, offset) + moreItems, err := w.wfArchive.ListWorkflows(namespace, limit, offset) if err != nil { return nil, err } @@ -79,14 +79,14 @@ func (w *archivedWorkflowServer) ListArchivedWorkflows(ctx context.Context, req } func (w *archivedWorkflowServer) GetArchivedWorkflow(ctx context.Context, req *GetArchivedWorkflowRequest) (*wfv1.Workflow, error) { - wf, err := w.repo.GetWorkflow(req.Uid) + wf, err := w.wfArchive.GetWorkflow(req.Uid) if err != nil { return nil, err } if wf == nil { return nil, status.Error(codes.NotFound, "not found") } - allowed, err := auth.CanI(ctx, "get", "workflow", wf.Namespace, wf.Name) + allowed, err := auth.CanI(ctx, "get", "workflows", wf.Namespace, wf.Name) if err != nil { return nil, err } @@ -101,14 +101,14 @@ func (w *archivedWorkflowServer) DeleteArchivedWorkflow(ctx context.Context, req if err != nil { return nil, err } - allowed, err := auth.CanI(ctx, "delete", "workflow", wf.Namespace, wf.Name) + allowed, err := auth.CanI(ctx, "delete", "workflows", wf.Namespace, wf.Name) if err != nil { return nil, err } if !allowed { return nil, status.Error(codes.PermissionDenied, "permission denied") } - err = w.repo.DeleteWorkflow(req.Uid) + err = w.wfArchive.DeleteWorkflow(req.Uid) if err != nil { return nil, err } diff --git a/cmd/server/workflowarchive/archived_workflow_server_test.go b/server/workflowarchive/archived_workflow_server_test.go similarity index 98% rename from cmd/server/workflowarchive/archived_workflow_server_test.go rename to server/workflowarchive/archived_workflow_server_test.go index f778db69b4eb..55cfe67c8ee7 100644 --- a/cmd/server/workflowarchive/archived_workflow_server_test.go +++ b/server/workflowarchive/archived_workflow_server_test.go @@ -4,6 +4,8 @@ import ( "context" "testing" + "github.com/argoproj/argo/server/auth" + "github.com/stretchr/testify/assert" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -14,7 +16,6 @@ import ( kubefake "k8s.io/client-go/kubernetes/fake" k8stesting "k8s.io/client-go/testing" - "github.com/argoproj/argo/cmd/server/auth" "github.com/argoproj/argo/persist/sqldb/mocks" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" argofake "github.com/argoproj/argo/pkg/client/clientset/versioned/fake" diff --git a/cmd/server/workflowarchive/workflow-archive.pb.go b/server/workflowarchive/workflow-archive.pb.go similarity index 89% rename from cmd/server/workflowarchive/workflow-archive.pb.go rename to server/workflowarchive/workflow-archive.pb.go index 1e0a56c6ab8d..f5169c1e0632 100644 --- a/cmd/server/workflowarchive/workflow-archive.pb.go +++ b/server/workflowarchive/workflow-archive.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cmd/server/workflowarchive/workflow-archive.proto +// source: server/workflowarchive/workflow-archive.proto package workflowarchive @@ -42,7 +42,7 @@ func (m *ListArchivedWorkflowsRequest) Reset() { *m = ListArchivedWorkfl func (m *ListArchivedWorkflowsRequest) String() string { return proto.CompactTextString(m) } func (*ListArchivedWorkflowsRequest) ProtoMessage() {} func (*ListArchivedWorkflowsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_393acb86a8d0f616, []int{0} + return fileDescriptor_d8c091cafb6e62fe, []int{0} } func (m *ListArchivedWorkflowsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -89,7 +89,7 @@ func (m *GetArchivedWorkflowRequest) Reset() { *m = GetArchivedWorkflowR func (m *GetArchivedWorkflowRequest) String() string { return proto.CompactTextString(m) } func (*GetArchivedWorkflowRequest) ProtoMessage() {} func (*GetArchivedWorkflowRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_393acb86a8d0f616, []int{1} + return fileDescriptor_d8c091cafb6e62fe, []int{1} } func (m *GetArchivedWorkflowRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -136,7 +136,7 @@ func (m *DeleteArchivedWorkflowRequest) Reset() { *m = DeleteArchivedWor func (m *DeleteArchivedWorkflowRequest) String() string { return proto.CompactTextString(m) } func (*DeleteArchivedWorkflowRequest) ProtoMessage() {} func (*DeleteArchivedWorkflowRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_393acb86a8d0f616, []int{2} + return fileDescriptor_d8c091cafb6e62fe, []int{2} } func (m *DeleteArchivedWorkflowRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -182,7 +182,7 @@ func (m *ArchivedWorkflowDeletedResponse) Reset() { *m = ArchivedWorkflo func (m *ArchivedWorkflowDeletedResponse) String() string { return proto.CompactTextString(m) } func (*ArchivedWorkflowDeletedResponse) ProtoMessage() {} func (*ArchivedWorkflowDeletedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_393acb86a8d0f616, []int{3} + return fileDescriptor_d8c091cafb6e62fe, []int{3} } func (m *ArchivedWorkflowDeletedResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -219,41 +219,40 @@ func init() { } func init() { - proto.RegisterFile("cmd/server/workflowarchive/workflow-archive.proto", fileDescriptor_393acb86a8d0f616) + proto.RegisterFile("server/workflowarchive/workflow-archive.proto", fileDescriptor_d8c091cafb6e62fe) } -var fileDescriptor_393acb86a8d0f616 = []byte{ - // 466 bytes of a gzipped FileDescriptorProto +var fileDescriptor_d8c091cafb6e62fe = []byte{ + // 464 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xcd, 0x8a, 0x13, 0x41, 0x10, 0xa6, 0x55, 0x04, 0x7b, 0x0f, 0x4a, 0xfb, 0xcb, 0x10, 0xe3, 0xda, 0xa7, 0x45, 0x49, 0xb5, - 0xb3, 0xeb, 0xc1, 0x8b, 0x87, 0xa8, 0xe0, 0x65, 0x41, 0xc8, 0x1e, 0x04, 0x6f, 0xbd, 0x33, 0x65, - 0xa7, 0xcd, 0x64, 0x7a, 0xec, 0xee, 0x4c, 0x10, 0xf1, 0xe2, 0x2b, 0x78, 0xf7, 0xe4, 0x4d, 0x7c, - 0x0f, 0x8f, 0x82, 0x2f, 0x20, 0xc1, 0x07, 0x91, 0xe9, 0xcc, 0xec, 0x2c, 0x99, 0x64, 0x23, 0xec, - 0xad, 0x52, 0x3f, 0xdf, 0xf7, 0x55, 0x7d, 0xe9, 0xa1, 0x71, 0x32, 0x4d, 0x85, 0x43, 0x5b, 0xa2, - 0x15, 0x73, 0x63, 0x27, 0x6f, 0x33, 0x33, 0x97, 0x36, 0x19, 0xeb, 0x12, 0x4f, 0x7e, 0x0f, 0xea, - 0x04, 0x14, 0xd6, 0x78, 0xc3, 0xae, 0xae, 0xf4, 0x45, 0x37, 0x94, 0x51, 0x26, 0xd4, 0x44, 0x15, - 0x2d, 0xdb, 0xa2, 0x9e, 0x32, 0x46, 0x65, 0x28, 0x64, 0xa1, 0x85, 0xcc, 0x73, 0xe3, 0xa5, 0xd7, - 0x26, 0x77, 0x75, 0xf5, 0xf1, 0xe4, 0x89, 0x03, 0x6d, 0xaa, 0xea, 0x54, 0x26, 0x63, 0x9d, 0xa3, - 0xfd, 0x20, 0x8a, 0x89, 0xaa, 0x12, 0x4e, 0x4c, 0xd1, 0x4b, 0x51, 0xc6, 0x42, 0x61, 0x8e, 0x56, - 0x7a, 0x4c, 0xeb, 0xa9, 0xe7, 0x4a, 0xfb, 0xf1, 0xec, 0x18, 0x12, 0x33, 0x15, 0xd2, 0x06, 0xd2, - 0x77, 0x21, 0x68, 0x47, 0x1b, 0x71, 0xa2, 0x8c, 0x65, 0x56, 0x8c, 0x65, 0x17, 0x84, 0xb7, 0xd4, - 0x22, 0x31, 0x16, 0xd7, 0x10, 0x71, 0x47, 0x7b, 0x87, 0xda, 0xf9, 0xe1, 0x72, 0xc3, 0xf4, 0x75, - 0x0d, 0xea, 0x46, 0xf8, 0x7e, 0x86, 0xce, 0xb3, 0x23, 0xba, 0x93, 0x69, 0xe7, 0x5f, 0x15, 0x61, - 0xa7, 0x3b, 0x64, 0x97, 0xec, 0xed, 0xec, 0xc7, 0xb0, 0x44, 0x86, 0xd3, 0x4b, 0x41, 0x31, 0x51, - 0x55, 0xc2, 0x41, 0xb5, 0x14, 0x94, 0x31, 0x1c, 0xb6, 0x83, 0xa3, 0xd3, 0x28, 0x1c, 0x68, 0xf4, - 0x12, 0x3b, 0x9c, 0x0d, 0xe5, 0x35, 0x7a, 0x71, 0xa6, 0xd3, 0x40, 0x75, 0x65, 0x54, 0x85, 0x3c, - 0xa6, 0x77, 0x5f, 0x60, 0x86, 0x1e, 0xff, 0x7f, 0xe4, 0x3e, 0xbd, 0xb7, 0xda, 0xbc, 0x84, 0x48, - 0x47, 0xe8, 0x0a, 0x93, 0x3b, 0xdc, 0xff, 0x7a, 0x89, 0xde, 0x5e, 0xed, 0x39, 0x42, 0x5b, 0xea, - 0x04, 0xd9, 0x0f, 0x42, 0x6f, 0xae, 0xbd, 0x0b, 0x1b, 0xc0, 0xca, 0xbf, 0x02, 0xce, 0xba, 0x5f, - 0x34, 0x84, 0xd6, 0x49, 0x68, 0x9c, 0x0c, 0x41, 0x7b, 0xaf, 0x06, 0x10, 0x1a, 0x27, 0xa1, 0x81, - 0xa9, 0xa0, 0x39, 0xff, 0xfc, 0xfb, 0xef, 0x97, 0x0b, 0x3d, 0x16, 0x05, 0x23, 0xcb, 0x58, 0xd4, - 0xc4, 0xe9, 0x60, 0x7e, 0xa2, 0xea, 0x3b, 0xa1, 0xd7, 0xd7, 0x9c, 0x94, 0x3d, 0xec, 0xa8, 0xdd, - 0x7c, 0xf8, 0xe8, 0xe9, 0xb9, 0xb4, 0xf2, 0xbd, 0xa0, 0x93, 0xb3, 0xdd, 0xcd, 0x3a, 0xc5, 0xc7, - 0x99, 0x4e, 0x3f, 0xb1, 0x6f, 0x84, 0xde, 0x5a, 0x6f, 0x28, 0x83, 0x8e, 0xe0, 0x33, 0x9d, 0x8f, - 0x1e, 0x75, 0xfa, 0xb7, 0xd8, 0xde, 0xc8, 0x7c, 0xb0, 0x55, 0xe6, 0xb3, 0xe1, 0xcf, 0x45, 0x9f, - 0xfc, 0x5a, 0xf4, 0xc9, 0x9f, 0x45, 0x9f, 0xbc, 0x39, 0xd8, 0xf8, 0x24, 0x37, 0x7f, 0x59, 0x8e, - 0x2f, 0x87, 0x57, 0x76, 0xf0, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x5b, 0x30, 0x9b, 0x6f, 0x7e, 0x04, - 0x00, 0x00, + 0xb3, 0x7a, 0xf0, 0xb2, 0x87, 0x55, 0xc1, 0xcb, 0x82, 0x90, 0x3d, 0x08, 0xde, 0x7a, 0x67, 0xca, + 0x4e, 0x9b, 0xc9, 0xf4, 0xd8, 0xdd, 0x99, 0x20, 0xe2, 0xc5, 0x57, 0xf0, 0xee, 0xc9, 0x9b, 0xf8, + 0x1e, 0x1e, 0x05, 0x5f, 0x40, 0x82, 0x0f, 0x22, 0xd3, 0x99, 0xd9, 0x59, 0x32, 0x93, 0x5d, 0x61, + 0x6f, 0x95, 0xfa, 0xf9, 0xbe, 0xaf, 0xea, 0x4b, 0x0f, 0x1d, 0x39, 0xb4, 0x25, 0x5a, 0xb1, 0x30, + 0x76, 0xfa, 0x36, 0x33, 0x0b, 0x69, 0x93, 0x89, 0x2e, 0xf1, 0xf8, 0xf7, 0xa8, 0x4e, 0x40, 0x61, + 0x8d, 0x37, 0xec, 0xea, 0x5a, 0x5f, 0x74, 0x43, 0x19, 0x65, 0x42, 0x4d, 0x54, 0xd1, 0xaa, 0x2d, + 0x1a, 0x28, 0x63, 0x54, 0x86, 0x42, 0x16, 0x5a, 0xc8, 0x3c, 0x37, 0x5e, 0x7a, 0x6d, 0x72, 0x57, + 0x57, 0x9f, 0x4c, 0x9f, 0x3a, 0xd0, 0xa6, 0xaa, 0xce, 0x64, 0x32, 0xd1, 0x39, 0xda, 0x0f, 0xa2, + 0x98, 0xaa, 0x2a, 0xe1, 0xc4, 0x0c, 0xbd, 0x14, 0x65, 0x2c, 0x14, 0xe6, 0x68, 0xa5, 0xc7, 0xb4, + 0x9e, 0x7a, 0xae, 0xb4, 0x9f, 0xcc, 0x8f, 0x20, 0x31, 0x33, 0x21, 0x6d, 0x20, 0x7d, 0x17, 0x82, + 0x76, 0xb4, 0x11, 0x27, 0xca, 0x58, 0x66, 0xc5, 0x44, 0x76, 0x41, 0x78, 0x4b, 0x2d, 0x12, 0x63, + 0xb1, 0x87, 0x88, 0x3b, 0x3a, 0x38, 0xd0, 0xce, 0xef, 0xaf, 0x36, 0x4c, 0x5f, 0xd7, 0xa0, 0x6e, + 0x8c, 0xef, 0xe7, 0xe8, 0x3c, 0x3b, 0xa4, 0x5b, 0x99, 0x76, 0xfe, 0x55, 0x11, 0x76, 0xba, 0x43, + 0xb6, 0xc9, 0xce, 0xd6, 0x6e, 0x0c, 0x2b, 0x64, 0x38, 0xb9, 0x14, 0x14, 0x53, 0x55, 0x25, 0x1c, + 0x54, 0x4b, 0x41, 0x19, 0xc3, 0x41, 0x3b, 0x38, 0x3e, 0x89, 0xc2, 0x81, 0x46, 0x2f, 0xb1, 0xc3, + 0xd9, 0x50, 0x5e, 0xa3, 0x17, 0xe7, 0x3a, 0x0d, 0x54, 0x57, 0xc6, 0x55, 0xc8, 0x63, 0x7a, 0xf7, + 0x05, 0x66, 0xe8, 0xf1, 0xff, 0x47, 0xee, 0xd3, 0x7b, 0xeb, 0xcd, 0x2b, 0x88, 0x74, 0x8c, 0xae, + 0x30, 0xb9, 0xc3, 0xdd, 0xaf, 0x97, 0xe8, 0xed, 0xf5, 0x9e, 0x43, 0xb4, 0xa5, 0x4e, 0x90, 0xfd, + 0x20, 0xf4, 0x66, 0xef, 0x5d, 0xd8, 0x08, 0xd6, 0xfe, 0x15, 0x70, 0xda, 0xfd, 0xa2, 0x7d, 0x68, + 0x9d, 0x84, 0xc6, 0xc9, 0x10, 0xb4, 0xf7, 0x6a, 0x00, 0xa1, 0x71, 0x12, 0x1a, 0x98, 0x0a, 0x9a, + 0xf3, 0xcf, 0xbf, 0xff, 0x7e, 0xb9, 0x30, 0x60, 0x51, 0x30, 0xb2, 0x8c, 0x45, 0x4d, 0x9c, 0x8e, + 0x16, 0xc7, 0xaa, 0xbe, 0x13, 0x7a, 0xbd, 0xe7, 0xa4, 0xec, 0x61, 0x47, 0xed, 0xe6, 0xc3, 0x47, + 0x7b, 0xe7, 0xd2, 0xca, 0x77, 0x82, 0x4e, 0xce, 0xb6, 0x37, 0xeb, 0x14, 0x1f, 0xe7, 0x3a, 0xfd, + 0xc4, 0xbe, 0x11, 0x7a, 0xab, 0xdf, 0x50, 0x06, 0x1d, 0xc1, 0xa7, 0x3a, 0x1f, 0x3d, 0xea, 0xf4, + 0x9f, 0x61, 0x7b, 0x23, 0xf3, 0xc1, 0x99, 0x32, 0x9f, 0xed, 0xfd, 0x5c, 0x0e, 0xc9, 0xaf, 0xe5, + 0x90, 0xfc, 0x59, 0x0e, 0xc9, 0x1b, 0xb1, 0xf1, 0x49, 0xf6, 0x7f, 0x55, 0x8e, 0x2e, 0x87, 0x17, + 0xf6, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4b, 0xcf, 0xc4, 0x0e, 0x76, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -405,7 +404,7 @@ var _ArchivedWorkflowService_serviceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "cmd/server/workflowarchive/workflow-archive.proto", + Metadata: "server/workflowarchive/workflow-archive.proto", } func (m *ListArchivedWorkflowsRequest) Marshal() (dAtA []byte, err error) { diff --git a/cmd/server/workflowarchive/workflow-archive.pb.gw.go b/server/workflowarchive/workflow-archive.pb.gw.go similarity index 99% rename from cmd/server/workflowarchive/workflow-archive.pb.gw.go rename to server/workflowarchive/workflow-archive.pb.gw.go index 8ed3b55b2d9d..42e8d911c919 100644 --- a/cmd/server/workflowarchive/workflow-archive.pb.gw.go +++ b/server/workflowarchive/workflow-archive.pb.gw.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: cmd/server/workflowarchive/workflow-archive.proto +// source: server/workflowarchive/workflow-archive.proto /* Package workflowarchive is a reverse proxy. diff --git a/cmd/server/workflowarchive/workflow-archive.proto b/server/workflowarchive/workflow-archive.proto similarity index 94% rename from cmd/server/workflowarchive/workflow-archive.proto rename to server/workflowarchive/workflow-archive.proto index 95a096979bd6..6b012f50b52c 100644 --- a/cmd/server/workflowarchive/workflow-archive.proto +++ b/server/workflowarchive/workflow-archive.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -option go_package = "github.com/argoproj/argo/cmd/server/workflowarchive"; +option go_package = "github.com/argoproj/argo/server/workflowarchive"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; diff --git a/cmd/server/workflowarchive/workflow-archive.swagger.json b/server/workflowarchive/workflow-archive.swagger.json similarity index 99% rename from cmd/server/workflowarchive/workflow-archive.swagger.json rename to server/workflowarchive/workflow-archive.swagger.json index 24cf7c490a6d..bb8a6206a707 100644 --- a/cmd/server/workflowarchive/workflow-archive.swagger.json +++ b/server/workflowarchive/workflow-archive.swagger.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "cmd/server/workflowarchive/workflow-archive.proto", + "title": "server/workflowarchive/workflow-archive.proto", "version": "version not set" }, "consumes": [ @@ -3235,7 +3235,7 @@ "v1alpha1TTLStrategy": { "type": "object", "properties": { - "secondsAfterCompleted": { + "secondsAfterCompletion": { "type": "integer", "format": "int32" }, @@ -3243,7 +3243,7 @@ "type": "integer", "format": "int32" }, - "secondsAfterFailed": { + "secondsAfterFailure": { "type": "integer", "format": "int32" } @@ -3607,7 +3607,7 @@ "ttlSecondsAfterFinished": { "type": "integer", "format": "int32", - "description": "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution\n(Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be\ndeleted after ttlSecondsAfterFinished expires. If this field is unset,\nttlSecondsAfterFinished will not expire. If this field is set to zero,\nttlSecondsAfterFinished expires immediately after the Workflow finishes.\nDEPRECATED: Use TTLStrategy.SecondsAfterCompleted instead." + "description": "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution\n(Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be\ndeleted after ttlSecondsAfterFinished expires. If this field is unset,\nttlSecondsAfterFinished will not expire. If this field is set to zero,\nttlSecondsAfterFinished expires immediately after the Workflow finishes.\nDEPRECATED: Use TTLStrategy.SecondsAfterCompletion instead." }, "ttlStrategy": { "$ref": "#/definitions/v1alpha1TTLStrategy", @@ -3688,10 +3688,9 @@ }, "description": "Nodes is a mapping between a node ID and the node's status." }, - "offloadNodeStatus": { - "type": "boolean", - "format": "boolean", - "description": "Whether on not node status has been offloaded to a database. If true, then Nodes and CompressedNodes will be empty." + "offloadNodeStatusVersion": { + "type": "string", + "description": "Whether on not node status has been offloaded to a database. If exists, then Nodes and CompressedNodes will be empty.\nThis will actually be populated with a hash of the offloaded data." }, "storedTemplates": { "type": "object", diff --git a/cmd/server/workflowtemplate/workflow-template.pb.go b/server/workflowtemplate/workflow-template.pb.go similarity index 80% rename from cmd/server/workflowtemplate/workflow-template.pb.go rename to server/workflowtemplate/workflow-template.pb.go index 0e04d2fb161f..690253d56d0d 100644 --- a/cmd/server/workflowtemplate/workflow-template.pb.go +++ b/server/workflowtemplate/workflow-template.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cmd/server/workflowtemplate/workflow-template.proto +// source: server/workflowtemplate/workflow-template.proto // Workflow Service // @@ -48,7 +48,7 @@ func (m *WorkflowTemplateCreateRequest) Reset() { *m = WorkflowTemplateC func (m *WorkflowTemplateCreateRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowTemplateCreateRequest) ProtoMessage() {} func (*WorkflowTemplateCreateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa03b43b9ae30de, []int{0} + return fileDescriptor_73c94a413b9efa43, []int{0} } func (m *WorkflowTemplateCreateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -111,7 +111,7 @@ func (m *WorkflowTemplateGetRequest) Reset() { *m = WorkflowTemplateGetR func (m *WorkflowTemplateGetRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowTemplateGetRequest) ProtoMessage() {} func (*WorkflowTemplateGetRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa03b43b9ae30de, []int{1} + return fileDescriptor_73c94a413b9efa43, []int{1} } func (m *WorkflowTemplateGetRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -173,7 +173,7 @@ func (m *WorkflowTemplateListRequest) Reset() { *m = WorkflowTemplateLis func (m *WorkflowTemplateListRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowTemplateListRequest) ProtoMessage() {} func (*WorkflowTemplateListRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa03b43b9ae30de, []int{2} + return fileDescriptor_73c94a413b9efa43, []int{2} } func (m *WorkflowTemplateListRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -229,7 +229,7 @@ func (m *WorkflowTemplateUpdateRequest) Reset() { *m = WorkflowTemplateU func (m *WorkflowTemplateUpdateRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowTemplateUpdateRequest) ProtoMessage() {} func (*WorkflowTemplateUpdateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa03b43b9ae30de, []int{3} + return fileDescriptor_73c94a413b9efa43, []int{3} } func (m *WorkflowTemplateUpdateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -292,7 +292,7 @@ func (m *WorkflowTemplateDeleteRequest) Reset() { *m = WorkflowTemplateD func (m *WorkflowTemplateDeleteRequest) String() string { return proto.CompactTextString(m) } func (*WorkflowTemplateDeleteRequest) ProtoMessage() {} func (*WorkflowTemplateDeleteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa03b43b9ae30de, []int{4} + return fileDescriptor_73c94a413b9efa43, []int{4} } func (m *WorkflowTemplateDeleteRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -352,7 +352,7 @@ func (m *WorkflowDeleteResponse) Reset() { *m = WorkflowDeleteResponse{} func (m *WorkflowDeleteResponse) String() string { return proto.CompactTextString(m) } func (*WorkflowDeleteResponse) ProtoMessage() {} func (*WorkflowDeleteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_ffa03b43b9ae30de, []int{5} + return fileDescriptor_73c94a413b9efa43, []int{5} } func (m *WorkflowDeleteResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -381,6 +381,69 @@ func (m *WorkflowDeleteResponse) XXX_DiscardUnknown() { var xxx_messageInfo_WorkflowDeleteResponse proto.InternalMessageInfo +type WorkflowTemplateLintRequest struct { + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + Template *v1alpha1.WorkflowTemplate `protobuf:"bytes,2,opt,name=template,proto3" json:"template,omitempty"` + CreateOptions *v1.CreateOptions `protobuf:"bytes,3,opt,name=createOptions,proto3" json:"createOptions,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *WorkflowTemplateLintRequest) Reset() { *m = WorkflowTemplateLintRequest{} } +func (m *WorkflowTemplateLintRequest) String() string { return proto.CompactTextString(m) } +func (*WorkflowTemplateLintRequest) ProtoMessage() {} +func (*WorkflowTemplateLintRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_73c94a413b9efa43, []int{6} +} +func (m *WorkflowTemplateLintRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *WorkflowTemplateLintRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_WorkflowTemplateLintRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *WorkflowTemplateLintRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_WorkflowTemplateLintRequest.Merge(m, src) +} +func (m *WorkflowTemplateLintRequest) XXX_Size() int { + return m.Size() +} +func (m *WorkflowTemplateLintRequest) XXX_DiscardUnknown() { + xxx_messageInfo_WorkflowTemplateLintRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_WorkflowTemplateLintRequest proto.InternalMessageInfo + +func (m *WorkflowTemplateLintRequest) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *WorkflowTemplateLintRequest) GetTemplate() *v1alpha1.WorkflowTemplate { + if m != nil { + return m.Template + } + return nil +} + +func (m *WorkflowTemplateLintRequest) GetCreateOptions() *v1.CreateOptions { + if m != nil { + return m.CreateOptions + } + return nil +} + func init() { proto.RegisterType((*WorkflowTemplateCreateRequest)(nil), "workflowtemplate.WorkflowTemplateCreateRequest") proto.RegisterType((*WorkflowTemplateGetRequest)(nil), "workflowtemplate.WorkflowTemplateGetRequest") @@ -388,56 +451,58 @@ func init() { proto.RegisterType((*WorkflowTemplateUpdateRequest)(nil), "workflowtemplate.WorkflowTemplateUpdateRequest") proto.RegisterType((*WorkflowTemplateDeleteRequest)(nil), "workflowtemplate.WorkflowTemplateDeleteRequest") proto.RegisterType((*WorkflowDeleteResponse)(nil), "workflowtemplate.WorkflowDeleteResponse") + proto.RegisterType((*WorkflowTemplateLintRequest)(nil), "workflowtemplate.WorkflowTemplateLintRequest") } func init() { - proto.RegisterFile("cmd/server/workflowtemplate/workflow-template.proto", fileDescriptor_ffa03b43b9ae30de) -} - -var fileDescriptor_ffa03b43b9ae30de = []byte{ - // 671 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x96, 0xcd, 0x6a, 0xd5, 0x40, - 0x14, 0xc7, 0x99, 0x56, 0xc4, 0x4e, 0x29, 0xc8, 0x58, 0xaf, 0x97, 0x58, 0x4b, 0xc9, 0x42, 0x2e, - 0xad, 0x9d, 0xe9, 0x6d, 0xab, 0x94, 0x2e, 0xdb, 0x4a, 0x11, 0x0a, 0x4a, 0xaa, 0x48, 0xdd, 0x4d, - 0x73, 0x8f, 0x69, 0xbc, 0x49, 0x26, 0x66, 0xa6, 0x29, 0x22, 0xdd, 0xf8, 0x04, 0x82, 0x2f, 0xe0, - 0xba, 0xb8, 0xf4, 0x05, 0x44, 0x10, 0x71, 0x25, 0xf8, 0x02, 0x52, 0x7c, 0x0b, 0x37, 0x92, 0xc9, - 0xcd, 0xcd, 0x47, 0xbf, 0xd2, 0x7a, 0x05, 0x77, 0xc3, 0xcc, 0x9c, 0x73, 0x7e, 0xff, 0xf3, 0x31, - 0x0c, 0x5e, 0xb0, 0xfd, 0x0e, 0x93, 0x10, 0xc5, 0x10, 0xb1, 0x3d, 0x11, 0x75, 0x9f, 0x7b, 0x62, - 0x4f, 0x81, 0x1f, 0x7a, 0x5c, 0x41, 0x7f, 0x63, 0x36, 0xdb, 0xa1, 0x61, 0x24, 0x94, 0x20, 0x57, - 0xab, 0x37, 0x8d, 0x71, 0x47, 0x38, 0x42, 0x1f, 0xb2, 0x64, 0x95, 0xde, 0x33, 0x26, 0x1c, 0x21, - 0x1c, 0x0f, 0x18, 0x0f, 0x5d, 0xc6, 0x83, 0x40, 0x28, 0xae, 0x5c, 0x11, 0xc8, 0xde, 0xe9, 0x62, - 0x77, 0x49, 0x52, 0x57, 0x24, 0xa7, 0x3e, 0xb7, 0x77, 0xdc, 0x00, 0xa2, 0x57, 0x2c, 0xec, 0x3a, - 0xc9, 0x86, 0x64, 0x3e, 0x28, 0xce, 0xe2, 0x36, 0x73, 0x20, 0x80, 0x88, 0x2b, 0xe8, 0xf4, 0xac, - 0x56, 0x1d, 0x57, 0xed, 0xec, 0x6e, 0x53, 0x5b, 0xf8, 0x8c, 0x47, 0x3a, 0xe8, 0x0b, 0xbd, 0xc8, - 0x4d, 0x33, 0x3a, 0x16, 0xb7, 0xb9, 0x17, 0xee, 0xf0, 0xa3, 0x4e, 0xcc, 0x3c, 0x34, 0xb3, 0x45, - 0x04, 0xc7, 0x04, 0x32, 0x7f, 0x23, 0x7c, 0xeb, 0x69, 0xcf, 0xd3, 0xe3, 0x9e, 0xce, 0xd5, 0x08, - 0xb8, 0x02, 0x0b, 0x5e, 0xee, 0x82, 0x54, 0x64, 0x02, 0x8f, 0x04, 0xdc, 0x07, 0x19, 0x72, 0x1b, - 0x9a, 0x68, 0x0a, 0xb5, 0x46, 0xac, 0x7c, 0x83, 0x70, 0x7c, 0x25, 0x4b, 0x4f, 0x73, 0x68, 0x0a, - 0xb5, 0x46, 0xe7, 0xef, 0xd3, 0x9c, 0x9d, 0x66, 0xec, 0x7a, 0x41, 0xc3, 0xae, 0x43, 0x13, 0x76, - 0x9a, 0xb1, 0xd3, 0x8c, 0x9d, 0x56, 0x19, 0xac, 0xbe, 0x5b, 0xb2, 0x85, 0xc7, 0x6c, 0x4d, 0xf4, - 0x30, 0xd4, 0x89, 0x6d, 0x0e, 0xeb, 0x38, 0x0b, 0x34, 0x95, 0x47, 0x8b, 0x99, 0xcd, 0x43, 0x24, - 0x99, 0xa5, 0x71, 0x9b, 0xae, 0x16, 0x4d, 0xad, 0xb2, 0x27, 0xf3, 0x3d, 0xc2, 0x46, 0x35, 0xf2, - 0x3a, 0xa8, 0x4c, 0x3a, 0xc1, 0x97, 0x12, 0xa5, 0x3d, 0xd5, 0x7a, 0x5d, 0x4e, 0xc7, 0x50, 0x35, - 0x1d, 0x8f, 0x30, 0x76, 0x40, 0x95, 0x41, 0xe7, 0xea, 0x81, 0xae, 0xf7, 0xed, 0xac, 0x82, 0x0f, - 0xf3, 0x2d, 0xc2, 0x37, 0xab, 0x88, 0x1b, 0xae, 0x54, 0xf5, 0xca, 0xb3, 0x89, 0x47, 0x3d, 0x57, - 0xf6, 0x81, 0xd2, 0x0a, 0xb5, 0xeb, 0x01, 0x6d, 0xe4, 0x86, 0x56, 0xd1, 0x8b, 0xf9, 0xf1, 0x98, - 0x9e, 0x79, 0x12, 0x76, 0x0a, 0x3d, 0x73, 0xfe, 0xc4, 0x15, 0xfb, 0x68, 0xf8, 0x9f, 0xf4, 0x91, - 0xf9, 0xe1, 0x18, 0xec, 0x35, 0xf0, 0xe0, 0x6f, 0xb0, 0xb7, 0xf0, 0x58, 0x47, 0xbb, 0xb8, 0x50, - 0x6f, 0xae, 0x15, 0x4d, 0xad, 0xb2, 0x27, 0xb3, 0x89, 0x1b, 0x19, 0x6d, 0x46, 0x29, 0x43, 0x11, - 0x48, 0x98, 0x3f, 0x18, 0xc1, 0x37, 0xaa, 0x42, 0x36, 0x21, 0x8a, 0x5d, 0x1b, 0xc8, 0x67, 0x84, - 0x1b, 0x69, 0xcb, 0x57, 0x6f, 0x10, 0x46, 0xab, 0x0f, 0x1a, 0x3d, 0x75, 0xf2, 0x8d, 0xc1, 0x54, - 0xc0, 0x6c, 0xbf, 0xf9, 0xf1, 0xeb, 0xdd, 0xd0, 0x8c, 0x79, 0x5b, 0x3f, 0x44, 0x71, 0xfb, 0xe8, - 0x83, 0x2b, 0xd9, 0xeb, 0x7e, 0x4a, 0xf7, 0x97, 0xd1, 0x34, 0xf9, 0x84, 0xf0, 0xb5, 0x75, 0x50, - 0x47, 0x24, 0xdc, 0x39, 0x5b, 0x42, 0x3e, 0xbe, 0x83, 0xe2, 0xbf, 0xab, 0xf9, 0x19, 0x99, 0xad, - 0xc7, 0x9f, 0xae, 0xf7, 0x13, 0x0d, 0xd7, 0x93, 0x11, 0xaa, 0xfa, 0x93, 0x64, 0xf6, 0x6c, 0x15, - 0x85, 0x09, 0x37, 0x1e, 0x0c, 0x44, 0x46, 0xe2, 0xd1, 0xa4, 0x5a, 0x4a, 0x8b, 0xd4, 0x2c, 0x05, - 0xf9, 0x86, 0x70, 0x23, 0x9d, 0xec, 0x8b, 0x74, 0x53, 0xe9, 0x4d, 0x18, 0x54, 0x35, 0x96, 0xb4, - 0x84, 0x79, 0xe3, 0x7c, 0xd5, 0x48, 0x9a, 0xea, 0x00, 0xe1, 0x46, 0x3a, 0x49, 0x17, 0x11, 0x53, - 0x7a, 0x29, 0x8c, 0xd6, 0xc9, 0x06, 0xe5, 0x61, 0xcd, 0xba, 0x67, 0xfa, 0x9c, 0xdd, 0xf3, 0x05, - 0xe1, 0xf1, 0x0d, 0x37, 0x50, 0xff, 0xcd, 0x14, 0xdf, 0xd3, 0x3a, 0xe6, 0xcc, 0x99, 0x9a, 0x3a, - 0x3c, 0x37, 0x50, 0xcb, 0x68, 0x7a, 0x65, 0xe5, 0xeb, 0xe1, 0x24, 0xfa, 0x7e, 0x38, 0x89, 0x7e, - 0x1e, 0x4e, 0xa2, 0x67, 0x8b, 0x27, 0xfe, 0x6b, 0x4e, 0xf9, 0xa1, 0x6d, 0x5f, 0xd6, 0x7f, 0x95, - 0x85, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x92, 0xf5, 0x89, 0x08, 0xc7, 0x09, 0x00, 0x00, + proto.RegisterFile("server/workflowtemplate/workflow-template.proto", fileDescriptor_73c94a413b9efa43) +} + +var fileDescriptor_73c94a413b9efa43 = []byte{ + // 686 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x56, 0xcd, 0x6a, 0x14, 0x4d, + 0x14, 0xa5, 0x92, 0x8f, 0x0f, 0x53, 0x21, 0x20, 0x65, 0x1c, 0x87, 0x36, 0x86, 0x50, 0x0b, 0x19, + 0x12, 0x53, 0x95, 0x49, 0x54, 0x42, 0x16, 0x2e, 0x4c, 0x24, 0x08, 0x01, 0xa5, 0xa3, 0x48, 0xdc, + 0x55, 0x26, 0xd7, 0x4e, 0x3b, 0x3d, 0x5d, 0x6d, 0x57, 0x65, 0x82, 0x48, 0x36, 0x3e, 0x81, 0xe0, + 0x0b, 0xb8, 0x14, 0x71, 0xe9, 0x0b, 0x88, 0x2e, 0xc4, 0x95, 0xe0, 0x0b, 0x48, 0xf0, 0x25, 0xc4, + 0x8d, 0x74, 0x75, 0xf7, 0xf4, 0xcf, 0x4c, 0x4c, 0x27, 0x8e, 0x2b, 0x77, 0x45, 0x55, 0xdd, 0x7b, + 0xcf, 0xb9, 0xf7, 0xf4, 0xe9, 0xc2, 0x5c, 0x41, 0xd8, 0x85, 0x90, 0xef, 0xcb, 0xb0, 0xfd, 0xc8, + 0x93, 0xfb, 0x1a, 0x3a, 0x81, 0x27, 0x34, 0xf4, 0x36, 0xe6, 0xd3, 0x1d, 0x16, 0x84, 0x52, 0x4b, + 0x72, 0xb6, 0x7c, 0xd3, 0x9a, 0x74, 0xa4, 0x23, 0xcd, 0x21, 0x8f, 0x56, 0xf1, 0x3d, 0x6b, 0xca, + 0x91, 0xd2, 0xf1, 0x80, 0x8b, 0xc0, 0xe5, 0xc2, 0xf7, 0xa5, 0x16, 0xda, 0x95, 0xbe, 0x4a, 0x4e, + 0xaf, 0xb6, 0x97, 0x15, 0x73, 0x65, 0x74, 0xda, 0x11, 0xad, 0x5d, 0xd7, 0x87, 0xf0, 0x29, 0x0f, + 0xda, 0x4e, 0xb4, 0xa1, 0x78, 0x07, 0xb4, 0xe0, 0xdd, 0x26, 0x77, 0xc0, 0x87, 0x50, 0x68, 0xd8, + 0x49, 0xa2, 0x56, 0x1d, 0x57, 0xef, 0xee, 0x6d, 0xb3, 0x96, 0xec, 0x70, 0x11, 0x9a, 0xa2, 0x8f, + 0xcd, 0x22, 0x0b, 0x4d, 0xd1, 0xf1, 0x6e, 0x53, 0x78, 0xc1, 0xae, 0xe8, 0x4f, 0x42, 0xb3, 0xd2, + 0xbc, 0x25, 0x43, 0x18, 0x50, 0x88, 0xfe, 0x44, 0xf8, 0xd2, 0x83, 0x24, 0xd3, 0xbd, 0x84, 0xe7, + 0x6a, 0x08, 0x42, 0x83, 0x0d, 0x4f, 0xf6, 0x40, 0x69, 0x32, 0x85, 0xc7, 0x7c, 0xd1, 0x01, 0x15, + 0x88, 0x16, 0xd4, 0xd1, 0x0c, 0x6a, 0x8c, 0xd9, 0xd9, 0x06, 0x11, 0xf8, 0x4c, 0xda, 0x9e, 0xfa, + 0xc8, 0x0c, 0x6a, 0x8c, 0x2f, 0xde, 0x62, 0x19, 0x76, 0x96, 0x62, 0x37, 0x0b, 0x16, 0xb4, 0x1d, + 0x16, 0x61, 0x67, 0x29, 0x76, 0x96, 0x62, 0x67, 0x65, 0x0c, 0x76, 0x2f, 0x2d, 0xd9, 0xc2, 0x13, + 0x2d, 0x83, 0xe8, 0x4e, 0x60, 0x1a, 0x5b, 0x1f, 0x35, 0x75, 0x96, 0x58, 0x4c, 0x8f, 0xe5, 0x3b, + 0x9b, 0x95, 0x88, 0x3a, 0xcb, 0xba, 0x4d, 0xb6, 0x9a, 0x0f, 0xb5, 0x8b, 0x99, 0xe8, 0x2b, 0x84, + 0xad, 0x72, 0xe5, 0x75, 0xd0, 0x29, 0x75, 0x82, 0xff, 0x8b, 0x98, 0x26, 0xac, 0xcd, 0xba, 0xd8, + 0x8e, 0x91, 0x72, 0x3b, 0xee, 0x62, 0xec, 0x80, 0x2e, 0x02, 0x5d, 0xa8, 0x06, 0x74, 0xbd, 0x17, + 0x67, 0xe7, 0x72, 0xd0, 0x17, 0x08, 0x5f, 0x2c, 0x43, 0xdc, 0x70, 0x95, 0xae, 0x36, 0x9e, 0x4d, + 0x3c, 0xee, 0xb9, 0xaa, 0x07, 0x28, 0x9e, 0x50, 0xb3, 0x1a, 0xa0, 0x8d, 0x2c, 0xd0, 0xce, 0x67, + 0xa1, 0xef, 0x06, 0x68, 0xe6, 0x7e, 0xb0, 0x93, 0xd3, 0xcc, 0xc9, 0x1b, 0x97, 0xd7, 0xd1, 0xe8, + 0x5f, 0xd1, 0x11, 0x7d, 0x3b, 0x00, 0xf6, 0x1a, 0x78, 0xf0, 0x27, 0xb0, 0xb7, 0xf0, 0xc4, 0x8e, + 0x49, 0x71, 0x2a, 0x6d, 0xae, 0xe5, 0x43, 0xed, 0x62, 0x26, 0x5a, 0xc7, 0xb5, 0x14, 0x6d, 0x8a, + 0x52, 0x05, 0xd2, 0x57, 0x40, 0x7f, 0x0c, 0x94, 0x84, 0xaf, 0xff, 0x81, 0x2f, 0x76, 0xf1, 0xf5, + 0x18, 0xbe, 0x50, 0xae, 0xbc, 0x09, 0x61, 0xd7, 0x6d, 0x01, 0xf9, 0x80, 0x70, 0x2d, 0x0e, 0x2e, + 0xdf, 0x20, 0x9c, 0x95, 0xcd, 0x9c, 0xfd, 0xd6, 0xf5, 0xac, 0xe1, 0xf4, 0x84, 0x36, 0x9f, 0x7f, + 0xfd, 0xfe, 0x72, 0x64, 0x8e, 0x5e, 0x36, 0x26, 0xdc, 0x6d, 0xf6, 0xff, 0x6c, 0x14, 0x7f, 0xd6, + 0x9b, 0xcd, 0xc1, 0x0a, 0x9a, 0x25, 0xef, 0x11, 0x3e, 0xb7, 0x0e, 0xba, 0x8f, 0xc2, 0x95, 0xe3, + 0x29, 0x64, 0xd6, 0x35, 0x2c, 0xfc, 0xd7, 0x0c, 0x7e, 0x4e, 0xe6, 0xab, 0xe1, 0x8f, 0xd7, 0x07, + 0x11, 0x87, 0xf3, 0x91, 0x7d, 0x94, 0xf3, 0x29, 0x32, 0x7f, 0x3c, 0x8b, 0x9c, 0xbb, 0x59, 0xb7, + 0x87, 0x42, 0x23, 0xca, 0x48, 0x99, 0xa1, 0xd2, 0x20, 0x15, 0x47, 0x41, 0x3e, 0x23, 0x5c, 0x8b, + 0x5d, 0xed, 0x34, 0x6a, 0x2a, 0xf8, 0xe1, 0xb0, 0xa6, 0xb1, 0x6c, 0x28, 0x2c, 0x5a, 0x27, 0x9b, + 0x46, 0x24, 0xaa, 0x37, 0x08, 0xd7, 0x62, 0x17, 0x39, 0x0d, 0x99, 0x82, 0x4b, 0x5a, 0x8d, 0xa3, + 0x03, 0x4a, 0x46, 0x95, 0xa8, 0x67, 0xf6, 0x84, 0xea, 0xf9, 0x88, 0xf0, 0x64, 0xe4, 0x67, 0x7d, + 0x50, 0x2b, 0x89, 0xc7, 0x1f, 0xf6, 0x37, 0x70, 0xdd, 0xb0, 0x58, 0xa0, 0x73, 0x15, 0x59, 0x78, + 0xae, 0xaf, 0x57, 0xd0, 0xec, 0xcd, 0x1b, 0x9f, 0x0e, 0xa7, 0xd1, 0x97, 0xc3, 0x69, 0xf4, 0xed, + 0x70, 0x1a, 0x3d, 0x5c, 0x38, 0xf2, 0x45, 0x77, 0xc4, 0xbb, 0x74, 0xfb, 0x7f, 0xf3, 0x42, 0x5b, + 0xfa, 0x15, 0x00, 0x00, 0xff, 0xff, 0x44, 0x24, 0xc1, 0x3b, 0xb9, 0x0a, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -457,7 +522,7 @@ type WorkflowTemplateServiceClient interface { ListWorkflowTemplates(ctx context.Context, in *WorkflowTemplateListRequest, opts ...grpc.CallOption) (*v1alpha1.WorkflowTemplateList, error) UpdateWorkflowTemplate(ctx context.Context, in *WorkflowTemplateUpdateRequest, opts ...grpc.CallOption) (*v1alpha1.WorkflowTemplate, error) DeleteWorkflowTemplate(ctx context.Context, in *WorkflowTemplateDeleteRequest, opts ...grpc.CallOption) (*WorkflowDeleteResponse, error) - LintWorkflowTemplate(ctx context.Context, in *WorkflowTemplateCreateRequest, opts ...grpc.CallOption) (*v1alpha1.WorkflowTemplate, error) + LintWorkflowTemplate(ctx context.Context, in *WorkflowTemplateLintRequest, opts ...grpc.CallOption) (*v1alpha1.WorkflowTemplate, error) } type workflowTemplateServiceClient struct { @@ -513,7 +578,7 @@ func (c *workflowTemplateServiceClient) DeleteWorkflowTemplate(ctx context.Conte return out, nil } -func (c *workflowTemplateServiceClient) LintWorkflowTemplate(ctx context.Context, in *WorkflowTemplateCreateRequest, opts ...grpc.CallOption) (*v1alpha1.WorkflowTemplate, error) { +func (c *workflowTemplateServiceClient) LintWorkflowTemplate(ctx context.Context, in *WorkflowTemplateLintRequest, opts ...grpc.CallOption) (*v1alpha1.WorkflowTemplate, error) { out := new(v1alpha1.WorkflowTemplate) err := c.cc.Invoke(ctx, "/workflowtemplate.WorkflowTemplateService/LintWorkflowTemplate", in, out, opts...) if err != nil { @@ -529,7 +594,7 @@ type WorkflowTemplateServiceServer interface { ListWorkflowTemplates(context.Context, *WorkflowTemplateListRequest) (*v1alpha1.WorkflowTemplateList, error) UpdateWorkflowTemplate(context.Context, *WorkflowTemplateUpdateRequest) (*v1alpha1.WorkflowTemplate, error) DeleteWorkflowTemplate(context.Context, *WorkflowTemplateDeleteRequest) (*WorkflowDeleteResponse, error) - LintWorkflowTemplate(context.Context, *WorkflowTemplateCreateRequest) (*v1alpha1.WorkflowTemplate, error) + LintWorkflowTemplate(context.Context, *WorkflowTemplateLintRequest) (*v1alpha1.WorkflowTemplate, error) } // UnimplementedWorkflowTemplateServiceServer can be embedded to have forward compatible implementations. @@ -551,7 +616,7 @@ func (*UnimplementedWorkflowTemplateServiceServer) UpdateWorkflowTemplate(ctx co func (*UnimplementedWorkflowTemplateServiceServer) DeleteWorkflowTemplate(ctx context.Context, req *WorkflowTemplateDeleteRequest) (*WorkflowDeleteResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteWorkflowTemplate not implemented") } -func (*UnimplementedWorkflowTemplateServiceServer) LintWorkflowTemplate(ctx context.Context, req *WorkflowTemplateCreateRequest) (*v1alpha1.WorkflowTemplate, error) { +func (*UnimplementedWorkflowTemplateServiceServer) LintWorkflowTemplate(ctx context.Context, req *WorkflowTemplateLintRequest) (*v1alpha1.WorkflowTemplate, error) { return nil, status.Errorf(codes.Unimplemented, "method LintWorkflowTemplate not implemented") } @@ -650,7 +715,7 @@ func _WorkflowTemplateService_DeleteWorkflowTemplate_Handler(srv interface{}, ct } func _WorkflowTemplateService_LintWorkflowTemplate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(WorkflowTemplateCreateRequest) + in := new(WorkflowTemplateLintRequest) if err := dec(in); err != nil { return nil, err } @@ -662,7 +727,7 @@ func _WorkflowTemplateService_LintWorkflowTemplate_Handler(srv interface{}, ctx FullMethod: "/workflowtemplate.WorkflowTemplateService/LintWorkflowTemplate", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(WorkflowTemplateServiceServer).LintWorkflowTemplate(ctx, req.(*WorkflowTemplateCreateRequest)) + return srv.(WorkflowTemplateServiceServer).LintWorkflowTemplate(ctx, req.(*WorkflowTemplateLintRequest)) } return interceptor(ctx, in, info, handler) } @@ -697,7 +762,7 @@ var _WorkflowTemplateService_serviceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "cmd/server/workflowtemplate/workflow-template.proto", + Metadata: "server/workflowtemplate/workflow-template.proto", } func (m *WorkflowTemplateCreateRequest) Marshal() (dAtA []byte, err error) { @@ -990,6 +1055,64 @@ func (m *WorkflowDeleteResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *WorkflowTemplateLintRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *WorkflowTemplateLintRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *WorkflowTemplateLintRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.CreateOptions != nil { + { + size, err := m.CreateOptions.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintWorkflowTemplate(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Template != nil { + { + size, err := m.Template.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintWorkflowTemplate(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintWorkflowTemplate(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintWorkflowTemplate(dAtA []byte, offset int, v uint64) int { offset -= sovWorkflowTemplate(v) base := offset @@ -1129,6 +1252,30 @@ func (m *WorkflowDeleteResponse) Size() (n int) { return n } +func (m *WorkflowTemplateLintRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovWorkflowTemplate(uint64(l)) + } + if m.Template != nil { + l = m.Template.Size() + n += 1 + l + sovWorkflowTemplate(uint64(l)) + } + if m.CreateOptions != nil { + l = m.CreateOptions.Size() + n += 1 + l + sovWorkflowTemplate(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func sovWorkflowTemplate(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1931,6 +2078,164 @@ func (m *WorkflowDeleteResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *WorkflowTemplateLintRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflowTemplate + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: WorkflowTemplateLintRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: WorkflowTemplateLintRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflowTemplate + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthWorkflowTemplate + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthWorkflowTemplate + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Template", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflowTemplate + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthWorkflowTemplate + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthWorkflowTemplate + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Template == nil { + m.Template = &v1alpha1.WorkflowTemplate{} + } + if err := m.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CreateOptions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflowTemplate + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthWorkflowTemplate + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthWorkflowTemplate + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.CreateOptions == nil { + m.CreateOptions = &v1.CreateOptions{} + } + if err := m.CreateOptions.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipWorkflowTemplate(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthWorkflowTemplate + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthWorkflowTemplate + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipWorkflowTemplate(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/cmd/server/workflowtemplate/workflow-template.pb.gw.go b/server/workflowtemplate/workflow-template.pb.gw.go similarity index 99% rename from cmd/server/workflowtemplate/workflow-template.pb.gw.go rename to server/workflowtemplate/workflow-template.pb.gw.go index 2fbaecdadbd7..4d116eaee4d6 100644 --- a/cmd/server/workflowtemplate/workflow-template.pb.gw.go +++ b/server/workflowtemplate/workflow-template.pb.gw.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: cmd/server/workflowtemplate/workflow-template.proto +// source: server/workflowtemplate/workflow-template.proto /* Package workflowtemplate is a reverse proxy. @@ -445,7 +445,7 @@ func local_request_WorkflowTemplateService_DeleteWorkflowTemplate_0(ctx context. } func request_WorkflowTemplateService_LintWorkflowTemplate_0(ctx context.Context, marshaler runtime.Marshaler, client WorkflowTemplateServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq WorkflowTemplateCreateRequest + var protoReq WorkflowTemplateLintRequest var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -480,7 +480,7 @@ func request_WorkflowTemplateService_LintWorkflowTemplate_0(ctx context.Context, } func local_request_WorkflowTemplateService_LintWorkflowTemplate_0(ctx context.Context, marshaler runtime.Marshaler, server WorkflowTemplateServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq WorkflowTemplateCreateRequest + var protoReq WorkflowTemplateLintRequest var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) diff --git a/cmd/server/workflowtemplate/workflow-template.proto b/server/workflowtemplate/workflow-template.proto similarity index 85% rename from cmd/server/workflowtemplate/workflow-template.proto rename to server/workflowtemplate/workflow-template.proto index 21eaf4bda961..1c78dbd80db7 100644 --- a/cmd/server/workflowtemplate/workflow-template.proto +++ b/server/workflowtemplate/workflow-template.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -option go_package = "github.com/argoproj/argo/cmd/server/workflowtemplate"; +option go_package = "github.com/argoproj/argo/server/workflowtemplate"; import "gogoproto/gogo.proto"; @@ -44,7 +44,11 @@ message WorkflowTemplateDeleteRequest { } message WorkflowDeleteResponse { } - +message WorkflowTemplateLintRequest { + string namespace = 1; + github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.WorkflowTemplate template = 2; + k8s.io.apimachinery.pkg.apis.meta.v1.CreateOptions createOptions = 3; +} service WorkflowTemplateService { rpc CreateWorkflowTemplate (WorkflowTemplateCreateRequest) returns (github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.WorkflowTemplate) { @@ -73,7 +77,7 @@ service WorkflowTemplateService { option (google.api.http).delete = "/api/v1/workflow-templates/{namespace}/{name}"; } - rpc LintWorkflowTemplate (WorkflowTemplateCreateRequest) returns (github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.WorkflowTemplate) { + rpc LintWorkflowTemplate (WorkflowTemplateLintRequest) returns (github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.WorkflowTemplate) { option (google.api.http) = { post: "/api/v1/workflow-templates/{namespace}/lint" body: "*" diff --git a/cmd/server/workflowtemplate/workflow-template.swagger.json b/server/workflowtemplate/workflow-template.swagger.json similarity index 99% rename from cmd/server/workflowtemplate/workflow-template.swagger.json rename to server/workflowtemplate/workflow-template.swagger.json index 57256d2c5b52..2a6ce2c2a699 100644 --- a/cmd/server/workflowtemplate/workflow-template.swagger.json +++ b/server/workflowtemplate/workflow-template.swagger.json @@ -149,7 +149,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/workflowtemplateWorkflowTemplateCreateRequest" + "$ref": "#/definitions/workflowtemplateWorkflowTemplateLintRequest" } } ], @@ -3616,6 +3616,20 @@ } } }, + "workflowtemplateWorkflowTemplateLintRequest": { + "type": "object", + "properties": { + "namespace": { + "type": "string" + }, + "template": { + "$ref": "#/definitions/v1alpha1WorkflowTemplate" + }, + "createOptions": { + "$ref": "#/definitions/v1CreateOptions" + } + } + }, "workflowtemplateWorkflowTemplateUpdateRequest": { "type": "object", "properties": { diff --git a/cmd/server/workflowtemplate/workflow_template_server.go b/server/workflowtemplate/workflow_template_server.go similarity index 96% rename from cmd/server/workflowtemplate/workflow_template_server.go rename to server/workflowtemplate/workflow_template_server.go index f57a68009726..8bb9c098274c 100644 --- a/cmd/server/workflowtemplate/workflow_template_server.go +++ b/server/workflowtemplate/workflow_template_server.go @@ -7,8 +7,8 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/argoproj/argo/cmd/server/auth" "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo/server/auth" "github.com/argoproj/argo/workflow/templateresolution" "github.com/argoproj/argo/workflow/validate" ) @@ -75,7 +75,7 @@ func (wts *WorkflowTemplateServer) DeleteWorkflowTemplate(ctx context.Context, r return &WorkflowDeleteResponse{}, nil } -func (wts *WorkflowTemplateServer) LintWorkflowTemplate(ctx context.Context, req *WorkflowTemplateCreateRequest) (*v1alpha1.WorkflowTemplate, error) { +func (wts *WorkflowTemplateServer) LintWorkflowTemplate(ctx context.Context, req *WorkflowTemplateLintRequest) (*v1alpha1.WorkflowTemplate, error) { wfClient := auth.GetWfClient(ctx) wftmplGetter := templateresolution.WrapWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().WorkflowTemplates(req.Namespace)) diff --git a/cmd/server/workflowtemplate/workflow_template_server_test.go b/server/workflowtemplate/workflow_template_server_test.go similarity index 97% rename from cmd/server/workflowtemplate/workflow_template_server_test.go rename to server/workflowtemplate/workflow_template_server_test.go index 20a6860f0789..c191c08232dc 100644 --- a/cmd/server/workflowtemplate/workflow_template_server_test.go +++ b/server/workflowtemplate/workflow_template_server_test.go @@ -5,11 +5,13 @@ import ( "encoding/json" "testing" - "github.com/argoproj/argo/cmd/server/auth" - v1alpha1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" - wftFake "github.com/argoproj/argo/pkg/client/clientset/versioned/fake" + "github.com/argoproj/argo/server/auth" + "github.com/stretchr/testify/assert" "k8s.io/client-go/kubernetes/fake" + + "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + wftFake "github.com/argoproj/argo/pkg/client/clientset/versioned/fake" ) const wftStr1 = ` @@ -55,7 +57,7 @@ const wftStr2 = ` "metadata": { "name": "workflow-template-whalesay-template2", "namespace": "default" - + }, "spec": { "templates": [ diff --git a/test/e2e/README.md b/test/e2e/README.md index b1a762423d76..54908b0d32c3 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -6,7 +6,7 @@ Notes: * Everything runs in the `argo` namespace (including MinIO). -* For speed, please only use `docker/whalesay:latest`. +* For speed, please only use `cowsay:v1`. * Test can take longer on CI. Adds 5s to timeout values. ## Debugging E2E Tests @@ -54,7 +54,7 @@ kubectl -n argo scale deploy/workflow-controller --replicas 0 The run `cmd/workflow-controller/main.go` using these arguments, which enable debug logging, and make sure you use locally build image: ``` ---loglevel debug --executor-image argoproj/argoexec:dev --executor-image-pull-policy Never +--loglevel debug --executor-image argoproj/argoexec:your-branch --executor-image-pull-policy Never ``` ### Running The Argo Server In Your IDE @@ -65,10 +65,24 @@ kubectl -n argo scale deploy/argo-server --replicas 0 Kill any port forwards on 2746. -The run `cmd/server/main.go` using these arguments, which enable debug logging, and make sure you use locally build image: +The run `server/main.go` using these arguments, which enable debug logging, and make sure you use locally build image: ``` -server --loglevel debug --auth-mode client +See dist/postgres.yaml +``` + +### Running The Argo Server In Your IDE + +``` +kubectl -n argo scale deploy/argo-server --replicas 0 +``` + +Kill any port forwards on 2746. + +The run `server/main.go` using these arguments, which enable debug logging, and make sure you use locally build image: + +``` +See dist/postgres.yaml ``` diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index 7e6a33051fcf..c4c42e7a2076 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -2,8 +2,6 @@ package e2e import ( "bufio" - "encoding/base64" - "fmt" "net/http" "strings" "testing" @@ -20,7 +18,6 @@ import ( wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo/test/e2e/fixtures" - "github.com/argoproj/argo/util/kubeconfig" ) const baseUrl = "http://localhost:2746" @@ -35,10 +32,11 @@ type ArgoServerSuite struct { func (s *ArgoServerSuite) BeforeTest(suiteName, testName string) { s.E2ESuite.BeforeTest(suiteName, testName) var err error - s.bearerToken, err = kubeconfig.GetBearerToken(s.RestConfig) + s.bearerToken, err = s.GetServiceAccountToken() if err != nil { panic(err) } + } func (s *ArgoServerSuite) AfterTest(suiteName, testName string) { @@ -75,116 +73,118 @@ func (s *ArgoServerSuite) TestInfo() { func (s *ArgoServerSuite) TestUnauthorized() { token := s.bearerToken defer func() { s.bearerToken = token }() - s.bearerToken = "" + s.bearerToken = "test-token" s.e(s.T()).GET("/api/v1/workflows/argo"). Expect(). Status(401) } +func (s *ArgoServerSuite) TestCookieAuth() { + token := s.bearerToken + defer func() { s.bearerToken = token }() + s.bearerToken = "" + s.e(s.T()).GET("/api/v1/workflows/argo"). + WithHeader("Cookie", "authorization="+token). + Expect(). + Status(200) +} func (s *ArgoServerSuite) TestPermission() { - s.T().SkipNow() // TODO - nsName := fmt.Sprintf("%s-%d", "test-rbac", time.Now().Unix()) - ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: nsName}} - s.Run("Create ns", func(t *testing.T) { - _, err := s.KubeClient.CoreV1().Namespaces().Create(ns) + nsName := fixtures.Namespace + // Create good serviceaccount + goodSaName := "argotestgood" + goodSa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: goodSaName}} + s.Run("CreateGoodSA", func(t *testing.T) { + _, err := s.KubeClient.CoreV1().ServiceAccounts(nsName).Create(goodSa) assert.NoError(t, err) }) defer func() { - // Clean up created namespace - _ = s.KubeClient.CoreV1().Namespaces().Delete(nsName, nil) + // Clean up created sa + _ = s.KubeClient.CoreV1().ServiceAccounts(nsName).Delete(goodSaName, nil) }() - forbiddenNsName := fmt.Sprintf("%s-%s", nsName, "fb") - forbiddenNs := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: forbiddenNsName}} - s.Run("Create forbidden ns", func(t *testing.T) { - _, err := s.KubeClient.CoreV1().Namespaces().Create(forbiddenNs) + + // Create bad serviceaccount + badSaName := "argotestbad" + badSa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: badSaName}} + s.Run("CreateBadSA", func(t *testing.T) { + _, err := s.KubeClient.CoreV1().ServiceAccounts(nsName).Create(badSa) assert.NoError(t, err) }) defer func() { - _ = s.KubeClient.CoreV1().Namespaces().Delete(forbiddenNsName, nil) + _ = s.KubeClient.CoreV1().ServiceAccounts(nsName).Delete(badSaName, nil) }() - // Create serviceaccount in good ns - saName := "argotest" - sa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: saName}} - s.Run("Create service account in good ns", func(t *testing.T) { - _, err := s.KubeClient.CoreV1().ServiceAccounts(nsName).Create(sa) - assert.NoError(t, err) - }) - // Create serviceaccount in forbidden ns - forbiddenSaName := "argotest" - forbiddenSa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: forbiddenSaName}} - s.Run("Create service account in forbidden ns", func(t *testing.T) { - _, err := s.KubeClient.CoreV1().ServiceAccounts(forbiddenNsName).Create(forbiddenSa) - assert.NoError(t, err) - }) - // Create RBAC Role in good ns - roleName := "argotest-role" - role := &rbacv1.Role{ - ObjectMeta: metav1.ObjectMeta{Name: roleName}, - Rules: []rbacv1.PolicyRule{ - { - APIGroups: []string{"argoproj.io"}, - Resources: []string{"workflows", "workflowtemplates", "cronworkflows", "workflows/finalizers", "workflowtemplates/finalizers", "cronworkflows/finalizers"}, - Verbs: []string{"create", "get", "list", "watch", "update", "patch", "delete"}, - }, - }, - } - s.Run("Create Role", func(t *testing.T) { - _, err := s.KubeClient.RbacV1().Roles(nsName).Create(role) + // Create RBAC Role + var roleName string + s.Run("LoadRoleYaml", func(t *testing.T) { + obj, err := fixtures.LoadObject("@testdata/argo-server-test-role.yaml") + assert.NoError(t, err) + role, _ := obj.(*rbacv1.Role) + roleName = role.Name + _, err = s.KubeClient.RbacV1().Roles(nsName).Create(role) assert.NoError(t, err) }) + defer func() { + _ = s.KubeClient.RbacV1().Roles(nsName).Delete(roleName, nil) + }() - // Create RBAC RoleBinding in good ns + // Create RBAC RoleBinding + roleBindingName := "argotest-role-binding" roleBinding := &rbacv1.RoleBinding{ - ObjectMeta: metav1.ObjectMeta{Name: "argotest-role-binding"}, - Subjects: []rbacv1.Subject{{Kind: "ServiceAccount", Name: saName}}, + ObjectMeta: metav1.ObjectMeta{Name: roleBindingName}, + Subjects: []rbacv1.Subject{{Kind: "ServiceAccount", Name: goodSaName}}, RoleRef: rbacv1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", Kind: "Role", Name: roleName, }, } - s.Run("Create RoleBinding", func(t *testing.T) { + s.Run("CreateRoleBinding", func(t *testing.T) { _, err := s.KubeClient.RbacV1().RoleBindings(nsName).Create(roleBinding) assert.NoError(t, err) }) + defer func() { + _ = s.KubeClient.RbacV1().RoleBindings(nsName).Delete(roleBindingName, nil) + }() - // Get token of serviceaccount in good ns + // Sleep 2 seconds to wait for serviceaccount token created. + // The secret creation slowness is seen in k3d. + time.Sleep(2 * time.Second) + + // Get token of good serviceaccount var goodToken string - s.Run("Get good serviceaccount token", func(t *testing.T) { - sAccount, err := s.KubeClient.CoreV1().ServiceAccounts(nsName).Get(saName, metav1.GetOptions{}) + s.Run("GetGoodSAToken", func(t *testing.T) { + sAccount, err := s.KubeClient.CoreV1().ServiceAccounts(nsName).Get(goodSaName, metav1.GetOptions{}) if assert.NoError(t, err) { secretName := sAccount.Secrets[0].Name secret, err := s.KubeClient.CoreV1().Secrets(nsName).Get(secretName, metav1.GetOptions{}) assert.NoError(t, err) - // Argo server API expects it to be encoded. - goodToken = base64.StdEncoding.EncodeToString(secret.Data["token"]) + goodToken = string(secret.Data["token"]) } }) - var forbiddenToken string - s.Run("Get forbidden serviceaccount token", func(t *testing.T) { - sAccount, err := s.KubeClient.CoreV1().ServiceAccounts(forbiddenNsName).Get(forbiddenSaName, metav1.GetOptions{}) + // Get token of bad serviceaccount + var badToken string + s.Run("GetBadSAToken", func(t *testing.T) { + sAccount, err := s.KubeClient.CoreV1().ServiceAccounts(nsName).Get(badSaName, metav1.GetOptions{}) assert.NoError(t, err) secretName := sAccount.Secrets[0].Name - secret, err := s.KubeClient.CoreV1().Secrets(forbiddenNsName).Get(secretName, metav1.GetOptions{}) + secret, err := s.KubeClient.CoreV1().Secrets(nsName).Get(secretName, metav1.GetOptions{}) assert.NoError(t, err) - // Argo server API expects it to be encoded. - forbiddenToken = base64.StdEncoding.EncodeToString(secret.Data["token"]) + badToken = string(secret.Data["token"]) }) token := s.bearerToken defer func() { s.bearerToken = token }() - // Test creating workflow in good ns + // Test creating workflow with good token + var uid string s.bearerToken = goodToken - s.Run("Create workflow in good ns", func(t *testing.T) { - s.bearerToken = goodToken - s.e(t).POST("/api/v1/workflows/" + nsName). + s.Run("CreateWFGoodToken", func(t *testing.T) { + uid = s.e(t).POST("/api/v1/workflows/" + nsName). WithBytes([]byte(`{ "workflow": { "metadata": { - "name": "test", + "name": "test-wf-good", "labels": { "argo-e2e": "true" } @@ -194,9 +194,9 @@ func (s *ArgoServerSuite) TestPermission() { { "name": "run-workflow", "container": { - "image": "docker/whalesay:latest", + "image": "cowsay:v1", "command": ["sh"], - "args": ["-c", "sleep 10"] + "args": ["-c", "sleep 1"] } } ], @@ -205,12 +205,15 @@ func (s *ArgoServerSuite) TestPermission() { } }`)). Expect(). - Status(200) + Status(200). + JSON(). + Path("$.metadata.uid"). + Raw().(string) }) - // Test list workflows in good ns - s.Run("List", func(t *testing.T) { - s.bearerToken = goodToken + // Test list workflows with good token + s.bearerToken = goodToken + s.Run("ListWFsGoodToken", func(t *testing.T) { s.e(t).GET("/api/v1/workflows/"+nsName). WithQuery("listOptions.labelSelector", "argo-e2e"). Expect(). @@ -219,17 +222,17 @@ func (s *ArgoServerSuite) TestPermission() { Path("$.items"). Array(). Length(). - Equal(1) + Gt(0) }) - // Test creating workflow in forbidden ns - s.Run("Create workflow in forbidden ns", func(t *testing.T) { - s.bearerToken = goodToken - s.e(t).POST("/api/v1/workflows/" + forbiddenNsName). + // Test creating workflow with bad token + s.bearerToken = badToken + s.Run("CreateWFBadToken", func(t *testing.T) { + s.e(t).POST("/api/v1/workflows/" + nsName). WithBytes([]byte(`{ "workflow": { "metadata": { - "name": "test", + "name": "test-wf-bad", "labels": { "argo-e2e": "true" } @@ -239,10 +242,10 @@ func (s *ArgoServerSuite) TestPermission() { { "name": "run-workflow", "container": { - "image": "docker/whalesay:latest", + "image": "cowsay:v1", "imagePullPolicy": "IfNotPresent", "command": ["sh"], - "args": ["-c", "sleep 10"] + "args": ["-c", "sleep 1"] } } ], @@ -254,14 +257,90 @@ func (s *ArgoServerSuite) TestPermission() { Status(403) }) - // Test list workflows in good ns with forbidden ns token - s.bearerToken = forbiddenToken - s.Run("List", func(t *testing.T) { - s.bearerToken = forbiddenToken + // Test list workflows with bad token + s.bearerToken = badToken + s.Run("ListWFsBadToken", func(t *testing.T) { s.e(t).GET("/api/v1/workflows/" + nsName). Expect(). Status(403) }) + + if s.Persistence.IsEnabled() { + + // Simply wait 10 seconds for the wf to be completed + s.Given(). + WorkflowName("test-wf-good"). + When(). + WaitForWorkflow(10 * time.Second) + + // Test list archived WFs with good token + s.bearerToken = goodToken + s.Run("ListArchivedWFsGoodToken", func(t *testing.T) { + s.e(t).GET("/api/v1/archived-workflows"). + WithQuery("listOptions.labelSelector", "argo-e2e"). + WithQuery("listOptions.fieldSelector", "metadata.namespace="+nsName). + Expect(). + Status(200). + JSON(). + Path("$.items"). + Array().Length().Gt(0) + }) + + // Test get archived wf with good token + s.bearerToken = goodToken + s.Run("GetArchivedWFsGoodToken", func(t *testing.T) { + s.e(t).GET("/api/v1/archived-workflows/"+uid). + WithQuery("listOptions.labelSelector", "argo-e2e"). + Expect(). + Status(200). + JSON(). + Path("$.metadata.name"). + Equal("test-wf-good") + }) + + // Test list archived WFs with bad token + // TODO: Uncomment following code after https://github.com/argoproj/argo/issues/2049 is resolved. + + // s.bearerToken = badToken + // s.Run("ListArchivedWFsBadToken", func(t *testing.T) { + // s.e(t).GET("/api/v1/archived-workflows"). + // WithQuery("listOptions.labelSelector", "argo-e2e"). + // WithQuery("listOptions.fieldSelector", "metadata.namespace="+nsName). + // Expect(). + // Status(200). + // JSON(). + // Path("$.items"). + // Array(). + // Length(). + // Equal(0) + // }) + + // Test get archived wf with bad token + s.bearerToken = badToken + s.Run("ListArchivedWFsBadToken", func(t *testing.T) { + s.e(t).GET("/api/v1/archived-workflows/"+uid). + WithQuery("listOptions.labelSelector", "argo-e2e"). + Expect(). + Status(403) + }) + + } + + // Test delete workflow with bad token + s.bearerToken = badToken + s.Run("DeleteWFWithBadToken", func(t *testing.T) { + s.e(t).DELETE("/api/v1/workflows/" + nsName + "/test-wf-good"). + Expect(). + Status(403) + }) + + // Test delete workflow with good token + s.bearerToken = goodToken + s.Run("DeleteWFWithGoodToken", func(t *testing.T) { + s.e(t).DELETE("/api/v1/workflows/" + nsName + "/test-wf-good"). + Expect(). + Status(200) + }) } func (s *ArgoServerSuite) TestLintWorkflow() { @@ -279,7 +358,7 @@ func (s *ArgoServerSuite) TestLintWorkflow() { { "name": "run-workflow", "container": { - "image": "docker/whalesay:latest", + "image": "cowsay:v1", "imagePullPolicy": "IfNotPresent" } } @@ -308,7 +387,7 @@ func (s *ArgoServerSuite) TestCreateWorkflowDryRun() { { "name": "run-workflow", "container": { - "image": "docker/whalesay:latest", + "image": "cowsay:v1", "imagePullPolicy": "IfNotPresent" } } @@ -321,7 +400,7 @@ func (s *ArgoServerSuite) TestCreateWorkflowDryRun() { Status(200) } -func (s *ArgoServerSuite) TestWorkflows() { +func (s *ArgoServerSuite) TestWorkflowService() { s.Run("Create", func(t *testing.T) { s.e(t).POST("/api/v1/workflows/argo"). @@ -338,7 +417,7 @@ func (s *ArgoServerSuite) TestWorkflows() { { "name": "run-workflow", "container": { - "image": "docker/whalesay:latest", + "image": "cowsay:v1", "imagePullPolicy": "IfNotPresent", "command": ["sh"], "args": ["-c", "sleep 10"] @@ -354,25 +433,43 @@ func (s *ArgoServerSuite) TestWorkflows() { }) s.Run("List", func(t *testing.T) { - // make sure list options work correctly s.Given(). - Workflow("@smoke/basic.yaml") + WorkflowName("test"). + When(). + WaitForWorkflowToStart(20 * time.Second) - s.e(t).GET("/api/v1/workflows/"). + j := s.e(t).GET("/api/v1/workflows/argo"). WithQuery("listOptions.labelSelector", "argo-e2e=subject"). Expect(). Status(200). - JSON(). + JSON() + j. Path("$.items"). Array(). Length(). Equal(1) + if s.Persistence.IsEnabled() { + // check we are loading offloaded node status + j.Path("$.items[0].status.offloadNodeStatusVersion"). + NotNull() + } + j.Path("$.items[0].status.nodes"). + NotNull() }) s.Run("Get", func(t *testing.T) { - s.e(t).GET("/api/v1/workflows/argo/test"). + j := s.e(t).GET("/api/v1/workflows/argo/test"). Expect(). - Status(200) + Status(200). + JSON() + if s.Persistence.IsEnabled() { + // check we are loading offloaded node status + j. + Path("$.status.offloadNodeStatusVersion"). + NotNull() + } + j.Path("$.status.nodes"). + NotNull() s.e(t).GET("/api/v1/workflows/argo/not-found"). Expect(). Status(404) @@ -431,7 +528,7 @@ func (s *ArgoServerSuite) TestWorkflows() { }) } -func (s *ArgoServerSuite) TestCronWorkflows() { +func (s *ArgoServerSuite) TestCronWorkflowService() { s.Run("Create", func(t *testing.T) { s.e(t).POST("/api/v1/cron-workflows/argo"). WithBytes([]byte(`{ @@ -450,7 +547,7 @@ func (s *ArgoServerSuite) TestCronWorkflows() { { "name": "whalesay", "container": { - "image": "docker/whalesay:latest", + "image": "cowsay:v1", "imagePullPolicy": "IfNotPresent" } } @@ -468,7 +565,7 @@ func (s *ArgoServerSuite) TestCronWorkflows() { s.Given(). CronWorkflow("@testdata/basic.yaml") - s.e(t).GET("/api/v1/cron-workflows/"). + s.e(t).GET("/api/v1/cron-workflows/argo"). WithQuery("listOptions.labelSelector", "argo-e2e=subject"). Expect(). Status(200). @@ -511,7 +608,7 @@ func (s *ArgoServerSuite) TestCronWorkflows() { { "name": "whalesay", "container": { - "image": "docker/whalesay:latest", + "image": "cowsay:v1", "imagePullPolicy": "IfNotPresent" } } @@ -534,7 +631,10 @@ func (s *ArgoServerSuite) TestCronWorkflows() { } // make sure we can download an artifact -func (s *ArgoServerSuite) TestWorkflowArtifact() { +func (s *ArgoServerSuite) TestArtifactServer() { + if !s.Persistence.IsEnabled() { + s.T().SkipNow() + } var uid types.UID s.Given(). Workflow("@smoke/basic.yaml"). @@ -548,37 +648,44 @@ func (s *ArgoServerSuite) TestWorkflowArtifact() { s.Run("GetArtifact", func(t *testing.T) { s.e(t).GET("/artifacts/argo/basic/basic/main-logs"). - WithQuery("Authorization", s.bearerToken). Expect(). Status(200). Body(). - Contains("🐙 Hello Argo!") + Contains(":) Hello Argo!") }) - - s.Run("GetArtifactByUid", func(t *testing.T) { + s.Run("GetArtifactByUID", func(t *testing.T) { s.e(t).DELETE("/api/v1/workflows/argo/basic"). Expect(). Status(200) s.e(t).GET("/artifacts-by-uid/{uid}/basic/main-logs", uid). - WithQuery("Authorization", s.bearerToken). Expect(). Status(200). Body(). - Contains("🐙 Hello Argo!") + Contains(":) Hello Argo!") + }) + + // as the artifact server has some special code for cookies, we best test that too + s.Run("GetArtifactByUIDUsingCookie", func(t *testing.T) { + token := s.bearerToken + defer func() { s.bearerToken = token }() + s.bearerToken = "" + s.e(t).GET("/artifacts-by-uid/{uid}/basic/main-logs", uid). + WithHeader("Cookie", "authorization="+token). + Expect(). + Status(200) }) } // do some basic testing on the stream methods -func (s *ArgoServerSuite) TestWorkflowStream() { +func (s *ArgoServerSuite) TestWorkflowServiceStream() { s.Given(). Workflow("@smoke/basic.yaml"). When(). - SubmitWorkflow() - - time.Sleep(1 * time.Second) + SubmitWorkflow(). + WaitForWorkflowToStart(10 * time.Second) // use the watch to make sure that the workflow has succeeded s.Run("Watch", func(t *testing.T) { @@ -589,7 +696,12 @@ func (s *ArgoServerSuite) TestWorkflowStream() { req.Close = true resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) - defer func() { _ = resp.Body.Close() }() + assert.NotNil(t, resp) + defer func() { + if resp != nil { + _ = resp.Body.Close() + } + }() if assert.Equal(t, 200, resp.StatusCode) { assert.Equal(t, resp.Header.Get("Content-Type"), "text/event-stream") s := bufio.NewScanner(resp.Body) @@ -627,7 +739,7 @@ func (s *ArgoServerSuite) TestWorkflowStream() { s := bufio.NewScanner(resp.Body) for s.Scan() { line := s.Text() - if strings.Contains(line, "🐙 Hello Argo!") { + if strings.Contains(line, ":) Hello Argo!") { break } } @@ -649,7 +761,10 @@ func (s *ArgoServerSuite) TestWorkflowStream() { }) } -func (s *ArgoServerSuite) TestArchivedWorkflow() { +func (s *ArgoServerSuite) TestArchivedWorkflowService() { + if !s.Persistence.IsEnabled() { + s.T().SkipNow() + } var uid types.UID s.Given(). Workflow("@smoke/basic.yaml"). @@ -660,13 +775,13 @@ func (s *ArgoServerSuite) TestArchivedWorkflow() { ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { uid = metadata.UID }) - s.Given(). - Workflow("@smoke/basic-2.yaml"). - When(). - SubmitWorkflow(). - WaitForWorkflow(15 * time.Second) - s.Run("List", func(t *testing.T) { + s.Given(). + Workflow("@smoke/basic-2.yaml"). + When(). + SubmitWorkflow(). + WaitForWorkflow(20 * time.Second) + s.e(t).GET("/api/v1/archived-workflows"). WithQuery("listOptions.labelSelector", "argo-e2e"). Expect(). @@ -716,7 +831,7 @@ func (s *ArgoServerSuite) TestArchivedWorkflow() { }) } -func (s *ArgoServerSuite) TestWorkflowTemplates() { +func (s *ArgoServerSuite) TestWorkflowTemplateService() { s.Run("Lint", func(t *testing.T) { s.e(t).POST("/api/v1/workflow-templates/argo/lint"). @@ -734,7 +849,7 @@ func (s *ArgoServerSuite) TestWorkflowTemplates() { "name": "run-workflow", "container": { "name": "", - "image": "docker/whalesay:latest", + "image": "cowsay:v1", "imagePullPolicy": "IfNotPresent" } } @@ -763,7 +878,7 @@ func (s *ArgoServerSuite) TestWorkflowTemplates() { "name": "run-workflow", "container": { "name": "", - "image": "docker/whalesay:latest", + "image": "cowsay:v1", "imagePullPolicy": "IfNotPresent" } } @@ -824,7 +939,7 @@ func (s *ArgoServerSuite) TestWorkflowTemplates() { "name": "run-workflow", "container": { "name": "", - "image": "docker/whalesay:dev", + "image": "cowsay:v2", "imagePullPolicy": "IfNotPresent" } } @@ -837,7 +952,7 @@ func (s *ArgoServerSuite) TestWorkflowTemplates() { Status(200). JSON(). Path("$.spec.templates[0].container.image"). - Equal("docker/whalesay:dev") + Equal("cowsay:v2") }) s.Run("Delete", func(t *testing.T) { diff --git a/test/e2e/cli_test.go b/test/e2e/cli_test.go index f04d541ec7fb..704109eea623 100644 --- a/test/e2e/cli_test.go +++ b/test/e2e/cli_test.go @@ -1,7 +1,6 @@ package e2e import ( - "os" "regexp" "testing" "time" @@ -21,12 +20,11 @@ type CLISuite struct { func (s *CLISuite) BeforeTest(suiteName, testName string) { s.E2ESuite.BeforeTest(suiteName, testName) - _ = os.Setenv("ARGO_SERVER", "localhost:2746") + } func (s *CLISuite) AfterTest(suiteName, testName string) { s.E2ESuite.AfterTest(suiteName, testName) - _ = os.Unsetenv("ARGO_SERVER") } func (s *CLISuite) TestCompletion() { @@ -39,7 +37,9 @@ func (s *CLISuite) TestCompletion() { func (s *CLISuite) TestToken() { s.Given().RunCli([]string{"token"}, func(t *testing.T, output string, err error) { assert.NoError(t, err) - assert.NotEmpty(t, output) + token, err := s.GetServiceAccountToken() + assert.NoError(t, err) + assert.Equal(t, token, output) }) } @@ -65,8 +65,6 @@ func (s *CLISuite) TestRoot() { assert.Contains(t, output, "ServiceAccount:") assert.Contains(t, output, "Status:") assert.Contains(t, output, "Created:") - assert.Contains(t, output, "Started:") - assert.Contains(t, output, "Duration:") }) var createdWorkflowName string @@ -83,9 +81,9 @@ func (s *CLISuite) TestRoot() { } createdWorkflowName = res[1] }). - WaitForWorkflowFromName(createdWorkflowName, 15*time.Second). + WaitForWorkflowName(createdWorkflowName, 15*time.Second). Then(). - ExpectWorkflowFromName(createdWorkflowName, func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + ExpectWorkflowName(createdWorkflowName, func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { assert.Equal(t, wfv1.NodeSucceeded, status.Phase) }) @@ -105,9 +103,9 @@ func (s *CLISuite) TestRoot() { } createdWorkflowName = res[1] }). - WaitForWorkflowFromName(createdWorkflowName, 15*time.Second). + WaitForWorkflowName(createdWorkflowName, 15*time.Second). Then(). - ExpectWorkflowFromName(createdWorkflowName, func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + ExpectWorkflowName(createdWorkflowName, func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { assert.Equal(t, wfv1.NodeSucceeded, status.Phase) }) } @@ -190,6 +188,9 @@ func (s *CLISuite) TestCron() { } func (s *CLISuite) TestArchive() { + if !s.Persistence.IsEnabled() { + s.T().SkipNow() + } var uid types.UID s.Given(). Workflow("@smoke/basic.yaml"). @@ -199,20 +200,24 @@ func (s *CLISuite) TestArchive() { Then(). ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { uid = metadata.UID - }).RunCli([]string{"archive", "list"}, func(t *testing.T, output string, err error) { - assert.NoError(t, err) - assert.Contains(t, output, "NAMESPACE NAME") - assert.Contains(t, output, "argo basic") - }) - s.Given().RunCli([]string{"archive", "get", string(uid)}, func(t *testing.T, output string, err error) { - assert.NoError(t, err) - assert.Contains(t, output, "Succeeded") - }) - s.Given().RunCli([]string{"archive", "delete", string(uid)}, func(t *testing.T, output string, err error) { - assert.NoError(t, err) - assert.Contains(t, output, "Archived workflow") - assert.Contains(t, output, "deleted") - }) + }). + RunCli([]string{"archive", "list"}, func(t *testing.T, output string, err error) { + if assert.NoError(t, err) { + assert.Contains(t, output, "NAMESPACE NAME") + assert.Contains(t, output, "argo basic") + } + }). + RunCli([]string{"archive", "get", string(uid)}, func(t *testing.T, output string, err error) { + if assert.NoError(t, err) { + assert.Contains(t, output, "Succeeded") + } + }). + RunCli([]string{"archive", "delete", string(uid)}, func(t *testing.T, output string, err error) { + if assert.NoError(t, err) { + assert.Contains(t, output, "Archived workflow") + assert.Contains(t, output, "deleted") + } + }) } func TestCliSuite(t *testing.T) { diff --git a/test/e2e/cron_test.go b/test/e2e/cron_test.go index e4d8af422bec..6418339c4c5e 100644 --- a/test/e2e/cron_test.go +++ b/test/e2e/cron_test.go @@ -2,9 +2,10 @@ package e2e import ( "fmt" - wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" - "github.com/argoproj/argo/test/e2e/fixtures" - "github.com/argoproj/argo/workflow/common" + "strconv" + "testing" + "time" + "github.com/argoproj/pkg/humanize" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -13,9 +14,10 @@ import ( "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" - "strconv" - "testing" - "time" + + wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo/test/e2e/fixtures" + "github.com/argoproj/argo/workflow/common" ) type CronSuite struct { diff --git a/test/e2e/expectedfailures/dag-disable-failFast.yaml b/test/e2e/expectedfailures/dag-disable-failFast.yaml index 683c990a1939..43ac5819a668 100644 --- a/test/e2e/expectedfailures/dag-disable-failFast.yaml +++ b/test/e2e/expectedfailures/dag-disable-failFast.yaml @@ -7,7 +7,7 @@ spec: templates: - name: a container: - image: docker/whalesay:latest + image: cowsay:v1 command: [cowsay] args: ["hello world"] - name: b @@ -26,7 +26,7 @@ spec: args: ["echo intentional failure; exit 2"] - name: d container: - image: docker/whalesay:latest + image: cowsay:v1 command: [cowsay] args: ["hello world"] - name: statis diff --git a/test/e2e/expectedfailures/dag-disbale-failFast-2.yaml b/test/e2e/expectedfailures/dag-disbale-failFast-2.yaml index 5d753aa5f785..466ea32cf25c 100644 --- a/test/e2e/expectedfailures/dag-disbale-failFast-2.yaml +++ b/test/e2e/expectedfailures/dag-disbale-failFast-2.yaml @@ -7,7 +7,7 @@ spec: templates: - name: a container: - image: docker/whalesay:latest + image: cowsay:v1 command: [cowsay] args: ["hello world"] - name: b diff --git a/test/e2e/expectedfailures/dag-noroot-branch-failed.yaml b/test/e2e/expectedfailures/dag-noroot-branch-failed.yaml index 867d4cc6f8b7..b700c7107698 100644 --- a/test/e2e/expectedfailures/dag-noroot-branch-failed.yaml +++ b/test/e2e/expectedfailures/dag-noroot-branch-failed.yaml @@ -7,7 +7,7 @@ spec: templates: - name: a container: - image: docker/whalesay:latest + image: cowsay:v1 command: [cowsay] args: ["hello world"] - name: b @@ -26,7 +26,7 @@ spec: args: ["echo intentional failure; exit 2"] - name: d container: - image: docker/whalesay:latest + image: cowsay:v1 command: [cowsay] args: ["hello world"] - name: statis diff --git a/test/e2e/expectedfailures/failed-step-event.yaml b/test/e2e/expectedfailures/failed-step-event.yaml new file mode 100644 index 000000000000..8e159ef15303 --- /dev/null +++ b/test/e2e/expectedfailures/failed-step-event.yaml @@ -0,0 +1,14 @@ +# e2e test to ensure the controller publishes +# an audit event marking the failure +# in case of node failure +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: failed-step-event- +spec: + entrypoint: exit + templates: + - name: exit + container: + image: cowsay:v1 + command: [sh, -c, exit 1] diff --git a/test/e2e/expectedfailures/output-artifact-not-optional.yaml b/test/e2e/expectedfailures/output-artifact-not-optional.yaml index d6fe97da86b6..cf401578c1b1 100644 --- a/test/e2e/expectedfailures/output-artifact-not-optional.yaml +++ b/test/e2e/expectedfailures/output-artifact-not-optional.yaml @@ -14,7 +14,7 @@ spec: - name: whalesay container: - image: docker/whalesay:latest + image: cowsay:v1 command: [sh, -c] args: ["cowsay hello world | tee /tmp/hello_world12.txt"] outputs: diff --git a/test/e2e/expectedfailures/pod-termination-failure.yaml b/test/e2e/expectedfailures/pod-termination-failure.yaml index b5c73618d6dd..d5d4040384c5 100644 --- a/test/e2e/expectedfailures/pod-termination-failure.yaml +++ b/test/e2e/expectedfailures/pod-termination-failure.yaml @@ -39,7 +39,7 @@ spec: args: ["echo sleeping for {{inputs.parameters.seconds}} seconds; sleep {{inputs.parameters.seconds}}; echo done"] - name: check-status script: - image: bitnami/kubectl + image: bitnami/kubectl:1.15.3-ol-7-r165 command: [bash] source: | host=`hostname`; @@ -57,7 +57,7 @@ spec: parameters: - name: pod container: - image: bitnami/kubectl + image: bitnami/kubectl:1.15.3-ol-7-r165 command: [bash, -c] args: ["kubectl delete po {{inputs.parameters.pod}}"] diff --git a/test/e2e/expectedfailures/volumes-pvc-fail-event.yaml b/test/e2e/expectedfailures/volumes-pvc-fail-event.yaml new file mode 100644 index 000000000000..69ad6c6fb772 --- /dev/null +++ b/test/e2e/expectedfailures/volumes-pvc-fail-event.yaml @@ -0,0 +1,42 @@ +# This example demonstrates that argo emits +# a WorkflowFailed event in case of pvc creation failure +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: volumes-pvc-fail-event- +spec: + entrypoint: volumes-pvc-example + volumeClaimTemplates: + - metadata: + name: workdir + spec: + accessModes: [ "InvalidAccessMode" ] + resources: + requests: + storage: 1Gi + + templates: + - name: volumes-pvc-example + steps: + - - name: generate + template: whalesay + - - name: print + template: print-message + + - name: whalesay + container: + image: cowsay:v1 + command: [sh, -c] + args: ["echo generating message in volume; cowsay hello world | tee /mnt/vol/hello_world.txt"] + volumeMounts: + - name: workdir + mountPath: /mnt/vol + + - name: print-message + container: + image: alpine:latest + command: [sh, -c] + args: ["echo getting message from volume; find /mnt/vol; cat /mnt/vol/hello_world.txt"] + volumeMounts: + - name: workdir + mountPath: /mnt/vol diff --git a/test/e2e/fixtures/e2e_suite.go b/test/e2e/fixtures/e2e_suite.go index 538ec4832db7..4ab6cfe180c4 100644 --- a/test/e2e/fixtures/e2e_suite.go +++ b/test/e2e/fixtures/e2e_suite.go @@ -3,8 +3,7 @@ package fixtures import ( "bufio" "fmt" - "os" - "path/filepath" + "strings" "testing" "time" @@ -16,55 +15,45 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "sigs.k8s.io/yaml" - "upper.io/db.v3/postgresql" "github.com/argoproj/argo/cmd/argo/commands" - "github.com/argoproj/argo/persist/sqldb" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo/pkg/client/clientset/versioned" "github.com/argoproj/argo/pkg/client/clientset/versioned/typed/workflow/v1alpha1" "github.com/argoproj/argo/util/kubeconfig" - "github.com/argoproj/argo/workflow/config" "github.com/argoproj/argo/workflow/packer" ) -var kubeConfig = os.Getenv("KUBECONFIG") - const Namespace = "argo" const label = "argo-e2e" func init() { - if kubeConfig == "" { - kubeConfig = filepath.Join(os.Getenv("HOME"), ".kube", "config") - } _ = commands.NewCommand() } type E2ESuite struct { suite.Suite - Diagnostics *Diagnostics - RestConfig *rest.Config - wfClient v1alpha1.WorkflowInterface - wfTemplateClient v1alpha1.WorkflowTemplateInterface - cronClient v1alpha1.CronWorkflowInterface - offloadNodeStatusRepo sqldb.OffloadNodeStatusRepo - KubeClient kubernetes.Interface + Env + Diagnostics *Diagnostics + Persistence *Persistence + RestConfig *rest.Config + wfClient v1alpha1.WorkflowInterface + wfTemplateClient v1alpha1.WorkflowTemplateInterface + cronClient v1alpha1.CronWorkflowInterface + KubeClient kubernetes.Interface } func (s *E2ESuite) SetupSuite() { - _, err := os.Stat(kubeConfig) - if os.IsNotExist(err) { - s.T().Skip("Skipping test: " + err.Error()) - } -} - -func (s *E2ESuite) BeforeTest(_, _ string) { - s.Diagnostics = &Diagnostics{} var err error s.RestConfig, err = kubeconfig.DefaultRestConfig() if err != nil { panic(err) } + token, err := s.GetServiceAccountToken() + if err != nil { + panic(err) + } + s.SetEnv(token) s.KubeClient, err = kubernetes.NewForConfig(s.RestConfig) if err != nil { panic(err) @@ -73,32 +62,36 @@ func (s *E2ESuite) BeforeTest(_, _ string) { s.wfClient = versioned.NewForConfigOrDie(s.RestConfig).ArgoprojV1alpha1().Workflows(Namespace) s.wfTemplateClient = versioned.NewForConfigOrDie(s.RestConfig).ArgoprojV1alpha1().WorkflowTemplates(Namespace) s.cronClient = versioned.NewForConfigOrDie(s.RestConfig).ArgoprojV1alpha1().CronWorkflows(Namespace) - { - cm, err := s.KubeClient.CoreV1().ConfigMaps(Namespace).Get("workflow-controller-configmap", metav1.GetOptions{}) - if err != nil { - panic(err) - } - wcConfig := &config.WorkflowControllerConfig{} - err = yaml.Unmarshal([]byte(cm.Data["config"]), wcConfig) - if err != nil { - panic(err) - } - wcConfig.Persistence.PostgreSQL.Host = "localhost" - // we assume that this is enabled for tests - session, tableName, err := sqldb.CreateDBSession(s.KubeClient, Namespace, wcConfig.Persistence) + s.Persistence = newPersistence(s.KubeClient) +} + +func (s *E2ESuite) TearDownSuite() { + s.Persistence.Close() + s.UnsetEnv() +} + +func (s *E2ESuite) BeforeTest(_, _ string) { + s.Diagnostics = &Diagnostics{} + + // delete all cron workflows + cronList, err := s.cronClient.List(metav1.ListOptions{LabelSelector: label}) + if err != nil { + panic(err) + } + for _, cronWf := range cronList.Items { + log.WithFields(log.Fields{"cronWorkflow": cronWf.Name}).Info("Deleting cron workflow") + err = s.cronClient.Delete(cronWf.Name, nil) if err != nil { panic(err) } - s.offloadNodeStatusRepo = sqldb.NewOffloadNodeStatusRepo(tableName, session) } - // delete all workflows list, err := s.wfClient.List(metav1.ListOptions{LabelSelector: label}) if err != nil { panic(err) } for _, wf := range list.Items { - logCtx := log.WithFields(log.Fields{"test": s.T().Name(), "workflow": wf.Name}) + logCtx := log.WithFields(log.Fields{"workflow": wf.Name}) logCtx.Infof("Deleting workflow") err = s.wfClient.Delete(wf.Name, &metav1.DeleteOptions{}) if err != nil { @@ -131,47 +124,38 @@ func (s *E2ESuite) BeforeTest(_, _ string) { time.Sleep(3 * time.Second) } } - // delete all cron workflows - cronList, err := s.cronClient.List(metav1.ListOptions{LabelSelector: label}) - if err != nil { - panic(err) - } - for _, cronWf := range cronList.Items { - logCtx := log.WithFields(log.Fields{"test": s.T().Name(), "cron workflow": cronWf.Name}) - logCtx.Infof("Deleting cron workflow") - err = s.cronClient.Delete(cronWf.Name, nil) - if err != nil { - panic(err) - } - } // delete all workflow templates wfTmpl, err := s.wfTemplateClient.List(metav1.ListOptions{LabelSelector: label}) if err != nil { panic(err) } for _, wfTmpl := range wfTmpl.Items { - logCtx := log.WithFields(log.Fields{"test": s.T().Name(), "workflow template": wfTmpl.Name}) - logCtx.Infof("Deleting workflow template") + log.WithField("template", wfTmpl.Name).Info("Deleting workflow template") err = s.wfTemplateClient.Delete(wfTmpl.Name, nil) if err != nil { panic(err) } } // create database collection - db, err := postgresql.Open(postgresql.ConnectionURL{User: "postgres", Password: "password", Host: "localhost"}) + s.Persistence.DeleteEverything() +} + +func (s *E2ESuite) GetServiceAccountToken() (string, error) { + // create the clientset + clientset, err := kubernetes.NewForConfig(s.RestConfig) if err != nil { - panic(err) + return "", err } - // delete everything offloaded - _, err = db.DeleteFrom("argo_workflows").Exec() + secretList, err := clientset.CoreV1().Secrets("argo").List(metav1.ListOptions{}) if err != nil { - panic(err) + return "", err } - _, err = db.DeleteFrom("argo_archived_workflows").Exec() - if err != nil { - panic(err) + for _, sec := range secretList.Items { + if strings.HasPrefix(sec.Name, "argo-server-token") { + return string(sec.Data["token"]), nil + } } - _ = db.Close() + return "", nil } func (s *E2ESuite) Run(name string, f func(t *testing.T)) { @@ -190,7 +174,7 @@ func (s *E2ESuite) AfterTest(_, _ string) { func (s *E2ESuite) printDiagnostics() { s.Diagnostics.Print() - wfs, err := s.wfClient.List(metav1.ListOptions{FieldSelector: "metadata.namespace=" + Namespace}) + wfs, err := s.wfClient.List(metav1.ListOptions{FieldSelector: "metadata.namespace=" + Namespace, LabelSelector: label}) if err != nil { s.T().Fatal(err) } @@ -274,6 +258,7 @@ func (s *E2ESuite) Given() *Given { client: s.wfClient, wfTemplateClient: s.wfTemplateClient, cronClient: s.cronClient, - offloadNodeStatusRepo: s.offloadNodeStatusRepo, + offloadNodeStatusRepo: s.Persistence.offloadNodeStatusRepo, + kubeClient: s.KubeClient, } } diff --git a/test/e2e/fixtures/env.go b/test/e2e/fixtures/env.go new file mode 100644 index 000000000000..feb2bde538c7 --- /dev/null +++ b/test/e2e/fixtures/env.go @@ -0,0 +1,15 @@ +package fixtures + +import "os" + +type Env struct { +} + +func (s *Env) SetEnv(token string) { + _ = os.Setenv("ARGO_SERVER", "localhost:2746") + _ = os.Setenv("ARGO_TOKEN", token) +} +func (s *Env) UnsetEnv() { + _ = os.Unsetenv("ARGO_SERVER") + _ = os.Unsetenv("ARGO_TOKEN") +} diff --git a/test/e2e/fixtures/given.go b/test/e2e/fixtures/given.go index 0ab8acc2a6bb..cff4a816b644 100644 --- a/test/e2e/fixtures/given.go +++ b/test/e2e/fixtures/given.go @@ -5,6 +5,7 @@ import ( "strings" "testing" + "k8s.io/client-go/kubernetes" "sigs.k8s.io/yaml" "github.com/argoproj/argo/persist/sqldb" @@ -22,6 +23,8 @@ type Given struct { wf *wfv1.Workflow wfTemplates []*wfv1.WorkflowTemplate cronWf *wfv1.CronWorkflow + workflowName string + kubeClient kubernetes.Interface } // creates a workflow based on the parameter, this may be: @@ -59,6 +62,17 @@ func (g *Given) Workflow(text string) *Given { g.t.Fatal(err) } } + if g.wf.GetLabels() == nil { + g.wf.SetLabels(map[string]string{}) + } + if g.wf.GetLabels()[label] == "" { + g.wf.GetLabels()[label] = "true" + } + return g +} + +func (g *Given) WorkflowName(name string) *Given { + g.workflowName = name return g } @@ -95,7 +109,9 @@ func (g *Given) WorkflowTemplate(text string) *Given { if wfTemplate.GetLabels() == nil { wfTemplate.SetLabels(map[string]string{}) } - wfTemplate.GetLabels()[label] = "true" + if wfTemplate.GetLabels()[label] == "" { + wfTemplate.GetLabels()[label] = "true" + } g.wfTemplates = append(g.wfTemplates, wfTemplate) } return g @@ -134,7 +150,9 @@ func (g *Given) CronWorkflow(text string) *Given { if g.cronWf.GetLabels() == nil { g.cronWf.SetLabels(map[string]string{}) } - g.cronWf.GetLabels()[label] = "true" + if g.cronWf.GetLabels()[label] == "" { + g.cronWf.GetLabels()[label] = "true" + } } return g } @@ -156,5 +174,7 @@ func (g *Given) When() *When { wfTemplateClient: g.wfTemplateClient, cronClient: g.cronClient, offloadNodeStatusRepo: g.offloadNodeStatusRepo, + workflowName: g.workflowName, + kubeClient: g.kubeClient, } } diff --git a/test/e2e/fixtures/persistence.go b/test/e2e/fixtures/persistence.go new file mode 100644 index 000000000000..e14c3dc7d4bb --- /dev/null +++ b/test/e2e/fixtures/persistence.go @@ -0,0 +1,71 @@ +package fixtures + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/yaml" + "upper.io/db.v3/lib/sqlbuilder" + + "github.com/argoproj/argo/persist/sqldb" + "github.com/argoproj/argo/workflow/config" +) + +type Persistence struct { + session sqlbuilder.Database + offloadNodeStatusRepo sqldb.OffloadNodeStatusRepo +} + +func newPersistence(kubeClient kubernetes.Interface) *Persistence { + cm, err := kubeClient.CoreV1().ConfigMaps(Namespace).Get("workflow-controller-configmap", metav1.GetOptions{}) + if err != nil { + panic(err) + } + wcConfig := &config.WorkflowControllerConfig{} + err = yaml.Unmarshal([]byte(cm.Data["config"]), wcConfig) + if err != nil { + panic(err) + } + persistence := wcConfig.Persistence + if persistence != nil { + if persistence.PostgreSQL != nil { + persistence.PostgreSQL.Host = "localhost" + } + if persistence.MySQL != nil { + persistence.MySQL.Host = "localhost" + } + session, tableName, err := sqldb.CreateDBSession(kubeClient, Namespace, persistence) + if err != nil { + panic(err) + } + offloadNodeStatusRepo := sqldb.NewOffloadNodeStatusRepo(session, persistence.GetClusterName(), tableName) + return &Persistence{session, offloadNodeStatusRepo} + } else { + return &Persistence{offloadNodeStatusRepo: sqldb.ExplosiveOffloadNodeStatusRepo} + } +} + +func (s *Persistence) IsEnabled() bool { + return s.offloadNodeStatusRepo.IsEnabled() +} + +func (s *Persistence) Close() { + if s.IsEnabled() { + err := s.session.Close() + if err != nil { + panic(err) + } + } +} + +func (s *Persistence) DeleteEverything() { + if s.IsEnabled() { + _, err := s.session.DeleteFrom("argo_workflows").Exec() + if err != nil { + panic(err) + } + _, err = s.session.DeleteFrom("argo_archived_workflows").Exec() + if err != nil { + panic(err) + } + } +} diff --git a/test/e2e/fixtures/then.go b/test/e2e/fixtures/then.go index c11c9445b1b5..5ec268488eb5 100644 --- a/test/e2e/fixtures/then.go +++ b/test/e2e/fixtures/then.go @@ -4,7 +4,9 @@ import ( "testing" log "github.com/sirupsen/logrus" + apiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" "github.com/argoproj/argo/persist/sqldb" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" @@ -20,13 +22,18 @@ type Then struct { client v1alpha1.WorkflowInterface cronClient v1alpha1.CronWorkflowInterface offloadNodeStatusRepo sqldb.OffloadNodeStatusRepo + kubeClient kubernetes.Interface } func (t *Then) ExpectWorkflow(block func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus)) *Then { - return t.ExpectWorkflowFromName(t.workflowName, block) + return t.expectWorkflow(t.workflowName, block) } -func (t *Then) ExpectWorkflowFromName(workflowName string, block func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus)) *Then { +func (t *Then) ExpectWorkflowName(workflowName string, block func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus)) *Then { + return t.expectWorkflow(workflowName, block) +} + +func (t *Then) expectWorkflow(workflowName string, block func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus)) *Then { if workflowName == "" { t.t.Fatal("No workflow to test") } @@ -35,12 +42,12 @@ func (t *Then) ExpectWorkflowFromName(workflowName string, block func(t *testing if err != nil { t.t.Fatal(err) } - if wf.Status.OffloadNodeStatus { - offloaded, err := t.offloadNodeStatusRepo.Get(wf.Name, wf.Namespace) + if wf.Status.IsOffloadNodeStatus() { + offloadedNodes, err := t.offloadNodeStatusRepo.Get(string(wf.UID), wf.GetOffloadNodeStatusVersion()) if err != nil { t.t.Fatal(err) } - wf.Status.Nodes = offloaded.Status.Nodes + wf.Status.Nodes = offloadedNodes } block(t.t, &wf.ObjectMeta, &wf.Status) return t @@ -51,7 +58,7 @@ func (t *Then) ExpectCron(block func(t *testing.T, cronWf *wfv1.CronWorkflow)) * if t.cronWorkflowName == "" { t.t.Fatal("No cron workflow to test") } - log.WithFields(log.Fields{"test": t.t.Name(), "cron workflow": t.cronWorkflowName}).Info("Checking expectation") + log.WithFields(log.Fields{"cronWorkflow": t.cronWorkflowName}).Info("Checking cron expectation") cronWf, err := t.cronClient.Get(t.cronWorkflowName, metav1.GetOptions{}) if err != nil { t.t.Fatal(err) @@ -61,17 +68,33 @@ func (t *Then) ExpectCron(block func(t *testing.T, cronWf *wfv1.CronWorkflow)) * } func (t *Then) ExpectWorkflowList(listOptions metav1.ListOptions, block func(t *testing.T, wfList *wfv1.WorkflowList)) *Then { - log.WithFields(log.Fields{"test": t.t.Name()}).Info("Getting relevant workflows") + log.Info("Listing workflows") wfList, err := t.client.List(listOptions) if err != nil { t.t.Fatal(err) } - log.WithFields(log.Fields{"test": t.t.Name()}).Info("Got relevant workflows") - log.WithFields(log.Fields{"test": t.t.Name()}).Info("Checking expectation") + log.Info("Checking expectation") block(t.t, wfList) return t } +func (t *Then) ExpectAuditEvents(block func(*testing.T, *apiv1.EventList)) *Then { + if t.workflowName == "" { + t.t.Fatal("No workflow to test") + } + log.WithFields(log.Fields{"workflow": t.workflowName}).Info("Checking expectation") + wf, err := t.client.Get(t.workflowName, metav1.GetOptions{}) + if err != nil { + t.t.Fatal(err) + } + eventList, err := t.kubeClient.CoreV1().Events(wf.ObjectMeta.Namespace).List(metav1.ListOptions{}) + if err != nil { + t.t.Fatal(err) + } + block(t.t, eventList) + return t +} + func (t *Then) RunCli(args []string, block func(t *testing.T, output string, err error)) *Then { output, err := runCli(t.diagnostics, args) block(t.t, output, err) diff --git a/test/e2e/fixtures/util.go b/test/e2e/fixtures/util.go index 7ef0a0cc48d1..e2128f014558 100644 --- a/test/e2e/fixtures/util.go +++ b/test/e2e/fixtures/util.go @@ -1,15 +1,45 @@ package fixtures import ( + "io/ioutil" + "os" "os/exec" + "strings" log "github.com/sirupsen/logrus" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" ) func runCli(diagnostics *Diagnostics, args []string) (string, error) { runArgs := append([]string{"-n", Namespace}, args...) + cmd := exec.Command("../../dist/argo", runArgs...) + cmd.Env = os.Environ() output, err := exec.Command("../../dist/argo", runArgs...).CombinedOutput() stringOutput := string(output) diagnostics.Log(log.Fields{"args": args, "output": stringOutput, "err": err}, "Run CLI") return stringOutput, err } + +// LoadObject is used to load yaml to runtime.Object +func LoadObject(text string) (runtime.Object, error) { + var yaml string + if strings.HasPrefix(text, "@") { + file := strings.TrimPrefix(text, "@") + f, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + yaml = string(f) + } else { + yaml = text + } + + decode := scheme.Codecs.UniversalDeserializer().Decode + obj, _, err := decode([]byte(yaml), nil, nil) + if err != nil { + return nil, err + } + return obj, nil +} diff --git a/test/e2e/fixtures/when.go b/test/e2e/fixtures/when.go index 1c5383e76a5a..4a489aaab41b 100644 --- a/test/e2e/fixtures/when.go +++ b/test/e2e/fixtures/when.go @@ -6,6 +6,7 @@ import ( "time" "github.com/argoproj/pkg/humanize" + "k8s.io/client-go/kubernetes" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -14,6 +15,7 @@ import ( "github.com/argoproj/argo/persist/sqldb" wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo/pkg/client/clientset/versioned/typed/workflow/v1alpha1" + "github.com/argoproj/argo/workflow/packer" ) type When struct { @@ -29,20 +31,21 @@ type When struct { workflowName string wfTemplateNames []string cronWorkflowName string + kubeClient kubernetes.Interface } func (w *When) SubmitWorkflow() *When { if w.wf == nil { w.t.Fatal("No workflow to submit") } - log.WithField("test", w.t.Name()).Info("Submitting workflow") + log.WithFields(log.Fields{"workflow": w.wf.Name}).Info("Submitting workflow") wf, err := w.client.Create(w.wf) if err != nil { w.t.Fatal(err) } else { w.workflowName = wf.Name } - log.WithField("test", w.t.Name()).Info("Workflow submitted") + log.WithFields(log.Fields{"workflow": wf.Name, "uid": wf.UID}).Info("Workflow submitted") return w } @@ -51,14 +54,14 @@ func (w *When) CreateWorkflowTemplates() *When { w.t.Fatal("No workflow templates to create") } for _, wfTmpl := range w.wfTemplates { - log.WithField("test", w.t.Name()).Infof("Creating workflow template %s", wfTmpl.Name) + log.WithField("template", wfTmpl.Name).Info("Creating workflow template") wfTmpl, err := w.wfTemplateClient.Create(wfTmpl) if err != nil { w.t.Fatal(err) } else { w.wfTemplateNames = append(w.wfTemplateNames, wfTmpl.Name) } - log.WithField("test", w.t.Name()).Infof("Workflow template created %s", wfTmpl.Name) + log.WithField("template", wfTmpl.Name).Info("Workflow template created") } return w } @@ -67,24 +70,21 @@ func (w *When) CreateCronWorkflow() *When { if w.cronWf == nil { w.t.Fatal("No cron workflow to create") } - log.WithField("test", w.t.Name()).Info("Creating cron workflow") + log.WithField("cronWorkflow", w.cronWf.Name).Info("Creating cron workflow") cronWf, err := w.cronClient.Create(w.cronWf) if err != nil { w.t.Fatal(err) } else { w.cronWorkflowName = cronWf.Name } - log.WithField("test", w.t.Name()).Info("Cron workflow created") + log.WithField("uid", cronWf.UID).Info("Cron workflow created") return w } -func (w *When) WaitForWorkflow(timeout time.Duration) *When { - return w.WaitForWorkflowFromName(w.workflowName, timeout) -} -func (w *When) WaitForWorkflowFromName(workflowName string, timeout time.Duration) *When { - logCtx := log.WithFields(log.Fields{"test": w.t.Name(), "workflow": workflowName}) - logCtx.Info("Waiting on workflow") +func (w *When) waitForWorkflow(workflowName string, test func(wf *wfv1.Workflow) bool, condition string, timeout time.Duration) *When { + logCtx := log.WithFields(log.Fields{"workflow": workflowName, "condition": condition, "timeout": timeout}) + logCtx.Info("Waiting for condition") opts := metav1.ListOptions{FieldSelector: fields.ParseSelectorOrDie(fmt.Sprintf("metadata.name=%s", workflowName)).String()} watch, err := w.client.Watch(opts) if err != nil { @@ -101,20 +101,56 @@ func (w *When) WaitForWorkflowFromName(workflowName string, timeout time.Duratio case event := <-watch.ResultChan(): wf, ok := event.Object.(*wfv1.Workflow) if ok { - if !wf.Status.FinishedAt.IsZero() { + logCtx.WithFields(log.Fields{"type": event.Type, "phase": wf.Status.Phase}).Info(wf.Status.Message) + w.hydrateWorkflow(wf) + if test(wf) { + logCtx.Infof("Condition met") return w } } else { - logCtx.WithField("event", event).Warn("Did not get workflow event") + logCtx.Error("not ok") } case <-timeoutCh: - w.t.Fatalf("timeout after %v waiting for finish", timeout) + w.t.Fatalf("timeout after %v waiting for condition %s", timeout, condition) } } } +func (w *When) hydrateWorkflow(wf *wfv1.Workflow) { + err := packer.DecompressWorkflow(wf) + if err != nil { + w.t.Fatal(err) + } + if wf.Status.IsOffloadNodeStatus() && w.offloadNodeStatusRepo.IsEnabled() { + offloadedNodes, err := w.offloadNodeStatusRepo.Get(string(wf.UID), wf.GetOffloadNodeStatusVersion()) + if err != nil { + w.t.Fatal(err) + } + wf.Status.Nodes = offloadedNodes + } +} +func (w *When) WaitForWorkflowToStart(timeout time.Duration) *When { + return w.waitForWorkflow(w.workflowName, func(wf *wfv1.Workflow) bool { + return !wf.Status.StartedAt.IsZero() + }, "to start", timeout) +} + +func (w *When) WaitForWorkflow(timeout time.Duration) *When { + return w.waitForWorkflow(w.workflowName, func(wf *wfv1.Workflow) bool { + return !wf.Status.FinishedAt.IsZero() + }, "to finish", timeout) +} + +func (w *When) WaitForWorkflowName(workflowName string, timeout time.Duration) *When { + return w.waitForWorkflow(workflowName, func(wf *wfv1.Workflow) bool { + return !wf.Status.FinishedAt.IsZero() + }, "to finish", timeout) +} + + + func (w *When) Wait(timeout time.Duration) *When { - logCtx := log.WithFields(log.Fields{"test": w.t.Name(), "cron workflow": w.cronWorkflowName}) + logCtx := log.WithFields(log.Fields{"cronWorkflow": w.cronWorkflowName}) logCtx.Infof("Waiting for %s", humanize.Duration(timeout)) time.Sleep(timeout) logCtx.Infof("Done waiting") @@ -122,7 +158,7 @@ func (w *When) Wait(timeout time.Duration) *When { } func (w *When) DeleteWorkflow() *When { - log.WithField("test", w.t.Name()).WithField("workflow", w.workflowName).Info("Deleting") + log.WithField("workflow", w.workflowName).Info("Deleting") err := w.client.Delete(w.workflowName, nil) if err != nil { w.t.Fatal(err) @@ -146,5 +182,6 @@ func (w *When) Then() *Then { client: w.client, cronClient: w.cronClient, offloadNodeStatusRepo: w.offloadNodeStatusRepo, + kubeClient: w.kubeClient, } } diff --git a/test/e2e/functional/artifact-input-output-samedir.yaml b/test/e2e/functional/artifact-input-output-samedir.yaml index 292dd59fd494..ea342c9587b7 100644 --- a/test/e2e/functional/artifact-input-output-samedir.yaml +++ b/test/e2e/functional/artifact-input-output-samedir.yaml @@ -34,7 +34,7 @@ spec: # generate a folder structure with directories - name: generate script: - image: docker/whalesay:latest + image: cowsay:v1 command: [sh, -xe] source: | sleep 1 @@ -61,7 +61,7 @@ spec: - name: hello path: /hello.txt container: - image: docker/whalesay:latest + image: cowsay:v1 command: [sh, -c] args: [" sleep 1 && diff --git a/test/e2e/functional/continue-on-failed.yaml b/test/e2e/functional/continue-on-failed.yaml index 212f7495b17f..7eeb7fc0a77f 100644 --- a/test/e2e/functional/continue-on-failed.yaml +++ b/test/e2e/functional/continue-on-failed.yaml @@ -28,9 +28,9 @@ spec: - name: whalesay container: - image: docker/whalesay:latest + image: cowsay:v1 - name: whalesplosion container: - image: docker/whalesay:latest + image: cowsay:v1 command: ["sh", "-c", "sleep 5 ; exit 1"] diff --git a/test/e2e/functional/custom_template_variable.yaml b/test/e2e/functional/custom_template_variable.yaml index f9ee8fca8df2..a4244b575d6c 100644 --- a/test/e2e/functional/custom_template_variable.yaml +++ b/test/e2e/functional/custom_template_variable.yaml @@ -27,6 +27,6 @@ spec: parameters: - name: message container: - image: docker/whalesay + image: cowsay:v1 command: [cowsay] args: ["{{custom.variable}}"] diff --git a/test/e2e/functional/global-parameters-complex.yaml b/test/e2e/functional/global-parameters-complex.yaml index 545ba400efc3..284ac87c70d4 100644 --- a/test/e2e/functional/global-parameters-complex.yaml +++ b/test/e2e/functional/global-parameters-complex.yaml @@ -44,6 +44,6 @@ spec: - name: message3 - name: message4 container: - image: docker/whalesay:latest + image: cowsay:v1 command: [cowsay] args: ["Global 1: {{workflow.parameters.message1}} Input 1: {{inputs.parameters.message1}} Input 2/Steps Input 1/Global 1: {{inputs.parameters.message2}} Input 3/Global 2: {{inputs.parameters.message3}} Input4/Steps Input 2 internal/Global 1: {{inputs.parameters.message4}}"] diff --git a/test/e2e/functional/hello-world.json b/test/e2e/functional/hello-world.json index ca252e4d1588..09e391ba0f48 100644 --- a/test/e2e/functional/hello-world.json +++ b/test/e2e/functional/hello-world.json @@ -10,7 +10,7 @@ { "name": "whalesay", "container": { - "image": "docker/whalesay:latest", + "image": "cowsay:v1", "command": [ "cowsay" ], diff --git a/test/e2e/functional/nested-dag-outputs.yaml b/test/e2e/functional/nested-dag-outputs.yaml index 8cc92c5003da..c15c30656418 100644 --- a/test/e2e/functional/nested-dag-outputs.yaml +++ b/test/e2e/functional/nested-dag-outputs.yaml @@ -35,7 +35,7 @@ spec: # container template which generates an output parameter and artifact - name: generate container: - image: docker/whalesay:latest + image: cowsay:v1 command: [sh, -c] args: [" sleep 1; diff --git a/test/e2e/functional/output-artifact-optional.yaml b/test/e2e/functional/output-artifact-optional.yaml index 803289d6ca85..ab1bb4f77850 100644 --- a/test/e2e/functional/output-artifact-optional.yaml +++ b/test/e2e/functional/output-artifact-optional.yaml @@ -14,7 +14,7 @@ spec: - name: whalesay container: - image: docker/whalesay:latest + image: cowsay:v1 command: [sh, -c] args: ["sleep 1; cowsay hello world | tee /tmp/hello_world12.txt"] outputs: diff --git a/test/e2e/functional/output-input-artifact-optional.yaml b/test/e2e/functional/output-input-artifact-optional.yaml index f1519df74d4e..4e16f5936165 100644 --- a/test/e2e/functional/output-input-artifact-optional.yaml +++ b/test/e2e/functional/output-input-artifact-optional.yaml @@ -19,7 +19,7 @@ spec: from: "{{steps.generate-artifact.outputs.artifacts.hello-art}}" - name: whalesay container: - image: docker/whalesay:latest + image: cowsay:v1 command: [sh, -c] args: ["sleep 1; cowsay hello world | tee /tmp/hello_world123.txt"] outputs: diff --git a/test/e2e/functional/output-param-different-uid.yaml b/test/e2e/functional/output-param-different-uid.yaml index dbb7942fc945..82ec88cfe41e 100644 --- a/test/e2e/functional/output-param-different-uid.yaml +++ b/test/e2e/functional/output-param-different-uid.yaml @@ -15,7 +15,7 @@ spec: - name: whalesay container: - image: docker/whalesay:latest + image: cowsay:v1 command: [sh, -c] args: ["sleep 1; cowsay hello world | tee /tmp/hello_world.txt"] securityContext: diff --git a/test/e2e/functional/pns-output-params.yaml b/test/e2e/functional/pns-output-params.yaml index fe0001d38322..ff2410a81436 100644 --- a/test/e2e/functional/pns-output-params.yaml +++ b/test/e2e/functional/pns-output-params.yaml @@ -23,7 +23,7 @@ spec: - name: whalesay container: - image: docker/whalesay:latest + image: cowsay:v1 command: [sh, -x, -c] args: [" sleep 1; @@ -60,7 +60,7 @@ spec: - name: C - name: D container: - image: docker/whalesay:latest + image: cowsay:v1 command: [cowsay] args: ["{{inputs.parameters.A}} {{inputs.parameters.B}} {{inputs.parameters.C}} {{inputs.parameters.D}}"] diff --git a/test/e2e/functional/retry-with-artifacts.yaml b/test/e2e/functional/retry-with-artifacts.yaml index 4a509d568504..ad22e89cf045 100644 --- a/test/e2e/functional/retry-with-artifacts.yaml +++ b/test/e2e/functional/retry-with-artifacts.yaml @@ -21,7 +21,7 @@ spec: retryStrategy: limit: 4 container: - image: docker/whalesay:latest + image: cowsay:v1 command: [sh, -c] args: ["sleep 1; cowsay hello world | tee /tmp/hello_world.txt"] outputs: diff --git a/test/e2e/functional/success-event.yaml b/test/e2e/functional/success-event.yaml new file mode 100644 index 000000000000..d63dd4406534 --- /dev/null +++ b/test/e2e/functional/success-event.yaml @@ -0,0 +1,13 @@ +# e2e test to ensure the controller publishes +# an audit event marking the success +# in case of workflow success +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: success-event- +spec: + entrypoint: exit + templates: + - name: exit + container: + image: cowsay:v1 diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index 46fda4e54275..2e2b89b1b269 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -1,6 +1,7 @@ package e2e import ( + "strings" "testing" "time" @@ -10,6 +11,9 @@ import ( wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo/test/e2e/fixtures" + "github.com/argoproj/argo/util/argo" + + apiv1 "k8s.io/api/core/v1" ) type FunctionalSuite struct { @@ -49,12 +53,12 @@ spec: - name: whalesay container: - image: docker/whalesay:latest + image: cowsay:v1 imagePullPolicy: IfNotPresent - name: whalesplosion container: - image: docker/whalesay:latest + image: cowsay:v1 imagePullPolicy: IfNotPresent command: ["sh", "-c", "sleep 5 ; exit 1"] `). @@ -93,6 +97,72 @@ func (s *FunctionalSuite) TestFastFailOnPodTermination() { }) } +func (s *FunctionalSuite) TestEventOnNodeFail() { + // Test whether an WorkflowFailed event (with appropriate message) is emitted in case of node failure + s.Given(). + Workflow("@expectedfailures/failed-step-event.yaml"). + When(). + SubmitWorkflow(). + WaitForWorkflow(30 * time.Second). + Then(). + ExpectAuditEvents(func(t *testing.T, events *apiv1.EventList) { + found := false + for _, e := range events.Items { + isAboutFailedStep := strings.HasPrefix(e.InvolvedObject.Name, "failed-step-event-") + isFailureEvent := e.Reason == argo.EventReasonWorkflowFailed + if isAboutFailedStep && isFailureEvent { + found = true + assert.Equal(t, "failed with exit code 1", e.Message) + } + } + assert.True(t, found, "event not found") + }) +} + +func (s *FunctionalSuite) TestEventOnWorkflowSuccess() { + // Test whether an WorkflowSuccess event is emitted in case of successfully completed workflow + s.Given(). + Workflow("@functional/success-event.yaml"). + When(). + SubmitWorkflow(). + WaitForWorkflow(60 * time.Second). + Then(). + ExpectAuditEvents(func(t *testing.T, events *apiv1.EventList) { + found := false + for _, e := range events.Items { + isAboutSuccess := strings.HasPrefix(e.InvolvedObject.Name, "success-event-") + isSuccessEvent := e.Reason == argo.EventReasonWorkflowSucceded + if isAboutSuccess && isSuccessEvent { + found = true + assert.Equal(t, "Workflow completed", e.Message) + } + } + assert.True(t, found, "event not found") + }) +} + +func (s *FunctionalSuite) TestEventOnPVCFail() { + // Test whether an WorkflowFailed event (with appropriate message) is emitted in case of error in creating the PVC + s.Given(). + Workflow("@expectedfailures/volumes-pvc-fail-event.yaml"). + When(). + SubmitWorkflow(). + WaitForWorkflow(120 * time.Second). + Then(). + ExpectAuditEvents(func(t *testing.T, events *apiv1.EventList) { + found := false + for _, e := range events.Items { + isAboutSuccess := strings.HasPrefix(e.InvolvedObject.Name, "volumes-pvc-fail-event-") + isFailureEvent := e.Reason == argo.EventReasonWorkflowFailed + if isAboutSuccess && isFailureEvent { + found = true + assert.True(t, strings.Contains(e.Message, "pvc create error"), "event should contain \"pvc create error\"") + } + } + assert.True(t, found, "event not found") + }) +} + func TestFunctionalSuite(t *testing.T) { suite.Run(t, new(FunctionalSuite)) } diff --git a/test/e2e/images/cowsay/Dockerfile b/test/e2e/images/cowsay/Dockerfile new file mode 100644 index 000000000000..39a7e3561a2a --- /dev/null +++ b/test/e2e/images/cowsay/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:14.04 + +RUN apt-get update && apt-get install -y cowsay --no-install-recommends && rm -rf /var/lib/apt/lists/* + +# "cowsay" installs to /usr/games +ENV PATH $PATH:/usr/games + +CMD ["cowsay"] \ No newline at end of file diff --git a/test/e2e/lintfail/disallow-unknown.yaml b/test/e2e/lintfail/disallow-unknown.yaml index 4d7c349cbf7c..7c5f2250d20a 100644 --- a/test/e2e/lintfail/disallow-unknown.yaml +++ b/test/e2e/lintfail/disallow-unknown.yaml @@ -7,7 +7,7 @@ spec: templates: - name: whalesay container: - image: docker/whalesay:latest + image: cowsay:v1 command: - cowsay args: diff --git a/test/e2e/lintfail/invalid-spec.yaml b/test/e2e/lintfail/invalid-spec.yaml index 5f6159cda7a5..b46b67dc1487 100644 --- a/test/e2e/lintfail/invalid-spec.yaml +++ b/test/e2e/lintfail/invalid-spec.yaml @@ -10,6 +10,6 @@ spec: templates: - name: whalesay container: - image: docker/whalesay:latest + image: cowsay:v1 command: [cowsay] args: ["hello world"] diff --git a/test/e2e/lintfail/malformed-spec.yaml b/test/e2e/lintfail/malformed-spec.yaml index b19afa576fa1..1cd7e02b4fc8 100644 --- a/test/e2e/lintfail/malformed-spec.yaml +++ b/test/e2e/lintfail/malformed-spec.yaml @@ -10,6 +10,6 @@ spec: templates: - name: whalesay container: - image: docker/whalesay:latest + image: cowsay:v1 command: [cowsay] args: ["hello world"] diff --git a/test/e2e/manifests/mysql.yaml b/test/e2e/manifests/mysql.yaml new file mode 100644 index 000000000000..b7906593b8bf --- /dev/null +++ b/test/e2e/manifests/mysql.yaml @@ -0,0 +1,518 @@ +# This is an auto-generated file. DO NOT EDIT +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cronworkflows.argoproj.io +spec: + group: argoproj.io + names: + kind: CronWorkflow + plural: cronworkflows + shortNames: + - cronwf + - cwf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflows.argoproj.io +spec: + additionalPrinterColumns: + - JSONPath: .status.phase + description: Status of the workflow + name: Status + type: string + - JSONPath: .status.startedAt + description: When the workflow was started + format: date-time + name: Age + type: date + group: argoproj.io + names: + kind: Workflow + plural: workflows + shortNames: + - wf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflowtemplates.argoproj.io +spec: + group: argoproj.io + names: + kind: WorkflowTemplate + plural: workflowtemplates + shortNames: + - wftmpl + scope: Namespaced + version: v1alpha1 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-role +rules: +- apiGroups: + - "" + resources: + - pods + - pods/exec + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - create + - delete +- apiGroups: + - argoproj.io + resources: + - workflows + - workflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete + - create +- apiGroups: + - argoproj.io + resources: + - workflowtemplates + - workflowtemplates/finalizers + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - get + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - cronworkflows + - cronworkflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-server-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - "" + resources: + - pods + - pods/exec + - pods/log + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - workflows + - workflowtemplates + - cronworkflows + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: workflow-role +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - watch + - patch +- apiGroups: + - "" + resources: + - pods/log + verbs: + - get + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-role +subjects: +- kind: ServiceAccount + name: argo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-server-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-server-role +subjects: +- kind: ServiceAccount + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: workflow-default-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: workflow-role +subjects: +- kind: ServiceAccount + name: default +--- +apiVersion: v1 +data: + config: | + artifactRepository: + archiveLogs: true + s3: + bucket: my-bucket + endpoint: minio:9000 + insecure: true + accessKeySecret: + name: my-minio-cred + key: accesskey + secretKeySecret: + name: my-minio-cred + key: secretkey + persistence: + connectionPool: + maxIdleConns: 100 + maxOpenConns: 0 + nodeStatusOffLoad: true + archive: true + mysql: + host: mysql + port: 3306 + database: argo + tableName: argo_workflows + userNameSecret: + name: argo-mysql-config + key: username + passwordSecret: + name: argo-mysql-config + key: password +kind: ConfigMap +metadata: + name: workflow-controller-configmap +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + app: mysql + name: argo-mysql-config +stringData: + password: password + username: mysql +type: Opaque +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + app: minio + name: my-minio-cred +stringData: + accesskey: admin + secretkey: password +type: Opaque +--- +apiVersion: v1 +kind: Service +metadata: + name: argo-server +spec: + ports: + - port: 2746 + targetPort: 2746 + selector: + app: argo-server +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: minio + name: minio +spec: + ports: + - port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: mysql + name: mysql +spec: + ports: + - port: 3306 + protocol: TCP + targetPort: 3306 + selector: + app: mysql +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: argo-server +spec: + selector: + matchLabels: + app: argo-server + template: + metadata: + labels: + app: argo-server + spec: + containers: + - args: + - server + - --namespaced + - --auth-mode + - client + - --loglevel + - debug + env: + - name: ARGO_TOKEN + value: password + - name: UPPERIO_DB_DEBUG + value: "1" + image: argoproj/argocli:latest + imagePullPolicy: Never + name: argo-server + ports: + - containerPort: 2746 + readinessProbe: + httpGet: + path: / + port: 2746 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 30 + serviceAccountName: argo-server +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: mysql + name: mysql +spec: + selector: + matchLabels: + app: mysql + template: + metadata: + labels: + app: mysql + name: mysql + spec: + containers: + - env: + - name: MYSQL_USER + value: mysql + - name: MYSQL_PASSWORD + value: password + - name: MYSQL_DATABASE + value: argo + - name: MYSQL_RANDOM_ROOT_PASSWORD + value: "yes" + image: mysql:8 + name: main + ports: + - containerPort: 5432 + readinessProbe: + exec: + command: + - mysql + - -u + - mysql + - -ppassword + - argo + - -e + - SELECT 1 + initialDelaySeconds: 15 + timeoutSeconds: 2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: workflow-controller +spec: + selector: + matchLabels: + app: workflow-controller + template: + metadata: + labels: + app: workflow-controller + spec: + containers: + - args: + - --configmap + - workflow-controller-configmap + - --executor-image + - argoproj/argoexec:latest + - --namespaced + - --loglevel + - debug + - --executor-image-pull-policy + - Never + - --container-runtime-executor + - pns + command: + - workflow-controller + env: + - name: ALWAYS_OFFLOAD_NODE_STATUS + value: "true" + - name: WORKFLOW_GC_PERIOD + value: 30s + - name: UPPERIO_DB_DEBUG + value: "1" + image: argoproj/workflow-controller:latest + imagePullPolicy: Never + name: workflow-controller + serviceAccountName: argo +--- +apiVersion: v1 +kind: Pod +metadata: + labels: + app: minio + name: minio +spec: + containers: + - command: + - minio + - server + - /data + env: + - name: MINIO_ACCESS_KEY + value: admin + - name: MINIO_SECRET_KEY + value: password + image: minio/minio:RELEASE.2019-12-17T23-16-33Z + lifecycle: + postStart: + exec: + command: + - mkdir + - -p + - /data/my-bucket + livenessProbe: + httpGet: + path: /minio/health/live + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 + name: main + ports: + - containerPort: 9000 + readinessProbe: + httpGet: + path: /minio/health/ready + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/test/e2e/manifests/mysql/kustomization.yaml b/test/e2e/manifests/mysql/kustomization.yaml new file mode 100644 index 000000000000..db8c9c84a454 --- /dev/null +++ b/test/e2e/manifests/mysql/kustomization.yaml @@ -0,0 +1,19 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +bases: + - ../../../../manifests/quick-start/mysql + +patchesJson6902: + - target: + version: v1 + group: apps + kind: Deployment + name: workflow-controller + path: overlays/workflow-controller-deployment.yaml + - target: + version: v1 + group: apps + kind: Deployment + name: argo-server + path: overlays/argo-server-deployment.yaml diff --git a/test/e2e/manifests/mysql/overlays/argo-server-deployment.yaml b/test/e2e/manifests/mysql/overlays/argo-server-deployment.yaml new file mode 100644 index 000000000000..26413d7ecd37 --- /dev/null +++ b/test/e2e/manifests/mysql/overlays/argo-server-deployment.yaml @@ -0,0 +1,23 @@ +# This is an auto-generated file. DO NOT EDIT +- op: replace + path: /spec/template/spec/containers/0/imagePullPolicy + value: Never +- op: add + path: /spec/template/spec/containers/0/args/- + value: --auth-mode +- op: add + path: /spec/template/spec/containers/0/args/- + value: client +- op: add + path: /spec/template/spec/containers/0/args/- + value: --loglevel +- op: add + path: /spec/template/spec/containers/0/args/- + value: debug +- op: add + path: /spec/template/spec/containers/0/env + value: + - name: ARGO_TOKEN + value: password + - name: UPPERIO_DB_DEBUG + value: "1" diff --git a/test/e2e/manifests/mysql/overlays/workflow-controller-deployment.yaml b/test/e2e/manifests/mysql/overlays/workflow-controller-deployment.yaml new file mode 100644 index 000000000000..2192bd96dbfa --- /dev/null +++ b/test/e2e/manifests/mysql/overlays/workflow-controller-deployment.yaml @@ -0,0 +1,31 @@ +# This is an auto-generated file. DO NOT EDIT +- op: replace + path: /spec/template/spec/containers/0/imagePullPolicy + value: Never +- op: add + path: /spec/template/spec/containers/0/args/- + value: --loglevel +- op: add + path: /spec/template/spec/containers/0/args/- + value: debug +- op: add + path: /spec/template/spec/containers/0/args/- + value: --executor-image-pull-policy +- op: add + path: /spec/template/spec/containers/0/args/- + value: Never +- op: add + path: /spec/template/spec/containers/0/args/- + value: --container-runtime-executor +- op: add + path: /spec/template/spec/containers/0/args/- + value: pns +- op: add + path: /spec/template/spec/containers/0/env + value: + - name: ALWAYS_OFFLOAD_NODE_STATUS + value: "true" + - name: WORKFLOW_GC_PERIOD + value: 30s + - name: UPPERIO_DB_DEBUG + value: "1" diff --git a/test/e2e/manifests/no-db.yaml b/test/e2e/manifests/no-db.yaml new file mode 100644 index 000000000000..a4d42ac86b20 --- /dev/null +++ b/test/e2e/manifests/no-db.yaml @@ -0,0 +1,433 @@ +# This is an auto-generated file. DO NOT EDIT +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cronworkflows.argoproj.io +spec: + group: argoproj.io + names: + kind: CronWorkflow + plural: cronworkflows + shortNames: + - cronwf + - cwf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflows.argoproj.io +spec: + additionalPrinterColumns: + - JSONPath: .status.phase + description: Status of the workflow + name: Status + type: string + - JSONPath: .status.startedAt + description: When the workflow was started + format: date-time + name: Age + type: date + group: argoproj.io + names: + kind: Workflow + plural: workflows + shortNames: + - wf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflowtemplates.argoproj.io +spec: + group: argoproj.io + names: + kind: WorkflowTemplate + plural: workflowtemplates + shortNames: + - wftmpl + scope: Namespaced + version: v1alpha1 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-role +rules: +- apiGroups: + - "" + resources: + - pods + - pods/exec + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - create + - delete +- apiGroups: + - argoproj.io + resources: + - workflows + - workflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete + - create +- apiGroups: + - argoproj.io + resources: + - workflowtemplates + - workflowtemplates/finalizers + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - get + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - cronworkflows + - cronworkflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-server-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - "" + resources: + - pods + - pods/exec + - pods/log + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - workflows + - workflowtemplates + - cronworkflows + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: workflow-role +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - watch + - patch +- apiGroups: + - "" + resources: + - pods/log + verbs: + - get + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-role +subjects: +- kind: ServiceAccount + name: argo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-server-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-server-role +subjects: +- kind: ServiceAccount + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: workflow-default-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: workflow-role +subjects: +- kind: ServiceAccount + name: default +--- +apiVersion: v1 +data: + config: | + artifactRepository: + archiveLogs: true + s3: + bucket: my-bucket + endpoint: minio:9000 + insecure: true + accessKeySecret: + name: my-minio-cred + key: accesskey + secretKeySecret: + name: my-minio-cred + key: secretkey +kind: ConfigMap +metadata: + name: workflow-controller-configmap +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + app: minio + name: my-minio-cred +stringData: + accesskey: admin + secretkey: password +type: Opaque +--- +apiVersion: v1 +kind: Service +metadata: + name: argo-server +spec: + ports: + - port: 2746 + targetPort: 2746 + selector: + app: argo-server +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: minio + name: minio +spec: + ports: + - port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: argo-server +spec: + selector: + matchLabels: + app: argo-server + template: + metadata: + labels: + app: argo-server + spec: + containers: + - args: + - server + - --namespaced + - --auth-mode + - client + - --loglevel + - debug + env: + - name: ARGO_TOKEN + value: password + - name: UPPERIO_DB_DEBUG + value: "1" + image: argoproj/argocli:latest + imagePullPolicy: Never + name: argo-server + ports: + - containerPort: 2746 + readinessProbe: + httpGet: + path: / + port: 2746 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 30 + serviceAccountName: argo-server +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: workflow-controller +spec: + selector: + matchLabels: + app: workflow-controller + template: + metadata: + labels: + app: workflow-controller + spec: + containers: + - args: + - --configmap + - workflow-controller-configmap + - --executor-image + - argoproj/argoexec:latest + - --namespaced + - --loglevel + - debug + - --executor-image-pull-policy + - Never + - --container-runtime-executor + - pns + command: + - workflow-controller + env: + - name: ALWAYS_OFFLOAD_NODE_STATUS + value: "true" + - name: WORKFLOW_GC_PERIOD + value: 30s + - name: UPPERIO_DB_DEBUG + value: "1" + image: argoproj/workflow-controller:latest + imagePullPolicy: Never + name: workflow-controller + serviceAccountName: argo +--- +apiVersion: v1 +kind: Pod +metadata: + labels: + app: minio + name: minio +spec: + containers: + - command: + - minio + - server + - /data + env: + - name: MINIO_ACCESS_KEY + value: admin + - name: MINIO_SECRET_KEY + value: password + image: minio/minio:RELEASE.2019-12-17T23-16-33Z + lifecycle: + postStart: + exec: + command: + - mkdir + - -p + - /data/my-bucket + livenessProbe: + httpGet: + path: /minio/health/live + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 + name: main + ports: + - containerPort: 9000 + readinessProbe: + httpGet: + path: /minio/health/ready + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/test/e2e/manifests/no-db/kustomization.yaml b/test/e2e/manifests/no-db/kustomization.yaml new file mode 100644 index 000000000000..440827648be7 --- /dev/null +++ b/test/e2e/manifests/no-db/kustomization.yaml @@ -0,0 +1,19 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +bases: + - ../../../../manifests/quick-start/no-db + +patchesJson6902: + - target: + version: v1 + group: apps + kind: Deployment + name: workflow-controller + path: overlays/workflow-controller-deployment.yaml + - target: + version: v1 + group: apps + kind: Deployment + name: argo-server + path: overlays/argo-server-deployment.yaml diff --git a/test/e2e/manifests/no-db/overlays/argo-server-deployment.yaml b/test/e2e/manifests/no-db/overlays/argo-server-deployment.yaml new file mode 100644 index 000000000000..26413d7ecd37 --- /dev/null +++ b/test/e2e/manifests/no-db/overlays/argo-server-deployment.yaml @@ -0,0 +1,23 @@ +# This is an auto-generated file. DO NOT EDIT +- op: replace + path: /spec/template/spec/containers/0/imagePullPolicy + value: Never +- op: add + path: /spec/template/spec/containers/0/args/- + value: --auth-mode +- op: add + path: /spec/template/spec/containers/0/args/- + value: client +- op: add + path: /spec/template/spec/containers/0/args/- + value: --loglevel +- op: add + path: /spec/template/spec/containers/0/args/- + value: debug +- op: add + path: /spec/template/spec/containers/0/env + value: + - name: ARGO_TOKEN + value: password + - name: UPPERIO_DB_DEBUG + value: "1" diff --git a/test/e2e/manifests/no-db/overlays/workflow-controller-deployment.yaml b/test/e2e/manifests/no-db/overlays/workflow-controller-deployment.yaml new file mode 100644 index 000000000000..2192bd96dbfa --- /dev/null +++ b/test/e2e/manifests/no-db/overlays/workflow-controller-deployment.yaml @@ -0,0 +1,31 @@ +# This is an auto-generated file. DO NOT EDIT +- op: replace + path: /spec/template/spec/containers/0/imagePullPolicy + value: Never +- op: add + path: /spec/template/spec/containers/0/args/- + value: --loglevel +- op: add + path: /spec/template/spec/containers/0/args/- + value: debug +- op: add + path: /spec/template/spec/containers/0/args/- + value: --executor-image-pull-policy +- op: add + path: /spec/template/spec/containers/0/args/- + value: Never +- op: add + path: /spec/template/spec/containers/0/args/- + value: --container-runtime-executor +- op: add + path: /spec/template/spec/containers/0/args/- + value: pns +- op: add + path: /spec/template/spec/containers/0/env + value: + - name: ALWAYS_OFFLOAD_NODE_STATUS + value: "true" + - name: WORKFLOW_GC_PERIOD + value: 30s + - name: UPPERIO_DB_DEBUG + value: "1" diff --git a/test/e2e/manifests/postgres.yaml b/test/e2e/manifests/postgres.yaml new file mode 100644 index 000000000000..dd612bf2df2e --- /dev/null +++ b/test/e2e/manifests/postgres.yaml @@ -0,0 +1,510 @@ +# This is an auto-generated file. DO NOT EDIT +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: cronworkflows.argoproj.io +spec: + group: argoproj.io + names: + kind: CronWorkflow + plural: cronworkflows + shortNames: + - cronwf + - cwf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflows.argoproj.io +spec: + additionalPrinterColumns: + - JSONPath: .status.phase + description: Status of the workflow + name: Status + type: string + - JSONPath: .status.startedAt + description: When the workflow was started + format: date-time + name: Age + type: date + group: argoproj.io + names: + kind: Workflow + plural: workflows + shortNames: + - wf + scope: Namespaced + version: v1alpha1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: workflowtemplates.argoproj.io +spec: + group: argoproj.io + names: + kind: WorkflowTemplate + plural: workflowtemplates + shortNames: + - wftmpl + scope: Namespaced + version: v1alpha1 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-role +rules: +- apiGroups: + - "" + resources: + - pods + - pods/exec + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - create + - delete +- apiGroups: + - argoproj.io + resources: + - workflows + - workflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete + - create +- apiGroups: + - argoproj.io + resources: + - workflowtemplates + - workflowtemplates/finalizers + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - get + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - cronworkflows + - cronworkflows/finalizers + verbs: + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argo-server-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - watch + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - "" + resources: + - pods + - pods/exec + - pods/log + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get +- apiGroups: + - argoproj.io + resources: + - workflows + - workflowtemplates + - cronworkflows + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: workflow-role +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - watch + - patch +- apiGroups: + - "" + resources: + - pods/log + verbs: + - get + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-role +subjects: +- kind: ServiceAccount + name: argo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: argo-server-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: argo-server-role +subjects: +- kind: ServiceAccount + name: argo-server +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: workflow-default-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: workflow-role +subjects: +- kind: ServiceAccount + name: default +--- +apiVersion: v1 +data: + config: | + artifactRepository: + archiveLogs: true + s3: + bucket: my-bucket + endpoint: minio:9000 + insecure: true + accessKeySecret: + name: my-minio-cred + key: accesskey + secretKeySecret: + name: my-minio-cred + key: secretkey + persistence: + connectionPool: + maxIdleConns: 100 + maxOpenConns: 0 + nodeStatusOffLoad: true + archive: true + postgresql: + host: postgres + port: 5432 + database: postgres + tableName: argo_workflows + userNameSecret: + name: argo-postgres-config + key: username + passwordSecret: + name: argo-postgres-config + key: password +kind: ConfigMap +metadata: + name: workflow-controller-configmap +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + app: postgres + name: argo-postgres-config +stringData: + password: password + username: postgres +type: Opaque +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + app: minio + name: my-minio-cred +stringData: + accesskey: admin + secretkey: password +type: Opaque +--- +apiVersion: v1 +kind: Service +metadata: + name: argo-server +spec: + ports: + - port: 2746 + targetPort: 2746 + selector: + app: argo-server +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: minio + name: minio +spec: + ports: + - port: 9000 + protocol: TCP + targetPort: 9000 + selector: + app: minio +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: postgres + name: postgres +spec: + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + app: postgres +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: argo-server +spec: + selector: + matchLabels: + app: argo-server + template: + metadata: + labels: + app: argo-server + spec: + containers: + - args: + - server + - --namespaced + - --auth-mode + - client + - --loglevel + - debug + env: + - name: ARGO_TOKEN + value: password + - name: UPPERIO_DB_DEBUG + value: "1" + image: argoproj/argocli:latest + imagePullPolicy: Never + name: argo-server + ports: + - containerPort: 2746 + readinessProbe: + httpGet: + path: / + port: 2746 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 30 + serviceAccountName: argo-server +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: postgres + name: postgres +spec: + selector: + matchLabels: + app: postgres + template: + metadata: + labels: + app: postgres + name: postgres + spec: + containers: + - env: + - name: POSTGRES_PASSWORD + value: password + image: postgres:12-alpine + name: main + ports: + - containerPort: 5432 + readinessProbe: + exec: + command: + - psql + - -U + - postgres + - -c + - SELECT 1 + initialDelaySeconds: 15 + timeoutSeconds: 2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: workflow-controller +spec: + selector: + matchLabels: + app: workflow-controller + template: + metadata: + labels: + app: workflow-controller + spec: + containers: + - args: + - --configmap + - workflow-controller-configmap + - --executor-image + - argoproj/argoexec:latest + - --namespaced + - --loglevel + - debug + - --executor-image-pull-policy + - Never + - --container-runtime-executor + - pns + command: + - workflow-controller + env: + - name: ALWAYS_OFFLOAD_NODE_STATUS + value: "true" + - name: WORKFLOW_GC_PERIOD + value: 30s + - name: UPPERIO_DB_DEBUG + value: "1" + image: argoproj/workflow-controller:latest + imagePullPolicy: Never + name: workflow-controller + serviceAccountName: argo +--- +apiVersion: v1 +kind: Pod +metadata: + labels: + app: minio + name: minio +spec: + containers: + - command: + - minio + - server + - /data + env: + - name: MINIO_ACCESS_KEY + value: admin + - name: MINIO_SECRET_KEY + value: password + image: minio/minio:RELEASE.2019-12-17T23-16-33Z + lifecycle: + postStart: + exec: + command: + - mkdir + - -p + - /data/my-bucket + livenessProbe: + httpGet: + path: /minio/health/live + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 + name: main + ports: + - containerPort: 9000 + readinessProbe: + httpGet: + path: /minio/health/ready + port: 9000 + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/test/e2e/manifests/postgres/kustomization.yaml b/test/e2e/manifests/postgres/kustomization.yaml new file mode 100644 index 000000000000..d3aeded8bb6d --- /dev/null +++ b/test/e2e/manifests/postgres/kustomization.yaml @@ -0,0 +1,19 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +bases: + - ../../../../manifests/quick-start/postgres + +patchesJson6902: + - target: + version: v1 + group: apps + kind: Deployment + name: workflow-controller + path: overlays/workflow-controller-deployment.yaml + - target: + version: v1 + group: apps + kind: Deployment + name: argo-server + path: overlays/argo-server-deployment.yaml diff --git a/test/e2e/manifests/postgres/overlays/argo-server-deployment.yaml b/test/e2e/manifests/postgres/overlays/argo-server-deployment.yaml new file mode 100644 index 000000000000..c797e479bf4a --- /dev/null +++ b/test/e2e/manifests/postgres/overlays/argo-server-deployment.yaml @@ -0,0 +1,22 @@ +- op: replace + path: /spec/template/spec/containers/0/imagePullPolicy + value: Never +- op: add + path: /spec/template/spec/containers/0/args/- + value: --auth-mode +- op: add + path: /spec/template/spec/containers/0/args/- + value: client +- op: add + path: /spec/template/spec/containers/0/args/- + value: --loglevel +- op: add + path: /spec/template/spec/containers/0/args/- + value: debug +- op: add + path: /spec/template/spec/containers/0/env + value: + - name: ARGO_TOKEN + value: password + - name: UPPERIO_DB_DEBUG + value: "1" diff --git a/test/e2e/manifests/postgres/overlays/workflow-controller-deployment.yaml b/test/e2e/manifests/postgres/overlays/workflow-controller-deployment.yaml new file mode 100644 index 000000000000..77df8a591c40 --- /dev/null +++ b/test/e2e/manifests/postgres/overlays/workflow-controller-deployment.yaml @@ -0,0 +1,30 @@ +- op: replace + path: /spec/template/spec/containers/0/imagePullPolicy + value: Never +- op: add + path: /spec/template/spec/containers/0/args/- + value: --loglevel +- op: add + path: /spec/template/spec/containers/0/args/- + value: debug +- op: add + path: /spec/template/spec/containers/0/args/- + value: --executor-image-pull-policy +- op: add + path: /spec/template/spec/containers/0/args/- + value: Never +- op: add + path: /spec/template/spec/containers/0/args/- + value: --container-runtime-executor +- op: add + path: /spec/template/spec/containers/0/args/- + value: pns +- op: add + path: /spec/template/spec/containers/0/env + value: + - name: ALWAYS_OFFLOAD_NODE_STATUS + value: "true" + - name: WORKFLOW_GC_PERIOD + value: 30s + - name: UPPERIO_DB_DEBUG + value: "1" diff --git a/test/e2e/smoke/artifact-passing.yaml b/test/e2e/smoke/artifact-passing.yaml index 9128ffefc2e5..e850eb16f238 100644 --- a/test/e2e/smoke/artifact-passing.yaml +++ b/test/e2e/smoke/artifact-passing.yaml @@ -20,7 +20,7 @@ spec: - name: generate-message container: - image: docker/whalesay:latest + image: cowsay:v1 command: [sh, -c] args: ["cowsay hello world | tee /tmp/hello_world.txt"] imagePullPolicy: IfNotPresent @@ -35,7 +35,7 @@ spec: - name: message path: /tmp/message container: - image: docker/whalesay:latest + image: cowsay:v1 imagePullPolicy: IfNotPresent command: [sh, -c] args: ["cat /tmp/message"] diff --git a/test/e2e/smoke/basic-2.yaml b/test/e2e/smoke/basic-2.yaml index a3adf6e016d9..d4a0a43d92c0 100644 --- a/test/e2e/smoke/basic-2.yaml +++ b/test/e2e/smoke/basic-2.yaml @@ -9,5 +9,5 @@ spec: templates: - name: run-workflow container: - image: docker/whalesay:latest + image: cowsay:v1 imagePullPolicy: IfNotPresent \ No newline at end of file diff --git a/test/e2e/smoke/basic.yaml b/test/e2e/smoke/basic.yaml index 47e4be729651..16037cc6be06 100644 --- a/test/e2e/smoke/basic.yaml +++ b/test/e2e/smoke/basic.yaml @@ -9,6 +9,6 @@ spec: templates: - name: run-workflow container: - image: docker/whalesay:latest - command: [cowsay, "🐙 Hello Argo!"] + image: cowsay:v1 + command: [cowsay, ":) Hello Argo!"] imagePullPolicy: IfNotPresent \ No newline at end of file diff --git a/test/e2e/smoke/workflow-template-whalesay-template.yaml b/test/e2e/smoke/workflow-template-whalesay-template.yaml index 1c0ae534f26e..5f6615af9418 100644 --- a/test/e2e/smoke/workflow-template-whalesay-template.yaml +++ b/test/e2e/smoke/workflow-template-whalesay-template.yaml @@ -9,6 +9,6 @@ spec: parameters: - name: message container: - image: docker/whalesay + image: cowsay:v1 command: [cowsay] args: ["{{inputs.parameters.message}}"] diff --git a/test/e2e/smoke_test.go b/test/e2e/smoke_test.go index 5bd1af7b5188..095efaaf7aac 100644 --- a/test/e2e/smoke_test.go +++ b/test/e2e/smoke_test.go @@ -16,12 +16,12 @@ type SmokeSuite struct { fixtures.E2ESuite } -func (s *SmokeSuite) TestBasic() { +func (s *SmokeSuite) TestBasicWorkflow() { s.Given(). Workflow("@smoke/basic.yaml"). When(). SubmitWorkflow(). - WaitForWorkflow(10 * time.Second). + WaitForWorkflow(15 * time.Second). Then(). ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, wf *wfv1.WorkflowStatus) { assert.Equal(t, wfv1.NodeSucceeded, wf.Phase) @@ -34,7 +34,7 @@ func (s *SmokeSuite) TestArtifactPassing() { Workflow("@smoke/artifact-passing.yaml"). When(). SubmitWorkflow(). - WaitForWorkflow(20 * time.Second). + WaitForWorkflow(30 * time.Second). Then(). ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { assert.Equal(t, wfv1.NodeSucceeded, status.Phase) @@ -48,7 +48,7 @@ func (s *SmokeSuite) TestWorkflowTemplateBasic() { When(). CreateWorkflowTemplates(). SubmitWorkflow(). - WaitForWorkflow(15 * time.Second). + WaitForWorkflow(60 * time.Second). Then(). ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { assert.Equal(t, wfv1.NodeSucceeded, status.Phase) diff --git a/test/e2e/testdata/argo-server-test-role.yaml b/test/e2e/testdata/argo-server-test-role.yaml new file mode 100644 index 000000000000..16e7375195d9 --- /dev/null +++ b/test/e2e/testdata/argo-server-test-role.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: argotest-role +rules: + - apiGroups: + - "argoproj.io" + resources: + - workflows + - workflowtemplates + - cronworkflows + verbs: + - create + - get + - list + - delete diff --git a/test/e2e/workflow_template_test.go b/test/e2e/workflow_template_test.go index c9b13379f777..07b5df5b0a8d 100644 --- a/test/e2e/workflow_template_test.go +++ b/test/e2e/workflow_template_test.go @@ -1,13 +1,15 @@ package e2e import ( - "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" - "github.com/argoproj/argo/test/e2e/fixtures" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" - "k8s.io/apimachinery/pkg/apis/meta/v1" "testing" "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" + "github.com/argoproj/argo/test/e2e/fixtures" ) type WorkflowTemplateSuite struct { @@ -35,7 +37,7 @@ spec: `).When(). CreateWorkflowTemplates(). SubmitWorkflow(). - WaitForWorkflow(15 * time.Second). + WaitForWorkflow(30 * time.Second). Then(). ExpectWorkflow(func(t *testing.T, metadata *v1.ObjectMeta, status *v1alpha1.WorkflowStatus) { assert.Equal(t, status.Phase, v1alpha1.NodeSucceeded) diff --git a/ui/package.json b/ui/package.json index bb51443379fc..343ef009ac1b 100644 --- a/ui/package.json +++ b/ui/package.json @@ -16,7 +16,7 @@ "argo-ui": "https://github.com/argoproj/argo-ui.git", "classnames": "^2.2.5", "dagre": "^0.8.2", - "event-source-polyfill": "^1.0.11", + "formik": "^2.1.2", "history": "^4.7.2", "js-yaml": "^3.13.1", "json-merge-patch": "^0.2.3", diff --git a/ui/src/app/app.tsx b/ui/src/app/app.tsx index 6350d4590db8..f7f0f234eff4 100644 --- a/ui/src/app/app.tsx +++ b/ui/src/app/app.tsx @@ -5,7 +5,7 @@ import {Redirect, Route, RouteComponentProps, Router, Switch} from 'react-router import {Layout, NavigationManager, Notifications, NotificationsManager, Popup, PopupManager, PopupProps} from 'argo-ui'; import {uiUrl} from './shared/base'; -import {AppContext, ContextApis, Provider} from './shared/context'; +import {ContextApis, Provider} from './shared/context'; import archivedWorkflows from './archived-workflows'; import cronWorkflows from './cron-workflows'; @@ -105,23 +105,7 @@ export class App extends React.Component<{}, {popupProps: PopupProps}> { - ; - } - - public componentWillMount() { - const router = (this.context as AppContext).router; - router.history.push(router.route.location.pathname.replace(timelineUrl, workflowsUrl)); - } - } - } - /> + diff --git a/ui/src/app/archived-workflows/components/archived-workflow-container.tsx b/ui/src/app/archived-workflows/components/archived-workflow-container.tsx index f52f9c82b3e6..5b7b63e7e012 100644 --- a/ui/src/app/archived-workflows/components/archived-workflow-container.tsx +++ b/ui/src/app/archived-workflows/components/archived-workflow-container.tsx @@ -5,7 +5,7 @@ import {ArchivedWorkflowList} from './archived-workflow-list/archived-workflow-l export const ArchivedWorkflowContainer = (props: RouteComponentProps) => ( - - + + ); diff --git a/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx b/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx index f993a9841f8f..b24f55c91c3a 100644 --- a/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx +++ b/ui/src/app/archived-workflows/components/archived-workflow-list/archived-workflow-list.tsx @@ -29,11 +29,11 @@ export class ArchivedWorkflowList extends BasePage, Sta } private get namespace() { - return this.queryParam('namespace') || ''; + return this.props.match.params.namespace || ''; } private set namespace(namespace: string) { - this.setQueryParams({namespace}); + document.location.href = uiUrl('archived-workflows/' + namespace); } constructor(props: RouteComponentProps, context: any) { @@ -42,8 +42,14 @@ export class ArchivedWorkflowList extends BasePage, Sta } public componentDidMount(): void { - services.archivedWorkflows - .list(this.namespace, this.continue) + services.info + .get() + .then(info => { + if (info.managedNamespace && info.managedNamespace !== this.namespace) { + this.namespace = info.managedNamespace; + } + return services.archivedWorkflows.list(this.namespace, this.continue); + }) .then(list => { this.setState({workflows: list.items || [], continue: list.metadata.continue || ''}); }) @@ -71,7 +77,7 @@ export class ArchivedWorkflowList extends BasePage, Sta ] }}>
-
{this.renderWorkflows()}
+
{this.renderWorkflows()}
); @@ -100,7 +106,7 @@ export class ArchivedWorkflowList extends BasePage, Sta
CREATED
{this.state.workflows.map(w => ( - +
diff --git a/ui/src/app/cron-workflows/components/cron-workflow-container.tsx b/ui/src/app/cron-workflows/components/cron-workflow-container.tsx index ce4015d20bd0..5b39ecb7fed1 100644 --- a/ui/src/app/cron-workflows/components/cron-workflow-container.tsx +++ b/ui/src/app/cron-workflows/components/cron-workflow-container.tsx @@ -5,7 +5,7 @@ import {CronWorkflowList} from './cron-workflow-list/cron-workflow-list'; export const CronWorkflowContainer = (props: RouteComponentProps) => ( - + ); diff --git a/ui/src/app/cron-workflows/components/cron-workflow-list/cron-workflow-list.tsx b/ui/src/app/cron-workflows/components/cron-workflow-list/cron-workflow-list.tsx index 9a2193462176..cd4ec31f4e88 100644 --- a/ui/src/app/cron-workflows/components/cron-workflow-list/cron-workflow-list.tsx +++ b/ui/src/app/cron-workflows/components/cron-workflow-list/cron-workflow-list.tsx @@ -22,11 +22,11 @@ interface State { export class CronWorkflowList extends BasePage, State> { private get namespace() { - return this.queryParam('namespace') || ''; + return this.props.match.params.namespace || ''; } - private set namespace(namespace) { - this.setQueryParams({namespace}); + private set namespace(namespace: string) { + document.location.href = uiUrl('cron-workflows/' + namespace); } private get sidePanel() { @@ -42,8 +42,14 @@ export class CronWorkflowList extends BasePage, State> } public componentDidMount(): void { - services.cronWorkflows - .list(this.namespace) + services.info + .get() + .then(info => { + if (info.managedNamespace && info.managedNamespace !== this.namespace) { + this.namespace = info.managedNamespace; + } + return services.cronWorkflows.list(this.namespace); + }) .then(cronWorkflows => this.setState({cronWorkflows})) .catch(error => this.setState({error})); } @@ -71,7 +77,7 @@ export class CronWorkflowList extends BasePage, State> tools: [ (this.namespace = namespace)} />] }}>
-
{this.renderCronWorkflows()}
+
{this.renderCronWorkflows()}
(this.sidePanel = null)}> localStorage.getItem('token'); +const getToken = () => { + for (const cookie of document.cookie.split(';')) { + if (cookie.startsWith('authorization=')) { + return cookie.substring(14); + } + } + return null; +}; + const maybeLoggedIn = () => !!getToken(); const logout = () => { - localStorage.removeItem('token'); + document.cookie = 'authorization=;'; document.location.reload(true); }; const login = (token: string) => { - localStorage.setItem('token', token); + document.cookie = 'authorization=' + token + ';'; document.location.href = '/'; }; export const Login = () => ( diff --git a/ui/src/app/shared/components/base-page.tsx b/ui/src/app/shared/components/base-page.tsx index c42efa99e0b5..5f23647ed798 100644 --- a/ui/src/app/shared/components/base-page.tsx +++ b/ui/src/app/shared/components/base-page.tsx @@ -46,8 +46,12 @@ export class BasePage

, S> extends React.Compo private pushParams(params: URLSearchParams) { this.appContext.router.history.push(`${this.props.match.url}?${params.toString()}`); setTimeout(() => { - this.componentWillUnmount(); - this.componentDidMount(); + if (this.componentWillUnmount) { + this.componentWillUnmount(); + } + if (this.componentDidMount) { + this.componentDidMount(); + } }, 300); } diff --git a/ui/src/app/shared/components/namespace-filter.tsx b/ui/src/app/shared/components/namespace-filter.tsx index 4b2790da7807..975b6054986e 100644 --- a/ui/src/app/shared/components/namespace-filter.tsx +++ b/ui/src/app/shared/components/namespace-filter.tsx @@ -25,6 +25,10 @@ export class NamespaceFilter extends React.Component { }; } + private get namespace() { + return this.state.namespace; + } + private set namespace(namespace: string) { this.setState(state => { const namespaces = state.namespaces; @@ -43,9 +47,12 @@ export class NamespaceFilter extends React.Component { services.info .get() .then(info => { - if (info.managedNamespace && info.managedNamespace !== this.namespace) { + if (info.managedNamespace) { + const namespaceChanged = info.managedNamespace !== this.namespace; this.setState({editable: false, namespace: info.managedNamespace}); - this.props.onChange(info.managedNamespace); + if (namespaceChanged) { + this.props.onChange(info.managedNamespace); + } } else { this.setState({editable: true}); } diff --git a/ui/src/app/shared/services/requests.ts b/ui/src/app/shared/services/requests.ts index 044dec66d31f..609056694f1c 100644 --- a/ui/src/app/shared/services/requests.ts +++ b/ui/src/app/shared/services/requests.ts @@ -14,11 +14,8 @@ enum ReadyState { DONE = 4 } -const getToken = () => localStorage.getItem('token'); - const auth = (req: SuperAgentRequest) => { - const token = getToken(); - return (token !== null ? req.auth(token, {type: 'bearer'}) : req).on('error', handle); + return req.on('error', handle); }; const handle = (err: any) => { @@ -52,12 +49,7 @@ export default { loadEventSource(url: string, allowAutoRetry = false): Observable { return Observable.create((observer: Observer) => { - const token = getToken(); - const headers: any = {}; - if (token !== null) { - headers.Authorization = `Bearer ${getToken()}`; - } - const eventSource = new EventSourcePolyfill(url, {headers}); + const eventSource = new EventSource(url); let opened = false; eventSource.onopen = (msg: any) => { if (!opened) { diff --git a/ui/src/app/workflow-templates/components/workflow-template-container.tsx b/ui/src/app/workflow-templates/components/workflow-template-container.tsx index cf9caecf26f8..f93c84ca53d6 100644 --- a/ui/src/app/workflow-templates/components/workflow-template-container.tsx +++ b/ui/src/app/workflow-templates/components/workflow-template-container.tsx @@ -5,7 +5,7 @@ import {WorkflowTemplateList} from './workflow-template-list/workflow-template-l export const WorkflowTemplateContainer = (props: RouteComponentProps) => ( - + ); diff --git a/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx b/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx index 4b988701b1c4..f40b3cc565bd 100644 --- a/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx +++ b/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx @@ -23,11 +23,11 @@ interface State { export class WorkflowTemplateList extends BasePage, State> { private get namespace() { - return this.queryParam('namespace') || ''; + return this.props.match.params.namespace || ''; } - private set namespace(namespace) { - this.setQueryParams({namespace}); + private set namespace(namespace: string) { + document.location.href = uiUrl('workflow-templates/' + namespace); } private get sidePanel() { @@ -44,8 +44,14 @@ export class WorkflowTemplateList extends BasePage, Sta } public componentDidMount(): void { - services.workflowTemplate - .list(this.namespace) + services.info + .get() + .then(info => { + if (info.managedNamespace && info.managedNamespace !== this.namespace) { + this.namespace = info.managedNamespace; + } + return services.workflowTemplate.list(this.namespace); + }) .then(templates => this.setState({templates})) .catch(error => this.setState({error})); } @@ -81,7 +87,7 @@ export class WorkflowTemplateList extends BasePage, Sta onSubmit={(value: WorkflowTemplate) => { return services.workflowTemplate .create(value, value.metadata.namespace) - .then(wf => ctx.navigation.goto(`/workflow-templates/${wf.metadata.namespace}/${wf.metadata.name}`)) + .then(wf => (document.location.href = uiUrl(`workflow-templates/${wf.metadata.namespace}/${wf.metadata.name}`))) .catch(error => this.setState({error})); }} /> @@ -107,7 +113,7 @@ export class WorkflowTemplateList extends BasePage, Sta } return (

-
+
diff --git a/ui/src/app/workflows/components/workflow-submit.tsx b/ui/src/app/workflows/components/workflow-submit.tsx new file mode 100644 index 000000000000..7e0479555cfb --- /dev/null +++ b/ui/src/app/workflows/components/workflow-submit.tsx @@ -0,0 +1,122 @@ +import {Formik} from 'formik'; +import * as jsYaml from 'js-yaml'; +import * as React from 'react'; +import * as models from '../../../models'; +import {ContextApis} from '../../shared/context'; +import {services} from '../../shared/services'; + +interface WorkflowSubmitProps { + defaultWorkflow: models.Workflow; + ctx: ContextApis; + currentNamespace: string; +} + +interface WorkflowSubmitState { + error?: Error; +} + +export class WorkflowSubmit extends React.Component { + constructor(props: WorkflowSubmitProps) { + super(props); + this.state = {}; + } + + public render() { + return ( +
+ { + services.workflows + .create(values.wf, values.wf.metadata.namespace || this.props.currentNamespace) + .then(wf => this.props.ctx.navigation.goto(`/workflows/${wf.metadata.namespace}/${wf.metadata.name}`)) + .then(_ => setSubmitting(false)) + .catch(error => { + this.setState({error}); + setSubmitting(false); + }); + }}> + {(formikApi: any) => ( +
+
+

Submit New Workflow

+ + {this.state.error && ( +

+ {this.state.error.message} +

+ )} +