Skip to content

Commit

Permalink
Host agent changes (#564)
Browse files Browse the repository at this point in the history
* host agent changes added for decoupling the installer

Co-authored-by: khannakshat7 <[email protected]>
Co-authored-by: Dharmjit Singh <[email protected]>
  • Loading branch information
3 people authored Jun 7, 2022
1 parent f6dc397 commit c7fb265
Show file tree
Hide file tree
Showing 10 changed files with 439 additions and 84 deletions.
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,
}
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")
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) {
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

0 comments on commit c7fb265

Please sign in to comment.