forked from hashicorp/packer
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request hashicorp#7294 from hyperonecom/hyperone
Add HyperOne builder
- Loading branch information
Showing
269 changed files
with
49,854 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package hyperone | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/hyperonecom/h1-client-go" | ||
) | ||
|
||
type Artifact struct { | ||
imageName string | ||
imageID string | ||
client *openapi.APIClient | ||
} | ||
|
||
func (a *Artifact) BuilderId() string { | ||
return BuilderID | ||
} | ||
|
||
func (a *Artifact) Files() []string { | ||
return nil | ||
} | ||
|
||
func (a *Artifact) Id() string { | ||
return a.imageID | ||
} | ||
|
||
func (a *Artifact) String() string { | ||
return fmt.Sprintf("Image '%s' created, ID: %s", a.imageName, a.imageID) | ||
} | ||
|
||
func (a *Artifact) State(name string) interface{} { | ||
return nil | ||
} | ||
|
||
func (a *Artifact) Destroy() error { | ||
if a.imageID == "" { | ||
// No image to destroy | ||
return nil | ||
} | ||
|
||
_, err := a.client.ImageApi.ImageDelete(context.TODO(), a.imageID) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package hyperone | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
|
||
"github.com/hashicorp/packer/common" | ||
"github.com/hashicorp/packer/helper/communicator" | ||
"github.com/hashicorp/packer/helper/multistep" | ||
"github.com/hashicorp/packer/packer" | ||
"github.com/hashicorp/packer/template/interpolate" | ||
"github.com/hyperonecom/h1-client-go" | ||
) | ||
|
||
const BuilderID = "hyperone.builder" | ||
|
||
type Builder struct { | ||
config Config | ||
runner multistep.Runner | ||
client *openapi.APIClient | ||
} | ||
|
||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { | ||
config, warnings, errs := NewConfig(raws...) | ||
if errs != nil { | ||
return warnings, errs | ||
} | ||
|
||
b.config = *config | ||
|
||
cfg := openapi.NewConfiguration() | ||
cfg.AddDefaultHeader("x-auth-token", b.config.Token) | ||
if b.config.Project != "" { | ||
cfg.AddDefaultHeader("x-project", b.config.Project) | ||
} | ||
|
||
if b.config.APIURL != "" { | ||
cfg.BasePath = b.config.APIURL | ||
} | ||
|
||
prefer := fmt.Sprintf("respond-async,wait=%d", int(b.config.StateTimeout.Seconds())) | ||
cfg.AddDefaultHeader("Prefer", prefer) | ||
|
||
b.client = openapi.NewAPIClient(cfg) | ||
|
||
return nil, nil | ||
} | ||
|
||
type wrappedCommandTemplate struct { | ||
Command string | ||
} | ||
|
||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { | ||
wrappedCommand := func(command string) (string, error) { | ||
ctx := b.config.ctx | ||
ctx.Data = &wrappedCommandTemplate{Command: command} | ||
return interpolate.Render(b.config.ChrootCommandWrapper, &ctx) | ||
} | ||
|
||
state := &multistep.BasicStateBag{} | ||
state.Put("config", &b.config) | ||
state.Put("client", b.client) | ||
state.Put("hook", hook) | ||
state.Put("ui", ui) | ||
state.Put("wrappedCommand", CommandWrapper(wrappedCommand)) | ||
|
||
steps := []multistep.Step{ | ||
&stepCreateSSHKey{}, | ||
&stepCreateVM{}, | ||
&communicator.StepConnect{ | ||
Config: &b.config.Comm, | ||
Host: getPublicIP, | ||
SSHConfig: b.config.Comm.SSHConfigFunc(), | ||
}, | ||
} | ||
|
||
if b.config.ChrootDisk { | ||
steps = append(steps, | ||
&stepPrepareDevice{}, | ||
&stepPreMountCommands{}, | ||
&stepMountChroot{}, | ||
&stepPostMountCommands{}, | ||
&stepMountExtra{}, | ||
&stepCopyFiles{}, | ||
&stepChrootProvision{}, | ||
&stepStopVM{}, | ||
&stepDetachDisk{}, | ||
&stepCreateVMFromDisk{}, | ||
&stepCreateImage{}, | ||
) | ||
} else { | ||
steps = append(steps, | ||
&common.StepProvision{}, | ||
&stepStopVM{}, | ||
&stepCreateImage{}, | ||
) | ||
} | ||
|
||
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) | ||
b.runner.Run(state) | ||
|
||
if rawErr, ok := state.GetOk("error"); ok { | ||
return nil, rawErr.(error) | ||
} | ||
|
||
artifact := &Artifact{ | ||
imageID: state.Get("image_id").(string), | ||
imageName: state.Get("image_name").(string), | ||
client: b.client, | ||
} | ||
|
||
return artifact, nil | ||
} | ||
|
||
func (b *Builder) Cancel() { | ||
if b.runner != nil { | ||
log.Println("Cancelling the runner...") | ||
b.runner.Cancel() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package hyperone | ||
|
||
import ( | ||
"os" | ||
"testing" | ||
|
||
builderT "github.com/hashicorp/packer/helper/builder/testing" | ||
) | ||
|
||
func TestBuilderAcc_basic(t *testing.T) { | ||
builderT.Test(t, builderT.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Builder: &Builder{}, | ||
Template: testBuilderAccBasic, | ||
}) | ||
} | ||
|
||
func TestBuilderAcc_chroot(t *testing.T) { | ||
builderT.Test(t, builderT.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Builder: &Builder{}, | ||
Template: testBuilderAccChroot, | ||
}) | ||
} | ||
|
||
func testAccPreCheck(t *testing.T) { | ||
if v := os.Getenv("HYPERONE_TOKEN"); v == "" { | ||
t.Fatal("HYPERONE_TOKEN must be set for acceptance tests") | ||
} | ||
} | ||
|
||
const testBuilderAccBasic = ` | ||
{ | ||
"builders": [{ | ||
"type": "test", | ||
"vm_type": "a1.nano", | ||
"source_image": "ubuntu", | ||
"disk_size": 10 | ||
}] | ||
} | ||
` | ||
|
||
const testBuilderAccChroot = ` | ||
{ | ||
"builders": [{ | ||
"type": "test", | ||
"source_image": "ubuntu", | ||
"disk_size": 10, | ||
"vm_type": "a1.nano", | ||
"chroot_disk": true, | ||
"chroot_command_wrapper": "sudo {{.Command}}", | ||
"pre_mount_commands": [ | ||
"parted {{.Device}} mklabel msdos mkpart primary 1M 100% set 1 boot on print", | ||
"mkfs.ext4 {{.Device}}1" | ||
], | ||
"post_mount_commands": [ | ||
"apt-get update", | ||
"apt-get install debootstrap", | ||
"debootstrap --arch amd64 bionic {{.MountPath}}" | ||
] | ||
}] | ||
} | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package hyperone | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"os" | ||
"path/filepath" | ||
"strconv" | ||
|
||
"github.com/hashicorp/packer/packer" | ||
) | ||
|
||
type CommandWrapper func(string) (string, error) | ||
|
||
// ChrootCommunicator works as a wrapper on SSHCommunicator, modyfing paths in | ||
// flight to be run in a chroot. | ||
type ChrootCommunicator struct { | ||
Chroot string | ||
CmdWrapper CommandWrapper | ||
Wrapped packer.Communicator | ||
} | ||
|
||
func (c *ChrootCommunicator) Start(cmd *packer.RemoteCmd) error { | ||
command := strconv.Quote(cmd.Command) | ||
chrootCommand, err := c.CmdWrapper( | ||
fmt.Sprintf("sudo chroot %s /bin/sh -c %s", c.Chroot, command)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
cmd.Command = chrootCommand | ||
|
||
return c.Wrapped.Start(cmd) | ||
} | ||
|
||
func (c *ChrootCommunicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error { | ||
dst = filepath.Join(c.Chroot, dst) | ||
return c.Wrapped.Upload(dst, r, fi) | ||
} | ||
|
||
func (c *ChrootCommunicator) UploadDir(dst string, src string, exclude []string) error { | ||
dst = filepath.Join(c.Chroot, dst) | ||
return c.Wrapped.UploadDir(dst, src, exclude) | ||
} | ||
|
||
func (c *ChrootCommunicator) Download(src string, w io.Writer) error { | ||
src = filepath.Join(c.Chroot, src) | ||
return c.Wrapped.Download(src, w) | ||
} | ||
|
||
func (c *ChrootCommunicator) DownloadDir(src string, dst string, exclude []string) error { | ||
src = filepath.Join(c.Chroot, src) | ||
return c.Wrapped.DownloadDir(src, dst, exclude) | ||
} |
Oops, something went wrong.