1
0
mirror of https://github.com/openshift/installer.git synced 2026-02-06 09:47:02 +01:00
Files
installer/pkg/types/machinepools.go
Pablo Fontanilla 5797d192d6 OCPEDGE-1517: add-tnf-agent-based-installer (#9946)
* agent/installconfig: Add two-node-with-fencing topology and refactor
two-node validation

* feat: add override for control plane fencing creds

Signed-off-by: ehila <ehila@redhat.com>

* Add TNF fencing credentials override test

* Update integration test with new validation result

* Update installer verification and tests to only allow URLs with redfish on them for Two Nodes with Fencing topology

* Update validation check for redfish

* Remove simultaneous dual replica feature set restriction

* Update fencing address validation to include port

* Update validation to disallow http

* Update and expand url validation tests

* Revert "Update validation to disallow http"

This reverts commit e9595a8d4f.

* Update variable name

* Update tests

* Add YAML tags to Credential struct for fencing

Add explicit yaml struct tags to the Credential type to ensure proper
YAML serialization with lowercase field names (e.g., 'hostname' instead
of 'hostName'). This is required for the assisted-service to correctly
parse the fencing credentials file.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add fencing credentials file generation for TNF clusters

Generate /etc/assisted/hostconfig/fencing-credentials.yaml containing
all fencing credentials from controlPlane.fencing.credentials[]. This
file is embedded in the agent ISO and consumed by assisted-service
during TNF cluster installation.

Key changes:
- Add OptionalInstallConfig to Ignition Dependencies()
- Add addFencingCredentials() function to generate the YAML file
- Call addFencingCredentials() in Generate() after NTP sources
- Add comprehensive unit tests for the new function

The single-file approach avoids directory naming collisions between
MAC-based host directories and hostname-based fencing credentials.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Revert fencing credentials override

The fencing credentials are now passed to assisted-service via the
hostconfig/fencing-credentials.yaml file embedded in the ISO, making
the install-config annotation override unnecessary.

This reverts commits:
- 105b3c95c9 Add TNF fencing credentials override test
- a06d1a766b feat: add override for control plane fencing creds

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Improve fencing credentials test coverage

Enhance TestIgnition_addFencingCredentials with:
- File owner verification (assert root ownership)
- Append behavior test with pre-existing files
- Fix misleading test name and add second credential to match
  valid TNF configuration (2 credentials required)
- Remove unused expectError field from test struct

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Support vendor-specific redfish schemes in fencing validation

Vendor-specific redfish schemes like idrac-redfish:// and ilo5-redfish://
use HTTPS (port 443) by default, so they should be valid without an
explicit port number.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* unit tests: Add missing OptionalInstallConfig dependency in ignition test

The TestIgnition_Generate test was panicking because the
OptionalInstallConfig asset was missing from the test dependencies.
This caused dependencies.Get() to return a nil value when the
addFencingCredentials function tried to access it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* agent: Refactor fencing credentials into standalone asset

Move fencing credentials generation from inline ignition.go code into a
proper FencingCredentials asset following the installer's asset pattern.

This refactor:
- Creates pkg/asset/agent/manifests/fencingcredentials.go as a
  WritableAsset with Dependencies, Generate, Files, and Load methods
- Adds comprehensive unit tests in fencingcredentials_test.go
- Integrates FencingCredentials into AgentManifests dependency graph
- Removes addFencingCredentials() from ignition.go
- Adds positive integration test for TNF with fencing credentials
- Changes output path from /etc/assisted/hostconfig/ to
  /etc/assisted/manifests/ (standard manifests location)

The asset automatically returns empty Files() for non-TNF clusters,
so no fencing-credentials.yaml is generated unless fencing is configured.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* agent: Improve fencing credentials code quality

- Add explicit YAML library aliasing for clarity (goyaml for marshal,
  k8syaml for unmarshal) with documentation explaining why different
  libraries are used for each operation
- Improve error message to include credential count for debugging
- Add test case for empty fencing credentials array

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* agent: Fix CI failures for gofmt and integration tests

- Add blank line between k8s.io and github.com/openshift import groups
  in ignition_test.go to satisfy gci formatting requirements
- Add featureSet: TechPreviewNoUpgrade to tnf_with_fencing_credentials
  integration test to enable the DualReplica feature gate required for
  TNF fencing configuration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* agent: Move fencing credentials to agentconfig package

FencingCredentials is a host-scoped configuration asset, not a
cluster-scoped manifest. Moving it from manifests/ to agentconfig/
aligns with the package's purpose and follows the pattern used by
other host configuration assets like AgentHosts.

This change also updates ignition.go to import from the new location
and removes the now-unused fencing credentials from agent.go manifests.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* agent: Add FencingCredentials to ignition test dependencies

The TestIgnition_Generate test was failing with a panic because the
FencingCredentials asset was added as a dependency to Ignition.Generate()
but wasn't included in the test's buildIgnitionAssetDefaultDependencies()
helper function.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* agent: Fix fencing credentials path in integration test

The integration test expected the fencing credentials file at
/etc/assisted/manifests/ but assisted-service reads it from
/etc/assisted/hostconfig/ (HOST_CONFIG_DIR default). The installer
correctly embeds the file at hostconfig/, so the test expectation
was wrong.

Changed test path from manifests to hostconfig to match both the
installer implementation and assisted-service expectations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* agent: Add nolint directive for gosec G101 false positive

The gosec linter flags fencingCredentialsFilename as "potential
hardcoded credentials" (G101) because the variable name contains
"credentials". This is a false positive - the variable contains
a filename string, not actual credentials.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* agent: Fix expected YAML field order in TNF integration test

The expected fencing-credentials.yaml had fields in a different order
than the actual YAML serialization output. Updated the expected file
to match the actual field order: hostname, username, password, address,
certificateVerification.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Signed-off-by: ehila <ehila@redhat.com>
Co-authored-by: ehila <ehila@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-05 12:30:34 +00:00

232 lines
8.2 KiB
Go

package types
import (
"github.com/openshift/installer/pkg/types/aws"
"github.com/openshift/installer/pkg/types/azure"
"github.com/openshift/installer/pkg/types/baremetal"
"github.com/openshift/installer/pkg/types/gcp"
"github.com/openshift/installer/pkg/types/ibmcloud"
"github.com/openshift/installer/pkg/types/nutanix"
"github.com/openshift/installer/pkg/types/openstack"
"github.com/openshift/installer/pkg/types/ovirt"
"github.com/openshift/installer/pkg/types/powervc"
"github.com/openshift/installer/pkg/types/powervs"
"github.com/openshift/installer/pkg/types/vsphere"
)
const (
// MachinePoolComputeRoleName name associated with the compute machinepool.
MachinePoolComputeRoleName = "worker"
// MachinePoolEdgeRoleName name associated with the compute edge machinepool.
MachinePoolEdgeRoleName = "edge"
// MachinePoolControlPlaneRoleName name associated with the control plane machinepool.
MachinePoolControlPlaneRoleName = "master"
// MachinePoolArbiterRoleName name associated with the control plane machinepool for smaller sized limited nodes.
MachinePoolArbiterRoleName = "arbiter"
)
// HyperthreadingMode is the mode of hyperthreading for a machine.
// +kubebuilder:validation:Enum="";Enabled;Disabled
type HyperthreadingMode string
const (
// HyperthreadingEnabled indicates that hyperthreading is enabled.
HyperthreadingEnabled HyperthreadingMode = "Enabled"
// HyperthreadingDisabled indicates that hyperthreading is disabled.
HyperthreadingDisabled HyperthreadingMode = "Disabled"
)
// Architecture is the instruction set architecture for the machines in a pool.
// +kubebuilder:validation:Enum="";amd64
type Architecture string
const (
// ArchitectureAMD64 indicates AMD64 (x86_64).
ArchitectureAMD64 = "amd64"
// ArchitectureS390X indicates s390x (IBM System Z).
ArchitectureS390X = "s390x"
// ArchitecturePPC64LE indicates ppc64 little endian (Power PC)
ArchitecturePPC64LE = "ppc64le"
// ArchitectureARM64 indicates arm (aarch64) systems
ArchitectureARM64 = "arm64"
)
// DiskType is the string representation of the three types disk setups
// +kubebuilder:validation:Enum=etcd;swap;user-defined
type DiskType string
const (
// Etcd indicates etcd disk setup.
Etcd DiskType = "etcd"
// Swap indicates swap disk setup.
Swap DiskType = "swap"
// UserDefined indicates user-defined disk setup.
UserDefined DiskType = "user-defined"
)
// Disk defines the type of disk (etcd, swap or user-defined) and the configuration
// of each disk type.
type Disk struct {
Type DiskType `json:"type,omitempty"`
UserDefined *DiskUserDefined `json:"userDefined,omitempty"`
Etcd *DiskEtcd `json:"etcd,omitempty"`
Swap *DiskSwap `json:"swap,omitempty"`
}
// DiskUserDefined defines a disk type of user-defined.
type DiskUserDefined struct {
PlatformDiskID string `json:"platformDiskID,omitempty"`
MountPath string `json:"mountPath,omitempty"`
}
// DiskSwap defines a disk type of swap.
type DiskSwap struct {
PlatformDiskID string `json:"platformDiskID,omitempty"`
}
// DiskEtcd defines a disk type of etcd.
type DiskEtcd struct {
PlatformDiskID string `json:"platformDiskID,omitempty"`
}
// MachinePool is a pool of machines to be installed.
type MachinePool struct {
// Name is the name of the machine pool.
// For the control plane machine pool, the name will always be "master".
// For the compute machine pools, the only valid name is "worker".
// For the arbiter machine pools, the only valid name is "arbiter".
Name string `json:"name"`
// Replicas is the machine count for the machine pool.
Replicas *int64 `json:"replicas,omitempty"`
// Platform is configuration for machine pool specific to the platform.
Platform MachinePoolPlatform `json:"platform"`
// Hyperthreading determines the mode of hyperthreading that machines in the
// pool will utilize.
// Default is for hyperthreading to be enabled.
//
// +kubebuilder:default=Enabled
// +optional
Hyperthreading HyperthreadingMode `json:"hyperthreading,omitempty"`
// Architecture is the instruction set architecture of the machine pool.
// Defaults to amd64.
//
// +kubebuilder:default=amd64
// +optional
Architecture Architecture `json:"architecture,omitempty"`
// Fencing stores the information about a baremetal host's management controller.
// Fencing may only be set for control plane nodes.
// +optional
Fencing *Fencing `json:"fencing,omitempty"`
// DiskSetup stores the type of disks that will be setup with MachineConfigs.
// The available types are etcd, swap and user-defined.
// +optional
DiskSetup []Disk `json:"diskSetup,omitempty"`
}
// MachinePoolPlatform is the platform-specific configuration for a machine
// pool. Only one of the platforms should be set.
type MachinePoolPlatform struct {
// AWS is the configuration used when installing on AWS.
AWS *aws.MachinePool `json:"aws,omitempty"`
// Azure is the configuration used when installing on Azure.
Azure *azure.MachinePool `json:"azure,omitempty"`
// BareMetal is the configuration used when installing on bare metal.
BareMetal *baremetal.MachinePool `json:"baremetal,omitempty"`
// GCP is the configuration used when installing on GCP
GCP *gcp.MachinePool `json:"gcp,omitempty"`
// IBMCloud is the configuration used when installing on IBM Cloud.
IBMCloud *ibmcloud.MachinePool `json:"ibmcloud,omitempty"`
// OpenStack is the configuration used when installing on OpenStack.
OpenStack *openstack.MachinePool `json:"openstack,omitempty"`
// VSphere is the configuration used when installing on vSphere.
VSphere *vsphere.MachinePool `json:"vsphere,omitempty"`
// Ovirt is the configuration used when installing on oVirt.
Ovirt *ovirt.MachinePool `json:"ovirt,omitempty"`
// PowerVC is the configuration used when installing on IBM Power VC.
PowerVC *powervc.MachinePool `json:"powervc,omitempty"`
// PowerVS is the configuration used when installing on IBM Power VS.
PowerVS *powervs.MachinePool `json:"powervs,omitempty"`
// Nutanix is the configuration used when installing on Nutanix.
Nutanix *nutanix.MachinePool `json:"nutanix,omitempty"`
}
// Name returns a string representation of the platform (e.g. "aws" if
// AWS is non-nil). It returns an empty string if no platform is
// configured.
func (p *MachinePoolPlatform) Name() string {
switch {
case p == nil:
return ""
case p.AWS != nil:
return aws.Name
case p.Azure != nil:
return azure.Name
case p.BareMetal != nil:
return baremetal.Name
case p.GCP != nil:
return gcp.Name
case p.IBMCloud != nil:
return ibmcloud.Name
case p.OpenStack != nil:
return openstack.Name
case p.VSphere != nil:
return vsphere.Name
case p.Ovirt != nil:
return ovirt.Name
case p.PowerVS != nil:
return powervs.Name
case p.Nutanix != nil:
return nutanix.Name
default:
return ""
}
}
// Fencing stores the information about a baremetal host's management controller.
type Fencing struct {
// Credentials stores the information about a baremetal host's management controller.
// +optional
Credentials []*Credential `json:"credentials,omitempty"`
}
// CertificateVerificationPolicy represents the options for CertificateVerification .
type CertificateVerificationPolicy string
const (
// CertificateVerificationEnabled enables ssl certificate verification.
CertificateVerificationEnabled CertificateVerificationPolicy = "Enabled"
// CertificateVerificationDisabled disables ssl certificate verification.
CertificateVerificationDisabled CertificateVerificationPolicy = "Disabled"
)
// Credential stores the information about a baremetal host's management controller.
type Credential struct {
HostName string `json:"hostName,omitempty" yaml:"hostname,omitempty" validate:"required,uniqueField"`
Username string `json:"username" yaml:"username" validate:"required"`
Password string `json:"password" yaml:"password" validate:"required"`
Address string `json:"address" yaml:"address" validate:"required,uniqueField"`
// CertificateVerification Defines whether ssl certificate verification is required or not.
// If omitted, the platform chooses a default, that default is enabled.
// +kubebuilder:default:="Enabled"
// +kubebuilder:validation:Enum=Enabled;Disabled
// +optional
CertificateVerification CertificateVerificationPolicy `json:"certificateVerification,omitempty" yaml:"certificateVerification,omitempty"`
}