Skip to content

Commit

Permalink
Issue #8: Support capturing output artifacts from dynamic fixtures
Browse files Browse the repository at this point in the history
  • Loading branch information
jessesuen committed Aug 23, 2017
1 parent 4a30a16 commit 9031173
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 6 deletions.
42 changes: 42 additions & 0 deletions .argo/test-yamls/fixtures-dynamic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,45 @@ args: ["
resources:
cpu_cores: 0.05
mem_mib: 64
---
type: workflow
version: 1
name: test-fixtures-dynamic-outputs
description: Workflow which exports artifacts produced by dynamic fixtures
inputs:
parameters:
COMMIT:
default: "%%session.commit%%"
REPO:
default: "%%session.repo%%"
fixtures:
- DYN_FIX_WITH_OUTPUTS:
template: test-dynamic-fixture-container-with-outputs
steps:
- WEB-CLIENT-INLINED:
image: alpine:latest
command: [sh, -c]
args: ["sleep 60"]
resources:
cpu_cores: 0.05
mem_mib: 64
outputs:
artifacts:
WF_OUTPUTS:
from: "%%fixtures.DYN_FIX_WITH_OUTPUTS.outputs.artifacts.BIN-DIR%%"

---
type: container
version: 1
name: test-dynamic-fixture-container-with-outputs
image: alpine:latest
command: [sh, -c]
args: ["sleep 999999"]
resources:
cpu_cores: 0.05
mem_mib: 64
outputs:
artifacts:
BIN-DIR:
path: /bin
21 changes: 19 additions & 2 deletions saas/axops/src/applatix.io/axops/service/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,27 @@ func buildReplaceMap(tmpl EmbeddedTemplateIf, arguments template.Arguments) (map
}
}

