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 }