Skip to content

Commit

Permalink
Add metal3 support
Browse files Browse the repository at this point in the history
  • Loading branch information
honza committed Nov 21, 2024
1 parent ec9120b commit 502eca1
Show file tree
Hide file tree
Showing 2,191 changed files with 123,214 additions and 45,938 deletions.
5 changes: 5 additions & 0 deletions cmd/cluster-capi-operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"os"
"time"

metal3v1 "github.com/metal3-io/cluster-api-provider-metal3/api/v1beta1"
"github.com/spf13/pflag"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
Expand Down Expand Up @@ -82,6 +83,7 @@ func initScheme(scheme *runtime.Scheme) {
utilruntime.Must(vspherev1.AddToScheme(scheme))
utilruntime.Must(mapiv1.AddToScheme(scheme))
utilruntime.Must(mapiv1beta1.AddToScheme(scheme))
utilruntime.Must(metal3v1.AddToScheme(scheme))
}

//nolint:funlen
Expand Down Expand Up @@ -280,6 +282,9 @@ func setupPlatformReconcilers(mgr manager.Manager, infra *configv1.Infrastructur
case configv1.OpenStackPlatformType:
setupReconcilers(mgr, infra, platform, &openstackv1.OpenStackCluster{}, containerImages, applyClient, apiextensionsClient, managedNamespace)
setupWebhooks(mgr)
case configv1.BareMetalPlatformType:
setupReconcilers(mgr, infra, platform, &metal3v1.Metal3Cluster{}, containerImages, applyClient, apiextensionsClient, managedNamespace)
setupWebhooks(mgr)
default:
klog.Infof("Detected platform %q is not supported, skipping capi controllers setup", platform)
setupUnsupportedController(mgr, managedNamespace)
Expand Down
2 changes: 1 addition & 1 deletion cmd/machine-api-migration/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func main() {
}

capiManagerOptions := capiflags.ManagerOptions{
MetricsBindAddr: ":8081",
DiagnosticsAddress: ":8081",
}

healthAddr := flag.String(
Expand Down
249 changes: 249 additions & 0 deletions e2e/baremetal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
package e2e

import (
"fmt"

bmov1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
metal3v1 "github.com/metal3-io/cluster-api-provider-metal3/api/v1beta1"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
yaml "sigs.k8s.io/yaml"

configv1 "github.com/openshift/api/config/v1"
mapiv1 "github.com/openshift/api/machine/v1beta1"
bmv1alpha1 "github.com/openshift/cluster-api-provider-baremetal/pkg/apis/baremetal/v1alpha1"
"github.com/openshift/cluster-capi-operator/e2e/framework"
)

const (
baremetalMachineTemplateName = "baremetal-machine-template"
)

var _ = Describe("Cluster API Baremetal MachineSet", Ordered, func() {
var baremetalMachineTemplate *metal3v1.Metal3MachineTemplate
var machineSet *clusterv1.MachineSet
var mapiMachineSpec *bmv1alpha1.BareMetalMachineProviderSpec

BeforeAll(func() {
if platform != configv1.BareMetalPlatformType {
Skip("Skipping Baremetal E2E tests")
}
framework.CreateCoreCluster(cl, clusterName, "Metal3Cluster")
mapiMachineSpec = getBaremetalMAPIProviderSpec(cl)
createBaremetalCluster(cl, mapiMachineSpec)
})

AfterEach(func() {
if platform != configv1.BareMetalPlatformType {
// Because AfterEach always runs, even when tests are skipped, we have to
// explicitly skip it here for other platforms.
Skip("Skipping Baremetal E2E tests")
}
framework.DeleteMachineSets(cl, machineSet)
framework.WaitForMachineSetsDeleted(cl, machineSet)
framework.DeleteObjects(cl, baremetalMachineTemplate)
})

It("should be able to run a machine", func() {
baremetalMachineTemplate = createBaremetalMachineTemplate(cl, mapiMachineSpec)

params := framework.NewMachineSetParams(
"baremetal-machineset",
clusterName,
"", // mapiMachineSpec.Zone,
1,
corev1.ObjectReference{
Kind: "Metal3MachineTemplate",
APIVersion: infraAPIVersion,
Name: baremetalMachineTemplateName,
},
)

params.UserDataSecret = "worker-user-data-managed"

machineSet = framework.CreateMachineSet(cl, params)

err := annotateMetal3Machine(machineSet)
Expect(err).ToNot(HaveOccurred(), "should not fail to annotate")

By("host has been annotated")

waitForBaremetalHost(cl)

})
})

func waitForBaremetalHost(cl client.Client) {
By("waiting for baremetal host")
Eventually(func() error {
bmh := bmov1alpha1.BareMetalHost{}
key := client.ObjectKey{
Namespace: "openshift-cluster-api",
Name: "ostest-extraworker-0",
}

err := cl.Get(ctx, key, &bmh)
if err != nil {
return err
}

fmt.Println("baremetalhost:", bmh.Name, bmh.Namespace, bmh.Status.Provisioning.State)
if bmh.Status.Provisioning.State != bmov1alpha1.StateProvisioned {
return fmt.Errorf("baremetalhost is not provisioned")
}

return nil
}, framework.WaitOverLong, framework.RetryMedium).Should(Succeed())

}

func annotateMetal3Machine(machineSet *clusterv1.MachineSet) error {
machines, err := framework.GetMachinesFromMachineSet(cl, machineSet)
if err != nil {
return err
}

if len(machines) == 0 {
By("Waiting for machines")
Eventually(func() bool {
machines, _ = framework.GetMachinesFromMachineSet(cl, machineSet)
return len(machines) != 0
}, framework.WaitLong, framework.RetryShort).Should(BeTrue())
}

metal3Machine := &metal3v1.Metal3Machine{}

// machines and metal3machines share a name
err = cl.Get(
ctx,
types.NamespacedName{
Name: machines[0].Name,
Namespace: machines[0].Namespace,
},
metal3Machine,
)

if err != nil {
return fmt.Errorf("failed to get a metal3machine: %v", err)
}

if metal3Machine.Annotations == nil {
metal3Machine.Annotations = make(map[string]string)
}

// The baremetalhost is created by dev-scripts and the naming is consistent.
// TODO: Should we try to make sure that the baremetalhost exists?
metal3Machine.Annotations["metal3.io/BareMetalHost"] = "openshift-cluster-api/ostest-extraworker-0"

err = cl.Update(ctx, metal3Machine)
if err != nil {
return fmt.Errorf("failed to update metal3machine: %v", err)
}

return nil
}

func getBaremetalMAPIProviderSpec(cl client.Client) *bmv1alpha1.BareMetalMachineProviderSpec {
machineSetList := &mapiv1.MachineSetList{}
Expect(cl.List(ctx, machineSetList, client.InNamespace(framework.MAPINamespace))).To(Succeed())

Expect(machineSetList.Items).ToNot(HaveLen(0))
machineSet := machineSetList.Items[0]
Expect(machineSet.Spec.Template.Spec.ProviderSpec.Value).ToNot(BeNil())

providerSpec := &bmv1alpha1.BareMetalMachineProviderSpec{}
Expect(yaml.Unmarshal(machineSet.Spec.Template.Spec.ProviderSpec.Value.Raw, providerSpec)).To(Succeed())

return providerSpec
}

func createBaremetalCluster(cl client.Client, mapiProviderSpec *bmv1alpha1.BareMetalMachineProviderSpec) *metal3v1.Metal3Cluster {
By("Creating Baremetal cluster")

host, port, err := framework.GetControlPlaneHostAndPort(cl)
if err != nil {
Expect(err).ToNot(HaveOccurred(), "should not fail getting the Control Plane host and port")
}

baremetalCluster := &metal3v1.Metal3Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: clusterName,
Namespace: framework.CAPINamespace,
// The ManagedBy Annotation is set so CAPI infra providers ignore the InfraCluster object,
// as that's managed externally, in this case by the cluster-capi-operator's infracluster controller.
Annotations: map[string]string{
clusterv1.ManagedByAnnotation: managedByAnnotationValueClusterCAPIOperatorInfraClusterController,
},
},
Spec: metal3v1.Metal3ClusterSpec{
ControlPlaneEndpoint: metal3v1.APIEndpoint{
Host: host,
Port: int(port),
},
// Network: metal3v1.Network{
// Name: &mapiProviderSpec.NetworkInterfaces[0].Network,
// },
// Region: mapiProviderSpec.Region,
// Project: mapiProviderSpec.ProjectID,
},
}

if err := cl.Create(ctx, baremetalCluster); err != nil && !apierrors.IsAlreadyExists(err) {
Expect(err).ToNot(HaveOccurred())
}

Eventually(func() (bool, error) {
patchedBaremetalCluster := &metal3v1.Metal3Cluster{}
err := cl.Get(ctx, client.ObjectKeyFromObject(baremetalCluster), patchedBaremetalCluster)
if err != nil {
return false, err
}

if patchedBaremetalCluster.Annotations == nil {
return false, nil
}

if _, ok := patchedBaremetalCluster.Annotations[clusterv1.ManagedByAnnotation]; !ok {
return false, nil
}

return patchedBaremetalCluster.Status.Ready, nil
}, framework.WaitShort).Should(BeTrue())

return baremetalCluster
}

