Skip to content

Commit

Permalink
add pkr plugin check cmd from packer core (#85)
Browse files Browse the repository at this point in the history
This is simplified to not pull in core as a dep. The drawback is that we don't actually start plugins to verify that it works with Packer and has a ConfigSpec func. We do start a binary, though. But, I think this is fine since if a plugin implements describe then we can be pretty sure it uses the SDK's function and interfaces.

Related to hashicorp/packer#11317

closes hashicorp/packer#11309
  • Loading branch information
azr authored Oct 11, 2021
1 parent b688c9d commit fef2ec6
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 0 deletions.
5 changes: 5 additions & 0 deletions cmd/packer-sdc/internal/plugincheck/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## `plugin-check`

`plugin-check` will check wether a plugin binary seems to work with packer.

Use: `packer-sdc plugin-check packer-plugin-happy-cloud`
117 changes: 117 additions & 0 deletions cmd/packer-sdc/internal/plugincheck/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package plugincheck

import (
_ "embed"
"encoding/json"
"fmt"
"log"
"os/exec"
"path/filepath"
"strings"

"github.com/pkg/errors"
)

var (
//go:embed README.md
readme string
)

type Command struct {
}

func (cmd *Command) Help() string {
return "\n" + readme
}

func (cmd *Command) Run(args []string) int {
if err := cmd.run(args); err != nil {
log.Printf("%v", err)
return 1
}
return 0
}

func (cmd *Command) run(args []string) error {

if len(args) != 1 {
cmd.Help()
return errors.New("plugin-check requires a plugin binary name as an argument.\n" +
"ex: 'packer-plugin-happycloud'. Check will be run on the binary.")
}

pluginName := args[0]

if isOldPlugin(pluginName) {
fmt.Printf("\n[WARNING] Plugin is named with old prefix `packer-[builder|provisioner|post-processor]-{name})`. " +
"These will be detected but Packer cannot install them automatically. " +
"The plugin must be a multi-component plugin named packer-plugin-{name} to be installable through the `packer init` command.\n" +
"See docs at: https://www.packer.io/docs/plugins.\n")
return nil
}

if err := checkPluginName(pluginName); err != nil {
return err
}

path, err := filepath.Abs(pluginName)
if err != nil {
return err
}

output, err := exec.Command(path, "describe").Output()
if err != nil {
return errors.Wrap(err, "failed to describe plugin")
}

desc := pluginDescription{}
err = json.Unmarshal(output, &desc)
if err != nil {
return errors.Wrap(err, "failed to json.Unmarshal plugin description")
}
if len(desc.Version) == 0 {
return errors.New("Version needs to be set")
}
if len(desc.SDKVersion) == 0 {
return errors.New("SDKVersion needs to be set")
}
if len(desc.APIVersion) == 0 {
return errors.New("APIVersion needs to be set")
}

if len(desc.Builders) == 0 && len(desc.PostProcessors) == 0 && len(desc.Datasources) == 0 {
return errors.New("this plugin defines no component.")
}
return nil
}

type pluginDescription struct {
Version string `json:"version"`
SDKVersion string `json:"sdk_version"`
APIVersion string `json:"api_version"`
Builders []string `json:"builders"`
PostProcessors []string `json:"post_processors"`
Datasources []string `json:"datasources"`
}

func isOldPlugin(pluginName string) bool {
return strings.HasPrefix(pluginName, "packer-builder-") ||
strings.HasPrefix(pluginName, "packer-provisioner-") ||
strings.HasPrefix(pluginName, "packer-post-processor-")
}

// checkPluginName checks for the possible valid names for a plugin,
// packer-plugin-* or packer-[builder|provisioner|post-processor]-*. If the name
// is prefixed with `packer-[builder|provisioner|post-processor]-`, packer won't
// be able to install it, therefore a WARNING will be shown.
func checkPluginName(name string) error {
if strings.HasPrefix(name, "packer-plugin-") {
return nil
}

return fmt.Errorf("plugin name is not valid")
}

func (cmd *Command) Synopsis() string {
return "Tell wether a plugin release looks valid for Packer."
}
4 changes: 4 additions & 0 deletions cmd/packer-sdc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"

mapstructure_to_hcl2 "github.com/hashicorp/packer-plugin-sdk/cmd/packer-sdc/internal/mapstructure-to-hcl2"
"github.com/hashicorp/packer-plugin-sdk/cmd/packer-sdc/internal/plugincheck"
"github.com/hashicorp/packer-plugin-sdk/cmd/packer-sdc/internal/renderdocs"
struct_markdown "github.com/hashicorp/packer-plugin-sdk/cmd/packer-sdc/internal/struct-markdown"
"github.com/hashicorp/packer-plugin-sdk/version"
Expand Down Expand Up @@ -37,6 +38,9 @@ func main() {
"renderdocs": func() (cli.Command, error) {
return &renderdocs.Command{}, nil
},
"plugin-check": func() (cli.Command, error) {
return &plugincheck.Command{}, nil
},
}

exitStatus, err := c.Run()
Expand Down

0 comments on commit fef2ec6

Please sign in to comment.