Skip to content

Commit d448674

Browse files
authored
fix: copy preflight results job fails with missing k0s binary (#2307)
* fix: copy preflight results job fails with missing k0s binary * f * f * f * f * f * f
1 parent 909abba commit d448674

File tree

5 files changed

+69
-27
lines changed

5 files changed

+69
-27
lines changed

e2e/scripts/common.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,15 @@ ensure_license_in_data_dir() {
321321
fi
322322
}
323323

324+
ensure_copy_host_preflight_results_configmap() {
325+
if ! kubectl get configmap -n embedded-cluster -l embedded-cluster/host-preflight-result --no-headers 2>/dev/null | grep -q host-preflight-results ; then
326+
echo "ConfigMap with label embedded-cluster/host-preflight-result not found in embedded-cluster namespace"
327+
kubectl get configmap -n embedded-cluster
328+
return 1
329+
fi
330+
return 0
331+
}
332+
324333
ensure_node_config() {
325334
if ! kubectl describe node | grep "controller-label" ; then
326335
echo "Failed to find controller-label"

e2e/scripts/single-node-airgap-install.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ main() {
104104
if ! ensure_license_in_data_dir; then
105105
exit 1
106106
fi
107+
108+
if ! ensure_copy_host_preflight_results_configmap; then
109+
exit 1
110+
fi
107111
fi
108112

109113
echo "kotsadm logs"

e2e/scripts/single-node-install.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ main() {
162162
if ! ensure_license_in_data_dir; then
163163
exit 1
164164
fi
165+
166+
if ! ensure_copy_host_preflight_results_configmap; then
167+
exit 1
168+
fi
165169
fi
166170

167171
echo "kotsadm logs"

operator/controllers/installation_controller.go

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727

2828
apv1b2 "github.com/k0sproject/k0s/pkg/apis/autopilot/v1beta2"
2929
k0shelm "github.com/k0sproject/k0s/pkg/apis/helm/v1beta1"
30-
"github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
30+
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
3131
"github.com/replicatedhq/embedded-cluster/operator/pkg/metrics"
3232
"github.com/replicatedhq/embedded-cluster/operator/pkg/openebs"
3333
"github.com/replicatedhq/embedded-cluster/operator/pkg/util"
@@ -67,8 +67,8 @@ var copyHostPreflightResultsJob = &batchv1.Job{
6767
Namespace: ecNamespace,
6868
},
6969
Spec: batchv1.JobSpec{
70-
BackoffLimit: ptr.To[int32](2),
71-
TTLSecondsAfterFinished: ptr.To[int32](0), // we don't want to keep the job around. Delete immediately after it finishes.
70+
BackoffLimit: ptr.To(int32(2)),
71+
TTLSecondsAfterFinished: ptr.To(int32(1 * 60)), // we don't want to keep the job around. Delete it shortly after it finishes.
7272
Template: corev1.PodTemplateSpec{
7373
Spec: corev1.PodSpec{
7474
ServiceAccountName: "embedded-cluster-operator",
@@ -77,16 +77,25 @@ var copyHostPreflightResultsJob = &batchv1.Job{
7777
Name: "host",
7878
VolumeSource: corev1.VolumeSource{
7979
HostPath: &corev1.HostPathVolumeSource{
80-
Path: v1beta1.DefaultDataDir,
81-
Type: ptr.To[corev1.HostPathType]("Directory"),
80+
Path: ecv1beta1.DefaultDataDir,
81+
Type: ptr.To(corev1.HostPathDirectory),
82+
},
83+
},
84+
},
85+
{
86+
Name: "k0s",
87+
VolumeSource: corev1.VolumeSource{
88+
HostPath: &corev1.HostPathVolumeSource{
89+
Path: runtimeconfig.K0sBinaryPath,
90+
Type: ptr.To(corev1.HostPathFile),
8291
},
8392
},
8493
},
8594
},
8695
RestartPolicy: corev1.RestartPolicyNever,
8796
Containers: []corev1.Container{
8897
{
89-
Name: "embedded-cluster-updater",
98+
Name: "copy-host-preflight-results",
9099
Image: "busybox:latest",
91100
Command: []string{
92101
"/bin/sh",
@@ -104,12 +113,23 @@ var copyHostPreflightResultsJob = &batchv1.Job{
104113
"echo '/embedded-cluster/support/host-preflight-results.json does not exist'; " +
105114
"fi",
106115
},
116+
Env: []corev1.EnvVar{
117+
{
118+
Name: "KUBECONFIG",
119+
Value: "", // make k0s kubectl not use admin.conf
120+
},
121+
},
107122
VolumeMounts: []corev1.VolumeMount{
108123
{
109124
Name: "host",
110125
MountPath: "/embedded-cluster",
111126
ReadOnly: false,
112127
},
128+
{
129+
Name: "k0s",
130+
MountPath: runtimeconfig.K0sBinaryPath,
131+
ReadOnly: true,
132+
},
113133
},
114134
},
115135
},
@@ -139,7 +159,7 @@ type InstallationReconciler struct {
139159
// NodeHasChanged returns true if the node configuration has changed when compared to
140160
// the node information we keep in the installation status. Returns a bool indicating
141161
// if a change was detected and a bool indicating if the node is new (not seen yet).
142-
func (r *InstallationReconciler) NodeHasChanged(in *v1beta1.Installation, ev metrics.NodeEvent) (bool, bool, error) {
162+
func (r *InstallationReconciler) NodeHasChanged(in *ecv1beta1.Installation, ev metrics.NodeEvent) (bool, bool, error) {
143163
for _, nodeStatus := range in.Status.NodesStatus {
144164
if nodeStatus.Name != ev.NodeName {
145165
continue
@@ -154,7 +174,7 @@ func (r *InstallationReconciler) NodeHasChanged(in *v1beta1.Installation, ev met
154174
}
155175

156176
// UpdateNodeStatus updates the node status in the Installation object status.
157-
func (r *InstallationReconciler) UpdateNodeStatus(in *v1beta1.Installation, ev metrics.NodeEvent) error {
177+
func (r *InstallationReconciler) UpdateNodeStatus(in *ecv1beta1.Installation, ev metrics.NodeEvent) error {
158178
hash, err := ev.Hash()
159179
if err != nil {
160180
return err
@@ -166,15 +186,15 @@ func (r *InstallationReconciler) UpdateNodeStatus(in *v1beta1.Installation, ev m
166186
in.Status.NodesStatus[i].Hash = hash
167187
return nil
168188
}
169-
in.Status.NodesStatus = append(in.Status.NodesStatus, v1beta1.NodeStatus{Name: ev.NodeName, Hash: hash})
189+
in.Status.NodesStatus = append(in.Status.NodesStatus, ecv1beta1.NodeStatus{Name: ev.NodeName, Hash: hash})
170190
return nil
171191
}
172192

173193
// ReconcileNodeStatuses reconciles the node statuses in the Installation object status. Installation
174194
// is not updated remotely but only in the memory representation of the object (aka caller must save
175195
// the object after the call). This function returns a batch of events that need to be sent back to
176196
// the metrics endpoint, these events represent changes in the node statuses.
177-
func (r *InstallationReconciler) ReconcileNodeStatuses(ctx context.Context, in *v1beta1.Installation) (*NodeEventsBatch, error) {
197+
func (r *InstallationReconciler) ReconcileNodeStatuses(ctx context.Context, in *ecv1beta1.Installation) (*NodeEventsBatch, error) {
178198
var nodes corev1.NodeList
179199
if err := r.List(ctx, &nodes); err != nil {
180200
return nil, fmt.Errorf("failed to list nodes: %w", err)
@@ -206,7 +226,7 @@ func (r *InstallationReconciler) ReconcileNodeStatuses(ctx context.Context, in *
206226
r.Recorder.Eventf(in, corev1.EventTypeNormal, "NodeUpdated", "Node %s has been updated", node.Name)
207227
batch.NodesUpdated = append(batch.NodesUpdated, event)
208228
}
209-
trimmed := []v1beta1.NodeStatus{}
229+
trimmed := []ecv1beta1.NodeStatus{}
210230
for _, nodeStatus := range in.Status.NodesStatus {
211231
if _, ok := seen[nodeStatus.Name]; ok {
212232
trimmed = append(trimmed, nodeStatus)
@@ -224,7 +244,7 @@ func (r *InstallationReconciler) ReconcileNodeStatuses(ctx context.Context, in *
224244
}
225245

226246
// ReportNodesChanges reports node changes to the metrics endpoint.
227-
func (r *InstallationReconciler) ReportNodesChanges(ctx context.Context, in *v1beta1.Installation, batch *NodeEventsBatch) {
247+
func (r *InstallationReconciler) ReportNodesChanges(ctx context.Context, in *ecv1beta1.Installation, batch *NodeEventsBatch) {
228248
for _, ev := range batch.NodesAdded {
229249
if err := metrics.NotifyNodeAdded(ctx, in.Spec.MetricsBaseURL, ev); err != nil {
230250
ctrl.LoggerFrom(ctx).Error(err, "failed to notify node added")
@@ -242,7 +262,7 @@ func (r *InstallationReconciler) ReportNodesChanges(ctx context.Context, in *v1b
242262
}
243263
}
244264

245-
func (r *InstallationReconciler) ReconcileOpenebs(ctx context.Context, in *v1beta1.Installation) error {
265+
func (r *InstallationReconciler) ReconcileOpenebs(ctx context.Context, in *ecv1beta1.Installation) error {
246266
log := ctrl.LoggerFrom(ctx)
247267

248268
err := openebs.CleanupStatefulPods(ctx, r.Client)
@@ -261,8 +281,8 @@ func (r *InstallationReconciler) ReconcileOpenebs(ctx context.Context, in *v1bet
261281
// status of the newest one is coherent with whole cluster status. Returns the newest
262282
// installation object.
263283
func (r *InstallationReconciler) CoalesceInstallations(
264-
ctx context.Context, items []v1beta1.Installation,
265-
) *v1beta1.Installation {
284+
ctx context.Context, items []ecv1beta1.Installation,
285+
) *ecv1beta1.Installation {
266286
sort.SliceStable(items, func(i, j int) bool {
267287
return items[j].Name < items[i].Name
268288
})
@@ -281,7 +301,7 @@ func (r *InstallationReconciler) CoalesceInstallations(
281301

282302
// ReadClusterConfigSpecFromSecret reads the cluster config from the secret pointed by spec.ConfigSecret
283303
// if it is set. This overrides the default configuration from spec.Config.
284-
func (r *InstallationReconciler) ReadClusterConfigSpecFromSecret(ctx context.Context, in *v1beta1.Installation) error {
304+
func (r *InstallationReconciler) ReadClusterConfigSpecFromSecret(ctx context.Context, in *ecv1beta1.Installation) error {
285305
if in.Spec.ConfigSecret == nil {
286306
return nil
287307
}
@@ -298,7 +318,7 @@ func (r *InstallationReconciler) ReadClusterConfigSpecFromSecret(ctx context.Con
298318

299319
// CopyHostPreflightResultsFromNodes copies the preflight results from any new node that is added to the cluster
300320
// A job is scheduled on the new node and the results copied from a host path
301-
func (r *InstallationReconciler) CopyHostPreflightResultsFromNodes(ctx context.Context, in *v1beta1.Installation, events *NodeEventsBatch) error {
321+
func (r *InstallationReconciler) CopyHostPreflightResultsFromNodes(ctx context.Context, in *ecv1beta1.Installation, events *NodeEventsBatch) error {
302322
log := ctrl.LoggerFrom(ctx)
303323

304324
if len(events.NodesAdded) == 0 {
@@ -328,7 +348,7 @@ func (r *InstallationReconciler) CopyHostPreflightResultsFromNodes(ctx context.C
328348
return nil
329349
}
330350

331-
func constructHostPreflightResultsJob(rc runtimeconfig.RuntimeConfig, in *v1beta1.Installation, nodeName string) *batchv1.Job {
351+
func constructHostPreflightResultsJob(rc runtimeconfig.RuntimeConfig, in *ecv1beta1.Installation, nodeName string) *batchv1.Job {
332352
labels := map[string]string{
333353
"embedded-cluster/node-name": nodeName,
334354
"embedded-cluster/installation": in.Name,
@@ -370,9 +390,9 @@ func (r *InstallationReconciler) Reconcile(ctx context.Context, req ctrl.Request
370390
if err != nil {
371391
return ctrl.Result{}, fmt.Errorf("failed to list installations: %w", err)
372392
}
373-
var items []v1beta1.Installation
393+
var items []ecv1beta1.Installation
374394
for _, in := range installs {
375-
if in.Status.State == v1beta1.InstallationStateObsolete {
395+
if in.Status.State == ecv1beta1.InstallationStateObsolete {
376396
continue
377397
}
378398
items = append(items, in)
@@ -472,7 +492,7 @@ func (r *InstallationReconciler) reconcileHostCABundle(ctx context.Context) erro
472492
// SetupWithManager sets up the controller with the Manager.
473493
func (r *InstallationReconciler) SetupWithManager(mgr ctrl.Manager) error {
474494
return ctrl.NewControllerManagedBy(mgr).
475-
For(&v1beta1.Installation{}).
495+
For(&ecv1beta1.Installation{}).
476496
Watches(&corev1.Node{}, &handler.EnqueueRequestForObject{}).
477497
Watches(&apv1b2.Plan{}, &handler.EnqueueRequestForObject{}).
478498
Watches(&k0shelm.Chart{}, &handler.EnqueueRequestForObject{}).

operator/controllers/installation_controller_test.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/go-logr/logr"
1313
"github.com/go-logr/logr/testr"
1414
"github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
15+
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
1516
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
1617
"github.com/stretchr/testify/assert"
1718
"github.com/stretchr/testify/require"
@@ -29,7 +30,7 @@ import (
2930
)
3031

3132
func TestInstallationReconciler_constructCreateCMCommand(t *testing.T) {
32-
in := &v1beta1.Installation{
33+
in := &ecv1beta1.Installation{
3334
ObjectMeta: metav1.ObjectMeta{
3435
Name: "install-name",
3536
},
@@ -39,24 +40,28 @@ func TestInstallationReconciler_constructCreateCMCommand(t *testing.T) {
3940
},
4041
},
4142
}
42-
rc := runtimeconfig.New(nil)
43+
44+
rc := runtimeconfig.New(in.Spec.RuntimeConfig)
45+
4346
job := constructHostPreflightResultsJob(rc, in, "my-node")
44-
require.Len(t, job.Spec.Template.Spec.Volumes, 1)
47+
48+
require.Len(t, job.Spec.Template.Spec.Volumes, 2)
49+
require.Equal(t, "host", job.Spec.Template.Spec.Volumes[0].Name)
4550
require.Equal(t, "/var/lib/embedded-cluster", job.Spec.Template.Spec.Volumes[0].VolumeSource.HostPath.Path)
4651
require.Len(t, job.Spec.Template.Spec.Containers, 1)
4752
require.Len(t, job.Spec.Template.Spec.Containers[0].Command, 4)
4853
kctlCmd := job.Spec.Template.Spec.Containers[0].Command[3]
4954
expected := "if [ -f /embedded-cluster/support/host-preflight-results.json ]; then /embedded-cluster/bin/kubectl create configmap ${HSPF_CM_NAME} --from-file=results.json=/embedded-cluster/support/host-preflight-results.json -n embedded-cluster --dry-run=client -oyaml | /embedded-cluster/bin/kubectl label -f - embedded-cluster/host-preflight-result=${EC_NODE_NAME} --local -o yaml | /embedded-cluster/bin/kubectl apply -f - && /embedded-cluster/bin/kubectl annotate configmap ${HSPF_CM_NAME} \"update-timestamp=$(date +'%Y-%m-%dT%H:%M:%SZ')\" --overwrite; else echo '/embedded-cluster/support/host-preflight-results.json does not exist'; fi"
5055
assert.Equal(t, expected, kctlCmd)
51-
require.Len(t, job.Spec.Template.Spec.Containers[0].Env, 2)
56+
require.Len(t, job.Spec.Template.Spec.Containers[0].Env, 3)
5257
assert.Equal(t, v1.EnvVar{
5358
Name: "EC_NODE_NAME",
5459
Value: "my-node",
55-
}, job.Spec.Template.Spec.Containers[0].Env[0])
60+
}, job.Spec.Template.Spec.Containers[0].Env[1])
5661
assert.Equal(t, v1.EnvVar{
5762
Name: "HSPF_CM_NAME",
5863
Value: "my-node-host-preflight-results",
59-
}, job.Spec.Template.Spec.Containers[0].Env[1])
64+
}, job.Spec.Template.Spec.Containers[0].Env[2])
6065
}
6166

6267
func TestInstallationReconciler_reconcileHostCABundle(t *testing.T) {

0 commit comments

Comments
 (0)