packer-cn/post-processor/yandex-export/step-prepare-tools.go

151 lines
4.0 KiB
Go

package yandexexport
import (
"context"
"fmt"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer/builder/yandex"
)
type StepPrepareTools struct{}
// Run reads the instance metadata and looks for the log entry
// indicating the cloud-init script finished.
func (s *StepPrepareTools) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packersdk.Ui)
comm := state.Get("communicator").(packersdk.Communicator)
pkgManager, errPkgManager := detectPkgManager(ctx, comm)
if which(ctx, comm, "qemu-img") != nil {
if errPkgManager != nil {
return yandex.StepHaltWithError(state, errPkgManager)
}
ui.Message("Install qemu-img...")
if err := pkgManager.InstallQemuIMG(ctx, comm); err != nil {
return yandex.StepHaltWithError(state, err)
}
}
if which(ctx, comm, "aws") != nil {
if errPkgManager != nil {
return yandex.StepHaltWithError(state, errPkgManager)
}
ui.Message("Install aws...")
if err := pkgManager.InstallAWS(ctx, comm); err != nil {
return yandex.StepHaltWithError(state, err)
}
}
return multistep.ActionContinue
}
// Cleanup nothing
func (s *StepPrepareTools) Cleanup(state multistep.StateBag) {}
func detectPkgManager(ctx context.Context, comm packersdk.Communicator) (pkgManager, error) {
if err := which(ctx, comm, "apt"); err == nil {
return &apt{}, nil
}
if err := which(ctx, comm, "yum"); err == nil {
return &yum{}, nil
}
return nil, fmt.Errorf("Cannot detect package manager")
}
func which(ctx context.Context, comm packersdk.Communicator, what string) error {
cmdCheckAPT := &packersdk.RemoteCmd{
Command: fmt.Sprintf("which %s", what),
}
if err := comm.Start(ctx, cmdCheckAPT); err != nil {
return err
}
if cmdCheckAPT.Wait() == 0 {
return nil
}
return fmt.Errorf("Not found: %s", what)
}
type pkgManager interface {
InstallQemuIMG(ctx context.Context, comm packersdk.Communicator) error
InstallAWS(ctx context.Context, comm packersdk.Communicator) error
}
type apt struct {
updated bool
}
func (p *apt) InstallAWS(ctx context.Context, comm packersdk.Communicator) error {
if err := p.Update(ctx, comm); err != nil {
return err
}
if err := execCMDWithSudo(ctx, comm, "apt install -y awscli"); err != nil {
return fmt.Errorf("Cannot install awscli")
}
return nil
}
func (p *apt) InstallQemuIMG(ctx context.Context, comm packersdk.Communicator) error {
if err := p.Update(ctx, comm); err != nil {
return err
}
if err := execCMDWithSudo(ctx, comm, "apt install -y qemu-utils"); err != nil {
return fmt.Errorf("Cannot install qemu-utils")
}
return nil
}
func (p *apt) Update(ctx context.Context, comm packersdk.Communicator) error {
if p.updated {
return nil
}
if err := execCMDWithSudo(ctx, comm, "apt update"); err != nil {
return fmt.Errorf("Cannot update: %s", err)
}
p.updated = true
return nil
}
type yum struct{}
func (p *yum) InstallAWS(ctx context.Context, comm packersdk.Communicator) error {
if which(ctx, comm, "pip3") != nil {
if err := execCMDWithSudo(ctx, comm, "yum install -y python3-pip"); err != nil {
return fmt.Errorf("Cannot install qemu-img: %s", err)
}
}
if err := execCMDWithSudo(ctx, comm, "pip3 install awscli"); err != nil {
return fmt.Errorf("Install awscli: %s", err)
}
return nil
}
func (p *yum) InstallQemuIMG(ctx context.Context, comm packersdk.Communicator) error {
if err := execCMDWithSudo(ctx, comm, "yum install -y libgcrypt qemu-img"); err != nil {
return fmt.Errorf("Cannot install qemu-img: %s", err)
}
return nil
}
func execCMDWithSudo(ctx context.Context, comm packersdk.Communicator, cmdStr string) error {
cmd := &packersdk.RemoteCmd{
Command: cmdStr,
}
if err := comm.Start(ctx, cmd); err != nil {
return err
}
if cmd.Wait() != 0 {
cmd := &packersdk.RemoteCmd{
Command: fmt.Sprintf("sudo %s", cmdStr),
}
if err := comm.Start(ctx, cmd); err != nil {
return err
}
if cmd.Wait() != 0 {
return fmt.Errorf("Bad exit code: %d", cmd.ExitStatus())
}
}
return nil
}