github.com/openshift/installer@v1.4.17/pkg/asset/imagebased/image/ignition.go (about)

     1  package image
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  
     8  	"github.com/coreos/ignition/v2/config/merge"
     9  	"github.com/coreos/ignition/v2/config/v3_2"
    10  	igntypes "github.com/coreos/ignition/v2/config/v3_2/types"
    11  
    12  	"github.com/openshift/installer/pkg/asset"
    13  	"github.com/openshift/installer/pkg/asset/ignition"
    14  	"github.com/openshift/installer/pkg/asset/ignition/bootstrap"
    15  	"github.com/openshift/installer/pkg/types"
    16  )
    17  
    18  const (
    19  	trustedBundlePath = "/etc/pki/ca-trust/source/anchors/additional-trust-bundle.pem"
    20  
    21  	registriesConfPath = "/etc/containers/registries.conf"
    22  
    23  	postDeploymentScriptPath = "/var/tmp/post.sh"
    24  )
    25  
    26  // Ignition is an asset that generates the image-based installer ignition file.
    27  type Ignition struct {
    28  	Config *igntypes.Config
    29  }
    30  
    31  // Name returns the human-friendly name of the asset.
    32  func (i *Ignition) Name() string {
    33  	return "Image-based Installer Ignition"
    34  }
    35  
    36  // Dependencies returns the assets on which the Ignition asset depends.
    37  func (i *Ignition) Dependencies() []asset.Asset {
    38  	return []asset.Asset{
    39  		&ImageBasedInstallationConfig{},
    40  		&RegistriesConf{},
    41  		&PostDeployment{},
    42  	}
    43  }
    44  
    45  type ibiConfigurationFile struct {
    46  	ExtraPartitionLabel  string `json:"extraPartitionLabel,omitempty"`
    47  	ExtraPartitionNumber uint   `json:"extraPartitionNumber,omitempty"`
    48  	ExtraPartitionStart  string `json:"extraPartitionStart,omitempty"`
    49  	InstallationDisk     string `json:"installationDisk"`
    50  	SeedImage            string `json:"seedImage"`
    51  	SeedVersion          string `json:"seedVersion"`
    52  	Shutdown             bool   `json:"shutdown,omitempty"`
    53  	SkipDiskCleanup      bool   `json:"skipDiskCleanup,omitempty"`
    54  }
    55  
    56  type ibiTemplateData struct {
    57  	SeedImage        string
    58  	Proxy            *types.Proxy
    59  	PullSecret       string
    60  	NetworkConfig    string
    61  	IBIConfiguration string
    62  }
    63  
    64  // Generate generates the image-based installer ignition.
    65  func (i *Ignition) Generate(_ context.Context, dependencies asset.Parents) error {
    66  	configAsset := &ImageBasedInstallationConfig{}
    67  	registriesConf := &RegistriesConf{}
    68  	postDeployment := &PostDeployment{}
    69  
    70  	dependencies.Get(configAsset, registriesConf, postDeployment)
    71  
    72  	ibiConfig := configAsset.Config
    73  	if ibiConfig == nil {
    74  		return fmt.Errorf("%s is required", configFilename)
    75  	}
    76  
    77  	config := &igntypes.Config{
    78  		Ignition: igntypes.Ignition{
    79  			Version: igntypes.MaxVersion.String(),
    80  		},
    81  		Passwd: igntypes.Passwd{
    82  			Users: []igntypes.PasswdUser{
    83  				{
    84  					Name: "core",
    85  					SSHAuthorizedKeys: []igntypes.SSHAuthorizedKey{
    86  						igntypes.SSHAuthorizedKey(ibiConfig.SSHKey),
    87  					},
    88  				},
    89  			},
    90  		},
    91  	}
    92  
    93  	ibiConfigFile := ibiConfigurationFile{
    94  		ExtraPartitionLabel:  ibiConfig.ExtraPartitionLabel,
    95  		ExtraPartitionNumber: ibiConfig.ExtraPartitionNumber,
    96  		ExtraPartitionStart:  ibiConfig.ExtraPartitionStart,
    97  		InstallationDisk:     ibiConfig.InstallationDisk,
    98  		SeedVersion:          ibiConfig.SeedVersion,
    99  		SeedImage:            ibiConfig.SeedImage,
   100  		Shutdown:             ibiConfig.Shutdown,
   101  		SkipDiskCleanup:      ibiConfig.SkipDiskCleanup,
   102  	}
   103  	ibiConfigJSON, err := json.Marshal(ibiConfigFile)
   104  	if err != nil {
   105  		return fmt.Errorf("failed to marshall the ibi-configuration data: %w", err)
   106  	}
   107  
   108  	ibiTemplateData := &ibiTemplateData{
   109  		SeedImage:        ibiConfig.SeedImage,
   110  		Proxy:            ibiConfig.Proxy,
   111  		PullSecret:       ibiConfig.PullSecret,
   112  		IBIConfiguration: string(ibiConfigJSON),
   113  		NetworkConfig:    ibiConfig.NetworkConfig.String(),
   114  	}
   115  
   116  	if len(registriesConf.Data) > 0 {
   117  		file := ignition.FileFromString(registriesConfPath, "root", 0o644, string(registriesConf.Data))
   118  		config.Storage.Files = append(config.Storage.Files, file)
   119  	}
   120  
   121  	if ibiConfig.AdditionalTrustBundle != "" {
   122  		file := ignition.FileFromString(trustedBundlePath, "root", 0o600, ibiConfig.AdditionalTrustBundle)
   123  		config.Storage.Files = append(config.Storage.Files, file)
   124  	}
   125  
   126  	if postDeployment.File != nil {
   127  		file := ignition.FileFromString(postDeploymentScriptPath, "root", 0o755, string(postDeployment.File.Data))
   128  		config.Storage.Files = append(config.Storage.Files, file)
   129  	}
   130  
   131  	if ibiConfig.IgnitionConfigOverride != "" {
   132  		if err := setIngnitionConfigOverride(config, ibiConfig.IgnitionConfigOverride); err != nil {
   133  			return fmt.Errorf("failed to override ignition config: %w", err)
   134  		}
   135  	}
   136  
   137  	if err := bootstrap.AddStorageFiles(config, "/", "imagebased/files", ibiTemplateData); err != nil {
   138  		return fmt.Errorf("failed to add image-based files to ignition config: %w", err)
   139  	}
   140  
   141  	enabledServices := defaultEnabledServices()
   142  	if ibiConfig.NetworkConfig.String() != "" {
   143  		enabledServices = append(enabledServices, "network-config.service")
   144  	}
   145  	if err := bootstrap.AddSystemdUnits(config, "imagebased/systemd/units", ibiTemplateData, enabledServices); err != nil {
   146  		return fmt.Errorf("failed to add image-based systemd units to ignition config: %w", err)
   147  	}
   148  
   149  	i.Config = config
   150  
   151  	return nil
   152  }
   153  
   154  func setIngnitionConfigOverride(config *igntypes.Config, override string) error {
   155  	ignitionConfigOverride, _, err := v3_2.Parse([]byte(override))
   156  	if err != nil {
   157  		return fmt.Errorf("failed to parse ignition config override: %w", err)
   158  	}
   159  
   160  	merged, _ := merge.MergeStructTranscribe(*config, ignitionConfigOverride)
   161  	marshaledMerged, err := json.Marshal(merged)
   162  	if err != nil {
   163  		return fmt.Errorf("failed to marshal merged ignition config: %w", err)
   164  	}
   165  
   166  	if err := json.Unmarshal(marshaledMerged, config); err != nil {
   167  		return fmt.Errorf("failed to unmarshal merged ignition config: %w", err)
   168  	}
   169  	return nil
   170  }
   171  
   172  func defaultEnabledServices() []string {
   173  	return []string{
   174  		"install-rhcos-and-restore-seed.service",
   175  	}
   176  }