Add FreeBSD support.
This commit is contained in:
parent
a28edbaa0b
commit
364c415294
|
@ -391,8 +391,11 @@ func checkHyperVGeneration(s string) interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
|
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
|
||||||
if runtime.GOOS != "linux" {
|
switch runtime.GOOS {
|
||||||
return nil, errors.New("the azure-chroot builder only works on Linux environments")
|
case "linux", "freebsd":
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return nil, errors.New("the azure-chroot builder only works on Linux and FreeBSD environments")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := b.config.ClientConfig.FillParameters()
|
err := b.config.ClientConfig.FillParameters()
|
||||||
|
|
|
@ -3,24 +3,18 @@ package chroot
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/packer/builder/azure/common/client"
|
"github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute"
|
||||||
|
|
||||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute"
|
|
||||||
"github.com/Azure/go-autorest/autorest/azure"
|
"github.com/Azure/go-autorest/autorest/azure"
|
||||||
"github.com/Azure/go-autorest/autorest/to"
|
"github.com/Azure/go-autorest/autorest/to"
|
||||||
|
"github.com/hashicorp/packer/builder/azure/common/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DiskAttacher interface {
|
type DiskAttacher interface {
|
||||||
AttachDisk(ctx context.Context, disk string) (lun int32, err error)
|
AttachDisk(ctx context.Context, disk string) (lun int32, err error)
|
||||||
DiskPathForLun(lun int32) string
|
|
||||||
WaitForDevice(ctx context.Context, i int32) (device string, err error)
|
WaitForDevice(ctx context.Context, i int32) (device string, err error)
|
||||||
DetachDisk(ctx context.Context, disk string) (err error)
|
DetachDisk(ctx context.Context, disk string) (err error)
|
||||||
WaitForDetach(ctx context.Context, diskID string) error
|
WaitForDetach(ctx context.Context, diskID string) error
|
||||||
|
@ -38,79 +32,6 @@ type diskAttacher struct {
|
||||||
vm *client.ComputeInfo // store info about this VM so that we don't have to ask metadata service on every call
|
vm *client.ComputeInfo // store info about this VM so that we don't have to ask metadata service on every call
|
||||||
}
|
}
|
||||||
|
|
||||||
func (diskAttacher) DiskPathForLun(lun int32) string {
|
|
||||||
return fmt.Sprintf("/dev/disk/azure/scsi1/lun%d", lun)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (da diskAttacher) WaitForDevice(ctx context.Context, lun int32) (device string, err error) {
|
|
||||||
path := da.DiskPathForLun(lun)
|
|
||||||
|
|
||||||
for {
|
|
||||||
link, err := os.Readlink(path)
|
|
||||||
if err == nil {
|
|
||||||
return filepath.Abs("/dev/disk/azure/scsi1/" + link)
|
|
||||||
} else if err != os.ErrNotExist {
|
|
||||||
if pe, ok := err.(*os.PathError); ok && pe.Err != syscall.ENOENT {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-time.After(100 * time.Millisecond):
|
|
||||||
// continue
|
|
||||||
case <-ctx.Done():
|
|
||||||
return "", ctx.Err()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (da *diskAttacher) DetachDisk(ctx context.Context, diskID string) error {
|
|
||||||
log.Println("Fetching list of disks currently attached to VM")
|
|
||||||
currentDisks, err := da.getDisks(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Removing %q from list of disks currently attached to VM", diskID)
|
|
||||||
newDisks := []compute.DataDisk{}
|
|
||||||
for _, disk := range currentDisks {
|
|
||||||
if disk.ManagedDisk != nil &&
|
|
||||||
!strings.EqualFold(to.String(disk.ManagedDisk.ID), diskID) {
|
|
||||||
newDisks = append(newDisks, disk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(currentDisks) == len(newDisks) {
|
|
||||||
return DiskNotFoundError
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("Updating new list of disks attached to VM")
|
|
||||||
err = da.setDisks(ctx, newDisks)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (da *diskAttacher) WaitForDetach(ctx context.Context, diskID string) error {
|
|
||||||
for { // loop until disk is not attached, timeout or error
|
|
||||||
list, err := da.getDisks(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if findDiskInList(list, diskID) == nil {
|
|
||||||
log.Println("Disk is no longer in VM model, assuming detached")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-time.After(time.Second): //continue
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var DiskNotFoundError = errors.New("Disk not found")
|
var DiskNotFoundError = errors.New("Disk not found")
|
||||||
|
|
||||||
func (da *diskAttacher) AttachDisk(ctx context.Context, diskID string) (int32, error) {
|
func (da *diskAttacher) AttachDisk(ctx context.Context, diskID string) (int32, error) {
|
||||||
|
@ -160,6 +81,53 @@ findFreeLun:
|
||||||
return lun, nil
|
return lun, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (da *diskAttacher) DetachDisk(ctx context.Context, diskID string) error {
|
||||||
|
log.Println("Fetching list of disks currently attached to VM")
|
||||||
|
currentDisks, err := da.getDisks(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Removing %q from list of disks currently attached to VM", diskID)
|
||||||
|
newDisks := []compute.DataDisk{}
|
||||||
|
for _, disk := range currentDisks {
|
||||||
|
if disk.ManagedDisk != nil &&
|
||||||
|
!strings.EqualFold(to.String(disk.ManagedDisk.ID), diskID) {
|
||||||
|
newDisks = append(newDisks, disk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(currentDisks) == len(newDisks) {
|
||||||
|
return DiskNotFoundError
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Updating new list of disks attached to VM")
|
||||||
|
err = da.setDisks(ctx, newDisks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (da *diskAttacher) WaitForDetach(ctx context.Context, diskID string) error {
|
||||||
|
for { // loop until disk is not attached, timeout or error
|
||||||
|
list, err := da.getDisks(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if findDiskInList(list, diskID) == nil {
|
||||||
|
log.Println("Disk is no longer in VM model, assuming detached")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Second): //continue
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (da *diskAttacher) getThisVM(ctx context.Context) (compute.VirtualMachine, error) {
|
func (da *diskAttacher) getThisVM(ctx context.Context) (compute.VirtualMachine, error) {
|
||||||
// getting resource info for this VM
|
// getting resource info for this VM
|
||||||
if da.vm == nil {
|
if da.vm == nil {
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
package chroot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (da diskAttacher) WaitForDevice(ctx context.Context, lun int32) (device string, err error) {
|
||||||
|
// This builder will always be running in Azure, where data disks show up
|
||||||
|
// on scbus5 target 0. The camcontrol command always outputs LUNs in
|
||||||
|
// unpadded hexadecimal format.
|
||||||
|
regexStr := fmt.Sprintf(`at scbus5 target 0 lun %x \(.*?da([\d]+)`, lun)
|
||||||
|
devRegex, err := regexp.Compile(regexStr)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
cmd := exec.Command("camcontrol", "devlist")
|
||||||
|
var out bytes.Buffer
|
||||||
|
cmd.Stdout = &out
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
outString := out.String()
|
||||||
|
scanner := bufio.NewScanner(strings.NewReader(outString))
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
// Check if this is the correct bus, target, and LUN.
|
||||||
|
if matches := devRegex.FindStringSubmatch(line); matches != nil {
|
||||||
|
// If this function immediately returns, devfs won't have
|
||||||
|
// created the device yet.
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
return fmt.Sprintf("/dev/da%s", matches[1]), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = scanner.Err(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(100 * time.Millisecond):
|
||||||
|
// continue
|
||||||
|
case <-ctx.Done():
|
||||||
|
return "", ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package chroot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func diskPathForLun(lun int32) string {
|
||||||
|
return fmt.Sprintf("/dev/disk/azure/scsi1/lun%d", lun)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (da diskAttacher) WaitForDevice(ctx context.Context, lun int32) (device string, err error) {
|
||||||
|
path := diskPathForLun(lun)
|
||||||
|
|
||||||
|
for {
|
||||||
|
link, err := os.Readlink(path)
|
||||||
|
if err == nil {
|
||||||
|
return filepath.Abs("/dev/disk/azure/scsi1/" + link)
|
||||||
|
} else if err != os.ErrNotExist {
|
||||||
|
if pe, ok := err.(*os.PathError); ok && pe.Err != syscall.ENOENT {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(100 * time.Millisecond):
|
||||||
|
// continue
|
||||||
|
case <-ctx.Done():
|
||||||
|
return "", ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/packer/common"
|
"github.com/hashicorp/packer/common"
|
||||||
|
@ -62,7 +63,13 @@ func (s *StepMountDevice) Run(ctx context.Context, state multistep.StateBag) mul
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceMount := fmt.Sprintf("%s%s", device, s.MountPartition)
|
var deviceMount string
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "freebsd":
|
||||||
|
deviceMount = fmt.Sprintf("%sp%s", device, s.MountPartition)
|
||||||
|
default:
|
||||||
|
deviceMount = fmt.Sprintf("%s%s", device, s.MountPartition)
|
||||||
|
}
|
||||||
|
|
||||||
state.Put("deviceMount", deviceMount)
|
state.Put("deviceMount", deviceMount)
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"github.com/hashicorp/packer/common"
|
"github.com/hashicorp/packer/common"
|
||||||
"github.com/hashicorp/packer/helper/multistep"
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
|
@ -31,12 +32,22 @@ func (s *StepCopyFiles) Run(ctx context.Context, state multistep.StateBag) multi
|
||||||
s.files = make([]string, 0, len(s.Files))
|
s.files = make([]string, 0, len(s.Files))
|
||||||
if len(s.Files) > 0 {
|
if len(s.Files) > 0 {
|
||||||
ui.Say("Copying files from host to chroot...")
|
ui.Say("Copying files from host to chroot...")
|
||||||
|
var removeDestinationOption string
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "freebsd":
|
||||||
|
// The -f option here is closer to GNU --remove-destination than
|
||||||
|
// what POSIX says -f should do.
|
||||||
|
removeDestinationOption = "-f"
|
||||||
|
default:
|
||||||
|
// This is the GNU binutils version.
|
||||||
|
removeDestinationOption = "--remove-destination"
|
||||||
|
}
|
||||||
for _, path := range s.Files {
|
for _, path := range s.Files {
|
||||||
ui.Message(path)
|
ui.Message(path)
|
||||||
chrootPath := filepath.Join(mountPath, path)
|
chrootPath := filepath.Join(mountPath, path)
|
||||||
log.Printf("Copying '%s' to '%s'", path, chrootPath)
|
log.Printf("Copying '%s' to '%s'", path, chrootPath)
|
||||||
|
|
||||||
cmdText, err := wrappedCommand(fmt.Sprintf("cp --remove-destination %s %s", path, chrootPath))
|
cmdText, err := wrappedCommand(fmt.Sprintf("cp %s %s %s", removeDestinationOption, path, chrootPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error building copy command: %s", err)
|
err := fmt.Errorf("Error building copy command: %s", err)
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
|
|
Loading…
Reference in New Issue