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