Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Host agent changes #564

Merged
merged 19 commits into from
Jun 7, 2022
3 changes: 2 additions & 1 deletion agent/cloudinit/cloudinit.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package cloudinit

import (
"context"
"encoding/base64"
"fmt"
"path/filepath"
Expand Down Expand Up @@ -71,7 +72,7 @@ func (se ScriptExecutor) Execute(bootstrapScript string) error {
}

for _, cmd := range cloudInitData.CommandsToExecute {
err := se.RunCmdExecutor.RunCmd(cmd)
err := se.RunCmdExecutor.RunCmd(context.TODO(), cmd)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("Error running the command %s", cmd))
}
Expand Down
2 changes: 1 addition & 1 deletion agent/cloudinit/cloudinit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ runCmd:
Expect(err).NotTo(HaveOccurred())

Expect(fakeCmdExecutor.RunCmdCallCount()).To(Equal(1))
cmd := fakeCmdExecutor.RunCmdArgsForCall(0)
_, cmd := fakeCmdExecutor.RunCmdArgsForCall(0)
Expect(cmd).To(Equal("echo 'some run command'"))
})

Expand Down
23 changes: 13 additions & 10 deletions agent/cloudinit/cloudinitfakes/fake_icmd_runner.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions agent/cloudinit/cmd_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
package cloudinit

import (
"context"
"os"
"os/exec"
)

//counterfeiter:generate . ICmdRunner
type ICmdRunner interface {
RunCmd(string) error
RunCmd(context.Context, string) error
}

// CmdRunner default implementer of ICmdRunner
Expand All @@ -19,8 +20,12 @@ type CmdRunner struct {
}

