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

     1  package image
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	igntypes "github.com/coreos/ignition/v2/config/v3_2/types"
    10  	"github.com/coreos/stream-metadata-go/arch"
    11  	"github.com/pkg/errors"
    12  	"github.com/sirupsen/logrus"
    13  
    14  	"github.com/openshift/installer/pkg/asset"
    15  	"github.com/openshift/installer/pkg/asset/agent/common"
    16  	"github.com/openshift/installer/pkg/asset/agent/manifests"
    17  	"github.com/openshift/installer/pkg/asset/agent/mirror"
    18  	"github.com/openshift/installer/pkg/asset/ignition"
    19  	"github.com/openshift/installer/pkg/asset/ignition/bootstrap"
    20  	"github.com/openshift/installer/pkg/types"
    21  	"github.com/openshift/installer/pkg/version"
    22  )
    23  
    24  const (
    25  	unconfiguredIgnitionFilename = "unconfigured-agent.ign"
    26  )
    27  
    28  // GetConfigImageFiles returns the list of files or file paths to be included in the config-image.
    29  func GetConfigImageFiles() []string {
    30  	return []string{
    31  		"/etc/assisted/manifests/pull-secret.yaml", //nolint:gosec // not hardcoded credentials
    32  		"/etc/assisted/manifests/cluster-deployment.yaml",
    33  		"/etc/assisted/manifests/cluster-image-set.yaml",
    34  		"/etc/assisted/manifests/agent-cluster-install.yaml",
    35  		"/etc/assisted/manifests/infraenv.yaml",
    36  		"/etc/assisted/manifests",       // optional nmstateconfig.yaml
    37  		"/etc/assisted/extra-manifests", // all files in directory
    38  		"/etc/assisted/hostconfig",      // all files in directory
    39  		"/etc/assisted/hostnames",       // all files in directory
    40  		"/etc/assisted/network",         // all files in directory
    41  		"/etc/NetworkManager/conf.d/clientid.conf",
    42  		"/etc/issue",
    43  		"/etc/systemd/system.conf.d/10-default-env.conf",
    44  		"/root/.docker/config.json",
    45  		"/usr/local/share/start-cluster/start-cluster.env",
    46  		"/usr/local/share/assisted-service/assisted-service.env",
    47  		"/opt/agent/tls/kubeadmin-password.hash", //nolint:gosec // not hardcoded credentials
    48  		"/opt/agent/tls/admin-kubeconfig-signer.key",
    49  		"/opt/agent/tls/admin-kubeconfig-signer.crt",
    50  		"/opt/agent/tls/kube-apiserver-lb-signer.key",
    51  		"/opt/agent/tls/kube-apiserver-lb-signer.crt",
    52  		"/opt/agent/tls/kube-apiserver-localhost-signer.key",
    53  		"/opt/agent/tls/kube-apiserver-localhost-signer.crt",
    54  		"/opt/agent/tls/kube-apiserver-service-network-signer.key",
    55  		"/opt/agent/tls/kube-apiserver-service-network-signer.crt",
    56  		rendezvousHostEnvPath, // This file must be last in the list
    57  	}
    58  }
    59  
    60  // UnconfiguredIgnition is an asset that generates the agent installer unconfigured
    61  // ignition file which excludes any cluster configuration.
    62  type UnconfiguredIgnition struct {
    63  	Config  *igntypes.Config
    64  	CPUArch string
    65  	File    *asset.File
    66  }
    67  
    68  // Name returns the human-friendly name of the asset.
    69  func (a *UnconfiguredIgnition) Name() string {
    70  	return "Agent Installer Unconfigured Ignition"
    71  }
    72  
    73  // Dependencies returns the assets on which the UnconfiguredIgnition asset depends.
    74  func (a *UnconfiguredIgnition) Dependencies() []asset.Asset {
    75  	return []asset.Asset{
    76  		&manifests.InfraEnv{},
    77  		&manifests.AgentPullSecret{},
    78  		&manifests.ClusterImageSet{},
    79  		&manifests.NMStateConfig{},
    80  		&mirror.RegistriesConf{},
    81  		&mirror.CaBundle{},
    82  		&common.InfraEnvID{},
    83  	}
    84  }
    85  
    86  // Generate generates the agent installer unconfigured ignition.
    87  func (a *UnconfiguredIgnition) Generate(_ context.Context, dependencies asset.Parents) error {
    88  	infraEnvAsset := &manifests.InfraEnv{}
    89  	infraEnvIDAsset := &common.InfraEnvID{}
    90  	clusterImageSetAsset := &manifests.ClusterImageSet{}
    91  	pullSecretAsset := &manifests.AgentPullSecret{}
    92  	nmStateConfigs := &manifests.NMStateConfig{}
    93  	dependencies.Get(infraEnvAsset, clusterImageSetAsset, pullSecretAsset, nmStateConfigs, infraEnvIDAsset)
    94  
    95  	infraEnv := infraEnvAsset.Config
    96  	clusterImageSet := clusterImageSetAsset.Config
    97  
    98  	config := igntypes.Config{
    99  		Ignition: igntypes.Ignition{
   100  			Version: igntypes.MaxVersion.String(),
   101  		},
   102  		Passwd: igntypes.Passwd{
   103  			Users: []igntypes.PasswdUser{
   104  				{
   105  					Name: "core",
   106  					SSHAuthorizedKeys: []igntypes.SSHAuthorizedKey{
   107  						igntypes.SSHAuthorizedKey(infraEnv.Spec.SSHAuthorizedKey),
   108  					},
   109  				},
   110  			},
   111  		},
   112  	}
   113  
   114  	// Default to x86_64
   115  	archName := arch.RpmArch(types.ArchitectureAMD64)
   116  	if infraEnv.Spec.CpuArchitecture != "" {
   117  		archName = infraEnv.Spec.CpuArchitecture
   118  	}
   119  	releaseImageList, err := releaseImageList(clusterImageSet.Spec.ReleaseImage, archName, []string{archName})
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	registriesConfig := &mirror.RegistriesConf{}
   125  	registryCABundle := &mirror.CaBundle{}
   126  	dependencies.Get(registriesConfig, registryCABundle)
   127  
   128  	infraEnvID := infraEnvIDAsset.ID
   129  	logrus.Debug("Generated random infra-env id ", infraEnvID)
   130  
   131  	openshiftVersion, err := version.Version()
   132  	if err != nil {
   133  		return err
   134  	}
   135  	osImage, err := getOSImagesInfo(archName, openshiftVersion, DefaultCoreOSStreamGetter)
   136  	if err != nil {
   137  		return err
   138  	}
   139  	a.CPUArch = *osImage.CPUArchitecture
   140  
   141  	configImageFiles := strings.Join(GetConfigImageFiles(), ",")
   142  
   143  	agentTemplateData := &agentTemplateData{
   144  		PullSecret:                pullSecretAsset.GetPullSecretData(),
   145  		ReleaseImages:             releaseImageList,
   146  		ReleaseImage:              clusterImageSet.Spec.ReleaseImage,
   147  		ReleaseImageMirror:        mirror.GetMirrorFromRelease(clusterImageSet.Spec.ReleaseImage, registriesConfig),
   148  		HaveMirrorConfig:          len(registriesConfig.MirrorConfig) > 0,
   149  		PublicContainerRegistries: getPublicContainerRegistries(registriesConfig),
   150  		InfraEnvID:                infraEnvID,
   151  		OSImage:                   osImage,
   152  		Proxy:                     infraEnv.Spec.Proxy,
   153  		ConfigImageFiles:          configImageFiles,
   154  	}
   155  
   156  	err = bootstrap.AddStorageFiles(&config, "/", "agent/files", agentTemplateData)
   157  	if err != nil {
   158  		return err
   159  	}
   160  
   161  	err = addBootstrapScripts(&config, clusterImageSetAsset.Config.Spec.ReleaseImage)
   162  	if err != nil {
   163  		return err
   164  	}
   165  
   166  	enabledServices := getDefaultEnabledServices()
   167  	if len(nmStateConfigs.StaticNetworkConfig) > 0 {
   168  		err = addStaticNetworkConfig(&config, nmStateConfigs.StaticNetworkConfig)
   169  		if err != nil {
   170  			return err
   171  		}
   172  
   173  		enabledServices = append(enabledServices, "pre-network-manager-config.service")
   174  	} else {
   175  		// Include the script in case it is needed in config step
   176  		nmStateScriptFilePath := "/usr/local/bin/pre-network-manager-config.sh"
   177  		nmStateScript := ignition.FileFromBytes(nmStateScriptFilePath, "root", 0755, []byte(manifests.PreNetworkConfigScript))
   178  		config.Storage.Files = append(config.Storage.Files, nmStateScript)
   179  	}
   180  
   181  	ztpManifestsToInclude := [...]asset.File{
   182  		*infraEnvAsset.File,
   183  		*clusterImageSetAsset.File,
   184  		*pullSecretAsset.File,
   185  	}
   186  
   187  	for _, file := range ztpManifestsToInclude {
   188  		manifestFile := ignition.FileFromBytes(filepath.Join(manifestPath, filepath.Base(file.Filename)),
   189  			"root", 0600, file.Data)
   190  		config.Storage.Files = append(config.Storage.Files, manifestFile)
   191  	}
   192  
   193  	// the agent-check-config-image.service added only to the unconfigured ignition
   194  	enabledServices = append(enabledServices, "agent-check-config-image.service")
   195  	err = bootstrap.AddSystemdUnits(&config, "agent/systemd/units", agentTemplateData, enabledServices)
   196  	if err != nil {
   197  		return err
   198  	}
   199  
   200  	addMirrorData(&config, registriesConfig, registryCABundle)
   201  
   202  	a.Config = &config
   203  
   204  	if err := a.generateFile(unconfiguredIgnitionFilename); err != nil {
   205  		return err
   206  	}
   207  
   208  	return nil
   209  }
   210  
   211  // PersistToFile writes the unconfigured ignition in the assets folder.
   212  func (a *UnconfiguredIgnition) PersistToFile(directory string) error {
   213  	if a.File == nil {
   214  		return errors.New("attempting to persist a UnconfiguredIgnition that has not been generated")
   215  	}
   216  	unconfiguredIgnFile := filepath.Join(directory, a.File.Filename)
   217  
   218  	err := os.WriteFile(unconfiguredIgnFile, a.File.Data, 0o644) //nolint:gosec // no sensitive info
   219  	if err != nil {
   220  		return err
   221  	}
   222  
   223  	logrus.Infof("Unconfigured-Ignition created in: %s", unconfiguredIgnFile)
   224  
   225  	return nil
   226  }
   227  
   228  func (a *UnconfiguredIgnition) generateFile(filename string) error {
   229  	data, err := ignition.Marshal(a.Config)
   230  	if err != nil {
   231  		return errors.Wrap(err, "failed to Marshal UnconfiguredIgnition config")
   232  	}
   233  	a.File = &asset.File{
   234  		Filename: filename,
   235  		Data:     data,
   236  	}
   237  	return nil
   238  }
   239  
   240  // Load returns the UnconfiguredIgnition from disk.
   241  func (a *UnconfiguredIgnition) Load(f asset.FileFetcher) (bool, error) {
   242  	// The UnconfiguredIgnition will not be needed by another asset so load is noop.
   243  	// This is implemented because it is required by WritableAsset
   244  	return false, nil
   245  }
   246  
   247  // Files returns the files generated by the asset.
   248  func (a *UnconfiguredIgnition) Files() []*asset.File {
   249  	// Return empty array because File will never be loaded.
   250  	return []*asset.File{}
   251  }