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 }