Add image creation from snapshot
Rename organization_id / access_key Update test / doc
This commit is contained in:
parent
9b611af7e6
commit
1fb13cc23e
|
@ -8,11 +8,17 @@ import (
|
|||
)
|
||||
|
||||
type Artifact struct {
|
||||
// The name of the image
|
||||
imageName string
|
||||
|
||||
// The ID of the image
|
||||
imageID string
|
||||
|
||||
// The name of the snapshot
|
||||
snapshotName string
|
||||
|
||||
// The ID of the snapshot
|
||||
snapshotId string
|
||||
snapshotID string
|
||||
|
||||
// The name of the region
|
||||
regionName string
|
||||
|
@ -31,11 +37,12 @@ func (*Artifact) Files() []string {
|
|||
}
|
||||
|
||||
func (a *Artifact) Id() string {
|
||||
return fmt.Sprintf("%s:%s", a.regionName, a.snapshotId)
|
||||
return fmt.Sprintf("%s:%s", a.regionName, a.imageID)
|
||||
}
|
||||
|
||||
func (a *Artifact) String() string {
|
||||
return fmt.Sprintf("A snapshot was created: '%v' (ID: %v) in region '%v'", a.snapshotName, a.snapshotId, a.regionName)
|
||||
return fmt.Sprintf("An image was created: '%v' (ID: %v) in region '%v' based on snapshot '%v' (ID: %v)",
|
||||
a.imageName, a.imageID, a.regionName, a.snapshotName, a.snapshotID)
|
||||
}
|
||||
|
||||
func (a *Artifact) State(name string) interface{} {
|
||||
|
@ -43,7 +50,13 @@ func (a *Artifact) State(name string) interface{} {
|
|||
}
|
||||
|
||||
func (a *Artifact) Destroy() error {
|
||||
log.Printf("Destroying image: %s (%s)", a.snapshotId, a.snapshotName)
|
||||
err := a.client.DeleteSnapshot(a.snapshotId)
|
||||
return err
|
||||
log.Printf("Destroying image: %s (%s)", a.imageID, a.imageName)
|
||||
if err := a.client.DeleteImage(a.imageID); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("Destroying snapshot: %s (%s)", a.snapshotID, a.snapshotName)
|
||||
if err := a.client.DeleteSnapshot(a.snapshotID); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ func TestArtifact_Impl(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestArtifactId(t *testing.T) {
|
||||
a := &Artifact{"packer-foobar", "cc586e45-5156-4f71-b223-cf406b10dd1c", "ams1", nil}
|
||||
expected := "ams1:cc586e45-5156-4f71-b223-cf406b10dd1c"
|
||||
a := &Artifact{"packer-foobar-image", "cc586e45-5156-4f71-b223-cf406b10dd1d", "packer-foobar-snapshot", "cc586e45-5156-4f71-b223-cf406b10dd1c", "ams1", nil}
|
||||
expected := "ams1:cc586e45-5156-4f71-b223-cf406b10dd1d"
|
||||
|
||||
if a.Id() != expected {
|
||||
t.Fatalf("artifact ID should match: %v", expected)
|
||||
|
@ -24,8 +24,8 @@ func TestArtifactId(t *testing.T) {
|
|||
}
|
||||
|
||||
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'"
|
||||
a := &Artifact{"packer-foobar-image", "cc586e45-5156-4f71-b223-cf406b10dd1d", "packer-foobar-snapshot", "cc586e45-5156-4f71-b223-cf406b10dd1c", "ams1", nil}
|
||||
expected := "An image was created: 'packer-foobar-image' (ID: cc586e45-5156-4f71-b223-cf406b10dd1d) in region 'ams1' based on snapshot 'packer-foobar-snapshot' (ID: cc586e45-5156-4f71-b223-cf406b10dd1c)"
|
||||
|
||||
if a.String() != expected {
|
||||
t.Fatalf("artifact string should match: %v", expected)
|
||||
|
|
|
@ -56,6 +56,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
new(common.StepProvision),
|
||||
new(stepShutdown),
|
||||
new(stepSnapshot),
|
||||
new(stepImage),
|
||||
new(stepTerminate),
|
||||
}
|
||||
|
||||
|
@ -72,8 +73,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
}
|
||||
|
||||
artifact := &Artifact{
|
||||
imageName: state.Get("image_name").(string),
|
||||
imageID: state.Get("image_id").(string),
|
||||
snapshotName: state.Get("snapshot_name").(string),
|
||||
snapshotId: state.Get("snapshot_id").(string),
|
||||
snapshotID: state.Get("snapshot_id").(string),
|
||||
regionName: state.Get("region").(string),
|
||||
client: client,
|
||||
}
|
||||
|
|
|
@ -9,12 +9,12 @@ import (
|
|||
|
||||
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",
|
||||
"api_access_key": "foo",
|
||||
"api_token": "bar",
|
||||
"region": "ams1",
|
||||
"commercial_type": "VC1S",
|
||||
"ssh_username": "root",
|
||||
"image": "image-uuid",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,13 +19,14 @@ type Config struct {
|
|||
Comm communicator.Config `mapstructure:",squash"`
|
||||
|
||||
Token string `mapstructure:"api_token"`
|
||||
Organization string `mapstructure:"api_organization"`
|
||||
Organization string `mapstructure:"api_access_key"`
|
||||
|
||||
Region string `mapstructure:"region"`
|
||||
Image string `mapstructure:"image"`
|
||||
CommercialType string `mapstructure:"commercial_type"`
|
||||
|
||||
SnapshotName string `mapstructure:"snapshot_name"`
|
||||
ImageName string `mapstructure:"image_name"`
|
||||
ServerName string `mapstructure:"server_name"`
|
||||
|
||||
UserAgent string
|
||||
|
@ -53,7 +54,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
|||
c.UserAgent = "Packer - Scaleway builder"
|
||||
|
||||
if c.Organization == "" {
|
||||
c.Organization = os.Getenv("SCALEWAY_API_ORGANIZATION")
|
||||
c.Organization = os.Getenv("SCALEWAY_API_ACCESS_KEY")
|
||||
}
|
||||
|
||||
if c.Token == "" {
|
||||
|
@ -61,7 +62,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
|||
}
|
||||
|
||||
if c.SnapshotName == "" {
|
||||
def, err := interpolate.Render("packer-{{timestamp}}", nil)
|
||||
def, err := interpolate.Render("snapshot-packer-{{timestamp}}", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -69,6 +70,15 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
|||
c.SnapshotName = def
|
||||
}
|
||||
|
||||
if c.ImageName == "" {
|
||||
def, err := interpolate.Render("image-packer-{{timestamp}}", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.ImageName = def
|
||||
}
|
||||
|
||||
if c.ServerName == "" {
|
||||
// Default to packer-[time-ordered-uuid]
|
||||
c.ServerName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package scaleway
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/scaleway/scaleway-cli/pkg/api"
|
||||
)
|
||||
|
||||
type stepImage struct{}
|
||||
|
||||
func (s *stepImage) Run(state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(*api.ScalewayAPI)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
c := state.Get("config").(Config)
|
||||
snapshotID := state.Get("snapshot_id").(string)
|
||||
bootscriptID := ""
|
||||
|
||||
ui.Say(fmt.Sprintf("Creating image: %v", c.ImageName))
|
||||
|
||||
image, err := client.GetImage(c.Image)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error getting initial image info: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if image.DefaultBootscript != nil {
|
||||
bootscriptID = image.DefaultBootscript.Identifier
|
||||
}
|
||||
|
||||
imageID, err := client.PostImage(snapshotID, c.ImageName, bootscriptID, image.Arch)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating image: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
log.Printf("Image ID: %s", imageID)
|
||||
state.Put("image_id", imageID)
|
||||
state.Put("image_name", c.ImageName)
|
||||
state.Put("region", c.Region)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *stepImage) Cleanup(state multistep.StateBag) {
|
||||
// no cleanup
|
||||
}
|
|
@ -2,14 +2,15 @@ package scaleway
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/scaleway/scaleway-cli/pkg/api"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type stepCreateServer struct {
|
||||
serverId string
|
||||
serverID string
|
||||
}
|
||||
|
||||
func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
@ -37,7 +38,7 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction {
|
|||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
s.serverId = server
|
||||
s.serverID = server
|
||||
|
||||
state.Put("server_id", server)
|
||||
|
||||
|
@ -45,7 +46,7 @@ func (s *stepCreateServer) Run(state multistep.StateBag) multistep.StepAction {
|
|||
}
|
||||
|
||||
func (s *stepCreateServer) Cleanup(state multistep.StateBag) {
|
||||
if s.serverId != "" {
|
||||
if s.serverID != "" {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -53,7 +54,7 @@ func (s *stepCreateServer) Cleanup(state multistep.StateBag) {
|
|||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Destroying server...")
|
||||
err := client.PostServerAction(s.serverId, "terminate")
|
||||
err := client.PostServerAction(s.serverID, "terminate")
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf(
|
||||
"Error destroying server. Please destroy it manually: %s", err))
|
||||
|
|
|
@ -13,11 +13,11 @@ 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)
|
||||
serverID := state.Get("server_id").(string)
|
||||
|
||||
ui.Say("Shutting down server...")
|
||||
|
||||
err := client.PostServerAction(serverId, "poweroff")
|
||||
err := client.PostServerAction(serverID, "poweroff")
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error stopping server: %s", err)
|
||||
|
@ -26,7 +26,7 @@ func (s *stepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
|||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
_, err = api.WaitForServerState(client, serverId, "stopped")
|
||||
_, err = api.WaitForServerState(client, serverID, "stopped")
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error shutting down server: %s", err)
|
||||
|
|
|
@ -15,10 +15,10 @@ 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)
|
||||
volumeID := state.Get("root_volume_id").(string)
|
||||
|
||||
ui.Say(fmt.Sprintf("Creating snapshot: %v", c.SnapshotName))
|
||||
snapshot, err := client.PostSnapshot(volumeId, c.SnapshotName)
|
||||
snapshot, err := client.PostSnapshot(volumeID, c.SnapshotName)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating snapshot: %s", err)
|
||||
state.Put("error", err)
|
||||
|
@ -26,15 +26,6 @@ func (s *stepSnapshot) Run(state multistep.StateBag) multistep.StepAction {
|
|||
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)
|
||||
|
|
|
@ -13,11 +13,11 @@ 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)
|
||||
serverID := state.Get("server_id").(string)
|
||||
|
||||
ui.Say("Terminating server...")
|
||||
|
||||
err := client.DeleteServerForce(serverId)
|
||||
err := client.DeleteServerForce(serverID)
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error terminating server: %s", err)
|
||||
|
|
|
@ -3,7 +3,7 @@ layout: docs
|
|||
sidebar_current: docs-builders-scaleway
|
||||
page_title: Scaleway - Builders
|
||||
description: |-
|
||||
The Scaleway Packer builder is able to create new snapshots for use with
|
||||
The Scaleway Packer builder is able to create new images for use with
|
||||
Scaleway BareMetal and Virtual cloud server. The builder takes a source image, runs any provisioning
|
||||
necessary on the image after launching it, then snapshots it into a reusable
|
||||
image. This reusable image can then be used as the foundation of new servers
|
||||
|
@ -15,7 +15,7 @@ description: |-
|
|||
|
||||
Type: `scaleway`
|
||||
|
||||
The `scaleway` Packer builder is able to create new snapshots for use with
|
||||
The `scaleway` Packer builder is able to create new images for use with
|
||||
[Scaleway](https://www.scaleway.com). The builder takes a source image,
|
||||
runs any provisioning necessary on the image after launching it, then snapshots
|
||||
it into a reusable image. This reusable image can then be used as the foundation
|
||||
|
@ -36,13 +36,15 @@ builder.
|
|||
|
||||
### Required:
|
||||
|
||||
- `api_organization` (string) - The organization ID to use to access your account.
|
||||
- `api_access_key` (string) - The api_access_key to use to access your account.
|
||||
It can also be specified via
|
||||
environment variable `SCALEWAY_API_ORGANIZATION`.
|
||||
environment variable `SCALEWAY_API_ACCESS_KEY`.
|
||||
Your access key is available in the ["Credentials" section](https://cloud.scaleway.com/#/credentials) of the control panel.
|
||||
|
||||
- `api_token` (string) - The organization TOKEN to use to access your account.
|
||||
It can also be specified via
|
||||
environment variable `SCALEWAY_API_TOKEN`.
|
||||
Your tokens are available in the ["Credentials" section](https://cloud.scaleway.com/#/credentials) of the control panel.
|
||||
|
||||
- `image` (string) - The UUID of the base image to use. This is the
|
||||
image that will be used to launch a new server and provision it. See
|
||||
|
@ -60,6 +62,9 @@ builder.
|
|||
|
||||
- `server_name` (string) - The name assigned to the server.
|
||||
|
||||
- `image_name` (string) - The name of the resulting image that will
|
||||
appear in your account.
|
||||
|
||||
- `snapshot_name` (string) - The name of the resulting snapshot that will
|
||||
appear in your account.
|
||||
|
||||
|
@ -71,7 +76,7 @@ access tokens:
|
|||
```json
|
||||
{
|
||||
"type": "scaleway",
|
||||
"api_organization": "YOUR ORGANIZATION KEY",
|
||||
"api_access_key": "YOUR API ACCESS KEY",
|
||||
"api_token": "YOUR TOKEN",
|
||||
"image": "f01f8a48-c026-48ac-9771-a70eaac0890e",
|
||||
"region": "par1",
|
||||
|
|
Loading…
Reference in New Issue