Skip to content

Commit

Permalink
feat: Add argo submit --verify hidden flag. Closes argoproj#5136 (a…
Browse files Browse the repository at this point in the history
…rgoproj#5141)

Signed-off-by: Alex Collins <[email protected]>
  • Loading branch information
alexec committed Feb 19, 2021
1 parent 377c5f8 commit 590df1d
Show file tree
Hide file tree
Showing 15 changed files with 136 additions and 129 deletions.
18 changes: 9 additions & 9 deletions .github/workflows/ci-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,14 @@ jobs:
echo '127.0.0.1 postgres' | sudo tee -a /etc/hosts
echo '127.0.0.1 mysql' | sudo tee -a /etc/hosts
git fetch --tags
KUBECONFIG=~/.kube/config make install PROFILE=mysql E2E_EXECUTOR=${{matrix.containerRuntimeExecutor}} ALWAYS_OFFLOAD_NODE_STATUS=true DEV_IMAGE=true STATIC_FILES=false
KUBECONFIG=~/.kube/config make start PROFILE=mysql E2E_EXECUTOR=${{matrix.containerRuntimeExecutor}} ALWAYS_OFFLOAD_NODE_STATUS=true DEV_IMAGE=true STATIC_FILES=false 2>&1 > /tmp/log/argo-e2e/argo.log &
PROFILE=mysql
ALWAYS_OFFLOAD_NODE_STATUS=true
if [ "${{matrix.test}}" = test-examples ]; then
PROFILE=minimal
ALWAYS_OFFLOAD_NODE_STATUS=false
fi
KUBECONFIG=~/.kube/config make install PROFILE=$PROFILE E2E_EXECUTOR=${{matrix.containerRuntimeExecutor}} ALWAYS_OFFLOAD_NODE_STATUS=${ALWAYS_OFFLOAD_NODE_STATUS} DEV_IMAGE=true STATIC_FILES=false
KUBECONFIG=~/.kube/config make start PROFILE=$PROFILE E2E_EXECUTOR=${{matrix.containerRuntimeExecutor}} ALWAYS_OFFLOAD_NODE_STATUS=${ALWAYS_OFFLOAD_NODE_STATUS} DEV_IMAGE=true STATIC_FILES=false 2>&1 > /tmp/log/argo-e2e/argo.log &
- name: Wait for Argo Server to be ready
env:
GOPATH: /home/runner/go
Expand All @@ -112,17 +118,11 @@ jobs:
GOPATH: /home/runner/go
run: make ${{ matrix.test }}
- name: Upload logs
if: ${{ always() }}
uses: actions/upload-artifact@v1
with:
name: ${{ matrix.test }}-${{matrix.containerRuntimeExecutor}}-${{ github.run_id }}-argo.log
path: /tmp/log/argo-e2e/argo.log
- name: Upload pod logs
if: ${{ failure() }}
uses: actions/upload-artifact@v1
with:
name: ${{ matrix.test }}-${{matrix.containerRuntimeExecutor}}-${{ github.run_id }}-pod.log
path: /tmp/log/argo-e2e/pod.log
path: /tmp/log/argo-e2e

codegen:
name: Codegen
Expand Down
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ endif
ifneq ($(CI),)
AUTH_MODE := client
endif

# Which mode to run in:
# * `local` run the workflow–controller and argo-server as single replicas on the local machine (default)
# * `kubernetes` run the workflow-controller and argo-server on the Kubernetes cluster
Expand Down Expand Up @@ -485,8 +486,8 @@ test-executor:
$(GOTEST) -timeout 5m -count 1 --tags executor -p 1 ./test/e2e

.PHONY: test-examples
test-examples:
$(GOTEST) -timeout 15m -count 1 --tags examples -p 1 ./test/e2e
test-examples: ./dist/argo
./hack/test-examples.sh

.PHONY: test-functional
test-functional:
Expand Down
11 changes: 8 additions & 3 deletions cmd/argo/commands/submit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ package commands