// For any immediate children of this template, replace usages of %%steps.STEPNAME.outputs.artifacts.ARTNAME%% with concrete services IDs.
// This is only needed with workflows, since containers don't have children, and deployments do not use outputs from child containers
// For any immediate children of this template, replace usages of %%steps.STEPNAME.outputs.artifacts.ARTNAME%% or
// %%fixtures.FIXNAME.outputs.artifacts.ARTNAME%% with concrete services IDs. This is only needed with workflows,
// since containers don't have children, and deployments do not use outputs from child containers
if tmpl.GetType() == template.TemplateTypeWorkflow {
wft := tmpl.(*EmbeddedWorkflowTemplate)
for _, parallelFixtures := range wft.Fixtures {
for fixRefName, ftr := range parallelFixtures {
if !ftr.IsDynamicFixture() {
continue
}
outputs := ftr.Template.GetOutputs()
if outputs == nil {
continue
}
// The following converts %%fixtures.STEP1.outputs.artifacts.ARTNAME%% to %%service.service_id.outputs.artifacts.ARTNAME%%
for artName := range outputs.Artifacts {
serviceOutputRef := fmt.Sprintf("%%%%service.%s.outputs.artifacts.%s%%%%", ftr.Id, artName)
replaceMap[fmt.Sprintf("%%%%fixtures.%s.outputs.artifacts.%s%%%%", fixRefName, artName)] = &serviceOutputRef
}
}
}
for _, parallelSteps := range wft.Steps {
for stepName, step := range parallelSteps {
if step.Template == nil {
Expand Down
2 changes: 1 addition & 1 deletion saas/common/src/applatix.io/template/param.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const (
var (
paramNameRegexStr = "[-0-9A-Za-z_]+"
paramNameRegex = regexp.MustCompile("^[-0-9A-Za-z_]+$")
ouputArtifactRegexp = regexp.MustCompile(`^%%steps\.` + paramNameRegexStr + `\.outputs\.artifacts\.` + paramNameRegexStr + `%%$`)
ouputArtifactRegexp = regexp.MustCompile(`^%%(steps|fixtures)\.` + paramNameRegexStr + `\.outputs\.artifacts\.` + paramNameRegexStr + `%%$`)
VarRegex = regexp.MustCompile("%%[-0-9A-Za-z_]+(\\.[-0-9A-Za-z_]+)*%%")
varRegexExact = regexp.MustCompile("^%%[-0-9A-Za-z_]+(\\.[-0-9A-Za-z_]+)*%%$")
listExpansionParamRegex = regexp.MustCompile("\\$\\$\\[(.*)\\]\\$\\$")
Expand Down
25 changes: 22 additions & 3 deletions saas/common/src/applatix.io/template/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ func (tmpl *WorkflowTemplate) ValidateContext(context *TemplateBuildContext) *ax
// the previous step group to the current scope
scopedParams := tmpl.parametersInScope()

// dynFixtureOutputs keeps track of any outputs produced by dynamic fixtures.
// We will add this to the scope after all steps complete
dynFixtureOutputs := paramMap{}

// Verify any dynamic fixtures. Template references must be container type
for i, parallelFixtures := range tmpl.Fixtures {
for fixRefName, ftr := range parallelFixtures {
Expand All @@ -190,6 +194,15 @@ func (tmpl *WorkflowTemplate) ValidateContext(context *TemplateBuildContext) *ax
if axErr != nil {
return axerror.ERR_AXDB_INVALID_PARAM.NewWithMessagef("fixtures[%d].%s: %v", i, fixRefName, axErr)
}
if ctrTemplate.Outputs != nil {
for artRefName := range ctrTemplate.Outputs.Artifacts {
p := param{
name: fmt.Sprintf("fixtures.%s.outputs.artifacts.%s", fixRefName, artRefName),
paramType: paramTypeArtifact,
}
dynFixtureOutputs[p.name] = p
}
}
}
}

Expand Down Expand Up @@ -271,6 +284,12 @@ func (tmpl *WorkflowTemplate) ValidateContext(context *TemplateBuildContext) *ax
}
}

// Add dynamic fixtures outputs to the scope
axErr := scopedParams.merge(dynFixtureOutputs)
if axErr != nil {
return axErr
}

// Do one last validation of all parameters used in the template
usedParams, axErr := tmpl.usedParameters()
if axErr != nil {
Expand All @@ -281,8 +300,8 @@ func (tmpl *WorkflowTemplate) ValidateContext(context *TemplateBuildContext) *ax
return axErr
}

// See if this workflow is exporting any artifacs. If so, verify that 'from' is
// referencing a valid step, and that step has expected artifact with the name.
// See if this workflow is exporting any artifacts. If so, verify that 'from' is
// referencing a valid step or fixture, and that step has expected artifact with the name.
if tmpl.Outputs != nil && tmpl.Outputs.Artifacts != nil {
for refName, art := range tmpl.Outputs.Artifacts {
if art.Path != "" {
Expand All @@ -292,7 +311,7 @@ func (tmpl *WorkflowTemplate) ValidateContext(context *TemplateBuildContext) *ax
return axerror.ERR_API_INVALID_PARAM.NewWithMessagef("outputs.artifacts.%s.from is required", refName)
}
if !ouputArtifactRegexp.MatchString(art.From) {
return axerror.ERR_API_INVALID_PARAM.NewWithMessagef("outputs.artifacts.%s.from invalid format '%s'. expected format: '%%%%steps.<step_name>.outputs.artifacts.<artifact_name>%%%%'", refName, art.From)
return axerror.ERR_API_INVALID_PARAM.NewWithMessagef("outputs.artifacts.%s.from invalid format '%s'. expected format: '%%%%(steps|fixtures).<REF_NAME>.outputs.artifacts.<ARTIFACT_NAME>%%%%'", refName, art.From)
}
pName := strings.Trim(art.From, "%")
_, ok := scopedParams[pName]
Expand Down

0 comments on commit 9031173

Please sign in to comment.