mirror of
https://github.com/openshift/installer.git
synced 2026-02-05 15:47:14 +01:00
OCPBUGS-38956: failed to install Nutanix OCP 4.16 cluster with DHCP
This commit is contained in:
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/vincent-petithory/dataurl"
|
||||
utilsnet "k8s.io/utils/net"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
configv1 "github.com/openshift/api/config/v1"
|
||||
"github.com/openshift/installer/data"
|
||||
@@ -39,6 +40,7 @@ import (
|
||||
"github.com/openshift/installer/pkg/asset/tls"
|
||||
"github.com/openshift/installer/pkg/types"
|
||||
baremetaltypes "github.com/openshift/installer/pkg/types/baremetal"
|
||||
nutanixtypes "github.com/openshift/installer/pkg/types/nutanix"
|
||||
vspheretypes "github.com/openshift/installer/pkg/types/vsphere"
|
||||
)
|
||||
|
||||
@@ -111,6 +113,7 @@ func (a *Common) Dependencies() []asset.Asset {
|
||||
&baremetal.IronicCreds{},
|
||||
&CVOIgnore{},
|
||||
&installconfig.InstallConfig{},
|
||||
&installconfig.ClusterID{},
|
||||
&kubeconfig.AdminInternalClient{},
|
||||
&kubeconfig.Kubelet{},
|
||||
&kubeconfig.LoopbackClient{},
|
||||
@@ -167,7 +170,8 @@ func (a *Common) Dependencies() []asset.Asset {
|
||||
func (a *Common) generateConfig(dependencies asset.Parents, templateData *bootstrapTemplateData) error {
|
||||
installConfig := &installconfig.InstallConfig{}
|
||||
bootstrapSSHKeyPair := &tls.BootstrapSSHKeyPair{}
|
||||
dependencies.Get(installConfig, bootstrapSSHKeyPair)
|
||||
clusterID := &installconfig.ClusterID{}
|
||||
dependencies.Get(installConfig, bootstrapSSHKeyPair, clusterID)
|
||||
|
||||
a.Config = &igntypes.Config{
|
||||
Ignition: igntypes.Ignition{
|
||||
@@ -218,6 +222,24 @@ func (a *Common) generateConfig(dependencies asset.Parents, templateData *bootst
|
||||
}},
|
||||
)
|
||||
|
||||
if platform == nutanixtypes.Name {
|
||||
// Inserts the file "/etc/hostname" with the bootstrap machine name to the bootstrap ignition data
|
||||
hostname := fmt.Sprintf("%s-bootstrap", clusterID.InfraID)
|
||||
hostnameFile := igntypes.File{
|
||||
Node: igntypes.Node{
|
||||
Path: "/etc/hostname",
|
||||
Overwrite: ptr.To(true),
|
||||
},
|
||||
FileEmbedded1: igntypes.FileEmbedded1{
|
||||
Mode: ptr.To(420),
|
||||
Contents: igntypes.Resource{
|
||||
Source: ptr.To(dataurl.EncodeBytes([]byte(hostname))),
|
||||
},
|
||||
},
|
||||
}
|
||||
a.Config.Storage.Files = append(a.Config.Storage.Files, hostnameFile)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ func GenerateMachines(clusterID string, config *types.InstallConfig, pool *types
|
||||
Spec: capv1.MachineSpec{
|
||||
ClusterName: clusterID,
|
||||
Bootstrap: capv1.Bootstrap{
|
||||
DataSecretName: ptr.To(fmt.Sprintf("%s-%s", clusterID, role)),
|
||||
DataSecretName: ptr.To(ntxMachine.Name),
|
||||
},
|
||||
InfrastructureRef: v1.ObjectReference{
|
||||
APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1",
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
|
||||
"github.com/coreos/stream-metadata-go/arch"
|
||||
"github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/utils/ptr"
|
||||
capz "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -512,7 +513,7 @@ func randomString(length int) string {
|
||||
|
||||
// Ignition provisions the Azure container that holds the bootstrap ignition
|
||||
// file.
|
||||
func (p Provider) Ignition(ctx context.Context, in clusterapi.IgnitionInput) ([]byte, error) {
|
||||
func (p Provider) Ignition(ctx context.Context, in clusterapi.IgnitionInput) ([]*corev1.Secret, error) {
|
||||
session, err := in.InstallConfig.Azure.Session()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get session: %w", err)
|
||||
@@ -557,5 +558,10 @@ func (p Provider) Ignition(ctx context.Context, in clusterapi.IgnitionInput) ([]
|
||||
return nil, fmt.Errorf("failed to create ignition shim: %w", err)
|
||||
}
|
||||
|
||||
return ignShim, nil
|
||||
ignSecrets := []*corev1.Secret{
|
||||
clusterapi.IgnitionSecret(ignShim, in.InfraID, "bootstrap"),
|
||||
clusterapi.IgnitionSecret(in.MasterIgnData, in.InfraID, "master"),
|
||||
}
|
||||
|
||||
return ignSecrets, nil
|
||||
}
|
||||
|
||||
@@ -249,10 +249,12 @@ func (i *InfraProvider) Provision(ctx context.Context, dir string, parents asset
|
||||
logrus.Debugf("No infrastructure ready requirements for the %s provider", i.impl.Name())
|
||||
}
|
||||
|
||||
masterIgnData := masterIgnAsset.Files()[0].Data
|
||||
bootstrapIgnData, err := injectInstallInfo(bootstrapIgnAsset.Files()[0].Data)
|
||||
if err != nil {
|
||||
return fileList, fmt.Errorf("unable to inject installation info: %w", err)
|
||||
}
|
||||
ignitionSecrets := []*corev1.Secret{}
|
||||
|
||||
// The cloud-platform may need to override the default
|
||||
// bootstrap ignition behavior.
|
||||
@@ -260,22 +262,27 @@ func (i *InfraProvider) Provision(ctx context.Context, dir string, parents asset
|
||||
ignInput := IgnitionInput{
|
||||
Client: cl,
|
||||
BootstrapIgnData: bootstrapIgnData,
|
||||
MasterIgnData: masterIgnData,
|
||||
InfraID: clusterID.InfraID,
|
||||
InstallConfig: installConfig,
|
||||
TFVarsAsset: tfvarsAsset,
|
||||
}
|
||||
|
||||
timer.StartTimer(ignitionStage)
|
||||
if bootstrapIgnData, err = p.Ignition(ctx, ignInput); err != nil {
|
||||
if ignitionSecrets, err = p.Ignition(ctx, ignInput); err != nil {
|
||||
return fileList, fmt.Errorf("failed preparing ignition data: %w", err)
|
||||
}
|
||||
timer.StopTimer(ignitionStage)
|
||||
} else {
|
||||
logrus.Debugf("No Ignition requirements for the %s provider", i.impl.Name())
|
||||
logrus.Debugf("Using default ignition for the %s provider", i.impl.Name())
|
||||
bootstrapIgnSecret := IgnitionSecret(bootstrapIgnData, clusterID.InfraID, "bootstrap")
|
||||
masterIgnSecret := IgnitionSecret(masterIgnData, clusterID.InfraID, "master")
|
||||
ignitionSecrets = append(ignitionSecrets, bootstrapIgnSecret, masterIgnSecret)
|
||||
}
|
||||
|
||||
for _, secret := range ignitionSecrets {
|
||||
machineManifests = append(machineManifests, secret)
|
||||
}
|
||||
bootstrapIgnSecret := IgnitionSecret(bootstrapIgnData, clusterID.InfraID, "bootstrap")
|
||||
masterIgnSecret := IgnitionSecret(masterIgnAsset.Files()[0].Data, clusterID.InfraID, "master")
|
||||
machineManifests = append(machineManifests, bootstrapIgnSecret, masterIgnSecret)
|
||||
|
||||
// Create the machine manifests.
|
||||
timer.StartTimer(machineStage)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/openshift/installer/pkg/asset/cluster/tfvars"
|
||||
@@ -46,18 +47,20 @@ type PreProvisionInput struct {
|
||||
WorkersAsset *machines.Worker
|
||||
}
|
||||
|
||||
// IgnitionProvider handles preconditions for bootstrap ignition and
|
||||
// generates ignition data for the CAPI bootstrap ignition secret.
|
||||
// IgnitionProvider handles preconditions for bootstrap ignition,
|
||||
// such as pushing to cloud storage. Returns bootstrap and master
|
||||
// ignition secrets.
|
||||
//
|
||||
// WARNING! Low-level primitive. Use only if absolutely necessary.
|
||||
type IgnitionProvider interface {
|
||||
Ignition(ctx context.Context, in IgnitionInput) ([]byte, error)
|
||||
Ignition(ctx context.Context, in IgnitionInput) ([]*corev1.Secret, error)
|
||||
}
|
||||
|
||||
// IgnitionInput collects the args passed to the IgnitionProvider call.
|
||||
type IgnitionInput struct {
|
||||
Client client.Client
|
||||
BootstrapIgnData []byte
|
||||
MasterIgnData []byte
|
||||
InfraID string
|
||||
InstallConfig *installconfig.InstallConfig
|
||||
TFVarsAsset *tfvars.TerraformVariables
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
capg "sigs.k8s.io/cluster-api-provider-gcp/api/v1beta1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
@@ -76,7 +77,7 @@ func (p Provider) PreProvision(ctx context.Context, in clusterapi.PreProvisionIn
|
||||
// populate the metadata field of the bootstrap instance as the data can be too large. Instead, the data is
|
||||
// added to a bucket. A signed url is generated to point to the bucket and the ignition data will be
|
||||
// updated to point to the url. This is also allows for bootstrap data to be edited after its initial creation.
|
||||
func (p Provider) Ignition(ctx context.Context, in clusterapi.IgnitionInput) ([]byte, error) {
|
||||
func (p Provider) Ignition(ctx context.Context, in clusterapi.IgnitionInput) ([]*corev1.Secret, error) {
|
||||
// Create the bucket and presigned url. The url is generated using a known/expected name so that the
|
||||
// url can be retrieved from the api by this name.
|
||||
bucketName := gcp.GetBootstrapStorageName(in.InfraID)
|
||||
@@ -104,6 +105,7 @@ func (p Provider) Ignition(ctx context.Context, in clusterapi.IgnitionInput) ([]
|
||||
return nil, fmt.Errorf("ignition failed to fill bucket: %w", err)
|
||||
}
|
||||
|
||||
var ignShim string
|
||||
for _, file := range in.TFVarsAsset.Files() {
|
||||
if file.Filename == tfvars.TfPlatformVarsFileName {
|
||||
var found bool
|
||||
@@ -113,16 +115,19 @@ func (p Provider) Ignition(ctx context.Context, in clusterapi.IgnitionInput) ([]
|
||||
return nil, fmt.Errorf("failed to unmarshal %s to json: %w", tfvars.TfPlatformVarsFileName, err)
|
||||
}
|
||||
|
||||
ignShim, found := tfvarsData["gcp_ignition_shim"].(string)
|
||||
ignShim, found = tfvarsData["gcp_ignition_shim"].(string)
|
||||
if !found {
|
||||
return nil, fmt.Errorf("failed to find ignition shim")
|
||||
}
|
||||
|
||||
return []byte(ignShim), nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to complete ignition process")
|
||||
ignSecrets := []*corev1.Secret{
|
||||
clusterapi.IgnitionSecret([]byte(ignShim), in.InfraID, "bootstrap"),
|
||||
clusterapi.IgnitionSecret(in.MasterIgnData, in.InfraID, "master"),
|
||||
}
|
||||
|
||||
return ignSecrets, nil
|
||||
}
|
||||
|
||||
// InfraReady is called once cluster.Status.InfrastructureReady
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
nutanixclientv3 "github.com/nutanix-cloud-native/prism-go-client/v3"
|
||||
"github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
@@ -120,10 +121,10 @@ func (p Provider) PreProvision(ctx context.Context, in infracapi.PreProvisionInp
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ignition handles preconditions for bootstrap ignition and
|
||||
// generates ignition data for the CAPI bootstrap ignition secret.
|
||||
// Ignition handles preconditions for bootstrap and master ignition and
|
||||
// generates the CAPI ignition data secrets.
|
||||
// Load the ignition iso image to prism_central.
|
||||
func (p Provider) Ignition(ctx context.Context, in infracapi.IgnitionInput) ([]byte, error) {
|
||||
func (p Provider) Ignition(ctx context.Context, in infracapi.IgnitionInput) ([]*corev1.Secret, error) {
|
||||
ic := in.InstallConfig.Config
|
||||
nutanixCl, err := nutanixtypes.CreateNutanixClientFromPlatform(ic.Platform.Nutanix)
|
||||
if err != nil {
|
||||
@@ -207,11 +208,25 @@ func (p Provider) Ignition(ctx context.Context, in infracapi.IgnitionInput) ([]b
|
||||
err = fmt.Errorf("failed to create/upload the bootstrap image object %s in PC: %w", imgName, err)
|
||||
}
|
||||
|
||||
return in.BootstrapIgnData, err
|
||||
return nil, err
|
||||
}
|
||||
logrus.Infof("Successfully created the bootstrap image object %s and uploaded its image data", imgName)
|
||||
|
||||
return in.BootstrapIgnData, nil
|
||||
ignSecrets := []*corev1.Secret{
|
||||
infracapi.IgnitionSecret(in.BootstrapIgnData, in.InfraID, "bootstrap"),
|
||||
}
|
||||
|
||||
for i := 0; i < int(*in.InstallConfig.Config.ControlPlane.Replicas); i++ {
|
||||
// Inserts the file "/etc/hostname" with the master machine name to the ignition data
|
||||
hostname := fmt.Sprintf("%s-master-%v", in.InfraID, i)
|
||||
masterIgnData, err := nutanixtypes.InsertHostnameIgnition(in.MasterIgnData, hostname)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to insert the file '/etc/hostname' to the ignition data for machine %q: %w", hostname, err)
|
||||
}
|
||||
ignSecrets = append(ignSecrets, infracapi.IgnitionSecret(masterIgnData, in.InfraID, fmt.Sprintf("master-%v", i)))
|
||||
}
|
||||
|
||||
return ignSecrets, nil
|
||||
}
|
||||
|
||||
// createImage creates the image object in PC, with the provided request input.
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
capo "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
@@ -131,7 +132,7 @@ func (p Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput)
|
||||
var _ clusterapi.IgnitionProvider = Provider{}
|
||||
|
||||
// Ignition uploads the bootstrap machine's Ignition file to OpenStack.
|
||||
func (p Provider) Ignition(ctx context.Context, in clusterapi.IgnitionInput) ([]byte, error) {
|
||||
func (p Provider) Ignition(ctx context.Context, in clusterapi.IgnitionInput) ([]*corev1.Secret, error) {
|
||||
logrus.Debugf("Uploading the bootstrap machine's Ignition file to OpenStack")
|
||||
var (
|
||||
bootstrapIgnData = in.BootstrapIgnData
|
||||
@@ -139,7 +140,16 @@ func (p Provider) Ignition(ctx context.Context, in clusterapi.IgnitionInput) ([]
|
||||
installConfig = in.InstallConfig
|
||||
)
|
||||
|
||||
return preprovision.UploadIgnitionAndBuildShim(ctx, installConfig.Config.Platform.OpenStack.Cloud, infraID, installConfig.Config.Proxy, bootstrapIgnData)
|
||||
ignShim, err := preprovision.UploadIgnitionAndBuildShim(ctx, installConfig.Config.Platform.OpenStack.Cloud, infraID, installConfig.Config.Proxy, bootstrapIgnData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload and build ignition shim: %w", err)
|
||||
}
|
||||
|
||||
ignSecrets := []*corev1.Secret{
|
||||
clusterapi.IgnitionSecret(ignShim, in.InfraID, "bootstrap"),
|
||||
clusterapi.IgnitionSecret(in.MasterIgnData, in.InfraID, "master"),
|
||||
}
|
||||
return ignSecrets, nil
|
||||
}
|
||||
|
||||
var _ clusterapi.PostProvider = Provider{}
|
||||
|
||||
@@ -9,11 +9,14 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
igntypes "github.com/coreos/ignition/v2/config/v3_2/types"
|
||||
"github.com/google/uuid"
|
||||
"github.com/kdomanski/iso9660"
|
||||
"github.com/nutanix-cloud-native/prism-go-client/utils"
|
||||
nutanixclientv3 "github.com/nutanix-cloud-native/prism-go-client/v3"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vincent-petithory/dataurl"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -194,3 +197,36 @@ func CategoryKey(infraID string) string {
|
||||
categoryKey := fmt.Sprintf("%s%s", categoryKeyPrefix, infraID)
|
||||
return categoryKey
|
||||
}
|
||||
|
||||
// InsertHostnameIgnition inserts the file "/etc/hostname" with the given hostname to the provided Ignition config data.
|
||||
func InsertHostnameIgnition(ignData []byte, hostname string) ([]byte, error) {
|
||||
ignConfig := &igntypes.Config{}
|
||||
if err := json.Unmarshal(ignData, &ignConfig); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal Ignition config: %w", err)
|
||||
}
|
||||
|
||||
hostnameFile := igntypes.File{
|
||||
Node: igntypes.Node{
|
||||
Path: "/etc/hostname",
|
||||
Overwrite: ptr.To(true),
|
||||
},
|
||||
FileEmbedded1: igntypes.FileEmbedded1{
|
||||
Mode: ptr.To(420),
|
||||
Contents: igntypes.Resource{
|
||||
Source: ptr.To(dataurl.EncodeBytes([]byte(hostname))),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if ignConfig.Storage.Files == nil {
|
||||
ignConfig.Storage.Files = make([]igntypes.File, 0)
|
||||
}
|
||||
ignConfig.Storage.Files = append(ignConfig.Storage.Files, hostnameFile)
|
||||
|
||||
ign, err := json.Marshal(ignConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal ignition data: %w", err)
|
||||
}
|
||||
|
||||
return ign, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user