Add Scaleway builder

This commit is contained in:
Edouard BONLIEU 2017-04-06 11:19:17 +02:00 committed by Matthew Hooker
parent 57faecbdd4
commit 7e36cfcff1
No known key found for this signature in database
GPG Key ID: 7B5F933D9CE8C6A1
17 changed files with 1002 additions and 0 deletions

View File

@ -0,0 +1,49 @@
package scaleway
import (
"fmt"
"log"
"github.com/scaleway/scaleway-cli/pkg/api"
)
type Artifact struct {
// The name of the snapshot
snapshotName string
// The ID of the snapshot
snapshotId string
// The name of the region
regionName string
// The client for making API calls
client *api.ScalewayAPI
}
func (*Artifact) BuilderId() string {
return BuilderId
}
func (*Artifact) Files() []string {
// No files with Scaleway
return nil
}
func (a *Artifact) Id() string {
return fmt.Sprintf("%s:%s", a.regionName, a.snapshotId)
}
func (a *Artifact) String() string {
return fmt.Sprintf("A snapshot was created: '%v' (ID: %v) in region '%v'", a.snapshotName, a.snapshotId, a.regionName)
}
func (a *Artifact) State(name string) interface{} {
return nil
}
func (a *Artifact) Destroy() error {
log.Printf("Destroying image: %s (%s)", a.snapshotId, a.snapshotName)
err := a.client.DeleteSnapshot(a.snapshotId)
return err
}

View File

@ -0,0 +1,33 @@
package scaleway
import (
"testing"
"github.com/hashicorp/packer/packer"
)
func TestArtifact_Impl(t *testing.T) {
var raw interface{}
raw = &Artifact{}
if _, ok := raw.(packer.Artifact); !ok {
t.Fatalf("Artifact should be artifact")
}
}
func TestArtifactId(t *testing.T) {
a := &Artifact{"packer-foobar", "cc586e45-5156-4f71-b223-cf406b10dd1c", "ams1", nil}
expected := "ams1:cc586e45-5156-4f71-b223-cf406b10dd1c"
if a.Id() != expected {
t.Fatalf("artifact ID should match: %v", expected)
}
}
func TestArtifactString(t *testing.T) {
a := &Artifact{"packer-foobar", "cc586e45-5156-4f71-b223-cf406b10dd1c", "ams1", nil}
expected := "A snapshot was created: 'packer-foobar' (ID: cc586e45-5156-4f71-b223-cf406b10dd1c) in region 'ams1'"
if a.String() != expected {
t.Fatalf("artifact string should match: %v", expected)
}
}

View File

@ -0,0 +1,89 @@
// The scaleway package contains a packer.Builder implementation
// that builds Scaleway images (snapshots).
package scaleway
import (
"fmt"
"log"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"github.com/scaleway/scaleway-cli/pkg/api"
)
// The unique id for the builder
const BuilderId = "pearkes.scaleway"
type Builder struct {
config Config
runner multistep.Runner
}
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
c, warnings, errs := NewConfig(raws...)
if errs != nil {
return warnings, errs
}
b.config = *c
return nil, nil
}
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
client, _ := api.NewScalewayAPI(b.config.Organization, b.config.Token, b.config.UserAgent, b.config.Region)
state := new(multistep.BasicStateBag)
state.Put("config", b.config)
state.Put("client", client)
state.Put("hook", hook)
state.Put("ui", ui)
steps := []multistep.Step{
&stepCreateSSHKey{
Debug: b.config.PackerDebug,
DebugKeyPath: fmt.Sprintf("scw_%s.pem", b.config.PackerBuildName),
},
new(stepCreateServer),
new(stepServerInfo),
&communicator.StepConnect{
Config: &b.config.Comm,
Host: commHost,
SSHConfig: sshConfig,
},
new(common.StepProvision),
new(stepShutdown),
new(stepSnapshot),
new(stepTerminate),
}
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
b.runner.Run(state)
if rawErr, ok := state.GetOk("error"); ok {
return nil, rawErr.(error)
}
if _, ok := state.GetOk("snapshot_name"); !ok {
log.Println("Failed to find snapshot_name in state. Bug?")
return nil, nil
}
artifact := &Artifact{
snapshotName: state.Get("snapshot_name").(string),
snapshotId: state.Get("snapshot_id").(string),
regionName: state.Get("region").(string),
client: client,
}
return artifact, nil
}
func (b *Builder) Cancel() {
if b.runner != nil {
log.Println("Cancelling the step runner...")
b.runner.Cancel()
}
}