func createBaremetalMachineTemplate(cl client.Client, mapiProviderSpec *bmv1alpha1.BareMetalMachineProviderSpec) *metal3v1.Metal3MachineTemplate {
By("Creating Baremetal machine template")

baremetalMachineSpec := metal3v1.Metal3MachineSpec{
CustomDeploy: &metal3v1.CustomDeploy{
Method: "install_coreos",
},
UserData: mapiProviderSpec.UserData,
}

baremetalMachineTemplate := &metal3v1.Metal3MachineTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: baremetalMachineTemplateName,
Namespace: framework.CAPINamespace,
},
Spec: metal3v1.Metal3MachineTemplateSpec{
Template: metal3v1.Metal3MachineTemplateResource{
Spec: baremetalMachineSpec,
},
},
}

if err := cl.Create(ctx, baremetalMachineTemplate); err != nil && !apierrors.IsAlreadyExists(err) {
Expect(err).ToNot(HaveOccurred())
}

return baremetalMachineTemplate
}
4 changes: 4 additions & 0 deletions e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"testing"

bmov1alpha1 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
metal3v1 "github.com/metal3-io/cluster-api-provider-metal3/api/v1beta1"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
Expand Down Expand Up @@ -44,6 +46,8 @@ func init() {
utilruntime.Must(mapiv1.AddToScheme(scheme.Scheme))
utilruntime.Must(ibmpowervsv1.AddToScheme(scheme.Scheme))
utilruntime.Must(vspherev1.AddToScheme(scheme.Scheme))
utilruntime.Must(metal3v1.AddToScheme(scheme.Scheme))
utilruntime.Must(bmov1alpha1.AddToScheme(scheme.Scheme))
}

