mirror of
https://github.com/kairos-io/kairos-agent.git
synced 2025-08-19 08:47:03 +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())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@ -75,28 +75,21 @@ func ManualInstall(c string, options map[string]string, strictValidations bool)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 reboot {
|
||||||
|
// Override from flags!
|
||||||
|
cc.Install.Reboot = true
|
||||||
|
}
|
||||||
|
|
||||||
if options["device"] == "" {
|
if poweroff {
|
||||||
// IF cc is nil we will panic, check beforehand.
|
// Override from flags!
|
||||||
// If we set no device then we will exit later down the line anyway
|
cc.Install.Poweroff = true
|
||||||
if cc.Install != nil {
|
|
||||||
if cc.Install.Device == "" {
|
|
||||||
options["device"] = detectDevice()
|
|
||||||
} else {
|
|
||||||
options["device"] = cc.Install.Device
|
|
||||||
}
|
}
|
||||||
|
if device != "" {
|
||||||
|
// Override from flags!
|
||||||
|
cc.Install.Device = device
|
||||||
}
|
}
|
||||||
}
|
return RunInstall(cc)
|
||||||
return RunInstall(options)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Install(dir ...string) error {
|
func Install(dir ...string) error {
|
||||||
@ -127,23 +120,19 @@ func Install(dir ...string) error {
|
|||||||
// runs the installation
|
// runs the installation
|
||||||
cc, err := config.Scan(collector.Directories(dir...), collector.MergeBootLine, collector.NoLogs)
|
cc, err := config.Scan(collector.Directories(dir...), collector.MergeBootLine, collector.NoLogs)
|
||||||
if err == nil && cc.Install != nil && cc.Install.Auto {
|
if err == nil && cc.Install != nil && cc.Install.Auto {
|
||||||
configStr, err := cc.String()
|
err = RunInstall(cc)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r["cc"] = configStr
|
|
||||||
r["device"] = cc.Install.Device
|
|
||||||
mergeOption(configStr, r)
|
|
||||||
|
|
||||||
err = RunInstall(r)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
svc, err := machine.Getty(1)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
svc.Start() //nolint:errcheck
|
svc.Start() //nolint:errcheck
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -196,44 +185,26 @@ func Install(dir ...string) error {
|
|||||||
|
|
||||||
// we receive a cloud config at this point
|
// we receive a cloud config at this point
|
||||||
cloudConfig, exists := r["cc"]
|
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 {
|
if exists {
|
||||||
yaml.Unmarshal([]byte(cloudConfig), &ccData) //nolint:errcheck
|
yaml.Unmarshal([]byte(cloudConfig), cc)
|
||||||
if hasHeader, head := config.HasHeader(cloudConfig, ""); hasHeader {
|
|
||||||
header = head
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
pterm.Info.Println("Starting installation")
|
||||||
|
|
||||||
if err := RunInstall(r); err != nil {
|
if err := RunInstall(cc); err != nil {
|
||||||
return err
|
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.")
|
||||||
|
|
||||||
|
}
|
||||||
|
if cc.Install.Poweroff {
|
||||||
|
pterm.Info.Println("Installation completed, rebooting in 5 seconds.")
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
utils.Prompt("") //nolint:errcheck
|
||||||
|
|
||||||
@ -242,37 +213,14 @@ func Install(dir ...string) error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
svc.Start() //nolint: errcheck
|
svc.Start() //nolint: errcheck
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunInstall(options map[string]string) error {
|
func RunInstall(c *config.Config) error {
|
||||||
cloudInit, ok := options["cc"]
|
if c.Install.Device == "" || c.Install.Device == "auto" {
|
||||||
if !ok {
|
c.Install.Device = detectDevice()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the installation Config from the system
|
// Load the installation Config from the system
|
||||||
@ -288,7 +236,12 @@ func RunInstall(options map[string]string) error {
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(f.Name())
|
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 {
|
if err != nil {
|
||||||
fmt.Printf("could not write cloud init to %s: %s\n", f.Name(), err.Error())
|
fmt.Printf("could not write cloud init to %s: %s\n", f.Name(), err.Error())
|
||||||
return err
|
return err
|
||||||
@ -306,17 +259,7 @@ func RunInstall(options map[string]string) error {
|
|||||||
}
|
}
|
||||||
installSpec.Active.Source = imgSource
|
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
|
// Check if values are correct
|
||||||
err = installSpec.Sanitize()
|
err = installSpec.Sanitize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -63,7 +63,7 @@ var _ = Describe("prepareConfiguration", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
var _ = Describe("RunInstall", func() {
|
var _ = Describe("RunInstall", func() {
|
||||||
var options map[string]string
|
var options *config.Config
|
||||||
var err error
|
var err error
|
||||||
var fs vfs.FS
|
var fs vfs.FS
|
||||||
var cleanup func()
|
var cleanup func()
|
||||||
@ -138,16 +138,11 @@ var _ = Describe("RunInstall", func() {
|
|||||||
_, err = fs.Create(device)
|
_, err = fs.Create(device)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
|
||||||
userConfig := `
|
options = &config.Config{
|
||||||
#cloud-config
|
Install: &config.Install{
|
||||||
|
Device: "/some/device",
|
||||||
install:
|
Image: "test",
|
||||||
image: test
|
},
|
||||||
`
|
|
||||||
|
|
||||||
options = map[string]string{
|
|
||||||
"device": "/some/device",
|
|
||||||
"cc": userConfig,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mainDisk := block.Disk{
|
mainDisk := block.Disk{
|
||||||
|
@ -3,6 +3,7 @@ package agent
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/kairos-io/kairos-agent/v2/internal/bus"
|
"github.com/kairos-io/kairos-agent/v2/internal/bus"
|
||||||
@ -229,12 +230,6 @@ func InteractiveInstall(debug, spawnShell bool) error {
|
|||||||
return InteractiveInstall(debug, spawnShell)
|
return InteractiveInstall(debug, spawnShell)
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &config.Config{
|
|
||||||
Install: &config.Install{
|
|
||||||
Device: device,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
usersToSet := map[string]schema.User{}
|
usersToSet := map[string]schema.User{}
|
||||||
|
|
||||||
stage := config.NetworkStage.String()
|
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)
|
dat, err := config.MergeYAML(cloudConfig, c, result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -272,12 +273,14 @@ func InteractiveInstall(debug, spawnShell bool) error {
|
|||||||
finalCloudConfig := config.AddHeader("#cloud-config", string(dat))
|
finalCloudConfig := config.AddHeader("#cloud-config", string(dat))
|
||||||
|
|
||||||
pterm.Info.Println("Starting installation")
|
pterm.Info.Println("Starting installation")
|
||||||
|
// Generate final config
|
||||||
|
|
||||||
|
cc := &config.Config{}
|
||||||
|
yaml.Unmarshal([]byte(finalCloudConfig), cc)
|
||||||
|
|
||||||
pterm.Info.Println(finalCloudConfig)
|
pterm.Info.Println(finalCloudConfig)
|
||||||
|
|
||||||
err = RunInstall(map[string]string{
|
err = RunInstall(cc)
|
||||||
"device": device,
|
|
||||||
"cc": finalCloudConfig,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pterm.Error.Println(err.Error())
|
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()
|
config := c.Args().First()
|
||||||
|
|
||||||
options := map[string]string{"device": c.String("device")}
|
return agent.ManualInstall(config, c.String("device"), c.Bool("reboot"), c.Bool("poweroff"), c.Bool("strict-validation"))
|
||||||
|
|
||||||
if c.Bool("poweroff") {
|
|
||||||
options["poweroff"] = "true"
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Bool("reboot") {
|
|
||||||
options["reboot"] = "true"
|
|
||||||
}
|
|
||||||
return agent.ManualInstall(config, options, c.Bool("strict-validation"))
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -497,12 +497,13 @@ func ReadConfigRunFromAgentConfig(c *agentConfig.Config) (*v1.RunConfig, error)
|
|||||||
cfg := NewRunConfig(WithLogger(v1.NewLogger()), WithImageExtractor(v1.OCIImageExtractor{}))
|
cfg := NewRunConfig(WithLogger(v1.NewLogger()), WithImageExtractor(v1.OCIImageExtractor{}))
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
cc, err := c.String()
|
ccString, err := c.Config.String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -511,8 +512,8 @@ func ReadConfigRunFromAgentConfig(c *agentConfig.Config) (*v1.RunConfig, error)
|
|||||||
viper.Set("debug", true)
|
viper.Set("debug", true)
|
||||||
}
|
}
|
||||||
configLogger(cfg.Logger, cfg.Fs)
|
configLogger(cfg.Logger, cfg.Fs)
|
||||||
// Store the full cloud-config in here, so we can reuse it afterward
|
// Store the full cloud-config in here, so we can reuse it afterward for the spec
|
||||||
cfg.FullCloudConfig = cc
|
cfg.FullCloudConfig = ccString
|
||||||
err = cfg.Sanitize()
|
err = cfg.Sanitize()
|
||||||
cfg.Logger.Debugf("Full config loaded: %s", litter.Sdump(cfg))
|
cfg.Logger.Debugf("Full config loaded: %s", litter.Sdump(cfg))
|
||||||
return cfg, err
|
return cfg, err
|
||||||
|
@ -146,7 +146,7 @@ func (r *RunConfig) Sanitize() error {
|
|||||||
|
|
||||||
// InstallSpec struct represents all the installation action details
|
// InstallSpec struct represents all the installation action details
|
||||||
type InstallSpec struct {
|
type InstallSpec struct {
|
||||||
Target string `yaml:"target,omitempty" mapstructure:"target"`
|
Target string `yaml:"device,omitempty" mapstructure:"device"`
|
||||||
Firmware string `yaml:"firmware,omitempty" mapstructure:"firmware"`
|
Firmware string `yaml:"firmware,omitempty" mapstructure:"firmware"`
|
||||||
PartTable string `yaml:"part-table,omitempty" mapstructure:"part-table"`
|
PartTable string `yaml:"part-table,omitempty" mapstructure:"part-table"`
|
||||||
Partitions ElementalPartitions `yaml:"partitions,omitempty" mapstructure:"partitions"`
|
Partitions ElementalPartitions `yaml:"partitions,omitempty" mapstructure:"partitions"`
|
||||||
|
Loading…
Reference in New Issue
Block a user