diff --git a/pkg/elementalcli/elementalcli.go b/pkg/elementalcli/elementalcli.go index f6c459979..027150092 100644 --- a/pkg/elementalcli/elementalcli.go +++ b/pkg/elementalcli/elementalcli.go @@ -87,7 +87,6 @@ func (r *runner) Reset(conf elementalv1.Reset) error { func mapToInstallEnv(conf elementalv1.Install) []string { var variables []string // See GetInstallKeyEnvMap() in https://github.com/rancher/elemental-toolkit/blob/main/pkg/constants/constants.go - variables = append(variables, formatEV("ELEMENTAL_INSTALL_CLOUD_INIT", strings.Join(conf.ConfigURLs[:], ","))) variables = append(variables, formatEV("ELEMENTAL_INSTALL_TARGET", conf.Device)) variables = append(variables, formatEV("ELEMENTAL_INSTALL_SYSTEM", conf.SystemURI)) variables = append(variables, formatEV("ELEMENTAL_INSTALL_FIRMWARE", conf.Firmware)) @@ -106,7 +105,6 @@ func mapToInstallEnv(conf elementalv1.Install) []string { func mapToResetEnv(conf elementalv1.Reset) []string { var variables []string // See GetResetKeyEnvMap() in https://github.com/rancher/elemental-toolkit/blob/main/pkg/constants/constants.go - variables = append(variables, formatEV("ELEMENTAL_RESET_CLOUD_INIT", strings.Join(conf.ConfigURLs[:], ","))) variables = append(variables, formatEV("ELEMENTAL_RESET_SYSTEM", conf.SystemURI)) variables = append(variables, formatEV("ELEMENTAL_RESET_PERSISTENT", strconv.FormatBool(conf.ResetPersistent))) variables = append(variables, formatEV("ELEMENTAL_RESET_OEM", strconv.FormatBool(conf.ResetOEM))) diff --git a/pkg/install/_testdata/after-hook-config-install.yaml b/pkg/install/_testdata/after-hook-config-install.yaml new file mode 100644 index 000000000..3858950a1 --- /dev/null +++ b/pkg/install/_testdata/after-hook-config-install.yaml @@ -0,0 +1,151 @@ +name: Elemental Finalize System +stages: + after-install: + - files: + - path: /run/elemental/oem/elemental-registration.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + name: Include registration config into installed system + stages: + initramfs: + - files: + - path: /oem/registration/config.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + elemental: + registration: + url: https://127.0.0.1.sslip.io/test/registration/endpoint + ca-cert: a test ca + emulate-tpm: true + emulated-tpm-seed: 9876543210 + no-smbios: true + auth: a test auth + network: {} + encoding: "" + ownerstring: "" + directories: + - path: /oem/registration + permissions: 448 + owner: 0 + group: 0 + if: '[ ! -f /oem/registration/config.yaml ]' + encoding: "" + ownerstring: "" + directories: + - path: /run/elemental/oem + permissions: 448 + owner: 0 + group: 0 + name: Registration Config + - files: + - path: /run/elemental/oem/elemental-state.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + name: Include registration state into installed system + stages: + initramfs: + - files: + - path: /oem/registration/state.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + initialRegistration: 2023-08-02T12:35:10.000000003Z + emulatedTPM: true + emulatedTPMSeed: 987654321 + encoding: "" + ownerstring: "" + directories: + - path: /oem/registration + permissions: 448 + owner: 0 + group: 0 + if: '[ ! -f /oem/registration/state.yaml ]' + encoding: "" + ownerstring: "" + directories: + - path: /run/elemental/oem + permissions: 448 + owner: 0 + group: 0 + name: Registration State Config + - files: + - path: /run/elemental/oem/elemental-cloud-init.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + #cloud-config + users: + - name: root + passwd: root + encoding: "" + ownerstring: "" + directories: + - path: /run/elemental/oem + permissions: 448 + owner: 0 + group: 0 + name: Cloud Init Config + - files: + - path: /run/elemental/oem/elemental-system-agent.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + name: Elemental System Agent Configuration + stages: + initramfs: + - files: + - path: /var/lib/elemental/agent/elemental_connection.json + permissions: 384 + owner: 0 + group: 0 + content: '{"kubeConfig":"apiVersion: v1\nclusters:\n- cluster:\n certificate-authority-data: YSB0ZXN0IGNh\n server: https://127.0.0.1.sslip.io/test/control/plane/endpoint\n name: cluster\ncontexts:\n- context:\n cluster: cluster\n user: user\n name: context\ncurrent-context: context\nkind: Config\npreferences: {}\nusers:\n- name: user\n user:\n token: a test token\n","namespace":"a test namespace","secretName":"a test secret name"}' + encoding: "" + ownerstring: "" + - path: /etc/rancher/elemental/agent/config.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + workDirectory: /var/lib/elemental/agent/work + localPlanDirectory: /var/lib/elemental/agent/plans + appliedPlanDirectory: /var/lib/elemental/agent/applied + remoteEnabled: true + connectionInfoFile: /var/lib/elemental/agent/elemental_connection.json + encoding: "" + ownerstring: "" + encoding: "" + ownerstring: "" + directories: + - path: /run/elemental/oem + permissions: 448 + owner: 0 + group: 0 + name: Elemental System Agent Config + - files: + - path: /run/elemental/oem/elemental-network.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + name: Test Network Config Applicator + stages: + foo: + - commands: + - bar + encoding: "" + ownerstring: "" + directories: + - path: /run/elemental/oem + permissions: 448 + owner: 0 + group: 0 + name: Network Config diff --git a/pkg/install/_testdata/after-hook-config-reset.yaml b/pkg/install/_testdata/after-hook-config-reset.yaml new file mode 100644 index 000000000..d4c76b472 --- /dev/null +++ b/pkg/install/_testdata/after-hook-config-reset.yaml @@ -0,0 +1,151 @@ +name: Elemental Finalize System +stages: + after-reset: + - files: + - path: /run/elemental/oem/elemental-registration.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + name: Include registration config into installed system + stages: + initramfs: + - files: + - path: /oem/registration/config.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + elemental: + registration: + url: https://127.0.0.1.sslip.io/test/registration/endpoint + ca-cert: a test ca + emulate-tpm: true + emulated-tpm-seed: 9876543210 + no-smbios: true + auth: a test auth + network: {} + encoding: "" + ownerstring: "" + directories: + - path: /oem/registration + permissions: 448 + owner: 0 + group: 0 + if: '[ ! -f /oem/registration/config.yaml ]' + encoding: "" + ownerstring: "" + directories: + - path: /run/elemental/oem + permissions: 448 + owner: 0 + group: 0 + name: Registration Config + - files: + - path: /run/elemental/oem/elemental-state.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + name: Include registration state into installed system + stages: + initramfs: + - files: + - path: /oem/registration/state.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + initialRegistration: 2023-08-02T12:35:10.000000003Z + emulatedTPM: true + emulatedTPMSeed: 987654321 + encoding: "" + ownerstring: "" + directories: + - path: /oem/registration + permissions: 448 + owner: 0 + group: 0 + if: '[ ! -f /oem/registration/state.yaml ]' + encoding: "" + ownerstring: "" + directories: + - path: /run/elemental/oem + permissions: 448 + owner: 0 + group: 0 + name: Registration State Config + - files: + - path: /run/elemental/oem/elemental-cloud-init.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + #cloud-config + users: + - name: root + passwd: root + encoding: "" + ownerstring: "" + directories: + - path: /run/elemental/oem + permissions: 448 + owner: 0 + group: 0 + name: Cloud Init Config + - files: + - path: /run/elemental/oem/elemental-system-agent.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + name: Elemental System Agent Configuration + stages: + initramfs: + - files: + - path: /var/lib/elemental/agent/elemental_connection.json + permissions: 384 + owner: 0 + group: 0 + content: '{"kubeConfig":"apiVersion: v1\nclusters:\n- cluster:\n certificate-authority-data: YSB0ZXN0IGNh\n server: https://127.0.0.1.sslip.io/test/control/plane/endpoint\n name: cluster\ncontexts:\n- context:\n cluster: cluster\n user: user\n name: context\ncurrent-context: context\nkind: Config\npreferences: {}\nusers:\n- name: user\n user:\n token: a test token\n","namespace":"a test namespace","secretName":"a test secret name"}' + encoding: "" + ownerstring: "" + - path: /etc/rancher/elemental/agent/config.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + workDirectory: /var/lib/elemental/agent/work + localPlanDirectory: /var/lib/elemental/agent/plans + appliedPlanDirectory: /var/lib/elemental/agent/applied + remoteEnabled: true + connectionInfoFile: /var/lib/elemental/agent/elemental_connection.json + encoding: "" + ownerstring: "" + encoding: "" + ownerstring: "" + directories: + - path: /run/elemental/oem + permissions: 448 + owner: 0 + group: 0 + name: Elemental System Agent Config + - files: + - path: /run/elemental/oem/elemental-network.yaml + permissions: 384 + owner: 0 + group: 0 + content: | + name: Test Network Config Applicator + stages: + foo: + - commands: + - bar + encoding: "" + ownerstring: "" + directories: + - path: /run/elemental/oem + permissions: 448 + owner: 0 + group: 0 + name: Network Config diff --git a/pkg/install/_testdata/cloud-init-config.yaml b/pkg/install/_testdata/cloud-init-config.yaml deleted file mode 100644 index fb49c03df..000000000 --- a/pkg/install/_testdata/cloud-init-config.yaml +++ /dev/null @@ -1,4 +0,0 @@ -#cloud-config -users: -- name: root - passwd: root diff --git a/pkg/install/_testdata/network-config-applicator.yaml b/pkg/install/_testdata/network-config-applicator.yaml deleted file mode 100644 index feb5d2a1c..000000000 --- a/pkg/install/_testdata/network-config-applicator.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: Test Network Config Applicator -stages: - foo: - - commands: - - bar diff --git a/pkg/install/_testdata/registration-config-config.yaml b/pkg/install/_testdata/registration-config-config.yaml deleted file mode 100644 index 8fc054399..000000000 --- a/pkg/install/_testdata/registration-config-config.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: Include registration config into installed system -stages: - initramfs: - - files: - - path: /oem/registration/config.yaml - permissions: 384 - owner: 0 - group: 0 - content: | - elemental: - registration: - url: https://127.0.0.1.sslip.io/test/registration/endpoint - ca-cert: a test ca - emulate-tpm: true - emulated-tpm-seed: 9876543210 - no-smbios: true - auth: a test auth - network: {} - encoding: "" - ownerstring: "" - directories: - - path: /oem/registration - permissions: 448 - owner: 0 - group: 0 - if: '[ ! -f /oem/registration/config.yaml ]' diff --git a/pkg/install/_testdata/registration-state-config.yaml b/pkg/install/_testdata/registration-state-config.yaml deleted file mode 100644 index 0feb15876..000000000 --- a/pkg/install/_testdata/registration-state-config.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: Include registration state into installed system -stages: - initramfs: - - files: - - path: /oem/registration/state.yaml - permissions: 384 - owner: 0 - group: 0 - content: | - initialRegistration: 2023-08-02T12:35:10.000000003Z - emulatedTPM: true - emulatedTPMSeed: 987654321 - encoding: "" - ownerstring: "" - directories: - - path: /oem/registration - permissions: 448 - owner: 0 - group: 0 - if: '[ ! -f /oem/registration/state.yaml ]' diff --git a/pkg/install/_testdata/system-agent-config.yaml b/pkg/install/_testdata/system-agent-config.yaml deleted file mode 100644 index 2e833ec47..000000000 --- a/pkg/install/_testdata/system-agent-config.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: Elemental System Agent Configuration -stages: - initramfs: - - files: - - path: /var/lib/elemental/agent/elemental_connection.json - permissions: 384 - owner: 0 - group: 0 - content: '{"kubeConfig":"apiVersion: v1\nclusters:\n- cluster:\n certificate-authority-data: YSB0ZXN0IGNh\n server: https://127.0.0.1.sslip.io/test/control/plane/endpoint\n name: cluster\ncontexts:\n- context:\n cluster: cluster\n user: user\n name: context\ncurrent-context: context\nkind: Config\npreferences: {}\nusers:\n- name: user\n user:\n token: a test token\n","namespace":"a test namespace","secretName":"a test secret name"}' - encoding: "" - ownerstring: "" - - path: /etc/rancher/elemental/agent/config.yaml - permissions: 384 - owner: 0 - group: 0 - content: | - workDirectory: /var/lib/elemental/agent/work - localPlanDirectory: /var/lib/elemental/agent/plans - appliedPlanDirectory: /var/lib/elemental/agent/applied - remoteEnabled: true - connectionInfoFile: /var/lib/elemental/agent/elemental_connection.json - encoding: "" - ownerstring: "" diff --git a/pkg/install/install.go b/pkg/install/install.go index 61d956884..ed5e61362 100644 --- a/pkg/install/install.go +++ b/pkg/install/install.go @@ -50,14 +50,15 @@ const ( registrationState = "/oem/registration/state.yaml" ) -// Temporary cloud-init configuration files. -// These paths will be passed to the `elemental` cli as additional `config-urls`. const ( - tempRegistrationConf = "/tmp/elemental-registration-conf.yaml" - tempRegistrationState = "/tmp/elemental-registration-state.yaml" - tempCloudInit = "/tmp/elemental-cloud-init.yaml" - tempSystemAgent = "/tmp/elemental-system-agent.yaml" - tempNetworkConfig = "/tmp/elemental-network-config.yaml" + afterInstallStage = "after-install" + afterResetStage = "after-reset" + elementalAfterHookPath = "/system/oem/elemental-after-hook.yaml" // Used in after-{install|reset} stages + registrationConfigPath = "/run/elemental/oem/elemental-registration.yaml" + stateConfigPath = "/run/elemental/oem/elemental-state.yaml" + cloudInitConfigPath = "/run/elemental/oem/elemental-cloud-init.yaml" + systemAgentConfigPath = "/run/elemental/oem/elemental-system-agent.yaml" + networkConfigPath = "/run/elemental/oem/elemental-network.yaml" ) type Installer interface { @@ -101,13 +102,10 @@ func (i *installer) InstallElemental(config elementalv1.Config, state register.S log.Warningf("Both device and device-selector set, using device-field '%s'", config.Elemental.Install.Device) } - additionalConfigs, err := i.getCloudInitConfigs(config, state, networkConfig) - if err != nil { - return fmt.Errorf("generating additional cloud configs: %w", err) + if err := i.writeAfterHookConfigurator(afterInstallStage, config, state, networkConfig); err != nil { + return fmt.Errorf("writing %s configurator: %w", afterInstallStage, err) } - config.Elemental.Install.ConfigURLs = append(config.Elemental.Install.ConfigURLs, additionalConfigs...) - if err := i.runner.Install(config.Elemental.Install); err != nil { return fmt.Errorf("failed to install elemental: %w", err) } @@ -121,11 +119,9 @@ func (i *installer) ResetElemental(config elementalv1.Config, state register.Sta config.Elemental.Reset.ConfigURLs = []string{} } - additionalConfigs, err := i.getCloudInitConfigs(config, state, networkConfig) - if err != nil { - return fmt.Errorf("generating additional cloud configs: %w", err) + if err := i.writeAfterHookConfigurator(afterResetStage, config, state, networkConfig); err != nil { + return fmt.Errorf("writing %s configurator: %w", afterResetStage, err) } - config.Elemental.Reset.ConfigURLs = append(config.Elemental.Reset.ConfigURLs, additionalConfigs...) if err := i.runner.Reset(config.Elemental.Reset); err != nil { return fmt.Errorf("failed to reset elemental: %w", err) @@ -239,66 +235,102 @@ func matchesGt(disk *block.Disk, req elementalv1.DeviceSelectorRequirement) (boo return diskSize.Cmp(keySize) == 1, nil } -// getCloudInitConfigs creates cloud-init configuration files that can be passed as additional `config-urls` -// to the `elemental` cli. We exploit this mechanism to persist information during `elemental install` -// or `elemental reset` calls into the newly installed or resetted system. -func (i *installer) getCloudInitConfigs(config elementalv1.Config, state register.State, networkConfig elementalv1.NetworkConfig) ([]string, error) { - configs := []string{} - agentConfPath, err := i.writeSystemAgentConfig(config.Elemental) +func (i *installer) writeAfterHookConfigurator(stage string, config elementalv1.Config, state register.State, networkConfig elementalv1.NetworkConfig) error { + afterHookConfigurator := schema.YipConfig{} + afterHookConfigurator.Name = "Elemental Finalize System" + afterHookConfigurator.Stages = map[string][]schema.Stage{ + stage: {}, + } + + // Registration + registrationYipBytes, err := i.registrationConfigYip(config.Elemental.Registration) if err != nil { - return nil, fmt.Errorf("writing system agent configuration: %w", err) + return fmt.Errorf("getting registration config yip: %w", err) } - configs = append(configs, agentConfPath) + registrationYip := yipAfterHookWrap(string(registrationYipBytes), registrationConfigPath, "Registration Config") + afterHookConfigurator.Stages[stage] = append(afterHookConfigurator.Stages[stage], registrationYip) - if len(config.CloudConfig) > 0 { - cloudInitPath, err := i.writeCloudInit(config.CloudConfig) - if err != nil { - return nil, fmt.Errorf("writing custom cloud-init file: %w", err) - } - configs = append(configs, cloudInitPath) + // State + stateYipBytes, err := i.registrationStateYip(state) + if err != nil { + return fmt.Errorf("getting registration state config yip: %w", err) } + stateYip := yipAfterHookWrap(string(stateYipBytes), stateConfigPath, "Registration State Config") + afterHookConfigurator.Stages[stage] = append(afterHookConfigurator.Stages[stage], stateYip) - registrationConfPath, err := i.writeRegistrationYAML(config.Elemental.Registration) + // Cloud Init + cloudInitYipBytes, err := i.cloudInitYip(config.CloudConfig) if err != nil { - return nil, fmt.Errorf("writing registration conf plan: %w", err) + return fmt.Errorf("getting cloud-init config yip: %w", err) } - configs = append(configs, registrationConfPath) + cloudInitYip := yipAfterHookWrap(string(cloudInitYipBytes), cloudInitConfigPath, "Cloud Init Config") + afterHookConfigurator.Stages[stage] = append(afterHookConfigurator.Stages[stage], cloudInitYip) - registrationStatePath, err := i.writeRegistrationState(state) + // Elemental System Agent + systemAgentYipBytes, err := i.elementalSystemAgentYip(config.Elemental) if err != nil { - return nil, fmt.Errorf("writing registration state plan: %w", err) + return fmt.Errorf("getting elemental system agent config yip: %w", err) + } + systemAgentYip := yipAfterHookWrap(string(systemAgentYipBytes), systemAgentConfigPath, "Elemental System Agent Config") + afterHookConfigurator.Stages[stage] = append(afterHookConfigurator.Stages[stage], systemAgentYip) + + // Network Config + networkConfigYipBytes, err := i.networkConfigYip(networkConfig) + if err != nil && !errors.Is(err, network.ErrEmptyConfig) { + return fmt.Errorf("getting network config yip: %w", err) + } + if !errors.Is(err, network.ErrEmptyConfig) { + networkConfigYip := yipAfterHookWrap(string(networkConfigYipBytes), networkConfigPath, "Network Config") + afterHookConfigurator.Stages[stage] = append(afterHookConfigurator.Stages[stage], networkConfigYip) } - configs = append(configs, registrationStatePath) - networkConfigPath, err := i.writeNetworkConfig(networkConfig) - if errors.Is(err, network.ErrEmptyConfig) { - // Nothing to do on an empty network config. - return configs, nil + // Create dir if not exist + if err := vfs.MkdirAll(i.fs, filepath.Dir(elementalAfterHookPath), 0700); err != nil { + return fmt.Errorf("creating directory '%s': %w", filepath.Dir(elementalAfterHookPath), err) } + // Create the after hook configurator yip + f, err := i.fs.Create(elementalAfterHookPath) if err != nil { - return nil, fmt.Errorf("writing temporary network config: %w", err) + return fmt.Errorf("creating file '%s': %w", elementalAfterHookPath, err) + } + defer f.Close() + + if err := yaml.NewEncoder(f).Encode(afterHookConfigurator); err != nil { + return fmt.Errorf("writing encoded after hook configurator: %w", err) } - configs = append(configs, networkConfigPath) - return configs, nil + return nil } -func (i *installer) writeRegistrationYAML(reg elementalv1.Registration) (string, error) { - f, err := i.fs.Create(tempRegistrationConf) - if err != nil { - return "", fmt.Errorf("creating temporary registration conf plan file: %w", err) +func yipAfterHookWrap(content string, path string, name string) schema.Stage { + config := schema.Stage{Name: name} + config.Directories = []schema.Directory{ + { + Path: filepath.Dir(path), + Permissions: 0700, + }, } - defer f.Close() + config.Files = []schema.File{ + { + Path: path, + Content: content, + Permissions: 0600, + }, + } + return config +} + +func (i *installer) registrationConfigYip(reg elementalv1.Registration) ([]byte, error) { registrationInBytes, err := yaml.Marshal(elementalv1.Config{ Elemental: elementalv1.Elemental{ Registration: reg, }, }) if err != nil { - return "", fmt.Errorf("marshalling registration config: %w", err) + return nil, fmt.Errorf("marshalling registration config: %w", err) } - if err := yaml.NewEncoder(f).Encode(schema.YipConfig{ + yipConfig := schema.YipConfig{ Name: "Include registration config into installed system", Stages: map[string][]schema.Stage{ "initramfs": { @@ -319,24 +351,23 @@ func (i *installer) writeRegistrationYAML(reg elementalv1.Registration) (string, }, }, }, - }); err != nil { - return "", fmt.Errorf("writing encoded registration config config: %w", err) } - return f.Name(), nil -} -func (i *installer) writeRegistrationState(state register.State) (string, error) { - f, err := i.fs.Create(tempRegistrationState) + yipConfigBytes, err := yaml.Marshal(yipConfig) if err != nil { - return "", fmt.Errorf("creating temporary registration state plan file: %w", err) + return nil, fmt.Errorf("marshalling yip registration config: %w", err) } - defer f.Close() + + return yipConfigBytes, nil +} + +func (i *installer) registrationStateYip(state register.State) ([]byte, error) { stateBytes, err := yaml.Marshal(state) if err != nil { - return "", fmt.Errorf("marshalling registration state: %w", err) + return nil, fmt.Errorf("marshalling registration state: %w", err) } - if err := yaml.NewEncoder(f).Encode(schema.YipConfig{ + yipConfig := schema.YipConfig{ Name: "Include registration state into installed system", Stages: map[string][]schema.Stage{ "initramfs": { @@ -357,47 +388,37 @@ func (i *installer) writeRegistrationState(state register.State) (string, error) }, }, }, - }); err != nil { - return "", fmt.Errorf("writing encoded registration state config: %w", err) } - return f.Name(), nil -} -func (i *installer) writeCloudInit(cloudConfig map[string]runtime.RawExtension) (string, error) { - f, err := i.fs.Create(tempCloudInit) + yipConfigBytes, err := yaml.Marshal(yipConfig) if err != nil { - return "", fmt.Errorf("creating temporary cloud init file: %w", err) + return nil, fmt.Errorf("marshalling yip state config: %w", err) } - defer f.Close() + return yipConfigBytes, nil +} + +func (i *installer) cloudInitYip(cloudConfig map[string]runtime.RawExtension) ([]byte, error) { bytes, err := util.MarshalCloudConfig(cloudConfig) if err != nil { - return "", fmt.Errorf("mashalling cloud config: %w", err) + return nil, fmt.Errorf("mashalling cloud config: %w", err) } - log.Debugf("Decoded CloudConfig:\n%s\n", string(bytes)) - if _, err = f.Write(bytes); err != nil { - return "", fmt.Errorf("writing cloud config: %w", err) - } - return f.Name(), nil + return bytes, nil } -func (i *installer) writeNetworkConfig(networkConfig elementalv1.NetworkConfig) (string, error) { +func (i *installer) networkConfigYip(networkConfig elementalv1.NetworkConfig) ([]byte, error) { networkYipConfig, err := i.networkConfigurator.GetNetworkConfigApplicator(networkConfig) if err != nil { - return "", fmt.Errorf("getting network config applicator: %w", err) + return nil, fmt.Errorf("getting network config applicator: %w", err) } - f, err := i.fs.Create(tempNetworkConfig) + yipConfigBytes, err := yaml.Marshal(networkYipConfig) if err != nil { - return "", fmt.Errorf("creating temporary network-config file: %w", err) + return nil, fmt.Errorf("marshalling yip network config: %w", err) } - defer f.Close() - if err := yaml.NewEncoder(f).Encode(networkYipConfig); err != nil { - return "", fmt.Errorf("writing encoded network-config: %w", err) - } - return f.Name(), nil + return yipConfigBytes, nil } func (i *installer) getConnectionInfoBytes(config elementalv1.Elemental) ([]byte, error) { @@ -492,15 +513,14 @@ func (i *installer) WriteLocalSystemAgentConfig(config elementalv1.Elemental) er return nil } -// Write system agent cloud-init config to be consumed by install -func (i *installer) writeSystemAgentConfig(config elementalv1.Elemental) (string, error) { +func (i *installer) elementalSystemAgentYip(config elementalv1.Elemental) ([]byte, error) { connectionInfoBytes, err := i.getConnectionInfoBytes(config) if err != nil { - return "", fmt.Errorf("getting connection info: %w", err) + return nil, fmt.Errorf("getting connection info: %w", err) } agentConfigBytes, err := i.getAgentConfigBytes() if err != nil { - return "", fmt.Errorf("getting agent config: %w", err) + return nil, fmt.Errorf("getting agent config: %w", err) } var stages []schema.Stage @@ -520,21 +540,19 @@ func (i *installer) writeSystemAgentConfig(config elementalv1.Elemental) (string }, }) - f, err := i.fs.Create(tempSystemAgent) - if err != nil { - return "", fmt.Errorf("creating temporary elemental-system-agent file: %w", err) - } - defer f.Close() - - if err := yaml.NewEncoder(f).Encode(schema.YipConfig{ + yipConfig := schema.YipConfig{ Name: "Elemental System Agent Configuration", Stages: map[string][]schema.Stage{ "initramfs": stages, }, - }); err != nil { - return "", fmt.Errorf("writing encoded system agent config: %w", err) } - return f.Name(), nil + + yipConfigBytes, err := yaml.Marshal(yipConfig) + if err != nil { + return nil, fmt.Errorf("marshalling yip system agent config: %w", err) + } + + return yipConfigBytes, nil } func (i *installer) cleanupResetPlan() error { diff --git a/pkg/install/install_test.go b/pkg/install/install_test.go index 3557883e2..5dc3e5f32 100644 --- a/pkg/install/install_test.go +++ b/pkg/install/install_test.go @@ -17,7 +17,6 @@ limitations under the License. package install import ( - "fmt" "os" "testing" "time" @@ -141,23 +140,10 @@ var _ = Describe("installer install elemental", Label("installer", "install"), f DeferCleanup(fsCleanup) }) It("should call elemental install", func() { - wantConfig := configFixture.DeepCopy() - wantConfig.Elemental.Install.ConfigURLs = append(wantConfig.Elemental.Install.ConfigURLs, additionalConfigs(fs)...) - cliRunner.EXPECT().Install(wantConfig.Elemental.Install).Return(nil) - networkConfigurator.EXPECT().GetNetworkConfigApplicator(elementalv1.NetworkConfig{}).Return(schema.YipConfig{}, network.ErrEmptyConfig) - Expect(install.InstallElemental(configFixture, stateFixture, elementalv1.NetworkConfig{})).ToNot(HaveOccurred()) - checkConfigs(fs) - }) - It("should install network config", func() { - wantConfig := configFixture.DeepCopy() - wantConfigs := additionalConfigs(fs) - wantConfigs = append(wantConfigs, networkConfig(fs)) - wantConfig.Elemental.Install.ConfigURLs = append(wantConfig.Elemental.Install.ConfigURLs, wantConfigs...) - cliRunner.EXPECT().Install(wantConfig.Elemental.Install).Return(nil) + cliRunner.EXPECT().Install(configFixture.Elemental.Install).Return(nil) networkConfigurator.EXPECT().GetNetworkConfigApplicator(networkConfigFixture).Return(networkConfigApplicatorFixture, nil) Expect(install.InstallElemental(configFixture, stateFixture, networkConfigFixture)).ToNot(HaveOccurred()) - checkConfigs(fs) - compareFiles(fs, tempNetworkConfig, "_testdata/network-config-applicator.yaml") + compareFiles(fs, elementalAfterHookPath, "_testdata/after-hook-config-install.yaml") }) }) @@ -305,12 +291,10 @@ var _ = Describe("installer reset elemental", Label("installer", "reset"), func( DeferCleanup(fsCleanup) }) It("should call elemental reset", func() { - wantConfig := configFixture.DeepCopy() - wantConfig.Elemental.Reset.ConfigURLs = append(wantConfig.Elemental.Reset.ConfigURLs, additionalConfigs(fs)...) - cliRunner.EXPECT().Reset(wantConfig.Elemental.Reset).Return(nil) - networkConfigurator.EXPECT().GetNetworkConfigApplicator(elementalv1.NetworkConfig{}).Return(schema.YipConfig{}, network.ErrEmptyConfig) - Expect(install.ResetElemental(configFixture, stateFixture, elementalv1.NetworkConfig{})).ToNot(HaveOccurred()) - checkConfigs(fs) + cliRunner.EXPECT().Reset(configFixture.Elemental.Reset).Return(nil) + networkConfigurator.EXPECT().GetNetworkConfigApplicator(networkConfigFixture).Return(networkConfigApplicatorFixture, nil) + Expect(install.ResetElemental(configFixture, stateFixture, networkConfigFixture)).ToNot(HaveOccurred()) + compareFiles(fs, elementalAfterHookPath, "_testdata/after-hook-config-reset.yaml") }) It("should remove reset plan", func() { Expect(fs.WriteFile(controllers.LocalResetPlanPath, []byte("{}\n"), os.FileMode(0600))).ToNot(HaveOccurred()) @@ -320,41 +304,8 @@ var _ = Describe("installer reset elemental", Label("installer", "reset"), func( _, err := fs.Stat(controllers.LocalResetPlanPath) Expect(err).To(MatchError(os.ErrNotExist)) }) - It("should install network config", func() { - wantConfig := configFixture.DeepCopy() - wantConfigs := additionalConfigs(fs) - wantConfigs = append(wantConfigs, networkConfig(fs)) - wantConfig.Elemental.Reset.ConfigURLs = append(wantConfig.Elemental.Reset.ConfigURLs, wantConfigs...) - cliRunner.EXPECT().Reset(wantConfig.Elemental.Reset).Return(nil) - networkConfigurator.EXPECT().GetNetworkConfigApplicator(networkConfigFixture).Return(networkConfigApplicatorFixture, nil) - Expect(install.ResetElemental(configFixture, stateFixture, networkConfigFixture)).ToNot(HaveOccurred()) - checkConfigs(fs) - compareFiles(fs, tempNetworkConfig, "_testdata/network-config-applicator.yaml") - }) }) -func additionalConfigs(fs *vfst.TestFS) []string { - // Prefix the go-vfs temp dir because that's what file.Name() returns - return []string{ - fmt.Sprintf("%s%s", fs.TempDir(), tempSystemAgent), - fmt.Sprintf("%s%s", fs.TempDir(), tempCloudInit), - fmt.Sprintf("%s%s", fs.TempDir(), tempRegistrationConf), - fmt.Sprintf("%s%s", fs.TempDir(), tempRegistrationState), - } -} - -func networkConfig(fs *vfst.TestFS) string { - // Prefix the go-vfs temp dir because that's what file.Name() returns - return fmt.Sprintf("%s%s", fs.TempDir(), tempNetworkConfig) -} - -func checkConfigs(fs vfs.FS) { - compareFiles(fs, tempRegistrationConf, "_testdata/registration-config-config.yaml") - compareFiles(fs, tempRegistrationState, "_testdata/registration-state-config.yaml") - compareFiles(fs, tempSystemAgent, "_testdata/system-agent-config.yaml") - compareFiles(fs, tempCloudInit, "_testdata/cloud-init-config.yaml") -} - func compareFiles(fs vfs.FS, got string, want string) { gotFile, err := fs.ReadFile(got) Expect(err).ToNot(HaveOccurred())