func TestAPIs(t *testing.T) {
Expand Down
5 changes: 3 additions & 2 deletions e2e/framework/machineset.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type machineSetParams struct {
failureDomain string
replicas int32
infrastructureRef corev1.ObjectReference
UserDataSecret string
}

// NewMachineSetParams returns a new machineSetParams object.
Expand All @@ -35,14 +36,14 @@ func NewMachineSetParams(msName, clusterName, failureDomain string, replicas int
replicas: replicas,
infrastructureRef: infrastructureRef,
failureDomain: failureDomain,
UserDataSecret: "worker-user-data",
}
}

// CreateMachineSet creates a new MachineSet resource.
func CreateMachineSet(cl client.Client, params machineSetParams) *clusterv1.MachineSet {
By(fmt.Sprintf("Creating MachineSet %q", params.msName))

userDataSecret := "worker-user-data"
ms := &clusterv1.MachineSet{
TypeMeta: metav1.TypeMeta{
Kind: "MachineSet",
Expand Down Expand Up @@ -70,7 +71,7 @@ func CreateMachineSet(cl client.Client, params machineSetParams) *clusterv1.Mach
},
Spec: clusterv1.MachineSpec{
Bootstrap: clusterv1.Bootstrap{
DataSecretName: &userDataSecret,
DataSecretName: &params.UserDataSecret,
},
ClusterName: params.clusterName,
InfrastructureRef: params.infrastructureRef,
Expand Down
Loading

0 comments on commit 502eca1

Please sign in to comment.