github.phpd.cn/hashicorp/packer@v1.3.2/template/template.go (about)

     1  package template
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/hashicorp/go-multierror"
     9  )
    10  
    11  // Template represents the parsed template that is used to configure
    12  // Packer builds.
    13  type Template struct {
    14  	// Path is the path to the template. This will be blank if Parse is
    15  	// used, but will be automatically populated by ParseFile.
    16  	Path string
    17  
    18  	Description string
    19  	MinVersion  string
    20  
    21  	Variables          map[string]*Variable
    22  	SensitiveVariables []*Variable
    23  	Builders           map[string]*Builder
    24  	Provisioners       []*Provisioner
    25  	PostProcessors     [][]*PostProcessor
    26  	Push               Push
    27  
    28  	// RawContents is just the raw data for this template
    29  	RawContents []byte
    30  }
    31  
    32  // Builder represents a builder configured in the template
    33  type Builder struct {
    34  	Name   string
    35  	Type   string
    36  	Config map[string]interface{}
    37  }
    38  
    39  // PostProcessor represents a post-processor within the template.
    40  type PostProcessor struct {
    41  	OnlyExcept `mapstructure:",squash"`
    42  
    43  	Type              string
    44  	KeepInputArtifact bool `mapstructure:"keep_input_artifact"`
    45  	Config            map[string]interface{}
    46  }
    47  
    48  // Provisioner represents a provisioner within the template.
    49  type Provisioner struct {
    50  	OnlyExcept `mapstructure:",squash"`
    51  
    52  	Type        string
    53  	Config      map[string]interface{}
    54  	Override    map[string]interface{}
    55  	PauseBefore time.Duration `mapstructure:"pause_before"`
    56  }
    57  
    58  // Push represents the configuration for pushing the template to Atlas.
    59  type Push struct {
    60  	Name    string
    61  	Address string
    62  	BaseDir string `mapstructure:"base_dir"`
    63  	Include []string
    64  	Exclude []string
    65  	Token   string
    66  	VCS     bool
    67  }
    68  
    69  // Variable represents a variable within the template
    70  type Variable struct {
    71  	Default  string
    72  	Required bool
    73  }
    74  
    75  // OnlyExcept is a struct that is meant to be embedded that contains the
    76  // logic required for "only" and "except" meta-parameters.
    77  type OnlyExcept struct {
    78  	Only   []string
    79  	Except []string
    80  }
    81  
    82  //-------------------------------------------------------------------
    83  // Functions
    84  //-------------------------------------------------------------------
    85  
    86  // Validate does some basic validation of the template on top of the
    87  // validation that occurs while parsing. If possible, we try to defer
    88  // validation to here. The validation errors that occur during parsing
    89  // are the minimal necessary to make sure parsing builds a reasonable
    90  // Template structure.
    91  func (t *Template) Validate() error {
    92  	var err error
    93  
    94  	// At least one builder must be defined
    95  	if len(t.Builders) == 0 {
    96  		err = multierror.Append(err, errors.New(
    97  			"at least one builder must be defined"))
    98  	}
    99  
   100  	// Verify that the provisioner overrides target builders that exist
   101  	for i, p := range t.Provisioners {
   102  		// Validate only/except
   103  		if verr := p.OnlyExcept.Validate(t); verr != nil {
   104  			for _, e := range multierror.Append(verr).Errors {
   105  				err = multierror.Append(err, fmt.Errorf(
   106  					"provisioner %d: %s", i+1, e))
   107  			}
   108  		}
   109  
   110  		// Validate overrides
   111  		for name := range p.Override {
   112  			if _, ok := t.Builders[name]; !ok {
   113  				err = multierror.Append(err, fmt.Errorf(
   114  					"provisioner %d: override '%s' doesn't exist",
   115  					i+1, name))
   116  			}
   117  		}
   118  	}
   119  
   120  	// Verify post-processors
   121  	for i, chain := range t.PostProcessors {
   122  		for j, p := range chain {
   123  			// Validate only/except
   124  			if verr := p.OnlyExcept.Validate(t); verr != nil {
   125  				for _, e := range multierror.Append(verr).Errors {
   126  					err = multierror.Append(err, fmt.Errorf(
   127  						"post-processor %d.%d: %s", i+1, j+1, e))
   128  				}
   129  			}
   130  		}
   131  	}
   132  
   133  	return err
   134  }
   135  
   136  // Skip says whether or not to skip the build with the given name.
   137  func (o *OnlyExcept) Skip(n string) bool {
   138  	if len(o.Only) > 0 {
   139  		for _, v := range o.Only {
   140  			if v == n {
   141  				return false
   142  			}
   143  		}
   144  
   145  		return true
   146  	}
   147  
   148  	if len(o.Except) > 0 {
   149  		for _, v := range o.Except {
   150  			if v == n {
   151  				return true
   152  			}
   153  		}
   154  
   155  		return false
   156  	}
   157  
   158  	return false
   159  }
   160  
   161  // Validate validates that the OnlyExcept settings are correct for a thing.
   162  func (o *OnlyExcept) Validate(t *Template) error {
   163  	if len(o.Only) > 0 && len(o.Except) > 0 {
   164  		return errors.New("only one of 'only' or 'except' may be specified")
   165  	}
   166  
   167  	var err error
   168  	for _, n := range o.Only {
   169  		if _, ok := t.Builders[n]; !ok {
   170  			err = multierror.Append(err, fmt.Errorf(
   171  				"'only' specified builder '%s' not found", n))
   172  		}
   173  	}
   174  	for _, n := range o.Except {
   175  		if _, ok := t.Builders[n]; !ok {
   176  			err = multierror.Append(err, fmt.Errorf(
   177  				"'except' specified builder '%s' not found", n))
   178  		}
   179  	}
   180  
   181  	return err
   182  }
   183  
   184  //-------------------------------------------------------------------
   185  // GoStringer
   186  //-------------------------------------------------------------------
   187  
   188  func (b *Builder) GoString() string {
   189  	return fmt.Sprintf("*%#v", *b)
   190  }
   191  
   192  func (p *Provisioner) GoString() string {
   193  	return fmt.Sprintf("*%#v", *p)
   194  }
   195  
   196  func (p *PostProcessor) GoString() string {
   197  	return fmt.Sprintf("*%#v", *p)
   198  }
   199  
   200  func (v *Variable) GoString() string {
   201  	return fmt.Sprintf("*%#v", *v)
   202  }