View File

@ -0,0 +1,237 @@
package scaleway
import (
"strconv"
"testing"
"github.com/hashicorp/packer/packer"
)
func testConfig() map[string]interface{} {
return map[string]interface{}{
"api_organization": "foo",
"api_token": "bar",
"region": "ams1",
"commercial_type": "VC1S",
"ssh_username": "root",
"image": "image-uuid",
}
}
func TestBuilder_ImplementsBuilder(t *testing.T) {
var raw interface{}
raw = &Builder{}
if _, ok := raw.(packer.Builder); !ok {
t.Fatalf("Builder should be a builder")
}
}
func TestBuilder_Prepare_BadType(t *testing.T) {
b := &Builder{}
c := map[string]interface{}{
"api_token": []string{},
}
warnings, err := b.Prepare(c)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err == nil {
t.Fatalf("prepare should fail")
}
}
func TestBuilderPrepare_InvalidKey(t *testing.T) {
var b Builder
config := testConfig()
config["i_should_not_be_valid"] = true
warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err == nil {
t.Fatal("should have error")
}
}
func TestBuilderPrepare_Region(t *testing.T) {
var b Builder
config := testConfig()
delete(config, "region")
warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err == nil {
t.Fatalf("should error")
}
expected := "ams1"
config["region"] = expected
b = Builder{}
warnings, err = b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if b.config.Region != expected {
t.Errorf("found %s, expected %s", b.config.Region, expected)
}
}
func TestBuilderPrepare_CommercialType(t *testing.T) {
var b Builder
config := testConfig()
delete(config, "commercial_type")
warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err == nil {
t.Fatalf("should error")
}
expected := "VC1S"
config["commercial_type"] = expected
b = Builder{}
warnings, err = b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if b.config.CommercialType != expected {
t.Errorf("found %s, expected %s", b.config.CommercialType, expected)
}
}
func TestBuilderPrepare_Image(t *testing.T) {
var b Builder
config := testConfig()
delete(config, "image")
warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err == nil {
t.Fatal("should error")
}
expected := "cc586e45-5156-4f71-b223-cf406b10dd1c"
config["image"] = expected
b = Builder{}
warnings, err = b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if b.config.Image != expected {
t.Errorf("found %s, expected %s", b.config.Image, expected)
}
}
func TestBuilderPrepare_SnapshotName(t *testing.T) {
var b Builder
config := testConfig()
warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if b.config.SnapshotName == "" {
t.Errorf("invalid: %s", b.config.SnapshotName)
}
config["snapshot_name"] = "foobarbaz"
b = Builder{}
warnings, err = b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
config["snapshot_name"] = "{{timestamp}}"
b = Builder{}
warnings, err = b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
_, err = strconv.ParseInt(b.config.SnapshotName, 0, 0)
if err != nil {
t.Fatalf("failed to parse int in template: %s", err)
}
}
func TestBuilderPrepare_ServerName(t *testing.T) {
var b Builder
config := testConfig()
warnings, err := b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if b.config.ServerName == "" {
t.Errorf("invalid: %s", b.config.ServerName)
}
config["server_name"] = "foobar"
b = Builder{}
warnings, err = b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
config["server_name"] = "foobar-{{timestamp}}"
b = Builder{}
warnings, err = b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
config["server_name"] = "foobar-{{"
b = Builder{}
warnings, err = b.Prepare(config)
if len(warnings) > 0 {
t.Fatalf("bad: %#v", warnings)
}
if err == nil {
t.Fatal("should have error")
}
}

