Skip to content

Commit d4f9654

Browse files
author
dwc0011
committed
Create new step ManualMountCommand and add to chroot builder
1 parent 061d1b8 commit d4f9654

File tree

2 files changed

+137
-5
lines changed

2 files changed

+137
-5
lines changed

builder/azure/chroot/builder.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ type Config struct {
6161
// a command with sudo or so on. This is a configuration template where the `.Command` variable
6262
// is replaced with the command to be run. Defaults to `{{.Command}}`.
6363
CommandWrapper string `mapstructure:"command_wrapper"`
64+
// Manual Mount Command that is executed to manually mount the
65+
// root device and before the post mount commands. The device and
66+
// mount path are provided by `{{.Device}}` and `{{.MountPath}}`.
67+
ManualMountCommand string `mapstructure:"manual_mount_command" required:"false"`
6468
// A series of commands to execute after attaching the root volume and before mounting the chroot.
6569
// This is not required unless using `from_scratch`. If so, this should include any partitioning
6670
// and filesystem creation commands. The path to the device is provided by `{{.Device}}`.
@@ -169,6 +173,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
169173
"command_wrapper",
170174
"post_mount_commands",
171175
"pre_mount_commands",
176+
"manual_mount_command",
172177
"mount_path",
173178
},
174179
},
@@ -611,11 +616,28 @@ func buildsteps(
611616
&chroot.StepPreMountCommands{
612617
Commands: config.PreMountCommands,
613618
},
614-
&StepMountDevice{
615-
MountOptions: config.MountOptions,
616-
MountPartition: config.MountPartition,
617-
MountPath: config.MountPath,
618-
},
619+
)
620+
621+
if config.ManualMountCommand == "" {
622+
addSteps(
623+
&StepMountDevice{
624+
MountOptions: config.MountOptions,
625+
MountPartition: config.MountPartition,
626+
MountPath: config.MountPath,
627+
},
628+
)
629+
} else {
630+
addSteps(
631+
&StepManualMountCommand{
632+
Command: config.ManualMountCommand,
633+
MountPartition: config.MountPartition,
634+
MountPath: config.MountPath,
635+
},
636+
)
637+
638+
}
639+
640+
addSteps(
619641
&chroot.StepPostMountCommands{
620642
Commands: config.PostMountCommands,
621643
},
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package chroot
5+
6+
// mostly borrowed from ./builder/amazon/chroot/step_mount_device.go
7+
8+
import (
9+
"bytes"
10+
"context"
11+
"fmt"
12+
"path/filepath"
13+
"runtime"
14+
15+
"github.com/hashicorp/packer-plugin-azure/builder/azure/common/log"
16+
17+
"github.com/hashicorp/packer-plugin-sdk/common"
18+
"github.com/hashicorp/packer-plugin-sdk/multistep"
19+
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
20+
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
21+
)
22+
23+
var _ multistep.Step = &StepManualMountCommand{}
24+
25+
type StepManualMountCommand struct {
26+
Command string
27+
MountPartition string
28+
MountPath string
29+
30+
mountPath string
31+
}
32+
33+
func (s *StepManualMountCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
34+
ui := state.Get("ui").(packersdk.Ui)
35+
device := state.Get("device").(string)
36+
config := state.Get("config").(*Config)
37+
38+
ictx := config.ctx
39+
40+
ictx.Data = &struct{ Device string }{Device: filepath.Base(device)}
41+
mountPath, err := interpolate.Render(s.MountPath, &ictx)
42+
43+
if err != nil {
44+
err := fmt.Errorf("error preparing mount directory: %s", err)
45+
state.Put("error", err)
46+
ui.Error(err.Error())
47+
return multistep.ActionHalt
48+
}
49+
50+
mountPath, err = filepath.Abs(mountPath)
51+
if err != nil {
52+
err := fmt.Errorf("error preparing mount directory: %s", err)
53+
state.Put("error", err)
54+
ui.Error(err.Error())
55+
return multistep.ActionHalt
56+
}
57+
58+
log.Printf("Mount path: %s", mountPath)
59+
60+
var deviceMount string
61+
switch runtime.GOOS {
62+
case "freebsd":
63+
deviceMount = fmt.Sprintf("%sp%s", device, s.MountPartition)
64+
default:
65+
deviceMount = fmt.Sprintf("%s%s", device, s.MountPartition)
66+
}
67+
68+
state.Put("deviceMount", deviceMount)
69+
70+
ui.Say("Mounting the root device...")
71+
stderr := new(bytes.Buffer)
72+
73+
log.Printf("[DEBUG] (step mount) mount command is %s", s.Command)
74+
cmd := common.ShellCommand(fmt.Sprintf("%s %s", s.Command, mountPath))
75+
cmd.Stderr = stderr
76+
if err := cmd.Run(); err != nil {
77+
err := fmt.Errorf(
78+
"error mounting root volume: %s\nStderr: %s", err, stderr.String())
79+
state.Put("error", err)
80+
ui.Error(err.Error())
81+
return multistep.ActionHalt
82+
}
83+
84+
// Set the mount path so we remember to unmount it later
85+
s.mountPath = mountPath
86+
state.Put("mount_path", s.mountPath)
87+
state.Put("mount_device_cleanup", s)
88+
89+
return multistep.ActionContinue
90+
}
91+
92+
func (s *StepManualMountCommand) Cleanup(state multistep.StateBag) {
93+
ui := state.Get("ui").(packersdk.Ui)
94+
if err := s.CleanupFunc(state); err != nil {
95+
ui.Error(err.Error())
96+
}
97+
}
98+
99+
func (s *StepManualMountCommand) CleanupFunc(state multistep.StateBag) error {
100+
if s.mountPath == "" {
101+
return nil
102+
}
103+
104+
ui := state.Get("ui").(packersdk.Ui)
105+
106+
ui.Say("Skipping Unmounting the root device, it is manually unmounted via manual mount command script...")
107+
108+
s.mountPath = ""
109+
return nil
110+
}

0 commit comments

Comments
 (0)