// RunCmd executes the command string
func (r CmdRunner) RunCmd(cmd string) error {
command := exec.Command("/bin/sh", "-c", cmd)
func (r CmdRunner) RunCmd(ctx context.Context, cmd string) error {
command := exec.CommandContext(ctx, "/bin/bash", "-c", cmd)
command.Stderr = os.Stderr
return command.Run()
command.Stdout = os.Stdout
if err := command.Run(); err != nil {
return err
}
return nil
}
4 changes: 2 additions & 2 deletions agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,7 @@ func main() {
os.Exit(1)
}
}
// Handle kubeconfig flag
// first look in the byoh path for the kubeconfig
// Handle kubeconfig flag first look in the byoh path for the kubeconfig
config, err := registration.LoadRESTClientConfig(registration.GetBYOHConfigPath())
if err != nil {
logger.Error(err, "client config load failed")
Expand Down Expand Up @@ -231,6 +230,7 @@ func main() {
K8sInstaller: k8sInstaller,
SkipK8sInstallation: skipInstallation,
UseInstallerController: useInstallerController,
DownloadPath: downloadpath,
khannakshat7 marked this conversation as resolved.
Show resolved Hide resolved
}
if err = hostReconciler.SetupWithManager(context.TODO(), mgr); err != nil {
logger.Error(err, "unable to create controller")
Expand Down
82 changes: 77 additions & 5 deletions agent/reconciler/host_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type HostReconciler struct {
K8sInstaller IK8sInstaller
SkipK8sInstallation bool
UseInstallerController bool
DownloadPath string
}

const (
Expand Down Expand Up @@ -94,6 +95,8 @@ func (r *HostReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctr

func (r *HostReconciler) reconcileNormal(ctx context.Context, byoHost *infrastructurev1beta1.ByoHost) (ctrl.Result, error) {
logger := ctrl.LoggerFrom(ctx)
logger = logger.WithValues("ByoHost", byoHost.Name)
logger.Info("reconcile normal")
khannakshat7 marked this conversation as resolved.
Show resolved Hide resolved
if byoHost.Status.MachineRef == nil {
logger.Info("Machine ref not yet set")
conditions.MarkFalse(byoHost, infrastructurev1beta1.K8sNodeBootstrapSucceeded, infrastructurev1beta1.WaitingForMachineRefReason, clusterv1.ConditionSeverityInfo, "")
Expand All @@ -117,10 +120,20 @@ func (r *HostReconciler) reconcileNormal(ctx context.Context, byoHost *infrastru
if r.SkipK8sInstallation {
logger.Info("Skipping installation of k8s components")
} else if r.UseInstallerController {
if byoHost.Spec.InstallationSecret == nil {
logger.Info("K8sInstallationSecret not ready")
conditions.MarkFalse(byoHost, infrastructurev1beta1.K8sNodeBootstrapSucceeded, infrastructurev1beta1.K8sInstallationSecretUnavailableReason, clusterv1.ConditionSeverityInfo, "")
return ctrl.Result{}, nil
if !conditions.IsTrue(byoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded) {
khannakshat7 marked this conversation as resolved.
Show resolved Hide resolved
if byoHost.Spec.InstallationSecret == nil {
logger.Info("InstallationSecret not ready")
conditions.MarkFalse(byoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded, infrastructurev1beta1.K8sInstallationSecretUnavailableReason, clusterv1.ConditionSeverityInfo, "")
return ctrl.Result{}, nil
}
err = r.executeInstallerController(ctx, byoHost)
if err != nil {
return ctrl.Result{}, err
}
r.Recorder.Event(byoHost, corev1.EventTypeNormal, "InstallScriptExecutionSucceeded", "install script executed")
conditions.MarkTrue(byoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded)
} else {
logger.Info("install script already executed")
}
} else {
err = r.installK8sComponents(ctx, byoHost)
Expand Down Expand Up @@ -156,6 +169,34 @@ func (r *HostReconciler) reconcileNormal(ctx context.Context, byoHost *infrastru
return ctrl.Result{}, nil
}

func (r *HostReconciler) executeInstallerController(ctx context.Context, byoHost *infrastructurev1beta1.ByoHost) error {
logger := ctrl.LoggerFrom(ctx)
secret := &corev1.Secret{}
err := r.Client.Get(ctx, types.NamespacedName{Name: byoHost.Spec.InstallationSecret.Name, Namespace: byoHost.Spec.InstallationSecret.Namespace}, secret)
if err != nil {
logger.Error(err, "error getting install and uninstall script")
r.Recorder.Eventf(byoHost, corev1.EventTypeWarning, "ReadInstallationSecretFailed", "install and uninstall script %s not found", byoHost.Spec.InstallationSecret.Name)
return err
}
installScript := string(secret.Data["install"])
uninstallScript := string(secret.Data["uninstall"])

byoHost.Spec.UninstallationScript = &uninstallScript
installScript, err = r.parseScript(ctx, installScript)
if err != nil {
return err
}
logger.Info("executing install script")
err = r.CmdRunner.RunCmd(ctx, installScript)
if err != nil {
logger.Error(err, "error executing installation script")
r.Recorder.Event(byoHost, corev1.EventTypeWarning, "InstallScriptExecutionFailed", "install script execution failed")
conditions.MarkFalse(byoHost, infrastructurev1beta1.K8sComponentsInstallationSucceeded, infrastructurev1beta1.K8sComponentsInstallationFailedReason, clusterv1.ConditionSeverityInfo, "")
return err
}
return nil
}

func (r *HostReconciler) reconcileDelete(ctx context.Context, byoHost *infrastructurev1beta1.ByoHost) (ctrl.Result, error) {
return ctrl.Result{}, nil
}
Expand All @@ -171,6 +212,18 @@ func (r *HostReconciler) getBootstrapScript(ctx context.Context, dataSecretName,
return bootstrapSecret, nil
}

func (r *HostReconciler) parseScript(ctx context.Context, script string) (string, error) {
data, err := cloudinit.TemplateParser{
Template: map[string]string{
"BundleDownloadPath": r.DownloadPath,
},
}.ParseTemplate(script)
if err != nil {
return "", fmt.Errorf("unable to apply install parsed template to the data object")
}
return data, nil
}

// SetupWithManager sets up the controller with the manager
func (r *HostReconciler) SetupWithManager(ctx context.Context, mgr manager.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
Expand Down Expand Up @@ -215,6 +268,23 @@ func (r *HostReconciler) hostCleanUp(ctx context.Context, byoHost *infrastructur
}
if r.SkipK8sInstallation {
logger.Info("Skipping uninstallation of k8s components")
} else if r.UseInstallerController {
if byoHost.Spec.UninstallationScript == nil {
return fmt.Errorf("UninstallationScript not found in Byohost %s", byoHost.Name)
}
logger.Info("Executing Uninstall script")
uninstallScript := *byoHost.Spec.UninstallationScript
uninstallScript, err = r.parseScript(ctx, uninstallScript)
if err != nil {
logger.Error(err, "error parsing Uninstallation script")
return err
}
err = r.CmdRunner.RunCmd(ctx, uninstallScript)
if err != nil {
logger.Error(err, "error execting Uninstallation script")
r.Recorder.Event(byoHost, corev1.EventTypeWarning, "UninstallScriptExecutionFailed", "uninstall script execution failed")
return err
}
} else {
err = r.uninstallk8sComponents(ctx, byoHost)
if err != nil {
Expand All @@ -236,6 +306,8 @@ func (r *HostReconciler) hostCleanUp(ctx context.Context, byoHost *infrastructur
return err
}

byoHost.Spec.InstallationSecret = nil
byoHost.Spec.UninstallationScript = nil
r.removeAnnotations(ctx, byoHost)
conditions.MarkFalse(byoHost, infrastructurev1beta1.K8sNodeBootstrapSucceeded, infrastructurev1beta1.K8sNodeAbsentReason, clusterv1.ConditionSeverityInfo, "")
return nil
Expand All @@ -245,7 +317,7 @@ func (r *HostReconciler) resetNode(ctx context.Context, byoHost *infrastructurev
logger := ctrl.LoggerFrom(ctx)
logger.Info("Running kubeadm reset")

err := r.CmdRunner.RunCmd(KubeadmResetCommand)
err := r.CmdRunner.RunCmd(ctx, KubeadmResetCommand)
if err != nil {
r.Recorder.Event(byoHost, corev1.EventTypeWarning, "ResetK8sNodeFailed", "k8s Node Reset failed")
return errors.Wrapf(err, "failed to exec kubeadm reset")
Expand Down
Loading