github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/fly/commands/internal/templatehelpers/yaml_template.go (about) 1 package templatehelpers 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 7 "github.com/pf-qiu/concourse/v6/atc" 8 "github.com/pf-qiu/concourse/v6/fly/commands/internal/flaghelpers" 9 "github.com/pf-qiu/concourse/v6/vars" 10 "sigs.k8s.io/yaml" 11 ) 12 13 type YamlTemplateWithParams struct { 14 filePath atc.PathFlag 15 templateVariablesFiles []atc.PathFlag 16 templateVariables []flaghelpers.VariablePairFlag 17 yamlTemplateVariables []flaghelpers.YAMLVariablePairFlag 18 instanceVars atc.InstanceVars 19 } 20 21 func NewYamlTemplateWithParams( 22 filePath atc.PathFlag, 23 templateVariablesFiles []atc.PathFlag, 24 templateVariables []flaghelpers.VariablePairFlag, 25 yamlTemplateVariables []flaghelpers.YAMLVariablePairFlag, 26 instanceVars atc.InstanceVars, 27 ) YamlTemplateWithParams { 28 return YamlTemplateWithParams{ 29 filePath: filePath, 30 templateVariablesFiles: templateVariablesFiles, 31 templateVariables: templateVariables, 32 yamlTemplateVariables: yamlTemplateVariables, 33 instanceVars: instanceVars, 34 } 35 } 36 37 func (yamlTemplate YamlTemplateWithParams) Evaluate( 38 allowEmpty bool, 39 strict bool, 40 ) ([]byte, error) { 41 config, err := ioutil.ReadFile(string(yamlTemplate.filePath)) 42 if err != nil { 43 return nil, fmt.Errorf("could not read file: %s", err.Error()) 44 } 45 46 if strict { 47 // We use a generic map here, since templates are not evaluated yet. 48 // (else a template string may cause an error when a struct is expected) 49 // If we don't check Strict now, then the subsequent steps will mask any 50 // duplicate key errors. 51 // We should consider being strict throughout the entire stack by default. 52 err = yaml.UnmarshalStrict(config, make(map[string]interface{})) 53 if err != nil { 54 return nil, fmt.Errorf("error parsing yaml before applying templates: %s", err.Error()) 55 } 56 } 57 58 var params []vars.Variables 59 60 // first, we take explicitly specified variables on the command line 61 var flagVarPairs vars.KVPairs 62 for _, f := range yamlTemplate.templateVariables { 63 flagVarPairs = append(flagVarPairs, vars.KVPair(f)) 64 } 65 for _, f := range yamlTemplate.yamlTemplateVariables { 66 flagVarPairs = append(flagVarPairs, vars.KVPair(f)) 67 } 68 69 instanceVarPairs := vars.StaticVariables(yamlTemplate.instanceVars).Flatten() 70 flagVarPairs = append(flagVarPairs, instanceVarPairs...) 71 72 params = append(params, flagVarPairs.Expand()) 73 74 // second, we take all files. with values in the files specified later on command line taking precedence over the 75 // same values in the files specified earlier on command line 76 for i := len(yamlTemplate.templateVariablesFiles) - 1; i >= 0; i-- { 77 path := yamlTemplate.templateVariablesFiles[i] 78 templateVars, err := ioutil.ReadFile(string(path)) 79 if err != nil { 80 return nil, fmt.Errorf("could not read template variables file (%s): %s", string(path), err.Error()) 81 } 82 83 var staticVars vars.StaticVariables 84 err = yaml.Unmarshal(templateVars, &staticVars) 85 if err != nil { 86 return nil, fmt.Errorf("could not unmarshal template variables (%s): %s", string(path), err.Error()) 87 } 88 89 params = append(params, staticVars) 90 } 91 92 evaluatedConfig, err := vars.NewTemplateResolver(config, params).Resolve(false, allowEmpty) 93 if err != nil { 94 return nil, err 95 } 96 97 return evaluatedConfig, nil 98 }