diff --git a/src/ignition/ignition.go b/src/ignition/ignition.go new file mode 100644 index 000000000..cbd0cf1fe --- /dev/null +++ b/src/ignition/ignition.go @@ -0,0 +1,49 @@ +package ignition + +import ( + "encoding/json" + "io/ioutil" + + "github.com/coreos/ignition/v2/config/validate" + + config_31 "github.com/coreos/ignition/v2/config/v3_1" + config_31_types "github.com/coreos/ignition/v2/config/v3_1/types" + + "github.com/pkg/errors" +) + +// ParseIgnitionFile reads an ignition config from a given path on disk +func ParseIgnitionFile(path string) (*config_31_types.Config, error) { + configBytes, err := ioutil.ReadFile(path) + if err != nil { + return nil, errors.Errorf("error reading file %s: %v", path, err) + } + config, _, err := config_31.Parse(configBytes) + if err != nil { + return nil, errors.Errorf("error parsing ignition: %v", err) + } + return &config, nil +} + +// WriteIgnitionFile writes an ignition config to a given path on disk +func WriteIgnitionFile(path string, config *config_31_types.Config) error { + updatedBytes, err := json.Marshal(config) + if err != nil { + return err + } + err = ioutil.WriteFile(path, updatedBytes, 0600) + if err != nil { + return errors.Wrapf(err, "error writing file %s", path) + } + return nil +} + +// MergeIgnitionConfig merges the specified configs and check the result is a valid Ignition config +func MergeIgnitionConfig(base *config_31_types.Config, overrides *config_31_types.Config) (*config_31_types.Config, error) { + config := config_31.Merge(*base, *overrides) + report := validate.ValidateWithContext(config, nil) + if report.IsFatal() { + return &config, errors.Errorf("merged ignition config is invalid: %s", report.String()) + } + return &config, nil +} diff --git a/src/installer/installer.go b/src/installer/installer.go index 30deea322..0f6781d4e 100644 --- a/src/installer/installer.go +++ b/src/installer/installer.go @@ -14,8 +14,11 @@ import ( "golang.org/x/sync/errgroup" v1 "k8s.io/api/core/v1" + config_31_types "github.com/coreos/ignition/v2/config/v3_1/types" + "github.com/openshift/assisted-installer/src/common" "github.com/openshift/assisted-installer/src/config" + "github.com/openshift/assisted-installer/src/ignition" "github.com/openshift/assisted-installer/src/inventory_client" "github.com/openshift/assisted-installer/src/k8s_client" "github.com/openshift/assisted-installer/src/ops" @@ -103,7 +106,6 @@ func (i *installer) InstallNode() error { if err != nil { return err } - i.Config.Role = string(models.HostRoleMaster) } else { ignitionPath, err = i.downloadHostIgnition() if err != nil { @@ -133,6 +135,34 @@ func (i *installer) InstallNode() error { return nil } +//updateSingleNodeIgnition will download the host ignition config and add the files under storage +func (i *installer) updateSingleNodeIgnition(singleNodeIgnitionPath string) error { + hostIgnitionPath, err := i.downloadHostIgnition() + if err != nil { + return err + } + singleNodeconfig, err := ignition.ParseIgnitionFile(singleNodeIgnitionPath) + if err != nil { + return err + } + hostConfig, err := ignition.ParseIgnitionFile(hostIgnitionPath) + if err != nil { + return err + } + // TODO: update this once we can get the full host specific overrides we have in the ignition + // Remove the Config part since we only want the rest of the overrides + hostConfig.Ignition.Config = config_31_types.IgnitionConfig{} + merged, mergeErr := ignition.MergeIgnitionConfig(singleNodeconfig, hostConfig) + if mergeErr != nil { + return errors.Wrapf(mergeErr, "failed to apply host ignition config overrides") + } + err = ignition.WriteIgnitionFile(singleNodeIgnitionPath, merged) + if err != nil { + return err + } + return nil +} + func (i *installer) writeImageToDisk(ignitionPath string) error { i.UpdateHostInstallProgress(models.HostStageWritingImageToDisk, "") interval := time.Second @@ -621,6 +651,12 @@ func (i *installer) createSingleNodeMasterIgnition() (string, error) { i.log.Errorf("Failed to find single node master ignition: %s", err) return "", err } + i.Config.Role = string(models.HostRoleMaster) + err = i.updateSingleNodeIgnition(singleNodeMasterIgnitionPath) + if err != nil { + return "", err + } + return singleNodeMasterIgnitionPath, nil }