mirror of
https://github.com/kairos-io/kairos-agent.git
synced 2025-04-27 11:21:44 +00:00
Rework install a bit more (#100)
Co-authored-by: Dimitris Karakasilis <dimitris@karakasilis.me>
This commit is contained in:
parent
956f86f99c
commit
bca3277b7d
@ -62,7 +62,7 @@ func mergeOption(cloudConfig string, r map[string]string) {
|
||||
}
|
||||
}
|
||||
|
||||
func ManualInstall(c string, options map[string]string, strictValidations bool) error {
|
||||
func ManualInstall(c, device string, reboot, poweroff, strictValidations bool) error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
@ -75,28 +75,21 @@ func ManualInstall(c string, options map[string]string, strictValidations bool)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configStr, err := cc.String()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options["cc"] = configStr
|
||||
// unlike Install device is already set
|
||||
// options["device"] = cc.Install.Device
|
||||
|
||||
mergeOption(configStr, options)
|
||||
|
||||
if options["device"] == "" {
|
||||
// IF cc is nil we will panic, check beforehand.
|
||||
// If we set no device then we will exit later down the line anyway
|
||||
if cc.Install != nil {
|
||||
if cc.Install.Device == "" {
|
||||
options["device"] = detectDevice()
|
||||
} else {
|
||||
options["device"] = cc.Install.Device
|
||||
}
|
||||
}
|
||||
if reboot {
|
||||
// Override from flags!
|
||||
cc.Install.Reboot = true
|
||||
}
|
||||
return RunInstall(options)
|
||||
|
||||
if poweroff {
|
||||
// Override from flags!
|
||||
cc.Install.Poweroff = true
|
||||
}
|
||||
if device != "" {
|
||||
// Override from flags!
|
||||
cc.Install.Device = device
|
||||
}
|
||||
return RunInstall(cc)
|
||||
}
|
||||
|
||||
func Install(dir ...string) error {
|
||||
@ -127,22 +120,18 @@ func Install(dir ...string) error {
|
||||
// runs the installation
|
||||
cc, err := config.Scan(collector.Directories(dir...), collector.MergeBootLine, collector.NoLogs)
|
||||
if err == nil && cc.Install != nil && cc.Install.Auto {
|
||||
configStr, err := cc.String()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r["cc"] = configStr
|
||||
r["device"] = cc.Install.Device
|
||||
mergeOption(configStr, r)
|
||||
|
||||
err = RunInstall(r)
|
||||
err = RunInstall(cc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
svc, err := machine.Getty(1)
|
||||
if err == nil {
|
||||
svc.Start() //nolint:errcheck
|
||||
if cc.Install.Reboot == false && cc.Install.Poweroff == false {
|
||||
pterm.DefaultInteractiveContinue.Options = []string{}
|
||||
pterm.DefaultInteractiveContinue.Show("Installation completed, press enter to go back to the shell.")
|
||||
svc, err := machine.Getty(1)
|
||||
if err == nil {
|
||||
svc.Start() //nolint:errcheck
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -196,83 +185,42 @@ func Install(dir ...string) error {
|
||||
|
||||
// we receive a cloud config at this point
|
||||
cloudConfig, exists := r["cc"]
|
||||
|
||||
// merge any options defined in it
|
||||
mergeOption(cloudConfig, r)
|
||||
|
||||
// now merge cloud config from system and
|
||||
// the one received from the agent-provider
|
||||
ccData := map[string]interface{}{}
|
||||
|
||||
// make sure the config we write has at least the #cloud-config header,
|
||||
// if any other was defined beforeahead
|
||||
header := "#cloud-config"
|
||||
if hasHeader, head := config.HasHeader(configStr, ""); hasHeader {
|
||||
header = head
|
||||
}
|
||||
|
||||
// What we receive take precedence over the one in the system. best-effort
|
||||
yaml.Unmarshal([]byte(configStr), &ccData) //nolint:errcheck
|
||||
if exists {
|
||||
yaml.Unmarshal([]byte(cloudConfig), &ccData) //nolint:errcheck
|
||||
if hasHeader, head := config.HasHeader(cloudConfig, ""); hasHeader {
|
||||
header = head
|
||||
}
|
||||
yaml.Unmarshal([]byte(cloudConfig), cc)
|
||||
}
|
||||
|
||||
out, err := yaml.Marshal(ccData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed marshalling cc: %w", err)
|
||||
}
|
||||
|
||||
r["cc"] = config.AddHeader(header, string(out))
|
||||
|
||||
pterm.Info.Println("Starting installation")
|
||||
|
||||
if err := RunInstall(r); err != nil {
|
||||
if err := RunInstall(cc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pterm.Info.Println("Installation completed, press enter to go back to the shell.")
|
||||
if cc.Install.Reboot {
|
||||
pterm.Info.Println("Installation completed, powering off in 5 seconds.")
|
||||
|
||||
utils.Prompt("") //nolint:errcheck
|
||||
}
|
||||
if cc.Install.Poweroff {
|
||||
pterm.Info.Println("Installation completed, rebooting in 5 seconds.")
|
||||
}
|
||||
|
||||
// give tty1 back
|
||||
svc, err := machine.Getty(1)
|
||||
if err == nil {
|
||||
svc.Start() //nolint: errcheck
|
||||
if cc.Install.Reboot == false && cc.Install.Poweroff == false {
|
||||
pterm.DefaultInteractiveContinue.Show("Installation completed, press enter to go back to the shell.")
|
||||
|
||||
utils.Prompt("") //nolint:errcheck
|
||||
|
||||
// give tty1 back
|
||||
svc, err := machine.Getty(1)
|
||||
if err == nil {
|
||||
svc.Start() //nolint: errcheck
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func RunInstall(options map[string]string) error {
|
||||
cloudInit, ok := options["cc"]
|
||||
if !ok {
|
||||
fmt.Println("cloudInit must be specified among options")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// TODO: Drop this and make a more straighforward way of getting the cloud-init and options?
|
||||
c := &config.Config{}
|
||||
yaml.Unmarshal([]byte(cloudInit), c) //nolint:errcheck
|
||||
|
||||
if c.Install == nil {
|
||||
c.Install = &config.Install{}
|
||||
}
|
||||
|
||||
// TODO: Im guessing this was used to try to override elemental values from env vars
|
||||
// Does it make sense anymore? We can now expose the whole options of elemental directly
|
||||
env := append(c.Install.Env, c.Env...)
|
||||
utils.SetEnv(env)
|
||||
|
||||
_, reboot := options["reboot"]
|
||||
_, poweroff := options["poweroff"]
|
||||
if poweroff {
|
||||
c.Install.Poweroff = true
|
||||
}
|
||||
if reboot {
|
||||
c.Install.Reboot = true
|
||||
func RunInstall(c *config.Config) error {
|
||||
if c.Install.Device == "" || c.Install.Device == "auto" {
|
||||
c.Install.Device = detectDevice()
|
||||
}
|
||||
|
||||
// Load the installation Config from the system
|
||||
@ -288,7 +236,12 @@ func RunInstall(options map[string]string) error {
|
||||
}
|
||||
defer os.RemoveAll(f.Name())
|
||||
|
||||
err = os.WriteFile(f.Name(), []byte(cloudInit), os.ModePerm)
|
||||
ccstring, err := c.String()
|
||||
if err != nil {
|
||||
installConfig.Logger.Error("Error creating temporary file for install config: %s\n", err.Error())
|
||||
return err
|
||||
}
|
||||
err = os.WriteFile(f.Name(), []byte(ccstring), os.ModePerm)
|
||||
if err != nil {
|
||||
fmt.Printf("could not write cloud init to %s: %s\n", f.Name(), err.Error())
|
||||
return err
|
||||
@ -306,17 +259,7 @@ func RunInstall(options map[string]string) error {
|
||||
}
|
||||
installSpec.Active.Source = imgSource
|
||||
}
|
||||
// Set the target device
|
||||
device, ok := options["device"]
|
||||
if !ok {
|
||||
fmt.Println("device must be specified among options")
|
||||
return fmt.Errorf("device must be specified among options")
|
||||
}
|
||||
|
||||
if device == "auto" {
|
||||
device = detectDevice()
|
||||
}
|
||||
installSpec.Target = device
|
||||
// Check if values are correct
|
||||
err = installSpec.Sanitize()
|
||||
if err != nil {
|
||||
|
@ -63,7 +63,7 @@ var _ = Describe("prepareConfiguration", func() {
|
||||
})
|
||||
|
||||
var _ = Describe("RunInstall", func() {
|
||||
var options map[string]string
|
||||
var options *config.Config
|
||||
var err error
|
||||
var fs vfs.FS
|
||||
var cleanup func()
|
||||
@ -138,16 +138,11 @@ var _ = Describe("RunInstall", func() {
|
||||
_, err = fs.Create(device)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
|
||||
userConfig := `
|
||||
#cloud-config
|
||||
|
||||
install:
|
||||
image: test
|
||||
`
|
||||
|
||||
options = map[string]string{
|
||||
"device": "/some/device",
|
||||
"cc": userConfig,
|
||||
options = &config.Config{
|
||||
Install: &config.Install{
|
||||
Device: "/some/device",
|
||||
Image: "test",
|
||||
},
|
||||
}
|
||||
|
||||
mainDisk := block.Disk{
|
||||
|
@ -3,6 +3,7 @@ package agent
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gopkg.in/yaml.v3"
|
||||
"strings"
|
||||
|
||||
"github.com/kairos-io/kairos-agent/v2/internal/bus"
|
||||
@ -229,12 +230,6 @@ func InteractiveInstall(debug, spawnShell bool) error {
|
||||
return InteractiveInstall(debug, spawnShell)
|
||||
}
|
||||
|
||||
c := &config.Config{
|
||||
Install: &config.Install{
|
||||
Device: device,
|
||||
},
|
||||
}
|
||||
|
||||
usersToSet := map[string]schema.User{}
|
||||
|
||||
stage := config.NetworkStage.String()
|
||||
@ -264,6 +259,12 @@ func InteractiveInstall(debug, spawnShell bool) error {
|
||||
},
|
||||
}}}
|
||||
|
||||
c := &config.Config{
|
||||
Install: &config.Install{
|
||||
Device: device,
|
||||
},
|
||||
}
|
||||
// Merge all yamls into one
|
||||
dat, err := config.MergeYAML(cloudConfig, c, result)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -272,12 +273,14 @@ func InteractiveInstall(debug, spawnShell bool) error {
|
||||
finalCloudConfig := config.AddHeader("#cloud-config", string(dat))
|
||||
|
||||
pterm.Info.Println("Starting installation")
|
||||
// Generate final config
|
||||
|
||||
cc := &config.Config{}
|
||||
yaml.Unmarshal([]byte(finalCloudConfig), cc)
|
||||
|
||||
pterm.Info.Println(finalCloudConfig)
|
||||
|
||||
err = RunInstall(map[string]string{
|
||||
"device": device,
|
||||
"cc": finalCloudConfig,
|
||||
})
|
||||
err = RunInstall(cc)
|
||||
if err != nil {
|
||||
pterm.Error.Println(err.Error())
|
||||
}
|
||||
|
11
main.go
11
main.go
@ -409,16 +409,7 @@ This command is meant to be used from the boot GRUB menu, but can be also starte
|
||||
}
|
||||
config := c.Args().First()
|
||||
|
||||
options := map[string]string{"device": c.String("device")}
|
||||
|
||||
if c.Bool("poweroff") {
|
||||
options["poweroff"] = "true"
|
||||
}
|
||||
|
||||
if c.Bool("reboot") {
|
||||
options["reboot"] = "true"
|
||||
}
|
||||
return agent.ManualInstall(config, options, c.Bool("strict-validation"))
|
||||
return agent.ManualInstall(config, c.String("device"), c.Bool("reboot"), c.Bool("poweroff"), c.Bool("strict-validation"))
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -497,12 +497,13 @@ func ReadConfigRunFromAgentConfig(c *agentConfig.Config) (*v1.RunConfig, error)
|
||||
cfg := NewRunConfig(WithLogger(v1.NewLogger()), WithImageExtractor(v1.OCIImageExtractor{}))
|
||||
var err error
|
||||
|
||||
cc, err := c.String()
|
||||
ccString, err := c.Config.String()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal([]byte(cc), &cfg)
|
||||
// Load any cloud-config values that override our default Config
|
||||
err = yaml.Unmarshal([]byte(ccString), &cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -511,8 +512,8 @@ func ReadConfigRunFromAgentConfig(c *agentConfig.Config) (*v1.RunConfig, error)
|
||||
viper.Set("debug", true)
|
||||
}
|
||||
configLogger(cfg.Logger, cfg.Fs)
|
||||
// Store the full cloud-config in here, so we can reuse it afterward
|
||||
cfg.FullCloudConfig = cc
|
||||
// Store the full cloud-config in here, so we can reuse it afterward for the spec
|
||||
cfg.FullCloudConfig = ccString
|
||||
err = cfg.Sanitize()
|
||||
cfg.Logger.Debugf("Full config loaded: %s", litter.Sdump(cfg))
|
||||
return cfg, err
|
||||
|
@ -146,7 +146,7 @@ func (r *RunConfig) Sanitize() error {
|
||||
|
||||
// InstallSpec struct represents all the installation action details
|
||||
type InstallSpec struct {
|
||||
Target string `yaml:"target,omitempty" mapstructure:"target"`
|
||||
Target string `yaml:"device,omitempty" mapstructure:"device"`
|
||||
Firmware string `yaml:"firmware,omitempty" mapstructure:"firmware"`
|
||||
PartTable string `yaml:"part-table,omitempty" mapstructure:"part-table"`
|
||||
Partitions ElementalPartitions `yaml:"partitions,omitempty" mapstructure:"partitions"`
|
||||
|
Loading…
Reference in New Issue
Block a user