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  }