103
builder/scaleway/config.go Normal file
View File

@ -0,0 +1,103 @@
package scaleway
import (
"errors"
"fmt"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/uuid"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/mapstructure"
)
type Config struct {
common.PackerConfig `mapstructure:",squash"`
Comm communicator.Config `mapstructure:",squash"`
Token string `mapstructure:"api_token"`
Organization string `mapstructure:"api_organization"`
Region string `mapstructure:"region"`
Image string `mapstructure:"image"`
CommercialType string `mapstructure:"commercial_type"`
SnapshotName string `mapstructure:"snapshot_name"`
ServerName string `mapstructure:"server_name"`
UserAgent string
ctx interpolate.Context
}
func NewConfig(raws ...interface{}) (*Config, []string, error) {
c := new(Config)
var md mapstructure.Metadata
err := config.Decode(c, &config.DecodeOpts{
Metadata: &md,
Interpolate: true,
InterpolateContext: &c.ctx,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{
"run_command",
},
},
}, raws...)
if err != nil {
return nil, nil, err
}
c.UserAgent = "Packer - Scaleway builder"
if c.SnapshotName == "" {
def, err := interpolate.Render("packer-{{timestamp}}", nil)
if err != nil {
panic(err)
}
c.SnapshotName = def
}
if c.ServerName == "" {
// Default to packer-[time-ordered-uuid]
c.ServerName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
}
var errs *packer.MultiError
if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
errs = packer.MultiErrorAppend(errs, es...)
}
if c.Organization == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("Scaleway Organization ID must be specified"))
}
if c.Token == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("Scaleway Token must be specified"))
}
if c.Region == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("region is required"))
}
if c.CommercialType == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("commercial type is required"))
}
if c.Image == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("image is required"))
}
if errs != nil && len(errs.Errors) > 0 {
return nil, nil, errs
}
common.ScrubConfig(c, c.Token)
return c, nil, nil
}

30
builder/scaleway/ssh.go Normal file
View File

@ -0,0 +1,30 @@
package scaleway
import (
"fmt"
"golang.org/x/crypto/ssh"
"github.com/mitchellh/multistep"
)
func commHost(state multistep.StateBag) (string, error) {
ipAddress := state.Get("server_ip").(string)
return ipAddress, nil
}
func sshConfig(state multistep.StateBag) (*ssh.ClientConfig, error) {
config := state.Get("config").(Config)
privateKey := state.Get("privateKey").(string)
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
}
return &ssh.ClientConfig{
User: config.Comm.SSHUsername,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
}, nil
}

View File