import (
"context"
"log"
"os"
"strings"

"github.com/argoproj/pkg/errors"
argoJson "github.com/argoproj/pkg/json"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -25,6 +24,7 @@ type cliSubmitOpts struct {
output string // --output
wait bool // --wait
watch bool // --watch
verify bool // --verify
log bool // --log
strict bool // --strict
priority *int32 // --priority
Expand Down Expand Up @@ -67,7 +67,7 @@ func NewSubmitCommand() *cobra.Command {
}

if !cliSubmitOpts.watch && len(cliSubmitOpts.getArgs.status) > 0 {
logrus.Warn("--status should only be used with --watch")
log.Warn("--status should only be used with --watch")
}

ctx, apiClient := client.NewAPIClient()
Expand All @@ -88,6 +88,8 @@ func NewSubmitCommand() *cobra.Command {
command.Flags().StringVarP(&cliSubmitOpts.output, "output", "o", "", "Output format. One of: name|json|yaml|wide")
command.Flags().BoolVarP(&cliSubmitOpts.wait, "wait", "w", false, "wait for the workflow to complete")
command.Flags().BoolVar(&cliSubmitOpts.watch, "watch", false, "watch the workflow until it completes")
command.Flags().BoolVar(&cliSubmitOpts.verify, "verify", false, "verify completed workflows by running the Python code in the workflows.argoproj.io/verify.py annotation")
errors.CheckError(command.Flags().MarkHidden("verify"))
command.Flags().BoolVar(&cliSubmitOpts.log, "log", false, "log the workflow until it completes")
command.Flags().BoolVar(&cliSubmitOpts.strict, "strict", true, "perform strict workflow validation")
command.Flags().Int32Var(&priority, "priority", 0, "workflow priority")
Expand Down Expand Up @@ -258,4 +260,7 @@ func waitWatchOrLog(ctx context.Context, serviceClient workflowpkg.WorkflowServi
watchWorkflow(ctx, serviceClient, namespace, workflow, cliSubmitOpts.getArgs)
}
}
if cliSubmitOpts.verify {
verifyWorkflows(ctx, serviceClient, namespace, workflowNames)
}
}
34 changes: 34 additions & 0 deletions cmd/argo/commands/verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package commands

import (
"context"
"fmt"
"os"

"github.com/TwinProduction/go-color"
"github.com/argoproj/pkg/errors"

workflowpkg "github.com/argoproj/argo-workflows/v3/pkg/apiclient/workflow"
"github.com/argoproj/argo-workflows/v3/workflow/verify"
)

func verifyWorkflows(ctx context.Context, serviceClient workflowpkg.WorkflowServiceClient, namespace string, workflowNames []string) {
_, _ = fmt.Fprintln(os.Stderr, "verifying workflows...")
failAtEnd := false
for _, name := range workflowNames {
wf, err := serviceClient.GetWorkflow(ctx, &workflowpkg.WorkflowGetRequest{
Namespace: namespace,
Name: name,
})
errors.CheckError(err)
if err := verify.Workflow(wf); err != nil {
_, _ = fmt.Fprintf(os.Stdout, "%s %s: %v\n", color.Ize(color.Red, "✖"), name, err)
failAtEnd = true
} else {
_, _ = fmt.Fprintf(os.Stdout, "%s %s\n", color.Ize(color.Green, "✔"), name)
}
}
if failAtEnd {
os.Exit(1)
}
}
2 changes: 0 additions & 2 deletions cmd/argo/commands/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,6 @@ func waitWorkflows(ctx context.Context, serviceClient workflowpkg.WorkflowServic
}

func waitOnOne(serviceClient workflowpkg.WorkflowServiceClient, ctx context.Context, wfName, namespace string, ignoreNotFound, quiet bool) bool {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
req := &workflowpkg.WatchWorkflowsRequest{
Namespace: namespace,
ListOptions: &metav1.ListOptions{
Expand Down
2 changes: 0 additions & 2 deletions cmd/argo/commands/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ func NewWatchCommand() *cobra.Command {
}

func watchWorkflow(ctx context.Context, serviceClient workflowpkg.WorkflowServiceClient, namespace string, workflow string, getArgs getFlags) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
req := &workflowpkg.WatchWorkflowsRequest{
Namespace: namespace,
ListOptions: &metav1.ListOptions{
Expand Down
8 changes: 8 additions & 0 deletions hack/test-examples.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -eu -o pipefail

kubectl delete wf -l workflows.argoproj.io/test

grep -lR 'workflows.argoproj.io/test' examples/* | while read f ; do
./dist/argo submit --watch --verify $f
done
9 changes: 2 additions & 7 deletions server/auth/gatekeeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package auth

import (
"context"
"encoding/json"
"fmt"
"net/http"
"sort"
Expand All @@ -27,6 +26,7 @@ import (
"github.com/argoproj/argo-workflows/v3/server/auth/sso"
"github.com/argoproj/argo-workflows/v3/server/auth/types"
servertypes "github.com/argoproj/argo-workflows/v3/server/types"
jsonutil "github.com/argoproj/argo-workflows/v3/util/json"
"github.com/argoproj/argo-workflows/v3/util/kubeconfig"
"github.com/argoproj/argo-workflows/v3/workflow/common"
)
Expand Down Expand Up @@ -203,15 +203,10 @@ func (s *gatekeeper) rbacAuthorization(ctx context.Context, claims *types.Claims
sort.Slice(serviceAccounts, func(i, j int) bool { return precedence(serviceAccounts[i]) > precedence(serviceAccounts[j]) })
for _, serviceAccount := range serviceAccounts {
rule := serviceAccount.Annotations[common.AnnotationKeyRBACRule]
data, err := json.Marshal(claims)
v, err := jsonutil.Jsonify(claims)
if err != nil {
return nil, fmt.Errorf("failed to marshall claims: %w", err)
}
v := make(map[string]interface{})
err = json.Unmarshal(data, &v)
if err != nil {
return nil, fmt.Errorf("failed to unmarshall claims: %w", err)
}
result, err := expr.Eval(rule, v)
if err != nil {
return nil, fmt.Errorf("failed to evaluate rule: %w", err)
Expand Down
8 changes: 2 additions & 6 deletions server/event/dispatch/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/argoproj/argo-workflows/v3/server/auth"
errorsutil "github.com/argoproj/argo-workflows/v3/util/errors"
"github.com/argoproj/argo-workflows/v3/util/instanceid"
jsonutil "github.com/argoproj/argo-workflows/v3/util/json"
"github.com/argoproj/argo-workflows/v3/util/labels"
waitutil "github.com/argoproj/argo-workflows/v3/util/wait"
"github.com/argoproj/argo-workflows/v3/workflow/common"
Expand Down Expand Up @@ -192,12 +193,7 @@ func expressionEnvironment(ctx context.Context, namespace, discriminator string,
"metadata": metaData(ctx),
"payload": payload,
}
data, err := json.Marshal(src)
if err != nil {
return nil, err
}
env := make(map[string]interface{})
return env, json.Unmarshal(data, &env)
return jsonutil.Jsonify(src)
}

func metaData(ctx context.Context) map[string]interface{} {
Expand Down
89 changes: 0 additions & 89 deletions test/e2e/examples_test.go

This file was deleted.

9 changes: 4 additions & 5 deletions util/flatten/flatten.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package flatten

import (
"encoding/json"
"fmt"
"reflect"

jsonutil "github.com/argoproj/argo-workflows/v3/util/json"
)

func toMap(in interface{}) map[string]interface{} {
data, _ := json.Marshal(in)
out := make(map[string]interface{})
_ = json.Unmarshal(data, &out)
return out
v, _ := jsonutil.Jsonify(in)
return v
}

func flattenWithPrefix(in map[string]interface{}, out map[string]string, prefix string) {
Expand Down
12 changes: 12 additions & 0 deletions util/json/jsonify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package json

import "encoding/json"

func Jsonify(v interface{}) (map[string]interface{}, error) {
data, err := json.Marshal(v)
if err != nil {
return nil, err
}
x := make(map[string]interface{})
return x, json.Unmarshal(data, &x)
}
9 changes: 5 additions & 4 deletions test/e2e/py.go → util/python/conversion.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package e2e
package python

import (
"reflect"

"github.com/go-python/gpython/py"

"github.com/argoproj/argo-workflows/v3/util/json"
)

func obj(v interface{}) py.Object {
Expand All @@ -19,7 +19,8 @@ func obj(v interface{}) py.Object {
case map[string]interface{}:
return dict(x)
default:
panic(reflect.TypeOf(x).String())
v, _ := json.Jsonify(v)
return obj(v)
}
}

Expand Down
24 changes: 24 additions & 0 deletions util/python/python.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package python

import (
"fmt"

_ "github.com/go-python/gpython/builtin"
"github.com/go-python/gpython/compile"
"github.com/go-python/gpython/py"
"github.com/go-python/gpython/vm"
)

func Run(s string, globals map[string]interface{}) error {
x, err := compile.Compile(s, "<stdin>", "exec", 0, true)
if err != nil {
return err
}
m := py.NewModule("__main__", "", nil, dict(globals))
code, ok := x.(*py.Code)
if !ok {
return fmt.Errorf("obj cannot be cast to code")
}
_, err = vm.EvalCode(code, m.Globals, nil)
return err
}
Loading

0 comments on commit 590df1d

Please sign in to comment.