github.phpd.cn/hashicorp/packer@v1.3.2/post-processor/checksum/post-processor.go (about)

     1  package checksum
     2  
     3  import (
     4  	"crypto/md5"
     5  	"crypto/sha1"
     6  	"crypto/sha256"
     7  	"crypto/sha512"
     8  	"fmt"
     9  	"hash"
    10  	"io"
    11  	"os"
    12  	"path/filepath"
    13  
    14  	"github.com/hashicorp/packer/common"
    15  	"github.com/hashicorp/packer/helper/config"
    16  	"github.com/hashicorp/packer/packer"
    17  	"github.com/hashicorp/packer/template/interpolate"
    18  )
    19  
    20  type Config struct {
    21  	common.PackerConfig `mapstructure:",squash"`
    22  
    23  	Keep          bool     `mapstructure:"keep_input_artifact"`
    24  	ChecksumTypes []string `mapstructure:"checksum_types"`
    25  	OutputPath    string   `mapstructure:"output"`
    26  	ctx           interpolate.Context
    27  }
    28  
    29  type PostProcessor struct {
    30  	config Config
    31  }
    32  
    33  type outputPathTemplate struct {
    34  	BuildName    string
    35  	BuilderType  string
    36  	ChecksumType string
    37  }
    38  
    39  func getHash(t string) hash.Hash {
    40  	var h hash.Hash
    41  	switch t {
    42  	case "md5":
    43  		h = md5.New()
    44  	case "sha1":
    45  		h = sha1.New()
    46  	case "sha224":
    47  		h = sha256.New224()
    48  	case "sha256":
    49  		h = sha256.New()
    50  	case "sha384":
    51  		h = sha512.New384()
    52  	case "sha512":
    53  		h = sha512.New()
    54  	}
    55  	return h
    56  }
    57  
    58  func (p *PostProcessor) Configure(raws ...interface{}) error {
    59  	err := config.Decode(&p.config, &config.DecodeOpts{
    60  		Interpolate:        true,
    61  		InterpolateContext: &p.config.ctx,
    62  		InterpolateFilter: &interpolate.RenderFilter{
    63  			Exclude: []string{"output"},
    64  		},
    65  	}, raws...)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	errs := new(packer.MultiError)
    70  
    71  	if p.config.ChecksumTypes == nil {
    72  		p.config.ChecksumTypes = []string{"md5"}
    73  	}
    74  
    75  	for _, k := range p.config.ChecksumTypes {
    76  		if h := getHash(k); h == nil {
    77  			errs = packer.MultiErrorAppend(errs,
    78  				fmt.Errorf("Unrecognized checksum type: %s", k))
    79  		}
    80  	}
    81  
    82  	if p.config.OutputPath == "" {
    83  		p.config.OutputPath = "packer_{{.BuildName}}_{{.BuilderType}}_{{.ChecksumType}}.checksum"
    84  	}
    85  
    86  	if err = interpolate.Validate(p.config.OutputPath, &p.config.ctx); err != nil {
    87  		errs = packer.MultiErrorAppend(
    88  			errs, fmt.Errorf("Error parsing target template: %s", err))
    89  	}
    90  
    91  	if len(errs.Errors) > 0 {
    92  		return errs
    93  	}
    94  
    95  	return nil
    96  }
    97  
    98  func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
    99  	files := artifact.Files()
   100  	var h hash.Hash
   101  
   102  	newartifact := NewArtifact(artifact.Files())
   103  	opTpl := &outputPathTemplate{
   104  		BuildName:   p.config.PackerBuildName,
   105  		BuilderType: p.config.PackerBuilderType,
   106  	}
   107  
   108  	for _, ct := range p.config.ChecksumTypes {
   109  		h = getHash(ct)
   110  		opTpl.ChecksumType = ct
   111  		p.config.ctx.Data = &opTpl
   112  
   113  		for _, art := range files {
   114  			checksumFile, err := interpolate.Render(p.config.OutputPath, &p.config.ctx)
   115  			if err != nil {
   116  				return nil, false, err
   117  			}
   118  
   119  			if _, err := os.Stat(checksumFile); err != nil {
   120  				newartifact.files = append(newartifact.files, checksumFile)
   121  			}
   122  			if err := os.MkdirAll(filepath.Dir(checksumFile), os.FileMode(0755)); err != nil {
   123  				return nil, false, fmt.Errorf("unable to create dir: %s", err.Error())
   124  			}
   125  			fw, err := os.OpenFile(checksumFile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(0644))
   126  			if err != nil {
   127  				return nil, false, fmt.Errorf("unable to create file %s: %s", checksumFile, err.Error())
   128  			}
   129  			fr, err := os.Open(art)
   130  			if err != nil {
   131  				fw.Close()
   132  				return nil, false, fmt.Errorf("unable to open file %s: %s", art, err.Error())
   133  			}
   134  
   135  			if _, err = io.Copy(h, fr); err != nil {
   136  				fr.Close()
   137  				fw.Close()
   138  				return nil, false, fmt.Errorf("unable to compute %s hash for %s", ct, art)
   139  			}
   140  			fr.Close()
   141  			fw.WriteString(fmt.Sprintf("%x\t%s\n", h.Sum(nil), filepath.Base(art)))
   142  			fw.Close()
   143  			h.Reset()
   144  		}
   145  	}
   146  
   147  	return newartifact, true, nil
   148  }