95 lines
2.5 KiB
Go
95 lines
2.5 KiB
Go
package yandexexport
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
|
"github.com/hashicorp/packer/builder/yandex"
|
|
)
|
|
|
|
type StepDump struct {
|
|
ExtraSize bool
|
|
SizeLimit int64
|
|
}
|
|
|
|
const (
|
|
dumpCommand = "%sqemu-img convert -O qcow2 -o cluster_size=2M %s disk.qcow2 2>&1"
|
|
)
|
|
|
|
// Run reads the instance metadata and looks for the log entry
|
|
// indicating the cloud-init script finished.
|
|
func (s *StepDump) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
|
ui := state.Get("ui").(packersdk.Ui)
|
|
comm := state.Get("communicator").(packersdk.Communicator)
|
|
|
|
device := "/dev/disk/by-id/virtio-doexport"
|
|
cmdDumpCheckAccess := &packersdk.RemoteCmd{
|
|
Command: fmt.Sprintf("qemu-img info %s", device),
|
|
}
|
|
if err := comm.Start(ctx, cmdDumpCheckAccess); err != nil {
|
|
return yandex.StepHaltWithError(state, err)
|
|
}
|
|
sudo := ""
|
|
if cmdDumpCheckAccess.Wait() != 0 {
|
|
sudo = "sudo "
|
|
}
|
|
|
|
if s.ExtraSize && which(ctx, comm, "losetup") == nil {
|
|
ui.Say("Map loop device...")
|
|
buff := new(bytes.Buffer)
|
|
cmd := &packersdk.RemoteCmd{
|
|
Command: fmt.Sprintf("%slosetup --show -r --sizelimit %d -f %s", sudo, s.SizeLimit, device),
|
|
Stdout: buff,
|
|
}
|
|
if err := comm.Start(ctx, cmd); err != nil {
|
|
return yandex.StepHaltWithError(state, err)
|
|
}
|
|
if cmd.Wait() != 0 {
|
|
return yandex.StepHaltWithError(state, fmt.Errorf("Cannot losetup: %d", cmd.ExitStatus()))
|
|
}
|
|
device = strings.TrimSpace(buff.String())
|
|
if device == "" {
|
|
return yandex.StepHaltWithError(state, fmt.Errorf("Bad lo device"))
|
|
}
|
|
}
|
|
wg := new(sync.WaitGroup)
|
|
defer wg.Wait()
|
|
ctxWithCancel, cancel := context.WithCancel(ctx)
|
|
defer cancel()
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
cmd := &packersdk.RemoteCmd{
|
|
Command: "while true ; do sleep 3; sudo kill -s SIGUSR1 $(pidof qemu-img); done",
|
|
}
|
|
|
|
err := cmd.RunWithUi(ctxWithCancel, comm, ui)
|
|
if err != nil && !errors.Is(err, context.Canceled) {
|
|
ui.Error("qemu-img signal sender error: " + err.Error())
|
|
return
|
|
}
|
|
}()
|
|
|
|
cmdDump := &packersdk.RemoteCmd{
|
|
Command: fmt.Sprintf(dumpCommand, sudo, device),
|
|
}
|
|
ui.Say("Dumping...")
|
|
if err := cmdDump.RunWithUi(ctx, comm, ui); err != nil {
|
|
return yandex.StepHaltWithError(state, err)
|
|
}
|
|
if cmdDump.ExitStatus() != 0 {
|
|
return yandex.StepHaltWithError(state, fmt.Errorf("Cannot dump disk, exit code: %d", cmdDump.ExitStatus()))
|
|
}
|
|
|
|
return multistep.ActionContinue
|
|
}
|
|
|
|
// Cleanup nothing
|
|
func (s *StepDump) Cleanup(state multistep.StateBag) {}
|