mirror of https://github.com/hashicorp/packer
Add `packer plugins` command and subcommands to interact with plugins (#11553)
* add basic docs for plugins command * refactor docs Co-Authored-By: Wilken Rivera <1749304+nywilken@users.noreply.github.com> * add plugins command * add plugins subcommands they do nothing for now * add plugins installed command + tests * add plugins install command * add remove plugin command * better docs for the plugins install command * remove duplicate content * better output for installed plugins * add plugins required command * Update plugins_install.go * add newline after `Usage:` * Update plugins_remove.go * Update plugins_required.go * Update plugins_remove.go * Update plugins_installed.go * Update plugins_install.go * add docs * Update plugins_install.go * fix typos * Update plugins_test.go * fix typos Co-Authored-By: Wilken Rivera <1749304+nywilken@users.noreply.github.com> * Update core_wrapper.go Co-Authored-By: Wilken Rivera <1749304+nywilken@users.noreply.github.com> * Update website/content/docs/commands/plugins/remove.mdx Co-authored-by: Wilken Rivera <wilken@hashicorp.com> * Update website/content/docs/commands/plugins/required.mdx Co-authored-by: Wilken Rivera <wilken@hashicorp.com> * Update website/content/docs/commands/plugins/required.mdx Co-authored-by: Wilken Rivera <wilken@hashicorp.com> * Update plugins_required.go * Update install.mdx * Update required.mdx * plugins requirement, warn when no plugin was found * Update website/content/docs/commands/plugins/required.mdx Co-authored-by: Wilken Rivera <wilken@hashicorp.com> Co-authored-by: Wilken Rivera <1749304+nywilken@users.noreply.github.com> Co-authored-by: Wilken Rivera <wilken@hashicorp.com>pull/11561/head
parent
759cadaf0d
commit
9f4a1281dd
@ -0,0 +1,32 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
type PluginsCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (c *PluginsCommand) Synopsis() string {
|
||||
return "Interact with Packer plugins and catalog"
|
||||
}
|
||||
|
||||
func (c *PluginsCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: packer plugins <subcommand> [options] [args]
|
||||
This command groups subcommands for interacting with Packer plugins.
|
||||
|
||||
Related but not under the "plugins" command :
|
||||
|
||||
- "packer init <path>" will install all plugins required by a config.
|
||||
`
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *PluginsCommand) Run(args []string) int {
|
||||
return cli.RunResultHelp
|
||||
}
|
||||
@ -0,0 +1,124 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
pluginsdk "github.com/hashicorp/packer-plugin-sdk/plugin"
|
||||
"github.com/hashicorp/packer/hcl2template/addrs"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
plugingetter "github.com/hashicorp/packer/packer/plugin-getter"
|
||||
"github.com/hashicorp/packer/packer/plugin-getter/github"
|
||||
pkrversion "github.com/hashicorp/packer/version"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
type PluginsInstallCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (c *PluginsInstallCommand) Synopsis() string {
|
||||
return "Install latest Packer plugin [matching version constraint]"
|
||||
}
|
||||
|
||||
func (c *PluginsInstallCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: packer plugins install <plugin> [<version constraint>]
|
||||
|
||||
This command will install the most recent compatible Packer plugin matching
|
||||
version constraint.
|
||||
When the version constraint is omitted, the most recent version will be
|
||||
installed.
|
||||
|
||||
Ex: packer plugins install github.com/hashicorp/happycloud v1.2.3
|
||||
`
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *PluginsInstallCommand) Run(args []string) int {
|
||||
ctx, cleanup := handleTermInterrupt(c.Ui)
|
||||
defer cleanup()
|
||||
|
||||
return c.RunContext(ctx, args)
|
||||
}
|
||||
|
||||
func (c *PluginsInstallCommand) RunContext(buildCtx context.Context, args []string) int {
|
||||
if len(args) < 1 || len(args) > 2 {
|
||||
return cli.RunResultHelp
|
||||
}
|
||||
|
||||
opts := plugingetter.ListInstallationsOptions{
|
||||
FromFolders: c.Meta.CoreConfig.Components.PluginConfig.KnownPluginFolders,
|
||||
BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{
|
||||
OS: runtime.GOOS,
|
||||
ARCH: runtime.GOARCH,
|
||||
APIVersionMajor: pluginsdk.APIVersionMajor,
|
||||
APIVersionMinor: pluginsdk.APIVersionMinor,
|
||||
Checksummers: []plugingetter.Checksummer{
|
||||
{Type: "sha256", Hash: sha256.New()},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
plugin, diags := addrs.ParsePluginSourceString(args[0])
|
||||
if diags.HasErrors() {
|
||||
c.Ui.Error(diags.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
// a plugin requirement that matches them all
|
||||
pluginRequirement := plugingetter.Requirement{
|
||||
Identifier: plugin,
|
||||
Implicit: false,
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
constraints, err := version.NewConstraint(args[1])
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
pluginRequirement.VersionConstraints = constraints
|
||||
}
|
||||
|
||||
getters := []plugingetter.Getter{
|
||||
&github.Getter{
|
||||
// In the past some terraform plugins downloads were blocked from a
|
||||
// specific aws region by s3. Changing the user agent unblocked the
|
||||
// downloads so having one user agent per version will help mitigate
|
||||
// that a little more. Especially in the case someone forks this
|
||||
// code to make it more aggressive or something.
|
||||
// TODO: allow to set this from the config file or an environment
|
||||
// variable.
|
||||
UserAgent: "packer-getter-github-" + pkrversion.String(),
|
||||
},
|
||||
}
|
||||
|
||||
newInstall, err := pluginRequirement.InstallLatest(plugingetter.InstallOptions{
|
||||
InFolders: opts.FromFolders,
|
||||
BinaryInstallationOptions: opts.BinaryInstallationOptions,
|
||||
Getters: getters,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
if newInstall != nil {
|
||||
msg := fmt.Sprintf("Installed plugin %s %s in %q", pluginRequirement.Identifier, newInstall.Version, newInstall.BinaryPath)
|
||||
ui := &packer.ColoredUi{
|
||||
Color: packer.UiColorCyan,
|
||||
Ui: c.Ui,
|
||||
}
|
||||
ui.Say(msg)
|
||||
return 0
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"log"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
plugingetter "github.com/hashicorp/packer/packer/plugin-getter"
|
||||
)
|
||||
|
||||
type PluginsInstalledCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (c *PluginsInstalledCommand) Synopsis() string {
|
||||
return "List all installed Packer plugin binaries"
|
||||
}
|
||||
|
||||
func (c *PluginsInstalledCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: packer plugins installed
|
||||
|
||||
This command lists all installed plugin binaries that match with the current
|
||||
OS and architecture. Packer's API version will be ignored.
|
||||
|
||||
`
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *PluginsInstalledCommand) Run(args []string) int {
|
||||
ctx, cleanup := handleTermInterrupt(c.Ui)
|
||||
defer cleanup()
|
||||
|
||||
return c.RunContext(ctx)
|
||||
}
|
||||
|
||||
func (c *PluginsInstalledCommand) RunContext(buildCtx context.Context) int {
|
||||
|
||||
opts := plugingetter.ListInstallationsOptions{
|
||||
FromFolders: c.Meta.CoreConfig.Components.PluginConfig.KnownPluginFolders,
|
||||
BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{
|
||||
OS: runtime.GOOS,
|
||||
ARCH: runtime.GOARCH,
|
||||
Checksummers: []plugingetter.Checksummer{
|
||||
{Type: "sha256", Hash: sha256.New()},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" && opts.Ext == "" {
|
||||
opts.BinaryInstallationOptions.Ext = ".exe"
|
||||
}
|
||||
|
||||
log.Printf("[TRACE] init: %#v", opts)
|
||||
|
||||
// a plugin requirement that matches them all
|
||||
allPlugins := plugingetter.Requirement{
|
||||
Accessor: "",
|
||||
VersionConstraints: nil,
|
||||
Identifier: nil,
|
||||
Implicit: false,
|
||||
}
|
||||
|
||||
installations, err := allPlugins.ListInstallations(opts)
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
for _, installation := range installations {
|
||||
c.Ui.Message(installation.BinaryPath)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/packer/hcl2template/addrs"
|
||||
plugingetter "github.com/hashicorp/packer/packer/plugin-getter"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
type PluginsRemoveCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (c *PluginsRemoveCommand) Synopsis() string {
|
||||
return "Remove Packer plugins [matching a version]"
|
||||
}
|
||||
|
||||
func (c *PluginsRemoveCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: packer plugins remove <plugin> [<version constraint>]
|
||||
|
||||
This command will remove all Packer plugins matching the version constraint
|
||||
for the current OS and architecture.
|
||||
When the version is omitted all installed versions will be removed.
|
||||
|
||||
Ex: packer plugins remove github.com/hashicorp/happycloud v1.2.3
|
||||
`
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *PluginsRemoveCommand) Run(args []string) int {
|
||||
ctx, cleanup := handleTermInterrupt(c.Ui)
|
||||
defer cleanup()
|
||||
|
||||
return c.RunContext(ctx, args)
|
||||
}
|
||||
|
||||
func (c *PluginsRemoveCommand) RunContext(buildCtx context.Context, args []string) int {
|
||||
if len(args) < 1 || len(args) > 2 {
|
||||
return cli.RunResultHelp
|
||||
}
|
||||
|
||||
opts := plugingetter.ListInstallationsOptions{
|
||||
FromFolders: c.Meta.CoreConfig.Components.PluginConfig.KnownPluginFolders,
|
||||
BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{
|
||||
OS: runtime.GOOS,
|
||||
ARCH: runtime.GOARCH,
|
||||
Checksummers: []plugingetter.Checksummer{
|
||||
{Type: "sha256", Hash: sha256.New()},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
plugin, diags := addrs.ParsePluginSourceString(args[0])
|
||||
if diags.HasErrors() {
|
||||
c.Ui.Error(diags.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
// a plugin requirement that matches them all
|
||||
pluginRequirement := plugingetter.Requirement{
|
||||
Identifier: plugin,
|
||||
Implicit: false,
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
constraints, err := version.NewConstraint(args[1])
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
pluginRequirement.VersionConstraints = constraints
|
||||
}
|
||||
|
||||
installations, err := pluginRequirement.ListInstallations(opts)
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
for _, installation := range installations {
|
||||
if err := os.Remove(installation.BinaryPath); err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
c.Ui.Message(installation.BinaryPath)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
pluginsdk "github.com/hashicorp/packer-plugin-sdk/plugin"
|
||||
plugingetter "github.com/hashicorp/packer/packer/plugin-getter"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
type PluginsRequiredCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (c *PluginsRequiredCommand) Synopsis() string {
|
||||
return "List plugins required by a config"
|
||||
}
|
||||
|
||||
func (c *PluginsRequiredCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: packer plugins required <path>
|
||||
|
||||
This command will list every Packer plugin required by a Packer config, in
|
||||
packer.required_plugins blocks. All binaries matching the required version
|
||||
constrain and the current OS and Architecture will be listed. The most recent
|
||||
version (and the first of the list) will be the one picked by Packer during a
|
||||
build.
|
||||
|
||||
Ex: packer plugins required require.pkr.hcl
|
||||
Ex: packer plugins required path/to/folder/
|
||||
`
|
||||
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *PluginsRequiredCommand) Run(args []string) int {
|
||||
ctx, cleanup := handleTermInterrupt(c.Ui)
|
||||
defer cleanup()
|
||||
|
||||
cfg, ret := c.ParseArgs(args)
|
||||
if ret != 0 {
|
||||
return ret
|
||||
}
|
||||
|
||||
return c.RunContext(ctx, cfg)
|
||||
}
|
||||
|
||||
func (c *PluginsRequiredCommand) ParseArgs(args []string) (*PluginsRequiredArgs, int) {
|
||||
var cfg PluginsRequiredArgs
|
||||
flags := c.Meta.FlagSet("plugins required", 0)
|
||||
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 {
|
||||
return &cfg, cli.RunResultHelp
|
||||
}
|
||||
cfg.Path = args[0]
|
||||
return &cfg, 0
|
||||
}
|
||||
|
||||
func (c *PluginsRequiredCommand) RunContext(buildCtx context.Context, cla *PluginsRequiredArgs) int {
|
||||
|
||||
packerStarter, ret := c.GetConfig(&cla.MetaArgs)
|
||||
if ret != 0 {
|
||||
return ret
|
||||
}
|
||||
|
||||
// Get plugins requirements
|
||||
reqs, diags := packerStarter.PluginRequirements()
|
||||
ret = writeDiags(c.Ui, nil, diags)
|
||||
if ret != 0 {
|
||||
return ret
|
||||
}
|
||||
|
||||
opts := plugingetter.ListInstallationsOptions{
|
||||
FromFolders: c.Meta.CoreConfig.Components.PluginConfig.KnownPluginFolders,
|
||||
BinaryInstallationOptions: plugingetter.BinaryInstallationOptions{
|
||||
OS: runtime.GOOS,
|
||||
ARCH: runtime.GOARCH,
|
||||
APIVersionMajor: pluginsdk.APIVersionMajor,
|
||||
APIVersionMinor: pluginsdk.APIVersionMinor,
|
||||
Checksummers: []plugingetter.Checksummer{
|
||||
{Type: "sha256", Hash: sha256.New()},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, pluginRequirement := range reqs {
|
||||
s := fmt.Sprintf("%s %s %q", pluginRequirement.Accessor, pluginRequirement.Identifier.String(), pluginRequirement.VersionConstraints.String())
|
||||
installs, err := pluginRequirement.ListInstallations(opts)
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
for _, install := range installs {
|
||||
s += fmt.Sprintf(" %s", install.BinaryPath)
|
||||
}
|
||||
c.Ui.Message(s)
|
||||
}
|
||||
|
||||
if len(reqs) == 0 {
|
||||
c.Ui.Message(`
|
||||
No plugins requirement found, make sure you reference a Packer config
|
||||
containing a packer.required_plugins block. See
|
||||
https://www.packer.io/docs/templates/hcl_templates/blocks/packer
|
||||
for more info.`)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
---
|
||||
description: |
|
||||
The "plugin" command groups subcommands for interacting with
|
||||
Packer's plugin and the plugin catalog.
|
||||
page_title: plugins Command
|
||||
---
|
||||
|
||||
# `plugins`
|
||||
|
||||
The `plugins` command groups subcommands for interacting with Packers' plugins.
|
||||
|
||||
```shell-session
|
||||
$ packer plugins -h
|
||||
Usage: packer plugins <subcommand> [options] [args]
|
||||
This command groups subcommands for interacting with Packer plugins.
|
||||
|
||||
Related but not under the "plugins" command :
|
||||
|
||||
- "packer init <path>" will install all plugins required by a config.
|
||||
|
||||
Subcommands:
|
||||
install Install latest Packer plugin [matching version constraint]
|
||||
installed List all installed Packer plugin binaries
|
||||
remove Remove Packer plugins [matching a version]
|
||||
required List plugins required by a config
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [`packer init`](/docs/commands/init) will install all required plugins.
|
||||
@ -0,0 +1,24 @@
|
||||
---
|
||||
description: |
|
||||
The "plugins install" command can install a plugin at a version constraint.
|
||||
page_title: plugins Command
|
||||
---
|
||||
|
||||
# `plugins install`
|
||||
|
||||
The `plugins install` subcommand installs a Packer plugin at a version constraint
|
||||
|
||||
```shell-session
|
||||
$ packer plugins install -h
|
||||
Usage: packer plugins install <plugin> [<version constraint>]
|
||||
|
||||
This command will install the most recent compatible Packer plugin matching
|
||||
version constraint. When the version constraint is omitted, the most recent
|
||||
version will be installed.
|
||||
|
||||
Ex: packer plugins install github.com/hashicorp/happycloud v1.2.3
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [`packer init`](/docs/commands/init) will install all required plugins.
|
||||
@ -0,0 +1,21 @@
|
||||
---
|
||||
description: |
|
||||
The "plugins installed" command will list installed plugins.
|
||||
page_title: plugins Command
|
||||
---
|
||||
|
||||
# `plugins installed`
|
||||
|
||||
The `plugins installed` subcommand lists installed Packer plugins
|
||||
|
||||
```shell-session
|
||||
$ packer plugins installed -h
|
||||
Usage: packer plugins installed
|
||||
|
||||
This command lists all installed plugin binaries that match with the current
|
||||
OS and architecture. Packer's API version will be ignored.
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [`packer init`](/docs/commands/init) will install all required plugins.
|
||||
@ -0,0 +1,24 @@
|
||||
---
|
||||
description: |
|
||||
The "plugins remove" command can remove a plugin at a version constraint.
|
||||
page_title: plugins Command
|
||||
---
|
||||
|
||||
# `plugins remove`
|
||||
|
||||
The `plugins remove` subcommand removes a Packer plugin at a version constraint
|
||||
|
||||
```shell-session
|
||||
$ packer plugins remove -h
|
||||
Usage: packer plugins remove <plugin> [<version constraint>]
|
||||
|
||||
This command will remove all Packer plugins matching the version constraint
|
||||
for the current OS and architecture.
|
||||
When the version is omitted all installed versions will be removed.
|
||||
|
||||
Ex: packer plugins remove github.com/hashicorp/happycloud v1.2.3
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [`packer init`](/docs/commands/init) will install all required plugins.
|
||||
@ -0,0 +1,30 @@
|
||||
---
|
||||
description: |
|
||||
The "plugins required" command lists all plugins required in a Packer configuration.
|
||||
page_title: plugins Command
|
||||
---
|
||||
|
||||
# `plugins required`
|
||||
|
||||
The `plugins required` command lists all plugins required by a Packer config and
|
||||
all the installed binaries that match the constraint. The first binary
|
||||
is the most up-to-date installed version and will be the one picked by Packer in a build.
|
||||
|
||||
```shell-session
|
||||
$ packer plugins required -h
|
||||
Usage: packer plugins required <path>
|
||||
|
||||
This command will list every Packer plugin required by a Packer config, in
|
||||
packer.required_plugins blocks. All binaries matching the required version
|
||||
constrain and the current OS and Architecture will be listed. The most recent
|
||||
version (and the first of the list) will be the one picked by Packer during a
|
||||
build.
|
||||
|
||||
|
||||
Ex: packer plugins required require.pkr.hcl
|
||||
Ex: packer plugins required path/to/folder/
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [`packer init`](/docs/commands/init) will install all required plugins.
|
||||
Loading…
Reference in new issue