@ -0,0 +1,61 @@
package scaleway
import (
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"github.com/scaleway/scaleway-cli/pkg/api"
"strings"
)
type stepCreateServer struct {
serverId string
}
func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*api.ScalewayAPI)
ui := state.Get("ui").(packer.Ui)
c := state.Get("config").(Config)
sshPubKey := state.Get("ssh_pubkey").(string)
ui.Say("Creating server...")
server, err := client.PostServer(api.ScalewayServerDefinition{
Name: c.ServerName,
Image: &c.Image,
Organization: c.Organization,
CommercialType: c.CommercialType,
Tags: []string{fmt.Sprintf("AUTHORIZED_KEY=%s", strings.TrimSpace(sshPubKey))},
})
err = client.PostServerAction(server, "poweron")
if err != nil {
err := fmt.Errorf("Error creating server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
s.serverId = server
state.Put("server_id", server)
return multistep.ActionContinue
}
func (s *stepCreateServer) Cleanup(state multistep.StateBag) {
if s.serverId != "" {
return
}
client := state.Get("client").(*api.ScalewayAPI)
ui := state.Get("ui").(packer.Ui)
ui.Say("Destroying server...")
err := client.PostServerAction(s.serverId, "terminate")
if err != nil {
ui.Error(fmt.Sprintf(
"Error destroying server. Please destroy it manually: %s", err))
}
}

View File

@ -0,0 +1,88 @@
package scaleway
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"os"
"runtime"
"strings"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"golang.org/x/crypto/ssh"
)
type stepCreateSSHKey struct {
Debug bool
DebugKeyPath string
}
func (s *stepCreateSSHKey) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
ui.Say("Creating temporary ssh key for server...")
priv, err := rsa.GenerateKey(rand.Reader, 2014)
if err != nil {
err := fmt.Errorf("Error creating temporary SSH key: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
// ASN.1 DER encoded form
priv_der := x509.MarshalPKCS1PrivateKey(priv)
priv_blk := pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil,
Bytes: priv_der,
}
// Set the private key in the statebag for later
state.Put("privateKey", string(pem.EncodeToMemory(&priv_blk)))
pub, _ := ssh.NewPublicKey(&priv.PublicKey)
pub_sshformat := string(ssh.MarshalAuthorizedKey(pub))
pub_sshformat = strings.Replace(pub_sshformat, " ", "_", -1)
log.Printf("temporary ssh key created")
// Remember some state for the future
state.Put("ssh_pubkey", string(pub_sshformat))
// If we're in debug mode, output the private key to the working directory.
if s.Debug {
ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath))
f, err := os.Create(s.DebugKeyPath)
if err != nil {
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
return multistep.ActionHalt
}
defer f.Close()
// Write the key out
if _, err := f.Write(pem.EncodeToMemory(&priv_blk)); err != nil {
state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
return multistep.ActionHalt
}
// Chmod it so that it is SSH ready
if runtime.GOOS != "windows" {
if err := f.Chmod(0600); err != nil {
state.Put("error", fmt.Errorf("Error setting permissions of debug key: %s", err))
return multistep.ActionHalt
}
}
}
return multistep.ActionContinue
}
func (s *stepCreateSSHKey) Cleanup(state multistep.StateBag) {
// SSH key is passed via tag. Nothing to do here.
return
}

View File

