Skip to content

Commit

Permalink
baremetal: monitor bootstrap process
Browse files Browse the repository at this point in the history
  • Loading branch information
honza committed Mar 28, 2024
1 parent 9c98f76 commit 63aceb2
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 0 deletions.
12 changes: 12 additions & 0 deletions cmd/openshift-install/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import (
"github.com/openshift/installer/pkg/types/baremetal"
"github.com/openshift/installer/pkg/types/gcp"
"github.com/openshift/installer/pkg/types/vsphere"
baremetalutils "github.com/openshift/installer/pkg/utils/baremetal"
cov1helpers "github.com/openshift/library-go/pkg/config/clusteroperator/v1helpers"
"github.com/openshift/library-go/pkg/route/routeapihelpers"
)
Expand Down Expand Up @@ -435,6 +436,17 @@ func waitForBootstrapComplete(ctx context.Context, config *rest.Config) *cluster
return newAPIError(err)
}

// baremetal: monitor control plane bootstrapping progress
if assetStore, err := assetstore.NewStore(command.RootOpts.Dir); err == nil {
if installConfig, err := assetStore.Load(&installconfig.InstallConfig{}); err == nil && installConfig != nil {
if installConfig.(*installconfig.InstallConfig).Config.Platform.Name() == baremetal.Name {
if err := baremetalutils.WaitForBaremetalBootstrapControlPlane(ctx, config); err != nil {
return newBootstrapError(err)
}
}
}
}

if err := waitForBootstrapConfigMap(ctx, client); err != nil {
return err
}
Expand Down
46 changes: 46 additions & 0 deletions pkg/types/baremetal/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package baremetal

import (
"context"
"time"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/dynamic"
)

// BmhCacheListerWatcher is an object that wraps the listing and wrapping
// functionality for baremetal host resources.
type BmhCacheListerWatcher struct {
Resource dynamic.ResourceInterface
}

// List returns a list of baremetal hosts as dynamic objects.
func (bc BmhCacheListerWatcher) List(options metav1.ListOptions) (runtime.Object, error) {
list, err := bc.Resource.List(context.TODO(), options)
if err != nil {
if err.Error() == "the server could not find the requested resource" {
return &unstructured.UnstructuredList{}, nil
}
}
return list, err
}

// Watch starts a watch over baremetal hosts.
func (bc BmhCacheListerWatcher) Watch(options metav1.ListOptions) (watch.Interface, error) {
w, err := bc.Resource.Watch(context.TODO(), options)
if err != nil {
if err.Error() == "the server could not find the requested resource" {
// We can't use watch.NewEmptyWatch here because it closes too quickly.
fake := watch.NewFake()
defer func() {
time.Sleep(time.Second * 2)
fake.Stop()
}()
return fake, nil
}
}
return w, err
}
7 changes: 7 additions & 0 deletions pkg/utils/baremetal/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# See the OWNERS docs: https://git.k8s.io/community/contributors/guide/owners.md
# This file just uses aliases defined in OWNERS_ALIASES.

approvers:
- baremetal-approvers
reviewers:
- baremetal-reviewers
100 changes: 100 additions & 0 deletions pkg/utils/baremetal/bootstrap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package baremetal

import (
"context"
"time"

baremetalhost "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
clientwatch "k8s.io/client-go/tools/watch"

"github.com/openshift/installer/pkg/types/baremetal"
)

func WaitForBaremetalBootstrapControlPlane(ctx context.Context, config *rest.Config) error {
timeout := 30 * time.Minute

client, err := dynamic.NewForConfig(config)
if err != nil {
return errors.Wrap(err, "creating a baremetal client")
}

r := client.Resource(baremetalhost.GroupVersion.WithResource("baremetalhosts")).Namespace("openshift-machine-api")
blw := baremetal.BmhCacheListerWatcher{
Resource: r,
}

untilTime := time.Now().Add(timeout)
timezone, _ := untilTime.Zone()
logrus.Infof("Waiting up to %v (until %v %s) for baremetal control plane to provision...",
timeout, untilTime.Format(time.Kitchen), timezone)

waitCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

masters := map[string]baremetalhost.BareMetalHost{}

_, err = clientwatch.UntilWithSync(
waitCtx,
blw,
&unstructured.Unstructured{},
nil,
func(event watch.Event) (bool, error) {
switch event.Type {
case watch.Added, watch.Modified:
default:
return false, nil
}

bmh := &baremetalhost.BareMetalHost{}

unstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(event.Object)
if err != nil {
return false, err
}

if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstr, bmh); err != nil {
logrus.Error("failed to convert to bmh", err)
return false, err
}

role, found := bmh.Labels["installer.openshift.io/role"]

if found && role == "control-plane" {
if bmh.Status.Provisioning.State == baremetalhost.StateNone {
// StateNone is an empty string
logrus.Infof(" baremetalhost: %s: uninitialized", bmh.Name)
} else {
logrus.Infof(" baremetalhost: %s: %s", bmh.Name, bmh.Status.Provisioning.State)
}

if bmh.Status.OperationalStatus == baremetalhost.OperationalStatusError {
logrus.Infof(" baremetalhost: %s: error: %s", bmh.Name, bmh.Status.ErrorMessage)
}
masters[bmh.Name] = *bmh
}

if len(masters) == 0 {
return false, nil
}

for _, master := range masters {
if master.Status.Provisioning.State != baremetalhost.StateProvisioned {
return false, nil
}
}

return true, nil
},
)

// TODO: store the contents of the `masters` var to a file so the provider can pick it up later

return err
}

0 comments on commit 63aceb2

Please sign in to comment.