mirror of
https://github.com/mcuadros/ascode
synced 2024-11-22 17:02:03 +01:00
terraform: plugin manager with provisioner support and tests
Signed-off-by: Máximo Cuadros <mcuadros@gmail.com>
This commit is contained in:
parent
c8eb85ef8f
commit
04ffa10c88
@ -28,7 +28,7 @@ func TestDocumentation(t *testing.T) {
|
||||
func TestDo(t *testing.T) {
|
||||
|
||||
pm := &terraform.PluginManager{".providers"}
|
||||
cli, meta := pm.Get("ignition", "1.1.0")
|
||||
cli, meta := pm.Provider("ignition", "1.1.0")
|
||||
fmt.Println(meta)
|
||||
|
||||
rpc, err := cli.Client()
|
||||
|
@ -49,7 +49,11 @@ type Provider struct {
|
||||
}
|
||||
|
||||
func MakeProvider(pm *terraform.PluginManager, name, version string) (*Provider, error) {
|
||||
cli, meta := pm.Get(name, version)
|
||||
cli, meta, err := pm.Provider(name, version, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rpc, err := cli.Client()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -3,25 +3,62 @@ package terraform
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
"github.com/hashicorp/terraform/command"
|
||||
tfplugin "github.com/hashicorp/terraform/plugin"
|
||||
"github.com/hashicorp/terraform/plugin/discovery"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
// PluginManager is a wrapper arround the terraform tools to download and execute
|
||||
// terraform plugins, like providers and provisioners.
|
||||
type PluginManager struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
func (m *PluginManager) Get(provider, version string) (*plugin.Client, discovery.PluginMeta) {
|
||||
meta, ok := m.getLocal(provider, version)
|
||||
if !ok {
|
||||
meta, ok = m.getRemote(provider, version)
|
||||
// Provider returns a client and the metadata for a given provider and version,
|
||||
// first try to locate the provider in the local path, if not found, it
|
||||
// downloads it from terraform registry. If forceLocal just tries to find
|
||||
// the binary in the local filesystem.
|
||||
func (m *PluginManager) Provider(provider, version string, forceLocal bool) (*plugin.Client, discovery.PluginMeta, error) {
|
||||
meta, ok := m.getLocal("provider", provider, version)
|
||||
if !ok && !forceLocal {
|
||||
var err error
|
||||
meta, ok, err = m.getProviderRemote(provider, version)
|
||||
if err != nil {
|
||||
return nil, discovery.PluginMeta{}, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return client(meta), meta
|
||||
return client(meta), meta, nil
|
||||
}
|
||||
|
||||
// Provisioner returns a client and the metadata for a given provisioner, it
|
||||
// try to locate it at the local Path, if not try to execute it from the
|
||||
// built-in plugins in the terraform binary.
|
||||
func (m *PluginManager) Provisioner(provisioner string) (*plugin.Client, discovery.PluginMeta, error) {
|
||||
meta, ok := m.getLocal("provisioner", provisioner, "")
|
||||
if ok {
|
||||
return client(meta), meta, nil
|
||||
}
|
||||
|
||||
// fallback to terraform internal provisioner.
|
||||
cmdLine, _ := command.BuildPluginCommandString("provisioner", provisioner)
|
||||
cmdArgv := strings.Split(cmdLine, command.TFSPACE)
|
||||
|
||||
// override the internal to the terraform binary.
|
||||
cmdArgv[0] = "terraform"
|
||||
|
||||
meta = discovery.PluginMeta{
|
||||
Name: provisioner,
|
||||
Path: strings.Join(cmdArgv, command.TFSPACE),
|
||||
}
|
||||
|
||||
return client(meta), meta, nil
|
||||
}
|
||||
|
||||
func client(m discovery.PluginMeta) *plugin.Client {
|
||||
@ -31,8 +68,10 @@ func client(m discovery.PluginMeta) *plugin.Client {
|
||||
Output: os.Stderr,
|
||||
})
|
||||
|
||||
cmdArgv := strings.Split(m.Path, command.TFSPACE)
|
||||
|
||||
return plugin.NewClient(&plugin.ClientConfig{
|
||||
Cmd: exec.Command(m.Path),
|
||||
Cmd: exec.Command(cmdArgv[0], cmdArgv[1:]...),
|
||||
HandshakeConfig: tfplugin.Handshake,
|
||||
VersionedPlugins: tfplugin.VersionedPlugins,
|
||||
Managed: true,
|
||||
@ -44,7 +83,7 @@ func client(m discovery.PluginMeta) *plugin.Client {
|
||||
|
||||
const defaultVersionContraint = "> 0"
|
||||
|
||||
func (m *PluginManager) getRemote(provider, v string) (discovery.PluginMeta, bool) {
|
||||
func (m *PluginManager) getProviderRemote(provider, v string) (discovery.PluginMeta, bool, error) {
|
||||
if v == "" {
|
||||
v = defaultVersionContraint
|
||||
}
|
||||
@ -55,16 +94,16 @@ func (m *PluginManager) getRemote(provider, v string) (discovery.PluginMeta, boo
|
||||
Ui: cli.NewMockUi(),
|
||||
}
|
||||
|
||||
pm, _, err := installer.Get(provider, discovery.ConstraintStr(v).MustParse())
|
||||
meta, _, err := installer.Get(provider, discovery.ConstraintStr(v).MustParse())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return discovery.PluginMeta{}, false, err
|
||||
}
|
||||
|
||||
return pm, true
|
||||
return meta, true, nil
|
||||
}
|
||||
|
||||
func (m *PluginManager) getLocal(provider, version string) (discovery.PluginMeta, bool) {
|
||||
set := discovery.FindPlugins("provider", []string{m.Path})
|
||||
func (m *PluginManager) getLocal(kind, provider, version string) (discovery.PluginMeta, bool) {
|
||||
set := discovery.FindPlugins(kind, []string{m.Path})
|
||||
set = set.WithName(provider)
|
||||
if len(set) == 0 {
|
||||
return discovery.PluginMeta{}, false
|
||||
|
64
terraform/plugins_test.go
Normal file
64
terraform/plugins_test.go
Normal file
@ -0,0 +1,64 @@
|
||||
package terraform
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/plugin/discovery"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPluginManager_Provider(t *testing.T) {
|
||||
path, err := ioutil.TempDir("", "provider")
|
||||
assert.NoError(t, err)
|
||||
|
||||
pm := &PluginManager{Path: path}
|
||||
cli, meta, err := pm.Provider("github", "2.1.0", false)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, cli)
|
||||
assert.Equal(t, meta.Version, discovery.VersionStr("2.1.0"))
|
||||
|
||||
cli, meta, err = pm.Provider("github", "2.1.0", true)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, cli)
|
||||
assert.Equal(t, meta.Version, discovery.VersionStr("2.1.0"))
|
||||
|
||||
cli, meta, err = pm.Provider("github", "2.1.0", false)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, cli)
|
||||
assert.Equal(t, meta.Version, discovery.VersionStr("2.1.0"))
|
||||
}
|
||||
|
||||
func TestPluginManager_ProviderDefault(t *testing.T) {
|
||||
path, err := ioutil.TempDir("", "provider")
|
||||
assert.NoError(t, err)
|
||||
|
||||
pm := &PluginManager{Path: path}
|
||||
cli, meta, err := pm.Provider("github", "", false)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, cli)
|
||||
assert.NotEqual(t, meta.Version, discovery.VersionStr("2.1.0"))
|
||||
|
||||
cli, meta, err = pm.Provider("github", "", true)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, cli)
|
||||
assert.NotEqual(t, meta.Version, discovery.VersionStr("2.1.0"))
|
||||
|
||||
fmt.Println(meta.Path)
|
||||
assert.Equal(t, strings.Index(meta.Path, path), 0)
|
||||
}
|
||||
|
||||
func TestPluginManager_ProvisionerDefault(t *testing.T) {
|
||||
path, err := ioutil.TempDir("", "provisioner")
|
||||
assert.NoError(t, err)
|
||||
|
||||
pm := &PluginManager{Path: path}
|
||||
cli, meta, err := pm.Provisioner("file")
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, cli)
|
||||
assert.Equal(t, strings.Index(meta.Path, "terraform-TFSPACE-internal-plugin-"), 0)
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user