@ -0,0 +1,44 @@
package scaleway
import (
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"github.com/scaleway/scaleway-cli/pkg/api"
)
type stepServerInfo struct{}
func (s *stepServerInfo) Run(state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*api.ScalewayAPI)
ui := state.Get("ui").(packer.Ui)
serverID := state.Get("server_id").(string)
ui.Say("Waiting for server to become active...")
_, err := api.WaitForServerState(client, serverID, "running")
if err != nil {
err := fmt.Errorf("Error waiting for server to become booted: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
server, err := client.GetServer(serverID)
if err != nil {
err := fmt.Errorf("Error retrieving server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
state.Put("server_ip", server.PublicAddress.IP)
state.Put("root_volume_id", server.Volumes["0"].Identifier)
return multistep.ActionContinue
}
func (s *stepServerInfo) Cleanup(state multistep.StateBag) {
// no cleanup
}

View File

@ -0,0 +1,43 @@
package scaleway
import (
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"github.com/scaleway/scaleway-cli/pkg/api"
)
type stepShutdown struct{}
func (s *stepShutdown) Run(state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*api.ScalewayAPI)
ui := state.Get("ui").(packer.Ui)
serverId := state.Get("server_id").(string)
ui.Say("Shutting down server...")
err := client.PostServerAction(serverId, "poweroff")
if err != nil {
err := fmt.Errorf("Error stopping server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
_, err = api.WaitForServerState(client, serverId, "stopped")
if err != nil {
err := fmt.Errorf("Error shutting down server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *stepShutdown) Cleanup(state multistep.StateBag) {
// no cleanup
}

View File

@ -0,0 +1,48 @@
package scaleway
import (
"fmt"
"log"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"github.com/scaleway/scaleway-cli/pkg/api"
)
type stepSnapshot struct{}
func (s *stepSnapshot) Run(state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*api.ScalewayAPI)
ui := state.Get("ui").(packer.Ui)
c := state.Get("config").(Config)
volumeId := state.Get("root_volume_id").(string)
ui.Say(fmt.Sprintf("Creating snapshot: %v", c.SnapshotName))
snapshot, err := client.PostSnapshot(volumeId, c.SnapshotName)
if err != nil {
err := fmt.Errorf("Error creating snapshot: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
log.Printf("Looking up snapshot ID for snapshot: %s", c.SnapshotName)
_, err = client.GetSnapshot(snapshot)
if err != nil {
err := fmt.Errorf("Error looking up snapshot ID: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
log.Printf("Snapshot ID: %s", snapshot)
state.Put("snapshot_id", snapshot)
state.Put("snapshot_name", c.SnapshotName)
state.Put("region", c.Region)
return multistep.ActionContinue
}
func (s *stepSnapshot) Cleanup(state multistep.StateBag) {
// no cleanup
}

View File

@ -0,0 +1,34 @@
package scaleway
import (
"fmt"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"github.com/scaleway/scaleway-cli/pkg/api"
)
type stepTerminate struct{}
func (s *stepTerminate) Run(state multistep.StateBag) multistep.StepAction {
client := state.Get("client").(*api.ScalewayAPI)
ui := state.Get("ui").(packer.Ui)
serverId := state.Get("server_id").(string)
ui.Say("Terminating server...")
err := client.DeleteServerForce(serverId)
if err != nil {
err := fmt.Errorf("Error terminating server: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *stepTerminate) Cleanup(state multistep.StateBag) {
// no cleanup
}

View File

@ -39,6 +39,7 @@ import (
parallelspvmbuilder "github.com/hashicorp/packer/builder/parallels/pvm"
profitbricksbuilder "github.com/hashicorp/packer/builder/profitbricks"
qemubuilder "github.com/hashicorp/packer/builder/qemu"
scalewaybuilder "github.com/hashicorp/packer/builder/scaleway"
tritonbuilder "github.com/hashicorp/packer/builder/triton"
virtualboxisobuilder "github.com/hashicorp/packer/builder/virtualbox/iso"
virtualboxovfbuilder "github.com/hashicorp/packer/builder/virtualbox/ovf"
@ -108,6 +109,7 @@ var Builders = map[string]packer.Builder{
"parallels-pvm": new(parallelspvmbuilder.Builder),
"profitbricks": new(profitbricksbuilder.Builder),
"qemu": new(qemubuilder.Builder),
"scaleway": new(scalewaybuilder.Builder),
"triton": new(tritonbuilder.Builder),
"virtualbox-iso": new(virtualboxisobuilder.Builder),
"virtualbox-ovf": new(virtualboxovfbuilder.Builder),

View File

@ -189,6 +189,8 @@ func providerFromBuilderName(name string) string {
switch name {
case "aws":
return "aws"
case "scaleway":
return "scaleway"
case "digitalocean":
return "digitalocean"
case "virtualbox":

View File

@ -26,6 +26,7 @@ var builtins = map[string]string{
"mitchellh.vmware-esx": "vmware",
"pearkes.digitalocean": "digitalocean",
"packer.googlecompute": "google",
"pearkes.scaleway": "scaleway",
"packer.parallels": "parallels",
"MSOpenTech.hyperv": "hyperv",
"transcend.qemu": "libvirt",
@ -221,6 +222,8 @@ func providerForName(name string) Provider {
switch name {
case "aws":
return new(AWSProvider)
case "scaleway":
return new(ScalewayProvider)
case "digitalocean":
return new(DigitalOceanProvider)
case "virtualbox":

View File

@ -0,0 +1,52 @@
package vagrant
import (
"bytes"
"fmt"
"github.com/hashicorp/packer/packer"
"strings"
"text/template"
)
type scalewayVagrantfileTemplate struct {
Image string ""
Region string ""
}
type ScalewayProvider struct{}
func (p *ScalewayProvider) KeepInputArtifact() bool {
return true
}
func (p *ScalewayProvider) Process(ui packer.Ui, artifact packer.Artifact, dir string) (vagrantfile string, metadata map[string]interface{}, err error) {
// Create the metadata
metadata = map[string]interface{}{"provider": "scaleway"}
// Determine the image and region...
tplData := &scalewayVagrantfileTemplate{}
parts := strings.Split(artifact.Id(), ":")
if len(parts) != 2 {
err = fmt.Errorf("Poorly formatted artifact ID: %s", artifact.Id())
return
}
tplData.Region = parts[0]
tplData.Image = parts[1]
// Build up the Vagrantfile
var contents bytes.Buffer
t := template.Must(template.New("vf").Parse(defaultScalewayVagrantfile))
err = t.Execute(&contents, tplData)
vagrantfile = contents.String()
return
}
var defaultScalewayVagrantfile = `
Vagrant.configure("2") do |config|
config.vm.provider :scaleway do |scaleway|
scaleway.image = "{{ .Image }}"
scaleway.region = "{{ .Region }}"
end
end
`

84
vendor/vendor.json vendored
View File

@ -233,6 +233,12 @@
"revision": "c2e73f942591b0f033a3c6df00f44badb2347c38",
"revisionTime": "2018-01-10T05:50:12Z"
},
{
"checksumSHA1": "8dVO3L8yAdQ17X3lAhIziyF3OFk=",
"path": "github.com/Sirupsen/logrus",
"revision": "10f801ebc38b33738c9d17d50860f484a0988ff5",
"revisionTime": "2017-03-17T14:32:14Z"
},
{
"checksumSHA1": "HttiPj314X1a0i2Jen1p6lRH/vE=",
"path": "github.com/aliyun/aliyun-oss-go-sdk/oss",
@ -589,6 +595,12 @@
"path": "github.com/biogo/hts/bgzf",
"revision": "50da7d4131a3b5c9d063932461cab4d1fafb20b0"
},
{
"checksumSHA1": "bFj0ceSRvaFFCfmS4el1PjWhcgw=",
"path": "github.com/creack/goselect",
"revision": "1bd5ca702c6154bccc56ecd598932ee8b295cab2",
"revisionTime": "2016-07-14T17:28:59Z"
},
{
"checksumSHA1": "Lf3uUXTkKK5DJ37BxQvxO1Fq+K8=",
"comment": "v1.0.0-3-g6d21280",
@ -638,6 +650,24 @@
"revision": "4c04abe183f449bd9ede285f0e5c7ee575d0dbe4",
"revisionTime": "2017-04-07T15:15:42Z"
},
{
"checksumSHA1": "1n5MBJthemxmfqU2gN3qLCd8s04=",
"path": "github.com/docker/docker/pkg/namesgenerator",
"revision": "fa3e2d5ab9b577cecd24201902bbe72b3f1b851c",
"revisionTime": "2017-04-06T12:40:27Z"
},
{
"checksumSHA1": "lThih54jzz9A4zHKEFb9SIV3Ed0=",
"path": "github.com/docker/docker/pkg/random",
"revision": "fa3e2d5ab9b577cecd24201902bbe72b3f1b851c",
"revisionTime": "2017-04-06T12:40:27Z"
},
{
"checksumSHA1": "rhLUtXvcmouYuBwOq9X/nYKzvNg=",
"path": "github.com/dustin/go-humanize",
"revision": "259d2a102b871d17f30e3cd9881a642961a1e486",
"revisionTime": "2017-02-28T07:34:54Z"
},
{
"checksumSHA1": "GCskdwYAPW2S34918Z5CgNMJ2Wc=",
"path": "github.com/dylanmei/iso8601",
@ -779,6 +809,12 @@
"revision": "95a28eb606def6aaaed082b6b82d3244b0552184",
"revisionTime": "2017-06-23T01:44:30Z"
},
{
"checksumSHA1": "xSmii71kfQASGNG2C8ttmHx9KTE=",
"path": "github.com/gorilla/websocket",
"revision": "a91eba7f97777409bc2c443f5534d41dd20c5720",
"revisionTime": "2017-03-19T17:27:27Z"
},
{
"checksumSHA1": "izBSRxLAHN+a/XpAku0in05UzlY=",
"comment": "20141209094003-92-g95fa852",
@ -1032,6 +1068,18 @@
"path": "github.com/mitchellh/reflectwalk",
"revision": "eecf4c70c626c7cfbb95c90195bc34d386c74ac6"
},
{
"checksumSHA1": "KhOVzKefFYORHdIVe+/gNAHB23A=",
"path": "github.com/moul/anonuuid",
"revision": "609b752a95effbbef26d134ac18ed6f57e01b98e",
"revisionTime": "2016-02-22T16:21:17Z"
},
{
"checksumSHA1": "WcXDSYIAP73RAvy22iD57nE/peI=",
"path": "github.com/moul/gotty-client",
"revision": "99224eea3278d662fce9124bb2bf6c2bb39f5160",
"revisionTime": "2017-02-05T09:54:39Z"
},
{
"checksumSHA1": "gcLub3oB+u4QrOJZcYmk/y2AP4k=",
"path": "github.com/nu7hatch/gouuid",
@ -1117,6 +1165,12 @@
"revision": "7bdb11aecb0e457ea23c86898c6b49bfc0eb4bb1",
"revisionTime": "2017-08-01T13:52:49Z"
},
{
"checksumSHA1": "DF3jZEw4lCq/SEaC7DIl/R+7S70=",
"path": "github.com/renstrom/fuzzysearch/fuzzy",
"revision": "2d205ac6ec17a839a94bdbfd16d2fa6c6dada2e0",
"revisionTime": "2016-03-31T20:48:55Z"
},
{
"checksumSHA1": "zmC8/3V4ls53DJlNTKDZwPSC/dA=",
"path": "github.com/satori/go.uuid",
@ -1129,6 +1183,24 @@
"revision": "5bf94b69c6b68ee1b541973bb8e1144db23a194b",
"revisionTime": "2017-03-21T23:07:31Z"
},
{
"checksumSHA1": "FFhSGe3Y3J1laR/6rwSS7U2esrk=",
"path": "github.com/scaleway/scaleway-cli/pkg/api",
"revision": "e50cb485747a4f25a361c90ef3ba05be79944c56",
"revisionTime": "2017-04-03T16:01:47Z"
},
{
"checksumSHA1": "kveaAmNlnvmIIuEkFcMlB+N7TqY=",
"path": "github.com/scaleway/scaleway-cli/pkg/sshcommand",
"revision": "e50cb485747a4f25a361c90ef3ba05be79944c56",
"revisionTime": "2017-04-03T16:01:47Z"
},
{
"checksumSHA1": "xM3G5ct9YYYnVIL3XMRrcf41xVw=",
"path": "github.com/scaleway/scaleway-cli/pkg/utils",
"revision": "e50cb485747a4f25a361c90ef3ba05be79944c56",
"revisionTime": "2017-04-03T16:01:47Z"
},
{
"checksumSHA1": "iydUphwYqZRq3WhstEdGsbvBAKs=",
"comment": "v1.1.4-4-g976c720",
@ -1281,6 +1353,12 @@
"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
"revisionTime": "2017-02-08T20:51:15Z"
},
{
"checksumSHA1": "xiderUuvye8Kpn7yX3niiJg32bE=",
"path": "golang.org/x/crypto/ssh/terminal",
"revision": "c2303dcbe84172e0c0da4c9f083eeca54c06f298",
"revisionTime": "2017-01-17T19:20:27Z"
},
{
"checksumSHA1": "GtamqiJoL7PGHsN454AoffBFMa8=",
"path": "golang.org/x/net/context",
@ -1342,6 +1420,12 @@
"path": "golang.org/x/oauth2/jwt",
"revision": "8a57ed94ffd43444c0879fe75701732a38afc985"
},
{
"checksumSHA1": "S0DP7Pn7sZUmXc55IzZnNvERu6s=",
"path": "golang.org/x/sync/errgroup",
"revision": "5a06fca2c336a4b2b2fcb45702e8c47621b2aa2c",
"revisionTime": "2017-03-17T17:13:11Z"
},
{
"checksumSHA1": "NzQ3QYllWwK+3GZliu11jMU6xwo=",
"path": "golang.org/x/sys/unix",