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

     1  package configimage
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	k8sjson "sigs.k8s.io/json"
    12  
    13  	"github.com/openshift/installer/pkg/asset"
    14  	"github.com/openshift/installer/pkg/asset/password"
    15  	"github.com/openshift/installer/pkg/asset/tls"
    16  	"github.com/openshift/installer/pkg/types"
    17  	"github.com/openshift/installer/pkg/types/imagebased"
    18  )
    19  
    20  const (
    21  	defaultChronyConf = `
    22  pool 0.rhel.pool.ntp.org iburst
    23  driftfile /var/lib/chrony/drift
    24  makestep 1.0 3
    25  rtcsync
    26  logdir /var/log/chrony`
    27  
    28  	userCABundleConfigMapName = "user-ca-bundle"
    29  )
    30  
    31  var (
    32  	clusterConfigurationFilename = filepath.Join(clusterConfigurationDir, "manifest.json")
    33  
    34  	_ asset.WritableAsset = (*ClusterConfiguration)(nil)
    35  )
    36  
    37  // ClusterConfiguration generates the image-based installer cluster configuration asset.
    38  type ClusterConfiguration struct {
    39  	File   *asset.File
    40  	Config *imagebased.SeedReconfiguration
    41  }
    42  
    43  // Name returns a human friendly name for the asset.
    44  func (*ClusterConfiguration) Name() string {
    45  	return "Image-based installer cluster configuration"
    46  }
    47  
    48  // Dependencies returns all of the dependencies directly needed to generate
    49  // the asset.
    50  func (*ClusterConfiguration) Dependencies() []asset.Asset {
    51  	return []asset.Asset{
    52  		&InstallConfig{},
    53  		&ClusterID{},
    54  		&tls.KubeAPIServerLBSignerCertKey{},
    55  		&tls.KubeAPIServerLocalhostSignerCertKey{},
    56  		&tls.KubeAPIServerServiceNetworkSignerCertKey{},
    57  		&tls.AdminKubeConfigSignerCertKey{},
    58  		&IngressOperatorSignerCertKey{},
    59  		&password.KubeadminPassword{},
    60  		&ImageBasedConfig{},
    61  	}
    62  }
    63  
    64  // Generate generates the Image-based Installer ClusterConfiguration manifest.
    65  func (cc *ClusterConfiguration) Generate(_ context.Context, dependencies asset.Parents) error {
    66  	installConfig := &InstallConfig{}
    67  	clusterID := &ClusterID{}
    68  	imageBasedConfig := &ImageBasedConfig{}
    69  	serverLBSignerCertKey := &tls.KubeAPIServerLBSignerCertKey{}
    70  	serverLocalhostSignerCertKey := &tls.KubeAPIServerLocalhostSignerCertKey{}
    71  	serverServiceNetworkSignerCertKey := &tls.KubeAPIServerServiceNetworkSignerCertKey{}
    72  	adminKubeConfigSignerCertKey := &tls.AdminKubeConfigSignerCertKey{}
    73  	ingressOperatorSignerCertKey := &IngressOperatorSignerCertKey{}
    74  
    75  	dependencies.Get(
    76  		installConfig,
    77  		clusterID,
    78  		imageBasedConfig,
    79  		serverLBSignerCertKey,
    80  		serverLocalhostSignerCertKey,
    81  		serverServiceNetworkSignerCertKey,
    82  		adminKubeConfigSignerCertKey,
    83  		ingressOperatorSignerCertKey,
    84  	)
    85  
    86  	pwd := &password.KubeadminPassword{}
    87  	dependencies.Get(pwd)
    88  	pwdHash := string(pwd.PasswordHash)
    89  
    90  	if installConfig.Config == nil || imageBasedConfig.Config == nil {
    91  		return cc.finish()
    92  	}
    93  
    94  	cc.Config = &imagebased.SeedReconfiguration{
    95  		APIVersion:            imagebased.SeedReconfigurationVersion,
    96  		BaseDomain:            installConfig.Config.BaseDomain,
    97  		ClusterID:             clusterID.UUID,
    98  		ClusterName:           installConfig.ClusterName(),
    99  		Hostname:              imageBasedConfig.Config.Hostname,
   100  		InfraID:               clusterID.InfraID,
   101  		KubeadminPasswordHash: pwdHash,
   102  		Proxy:                 installConfig.Config.Proxy,
   103  		PullSecret:            installConfig.Config.PullSecret,
   104  		RawNMStateConfig:      imageBasedConfig.Config.NetworkConfig.String(),
   105  		ReleaseRegistry:       imageBasedConfig.Config.ReleaseRegistry,
   106  		SSHKey:                installConfig.Config.SSHKey,
   107  	}
   108  
   109  	if len(imageBasedConfig.Config.AdditionalNTPSources) > 0 {
   110  		cc.Config.ChronyConfig = chronyConfWithAdditionalNTPSources(imageBasedConfig.Config.AdditionalNTPSources)
   111  	}
   112  
   113  	if installConfig.Config.AdditionalTrustBundle != "" {
   114  		cc.Config.AdditionalTrustBundle = imagebased.AdditionalTrustBundle{
   115  			UserCaBundle: installConfig.Config.AdditionalTrustBundle,
   116  		}
   117  
   118  		if installConfig.Config.AdditionalTrustBundlePolicy == types.PolicyAlways ||
   119  			(installConfig.Config.AdditionalTrustBundlePolicy == types.PolicyProxyOnly && installConfig.Config.Proxy != nil) {
   120  			cc.Config.AdditionalTrustBundle.ProxyConfigmapName = userCABundleConfigMapName
   121  			cc.Config.AdditionalTrustBundle.ProxyConfigmapBundle = installConfig.Config.AdditionalTrustBundle
   122  		}
   123  	}
   124  
   125  	cc.Config.KubeconfigCryptoRetention = imagebased.KubeConfigCryptoRetention{
   126  		KubeAPICrypto: imagebased.KubeAPICrypto{
   127  			ServingCrypto: imagebased.ServingCrypto{
   128  				LoadbalancerSignerPrivateKey:   string(serverLBSignerCertKey.Key()),
   129  				LocalhostSignerPrivateKey:      string(serverLocalhostSignerCertKey.Key()),
   130  				ServiceNetworkSignerPrivateKey: string(serverServiceNetworkSignerCertKey.Key()),
   131  			},
   132  			ClientAuthCrypto: imagebased.ClientAuthCrypto{
   133  				AdminCACertificate: string(adminKubeConfigSignerCertKey.Cert()),
   134  			},
   135  		},
   136  		IngresssCrypto: imagebased.IngresssCrypto{
   137  			IngressCA: string(ingressOperatorSignerCertKey.Key()),
   138  		},
   139  	}
   140  
   141  	// validation for the length of the MachineNetwork is performed in the InstallConfig
   142  	cc.Config.MachineNetwork = installConfig.Config.Networking.MachineNetwork[0].CIDR.String()
   143  
   144  	clusterConfigurationData, err := json.Marshal(cc.Config)
   145  	if err != nil {
   146  		return fmt.Errorf("failed to marshal image-based installer ClusterConfiguration: %w", err)
   147  	}
   148  
   149  	cc.File = &asset.File{
   150  		Filename: clusterConfigurationFilename,
   151  		Data:     clusterConfigurationData,
   152  	}
   153  
   154  	return cc.finish()
   155  }
   156  
   157  // Files returns the files generated by the asset.
   158  func (cc *ClusterConfiguration) Files() []*asset.File {
   159  	if cc.File != nil {
   160  		return []*asset.File{cc.File}
   161  	}
   162  	return []*asset.File{}
   163  }
   164  
   165  // Load returns ClusterConfiguration asset from the disk.
   166  func (cc *ClusterConfiguration) Load(f asset.FileFetcher) (bool, error) {
   167  	file, err := f.FetchByName(clusterConfigurationFilename)
   168  	if err != nil {
   169  		if os.IsNotExist(err) {
   170  			return false, nil
   171  		}
   172  		return false, fmt.Errorf("failed to load %s file: %w", clusterConfigurationFilename, err)
   173  	}
   174  
   175  	config := &imagebased.SeedReconfiguration{}
   176  	strErrs, err := k8sjson.UnmarshalStrict(file.Data, config)
   177  	if len(strErrs) > 0 {
   178  		return false, fmt.Errorf("failed to unmarshal %s: %w", clusterConfigurationFilename, errors.Join(strErrs...))
   179  	}
   180  	if err != nil {
   181  		return false, fmt.Errorf("failed to unmarshal %s: invalid JSON syntax", clusterConfigurationFilename)
   182  	}
   183  
   184  	cc.File, cc.Config = file, config
   185  	if err = cc.finish(); err != nil {
   186  		return false, err
   187  	}
   188  
   189  	return true, nil
   190  }
   191  
   192  func (cc *ClusterConfiguration) finish() error {
   193  	if cc.Config == nil {
   194  		return errors.New("missing configuration or manifest file")
   195  	}
   196  	return nil
   197  }
   198  
   199  func chronyConfWithAdditionalNTPSources(sources []string) string {
   200  	content := defaultChronyConf[:]
   201  	for _, source := range sources {
   202  		content += fmt.Sprintf("\nserver %s iburst", source)
   203  	}
   204  	return content
   205  }