Skip to content

Commit

Permalink
fix: Make jq work. Fixes argoproj#9860 (argoproj#10150)
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Collins <[email protected]>
  • Loading branch information
alexec authored Dec 1, 2022
1 parent a6aca18 commit 55e9697
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 25 deletions.
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ RUN apk update && apk add --no-cache \
curl \
gcc \
bash \
jq \
mailcap

WORKDIR /go/src/github.com/argoproj/argo-workflows
Expand Down Expand Up @@ -43,6 +42,9 @@ RUN --mount=type=cache,target=/root/.yarn \

FROM builder as argoexec-build

RUN curl -L -o /usr/local/bin/jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 && \
chmod +x /usr/local/bin/jq

# Tell git to forget about all of the files that were not included because of .dockerignore in order to ensure that
# the git state is "clean" even though said .dockerignore files are not present
RUN cat .dockerignore >> .gitignore
Expand Down Expand Up @@ -85,7 +87,7 @@ FROM bitnami/kubectl:1.24.8 as kubectl
FROM gcr.io/distroless/static as argoexec

COPY --from=kubectl /opt/bitnami/kubectl/bin/kubectl /bin/
COPY --from=argoexec-build /usr/bin/jq /bin/
COPY --from=argoexec-build /usr/local/bin/jq /bin/
COPY --from=argoexec-build /go/src/github.com/argoproj/argo-workflows/dist/argoexec /bin/
COPY --from=argoexec-build /etc/mime.types /etc/mime.types
COPY hack/ssh_known_hosts /etc/ssh/
Expand Down
19 changes: 19 additions & 0 deletions test/e2e/resource_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,25 @@ spec:
})
}

func (s *ResourceTemplateSuite) TestResourceTemplateWithOutputs() {
s.Given().
Workflow("@testdata/resource-templates/outputs.yaml").
When().
SubmitWorkflow().
WaitForWorkflow(fixtures.ToBeSucceeded).
Then().
ExpectWorkflow(func(t *testing.T, md *metav1.ObjectMeta, status *wfv1.WorkflowStatus) {
outputs := status.Nodes[md.Name].Outputs
if assert.NotNil(t, outputs) {
parameters := outputs.Parameters
if assert.Len(t, parameters, 2) {
assert.Equal(t, "my-pod", parameters[0].Value.String(), "metadata.name is capture for json")
assert.Equal(t, "my-pod", parameters[1].Value.String(), "metadata.name is capture for jq")
}
}
})
}

func TestResourceTemplateSuite(t *testing.T) {
suite.Run(t, new(ResourceTemplateSuite))
}
31 changes: 31 additions & 0 deletions test/e2e/testdata/resource-templates/outputs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: outputs-
spec:
entrypoint: main
templates:
- name: main
resource:
action: create
setOwnerReference: true
successCondition: status.phase == Succeeded
failureCondition: status.phase == Failed
manifest: |
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: main
image: argoproj/argosay:v2
restartPolicy: Never
outputs:
parameters:
- name: json
valueFrom:
jsonPath: '{.metadata.name}'
- name: jq
valueFrom:
jqFilter: '.metadata.name'
42 changes: 19 additions & 23 deletions workflow/executor/resource.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package executor

import (
"bytes"
"context"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -294,37 +295,32 @@ func (we *WorkflowExecutor) SaveResourceParameters(ctx context.Context, resource
we.Template.Outputs.Parameters[i].Value = wfv1.AnyStringPtr(output)
continue
}
var cmd *exec.Cmd
outputFormat := ""
if param.ValueFrom.JSONPath != "" {
args := []string{"get", resourceName, "-o", fmt.Sprintf("jsonpath=%s", param.ValueFrom.JSONPath)}
if resourceNamespace != "" {
args = append(args, "-n", resourceNamespace)
}
cmd = exec.Command("kubectl", args...)
outputFormat = fmt.Sprintf("jsonpath=%s", param.ValueFrom.JSONPath)
} else if param.ValueFrom.JQFilter != "" {
resArgs := []string{resourceName}
if resourceNamespace != "" {
resArgs = append(resArgs, "-n", resourceNamespace)
}
cmdStr := fmt.Sprintf("kubectl get %s -o json | jq -rc '%s'", strings.Join(resArgs, " "), param.ValueFrom.JQFilter)
cmd = exec.Command(cmdStr)
outputFormat = "json"
} else {
continue
}
log.Info(cmd.Args)
out, err := cmd.Output()
kubectl := exec.Command("kubectl", "-n", resourceNamespace, "get", resourceName, "-o", outputFormat)
out, err := kubectl.Output()
log.WithError(err).WithField("out", string(out)).WithField("args", kubectl.Args).Info("kubectl")
if err != nil {
// We have a default value to use instead of returning an error
if param.ValueFrom.Default != nil {
out = []byte(param.ValueFrom.Default.String())
} else {
if exErr, ok := err.(*exec.ExitError); ok {
log.Errorf("`%s` stderr:\n%s", cmd.Args, string(exErr.Stderr))
}
return errors.InternalWrapError(err)
}
return err
}
output := string(out)
if param.ValueFrom.JQFilter != "" {
jq := exec.Command("jq", "-rc", param.ValueFrom.JQFilter)
jq.Stdin = bytes.NewBuffer(out)
out, err := jq.Output()
log.WithError(err).WithField("out", string(out)).WithField("args", jq.Args).Info("jq")
if err != nil {
return err
}
output = strings.TrimSpace(string(out))
}

we.Template.Outputs.Parameters[i].Value = wfv1.AnyStringPtr(output)
log.Infof("Saved output parameter: %s, value: %s", param.Name, output)
}
Expand Down

0 comments on commit 55e9697

Please sign in to comment.