mirror of
https://github.com/hashicorp/packer.git
synced 2026-11-05 03:48:27 -05:00
* fix: run make generate to fix test errors (#13719) * ci: bump lock-threads to v6 so the scheduled lock job can run (#13693) The pinned version validates its github-token input with a 100 character cap, and the Actions token now exceeds that, so every run fails before locking anything: ##[error]"github-token" length must be less than or equal to 100 characters long v6 raised the cap to 1000 (v4 and v5.0.x both still validate max(100)). Every input this workflow passes exists unchanged in the v6 schema, so the pin bump is the whole fix. Pinned to the v6.0.2 release commit. Co-authored-by: Tushar Pagar <[email protected]> * build(deps): bump the actions group across 1 directory with 7 updates (#13720) Bumps the actions group with 7 updates in the / directory: | Package | From | To | | --- | --- | --- | | [aws-actions/configure-aws-credentials](https://github.com/aws-actions/configure-aws-credentials) | `6.2.3` | `6.3.0` | | [hashicorp/actions-generate-metadata](https://github.com/hashicorp/actions-generate-metadata) | `1.1.4` | `1.3.1` | | [actions/upload-artifact](https://github.com/actions/upload-artifact) | `7.0.1` | `7.0.2` | | [hashicorp/actions-go-build](https://github.com/hashicorp/actions-go-build) | `1.1.2` | `1.1.3` | | [hashicorp/actions-docker-build](https://github.com/hashicorp/actions-docker-build) | `2.2.1` | `2.3.0` | | [github/issue-labeler](https://github.com/github/issue-labeler) | `3.4` | `3.5` | | [actions/download-artifact](https://github.com/actions/download-artifact) | `8.0.1` | `8.0.2` | Updates `aws-actions/configure-aws-credentials` from 6.2.3 to 6.3.0 - [Release notes](https://github.com/aws-actions/configure-aws-credentials/releases) - [Changelog](https://github.com/aws-actions/configure-aws-credentials/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws-actions/configure-aws-credentials/compare/e6de054238d6b7531b4efff3b6587d9aade6a06c...e1253824e5c10ff9df46874f81ed3ec929e19cfd) Updates `hashicorp/actions-generate-metadata` from 1.1.4 to 1.3.1 - [Release notes](https://github.com/hashicorp/actions-generate-metadata/releases) - [Commits](https://github.com/hashicorp/actions-generate-metadata/compare/a43468dfb100445f2c2aa52cdc3d57b2c982a0f3...aff2981e4d616c852cf7652a8019e719e7a1cce0) Updates `actions/upload-artifact` from 7.0.1 to 7.0.2 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/043fb46d1a93c77aae656e7c1c64a875d1fc6a0a...cf430e030ddbb5b0abf93d22962f4752f3646cd9) Updates `hashicorp/actions-go-build` from 1.1.2 to 1.1.3 - [Release notes](https://github.com/hashicorp/actions-go-build/releases) - [Changelog](https://github.com/hashicorp/actions-go-build/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/actions-go-build/compare/dd7ca5a30c402c933e1fe61e0ff7165e5c4ee9e4...3f078f63a57c91c3e07285183d22e47869fe0dce) Updates `hashicorp/actions-docker-build` from 2.2.1 to 2.3.0 - [Release notes](https://github.com/hashicorp/actions-docker-build/releases) - [Changelog](https://github.com/hashicorp/actions-docker-build/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/actions-docker-build/compare/e12557abf02a40557313ab2839d6cd2c6705261e...595f29357108da6d4767b6a48e5f01f25de0c131) Updates `github/issue-labeler` from 3.4 to 3.5 - [Release notes](https://github.com/github/issue-labeler/releases) - [Commits](https://github.com/github/issue-labeler/compare/c1b0f9f52a63158c4adc09425e858e87b32e9685...ccca1e16fcb66762200e616fc29b57b940c1cb67) Updates `actions/download-artifact` from 8.0.1 to 8.0.2 - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c...9000827ccba6bdab643e8b6fd33ac0654aef8333) --- updated-dependencies: - dependency-name: aws-actions/configure-aws-credentials dependency-version: 6.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: hashicorp/actions-generate-metadata dependency-version: 1.3.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: actions/upload-artifact dependency-version: 7.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: hashicorp/actions-go-build dependency-version: 1.1.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: hashicorp/actions-docker-build dependency-version: 2.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: github/issue-labeler dependency-version: '3.5' dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: actions/download-artifact dependency-version: 8.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * [COMPLIANCE] Add/Update Copyright Headers (#13718) * [COMPLIANCE] Add/Update Copyright Headers * fix: add the copyright header to the source file --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com> Co-authored-by: Taru Garg <[email protected]> * build(deps): bump github.com/hashicorp/hcp-sdk-go (#13722) Bumps [github.com/hashicorp/hcp-sdk-go](https://github.com/hashicorp/hcp-sdk-go) from 0.175.0 to 0.176.0. - [Release notes](https://github.com/hashicorp/hcp-sdk-go/releases) - [Changelog](https://github.com/hashicorp/hcp-sdk-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/hcp-sdk-go/compare/v0.175.0...v0.176.0) --- updated-dependencies: - dependency-name: github.com/hashicorp/hcp-sdk-go dependency-version: 0.176.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update dependencies in plugin_tester module (#13728) - Bump Go version from 1.26.8 to 1.26.10 - Upgrade github.com/hashicorp/hcl/v2 from v2.24.0 to v2.25.0 - Upgrade github.com/hashicorp/packer-plugin-sdk from v0.6.11 to v0.6.13 - Upgrade github.com/zclconf/go-cty from v1.18.1 to v1.19.0 - Add indirect dependencies for aws-sdk-go-v2 and related packages - Upgrade various indirect dependencies including golang.org/x/crypto, golang.org/x/net, and golang.org/x/text - Remove deprecated dependency on github.com/jmespath/go-jmespath * changelog: update to version 1.16.2 with bug fixes, improvements, and dependency updates --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Taru Garg <[email protected]> Co-authored-by: Tushar Pagar <[email protected]> Co-authored-by: Tushar Pagar <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
412 lines
11 KiB
Go
Executable File
412 lines
11 KiB
Go
Executable File
// Copyright IBM Corp. 2024, 2026
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
// Generate Plugins is a small program that updates the lists of plugins in
|
|
// command/plugin.go so they will be compiled into the main packer binary.
|
|
//
|
|
// See https://github.com/hashicorp/packer/pull/2608 for details.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
|
|
"golang.org/x/tools/imports"
|
|
)
|
|
|
|
const target = "command/execute.go"
|
|
|
|
func main() {
|
|
wd, _ := os.Getwd()
|
|
if filepath.Base(wd) != "packer" {
|
|
log.Fatalf("This program must be invoked in the packer project root; in %s", wd)
|
|
}
|
|
|
|
// Collect all of the data we need about plugins we have in the project
|
|
builders, err := discoverBuilders()
|
|
if err != nil {
|
|
log.Fatalf("Failed to discover builders: %s", err)
|
|
}
|
|
|
|
provisioners, err := discoverProvisioners()
|
|
if err != nil {
|
|
log.Fatalf("Failed to discover provisioners: %s", err)
|
|
}
|
|
|
|
postProcessors, err := discoverPostProcessors()
|
|
if err != nil {
|
|
log.Fatalf("Failed to discover post processors: %s", err)
|
|
}
|
|
|
|
datasources, err := discoverDatasources()
|
|
if err != nil {
|
|
log.Fatalf("Failed to discover Datasources: %s", err)
|
|
}
|
|
|
|
// Do some simple code generation and templating
|
|
output := source
|
|
output = strings.Replace(output, "IMPORTS", makeImports(builders, provisioners, postProcessors, datasources), 1)
|
|
output = strings.Replace(output, "BUILDERS", makeMap("Builders", "Builder", builders), 1)
|
|
output = strings.Replace(output, "PROVISIONERS", makeMap("Provisioners", "Provisioner", provisioners), 1)
|
|
output = strings.Replace(output, "POSTPROCESSORS", makeMap("PostProcessors", "PostProcessor", postProcessors), 1)
|
|
output = strings.Replace(output, "DATASOURCES", makeMap("Datasources", "Datasource", datasources), 1)
|
|
|
|
// TODO sort the lists of plugins so we are not subjected to random OS ordering of the plugin lists
|
|
// TODO format the file
|
|
|
|
// Write our generated code to the command/plugin.go file
|
|
file, err := os.Create(target)
|
|
if err != nil {
|
|
log.Fatalf("Failed to open %s for writing: %s", target, err)
|
|
}
|
|
defer file.Close()
|
|
|
|
output = string(goFmt(target, []byte(output)))
|
|
|
|
_, err = file.WriteString(output)
|
|
if err != nil {
|
|
log.Fatalf("Failed writing to %s: %s", target, err)
|
|
}
|
|
|
|
log.Printf("Generated %s", target)
|
|
}
|
|
|
|
func goFmt(filename string, b []byte) []byte {
|
|
fb, err := imports.Process(filename, b, nil)
|
|
if err != nil {
|
|
log.Printf("formatting err: %v", err)
|
|
return b
|
|
}
|
|
return fb
|
|
}
|
|
|
|
type plugin struct {
|
|
Package string // This plugin's package name (iso)
|
|
PluginName string // Name of plugin (vmware-iso)
|
|
TypeName string // Type of plugin (builder)
|
|
Path string // Path relative to packer root (builder/vmware/iso)
|
|
ImportName string // PluginName+TypeName (vmwareisobuilder)
|
|
}
|
|
|
|
// makeMap creates a map named Name with type packer.Name that looks something
|
|
// like this:
|
|
//
|
|
// var Builders = map[string]packersdk.Builder{
|
|
// "amazon-chroot": new(chroot.Builder),
|
|
// "amazon-ebs": new(ebs.Builder),
|
|
// "amazon-instance": new(instance.Builder),
|
|
func makeMap(varName, varType string, items []plugin) string {
|
|
output := ""
|
|
|
|
output += fmt.Sprintf("var %s = map[string]packersdk.%s{\n", varName, varType)
|
|
for _, item := range items {
|
|
output += fmt.Sprintf("\t\"%s\": new(%s.%s),\n", item.PluginName, item.ImportName, item.TypeName)
|
|
}
|
|
output += "}\n"
|
|
return output
|
|
}
|
|
|
|
func makeImports(builders, provisioners, postProcessors, Datasources []plugin) string {
|
|
plugins := []string{}
|
|
|
|
for _, builder := range builders {
|
|
plugins = append(plugins, fmt.Sprintf("\t%s \"github.com/hashicorp/packer/%s\"\n", builder.ImportName, filepath.ToSlash(builder.Path)))
|
|
}
|
|
|
|
for _, provisioner := range provisioners {
|
|
plugins = append(plugins, fmt.Sprintf("\t%s \"github.com/hashicorp/packer/%s\"\n", provisioner.ImportName, filepath.ToSlash(provisioner.Path)))
|
|
}
|
|
|
|
for _, postProcessor := range postProcessors {
|
|
plugins = append(plugins, fmt.Sprintf("\t%s \"github.com/hashicorp/packer/%s\"\n", postProcessor.ImportName, filepath.ToSlash(postProcessor.Path)))
|
|
}
|
|
|
|
for _, datasource := range Datasources {
|
|
plugins = append(plugins, fmt.Sprintf("\t%s \"github.com/hashicorp/packer/%s\"\n", datasource.ImportName, filepath.ToSlash(datasource.Path)))
|
|
}
|
|
|
|
// Make things pretty
|
|
sort.Strings(plugins)
|
|
|
|
return strings.Join(plugins, "")
|
|
}
|
|
|
|
// listDirectories recursively lists directories under the specified path
|
|
func listDirectories(path string) ([]string, error) {
|
|
names := []string{}
|
|
items, err := os.ReadDir(path)
|
|
if err != nil {
|
|
return names, err
|
|
}
|
|
|
|
for _, item := range items {
|
|
// We only want directories
|
|
if !item.IsDir() ||
|
|
item.Name() == "common" {
|
|
continue
|
|
}
|
|
currentDir := filepath.Join(path, item.Name())
|
|
names = append(names, currentDir)
|
|
|
|
// Do some recursion
|
|
subNames, err := listDirectories(currentDir)
|
|
if err == nil {
|
|
names = append(names, subNames...)
|
|
}
|
|
}
|
|
|
|
return names, nil
|
|
}
|
|
|
|
// deriveName determines the name of the plugin (what you'll see in a packer
|
|
// template) based on the filesystem path. We use two rules:
|
|
//
|
|
// Start with -> builder/virtualbox/iso
|
|
//
|
|
// 1. Strip the root -> virtualbox/iso
|
|
// 2. Switch slash / to dash - -> virtualbox-iso
|
|
func deriveName(root, full string) string {
|
|
short, _ := filepath.Rel(root, full)
|
|
bits := strings.Split(short, string(os.PathSeparator))
|
|
return strings.Join(bits, "-")
|
|
}
|
|
|
|
// deriveImport will build a unique import identifier based on packageName and
|
|
// the result of deriveName()
|
|
//
|
|
// This will be something like -> virtualboxisobuilder
|
|
//
|
|
// Which is long, but deterministic and unique.
|
|
func deriveImport(typeName, derivedName string) string {
|
|
return strings.Replace(derivedName, "-", "", -1) + strings.ToLower(typeName)
|
|
}
|
|
|
|
// discoverTypesInPath searches for types of typeID in path and returns a list
|
|
// of plugins it finds.
|
|
func discoverTypesInPath(path, typeID string) ([]plugin, error) {
|
|
postProcessors := []plugin{}
|
|
|
|
dirs, err := listDirectories(path)
|
|
if err != nil {
|
|
return postProcessors, err
|
|
}
|
|
|
|
for _, dir := range dirs {
|
|
fset := token.NewFileSet()
|
|
goPackages, err := parser.ParseDir(fset, dir, nil, parser.AllErrors)
|
|
if err != nil {
|
|
return postProcessors, fmt.Errorf("Failed parsing directory %s: %s", dir, err)
|
|
}
|
|
|
|
for _, goPackage := range goPackages {
|
|
ast.PackageExports(goPackage)
|
|
ast.Inspect(goPackage, func(n ast.Node) bool {
|
|
switch x := n.(type) {
|
|
case *ast.TypeSpec:
|
|
if x.Name.Name == typeID {
|
|
derivedName := deriveName(path, dir)
|
|
postProcessors = append(postProcessors, plugin{
|
|
Package: goPackage.Name,
|
|
PluginName: derivedName,
|
|
ImportName: deriveImport(x.Name.Name, derivedName),
|
|
TypeName: x.Name.Name,
|
|
Path: dir,
|
|
})
|
|
// The AST stops parsing when we return false. Once we
|
|
// find the symbol we want we can stop parsing.
|
|
|
|
// DEBUG:
|
|
// fmt.Printf("package %#v\n", goPackage)
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
}
|
|
|
|
return postProcessors, nil
|
|
}
|
|
|
|
func discoverBuilders() ([]plugin, error) {
|
|
path := "./builder"
|
|
typeID := "Builder"
|
|
return discoverTypesInPath(path, typeID)
|
|
}
|
|
|
|
func discoverDatasources() ([]plugin, error) {
|
|
path := "./datasource"
|
|
typeID := "Datasource"
|
|
return discoverTypesInPath(path, typeID)
|
|
}
|
|
|
|
func discoverProvisioners() ([]plugin, error) {
|
|
path := "./provisioner"
|
|
typeID := "Provisioner"
|
|
return discoverTypesInPath(path, typeID)
|
|
}
|
|
|
|
func discoverPostProcessors() ([]plugin, error) {
|
|
path := "./post-processor"
|
|
typeID := "PostProcessor"
|
|
return discoverTypesInPath(path, typeID)
|
|
}
|
|
|
|
const source = `// Copyright IBM Corp. 2024, 2026
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
//
|
|
// This file is automatically generated by scripts/generate-plugins.go -- Do not edit!
|
|
//
|
|
|
|
package command
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/packer/packer"
|
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
|
"github.com/hashicorp/packer-plugin-sdk/plugin"
|
|
"github.com/hashicorp/packer-plugin-sdk/rpc"
|
|
|
|
IMPORTS
|
|
)
|
|
|
|
type ExecuteCommand struct {
|
|
Meta
|
|
}
|
|
|
|
BUILDERS
|
|
|
|
PROVISIONERS
|
|
|
|
POSTPROCESSORS
|
|
|
|
DATASOURCES
|
|
|
|
var pluginRegexp = regexp.MustCompile("packer-(builder|post-processor|provisioner|datasource)-(.+)")
|
|
|
|
type ExecuteArgs struct {
|
|
UseProtobuf bool
|
|
CommandType string
|
|
}
|
|
|
|
func (ea *ExecuteArgs) AddFlagSets(flags *flag.FlagSet) {
|
|
flags.BoolVar(&ea.UseProtobuf, "protobuf", false, "Use protobuf for serialising data over the wire instead of gob")
|
|
}
|
|
|
|
func (c *ExecuteCommand) ParseArgs(args []string) (*ExecuteArgs, int) {
|
|
var cfg ExecuteArgs
|
|
flags := c.Meta.FlagSet("")
|
|
flags.Usage = func() { c.Ui.Say(c.Help()) }
|
|
cfg.AddFlagSets(flags)
|
|
if err := flags.Parse(args); err != nil {
|
|
return &cfg, 1
|
|
}
|
|
|
|
args = flags.Args()
|
|
if len(args) != 1 {
|
|
flags.Usage()
|
|
return &cfg, 1
|
|
}
|
|
cfg.CommandType = args[0]
|
|
return &cfg, 0
|
|
}
|
|
|
|
func (c *ExecuteCommand) Run(args []string) int {
|
|
cfg, ret := c.ParseArgs(args)
|
|
if ret != 0 {
|
|
return ret
|
|
}
|
|
|
|
return c.RunContext(cfg)
|
|
}
|
|
|
|
|
|
func (c *ExecuteCommand) RunContext(args *ExecuteArgs) int {
|
|
// Plugin will match something like "packer-builder-amazon-ebs"
|
|
parts := pluginRegexp.FindStringSubmatch(args.CommandType)
|
|
if len(parts) != 3 {
|
|
c.Ui.Error(c.Help())
|
|
return 1
|
|
}
|
|
pluginType := parts[1] // capture group 1 (builder|post-processor|provisioner)
|
|
pluginName := parts[2] // capture group 2 (.+)
|
|
|
|
server, err := plugin.Server()
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf("Error starting plugin server: %s", err))
|
|
return 1
|
|
}
|
|
|
|
if args.UseProtobuf {
|
|
server.UseProto = true
|
|
}
|
|
|
|
switch pluginType {
|
|
case "builder":
|
|
builder, found := Builders[pluginName]
|
|
if !found {
|
|
c.Ui.Error(fmt.Sprintf("Could not load builder: %s", pluginName))
|
|
return 1
|
|
}
|
|
server.RegisterBuilder(builder)
|
|
case "provisioner":
|
|
provisioner, found := Provisioners[pluginName]
|
|
if !found {
|
|
c.Ui.Error(fmt.Sprintf("Could not load provisioner: %s", pluginName))
|
|
return 1
|
|
}
|
|
server.RegisterProvisioner(provisioner)
|
|
case "post-processor":
|
|
postProcessor, found := PostProcessors[pluginName]
|
|
if !found {
|
|
c.Ui.Error(fmt.Sprintf("Could not load post-processor: %s", pluginName))
|
|
return 1
|
|
}
|
|
server.RegisterPostProcessor(postProcessor)
|
|
case "datasource":
|
|
datasource, found := Datasources[pluginName]
|
|
if !found {
|
|
c.Ui.Error(fmt.Sprintf("Could not load datasource: %s", pluginName))
|
|
return 1
|
|
}
|
|
server.RegisterDatasource(datasource)
|
|
}
|
|
|
|
server.Serve()
|
|
|
|
return 0
|
|
}
|
|
|
|
func (*ExecuteCommand) Help() string {
|
|
helpText := ` + "`" + `
|
|
Usage: packer execute [options] PLUGIN
|
|
|
|
Runs an internally-compiled version of a plugin from the packer binary.
|
|
|
|
NOTE: this is an internal command and you should not call it yourself.
|
|
|
|
Options:
|
|
|
|
--protobuf: use protobuf for serialising data over-the-wire instead of gob.
|
|
` + "`" + `
|
|
|
|
return strings.TrimSpace(helpText)
|
|
}
|
|
|
|
func (c *ExecuteCommand) Synopsis() string {
|
|
return "internal plugin command"
|
|
}
|
|
`
|