Skip to content

Commit

Permalink
replace CommandContext param with RestartOptions type
Browse files Browse the repository at this point in the history
inspired by the 'GetOptions' type in the [kubectl get command](https://github.com/kubernetes/kubectl/blob/master/pkg/cmd/get/get.go#L56-L86),
mostly because `CommandContext` is confusing (I know, I contributed to it!)

Signed-off-by: Xavier Coulon <[email protected]>
  • Loading branch information
xcoulon committed Mar 19, 2024
1 parent dd44578 commit 35a6fba
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 76 deletions.
25 changes: 12 additions & 13 deletions pkg/cmd/adm/register_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,10 @@ func NewRegisterMemberCmd() *cobra.Command {
Long: `Downloads the 'add-cluster.sh' script from the 'toolchain-cicd' repo and calls it twice: once to register the Host cluster in the Member cluster and once to register the Member cluster in the host cluster.`,
RunE: func(cmd *cobra.Command, args []string) error {
term := ioutils.NewTerminal(cmd.InOrStdin, cmd.OutOrStdout)
ctx := clicontext.NewCommandContext(term, client.DefaultNewClient, client.DefaultNewRESTClient)
newCommand := func(name string, args ...string) *exec.Cmd {
return exec.Command(name, args...)
}
return registerMemberCluster(ctx, newCommand, hostKubeconfig, memberKubeconfig)
return registerMemberCluster(context.Background(), term, client.DefaultNewClient, newCommand, hostKubeconfig, memberKubeconfig)

Check warning on line 43 in pkg/cmd/adm/register_member.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/adm/register_member.go#L43

Added line #L43 was not covered by tests
},
}
defaultKubeconfigPath := ""
Expand All @@ -55,15 +54,15 @@ func NewRegisterMemberCmd() *cobra.Command {
return cmd
}

func registerMemberCluster(ctx *clicontext.CommandContext, newCommand client.CommandCreator, hostKubeconfig, memberKubeconfig string) error {
ctx.AskForConfirmation(ioutils.WithMessagef("register member cluster from kubeconfig %s. Be aware that the ksctl disables automatic approval to prevent new users being provisioned to the new member cluster. "+
func registerMemberCluster(ctx context.Context, term ioutils.Terminal, newClient clicontext.NewClientFunc, newCommand client.CommandCreator, hostKubeconfig, memberKubeconfig string) error {
term.AskForConfirmation(ioutils.WithMessagef("register member cluster from kubeconfig %s. Be aware that the ksctl disables automatic approval to prevent new users being provisioned to the new member cluster. "+
"You will need to enable it again manually.", memberKubeconfig))

hostClusterConfig, err := configuration.LoadClusterConfig(ctx, configuration.HostName)
hostClusterConfig, err := configuration.LoadClusterConfig(term, configuration.HostName)
if err != nil {
return err
}
hostClusterClient, err := ctx.NewClient(hostClusterConfig.Token, hostClusterConfig.ServerAPI)
hostClusterClient, err := newClient(hostClusterConfig.Token, hostClusterConfig.ServerAPI)
if err != nil {
return err
}
Expand All @@ -72,23 +71,23 @@ func registerMemberCluster(ctx *clicontext.CommandContext, newCommand client.Com
return err
}

if err := runAddClusterScript(ctx, newCommand, configuration.Host, hostKubeconfig, memberKubeconfig); err != nil {
if err := runAddClusterScript(term, newCommand, configuration.Host, hostKubeconfig, memberKubeconfig); err != nil {
return err
}
if err := runAddClusterScript(ctx, newCommand, configuration.Member, hostKubeconfig, memberKubeconfig); err != nil {
if err := runAddClusterScript(term, newCommand, configuration.Member, hostKubeconfig, memberKubeconfig); err != nil {
return err
}

warningMessage := "The automatic approval was disabled!\n Configure the new member cluster in ToolchainConfig and apply the changes to the cluster."

if err := restartHostOperator(ctx, hostClusterClient, hostClusterConfig); err != nil {
if err := restartHostOperator(ctx, term, hostClusterClient, hostClusterConfig); err != nil {
return fmt.Errorf("%w\nIn Additon, there is another warning you should be aware of:\n%s", err, warningMessage)
}

ctx.Printlnf("!!!!!!!!!!!!!!!")
ctx.Printlnf("!!! WARNING !!!")
ctx.Printlnf("!!!!!!!!!!!!!!!")
ctx.Printlnf(warningMessage)
term.Printlnf("!!!!!!!!!!!!!!!")
term.Printlnf("!!! WARNING !!!")
term.Printlnf("!!!!!!!!!!!!!!!")
term.Printlnf(warningMessage)
return nil
}

Expand Down
21 changes: 8 additions & 13 deletions pkg/cmd/adm/register_member_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/codeready-toolchain/toolchain-common/pkg/test/config"
_ "github.com/kubesaw/ksctl/pkg/client"
"github.com/kubesaw/ksctl/pkg/configuration"
clicontext "github.com/kubesaw/ksctl/pkg/context"
. "github.com/kubesaw/ksctl/pkg/test"

"github.com/h2non/gock"
Expand Down Expand Up @@ -55,14 +54,13 @@ func TestRegisterMember(t *testing.T) {
t.Run("When automatic approval is enabled", func(t *testing.T) {
term := NewFakeTerminalWithResponse("Y")
toolchainConfig := config.NewToolchainConfigObj(t, config.AutomaticApproval().Enabled(true))
newClient, newRESTClient, fakeClient := NewFakeClients(t, toolchainConfig, deployment)
newClient, _, fakeClient := NewFakeClients(t, toolchainConfig, deployment)
numberOfUpdateCalls := 0
fakeClient.MockUpdate = whenDeploymentThenUpdated(t, fakeClient, hostDeploymentName, 1, &numberOfUpdateCalls)
ctx := clicontext.NewCommandContext(term, newClient, newRESTClient)
counter = 0

// when
err := registerMemberCluster(ctx, ocCommandCreator, hostKubeconfig, memberKubeconfig)
err := registerMemberCluster(context.Background(), term, newClient, ocCommandCreator, hostKubeconfig, memberKubeconfig)

// then
require.NoError(t, err)
Expand All @@ -87,18 +85,17 @@ func TestRegisterMember(t *testing.T) {

t.Run("When toolchainConfig is not present", func(t *testing.T) {
term := NewFakeTerminalWithResponse("Y")
newClient, newRESTClient, fakeClient := NewFakeClients(t, deployment)
newClient, _, fakeClient := NewFakeClients(t, deployment)
fakeClient.MockUpdate = func(ctx context.Context, obj runtimeclient.Object, opts ...runtimeclient.UpdateOption) error {
if _, ok := obj.(*toolchainv1alpha1.ToolchainConfig); ok {
return fmt.Errorf("should not be called")
}
return fakeClient.Client.Update(ctx, obj, opts...)
}
ctx := clicontext.NewCommandContext(term, newClient, newRESTClient)
counter = 0

// when
err := registerMemberCluster(ctx, ocCommandCreator, hostKubeconfig, memberKubeconfig)
err := registerMemberCluster(context.Background(), term, newClient, ocCommandCreator, hostKubeconfig, memberKubeconfig)

// then
require.NoError(t, err)
Expand All @@ -113,18 +110,17 @@ func TestRegisterMember(t *testing.T) {
t.Run("When automatic approval is disabled", func(t *testing.T) {
term := NewFakeTerminalWithResponse("Y")
toolchainConfig := config.NewToolchainConfigObj(t, config.AutomaticApproval().Enabled(false))
newClient, newRESTClient, fakeClient := NewFakeClients(t, toolchainConfig, deployment)
newClient, _, fakeClient := NewFakeClients(t, toolchainConfig, deployment)
fakeClient.MockUpdate = func(ctx context.Context, obj runtimeclient.Object, opts ...runtimeclient.UpdateOption) error {
if _, ok := obj.(*toolchainv1alpha1.ToolchainConfig); ok {
return fmt.Errorf("should not be called")
}
return fakeClient.Client.Update(ctx, obj, opts...)
}
ctx := clicontext.NewCommandContext(term, newClient, newRESTClient)
counter = 0

// when
err := registerMemberCluster(ctx, ocCommandCreator, hostKubeconfig, memberKubeconfig)
err := registerMemberCluster(context.Background(), term, newClient, ocCommandCreator, hostKubeconfig, memberKubeconfig)

// then
require.NoError(t, err)
Expand All @@ -143,15 +139,14 @@ func TestRegisterMember(t *testing.T) {
toolchainConfig := config.NewToolchainConfigObj(t, config.AutomaticApproval().Enabled(false))
toolchainConfig2 := config.NewToolchainConfigObj(t, config.AutomaticApproval().Enabled(true))
toolchainConfig2.Name = "config2"
newClient, newRESTClient, fakeClient := NewFakeClients(t, toolchainConfig, toolchainConfig2, deployment)
newClient, _, fakeClient := NewFakeClients(t, toolchainConfig, toolchainConfig2, deployment)
fakeClient.MockUpdate = func(ctx context.Context, obj runtimeclient.Object, opts ...runtimeclient.UpdateOption) error {
return fmt.Errorf("should not be called")
}
ctx := clicontext.NewCommandContext(term, newClient, newRESTClient)
counter = 0

// when
err := registerMemberCluster(ctx, ocCommandCreator, hostKubeconfig, memberKubeconfig)
err := registerMemberCluster(context.Background(), term, newClient, ocCommandCreator, hostKubeconfig, memberKubeconfig)

// then
require.Error(t, err)
Expand Down
55 changes: 31 additions & 24 deletions pkg/cmd/adm/restart.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,68 +28,75 @@ func NewRestartCmd() *cobra.Command {
If no deployment name is provided, then it lists all existing deployments in the namespace.`,
Args: cobra.RangeArgs(0, 1),
RunE: func(cmd *cobra.Command, args []string) error {
term := ioutils.NewTerminal(cmd.InOrStdin, cmd.OutOrStdout)
ctx := clicontext.NewCommandContext(term, client.DefaultNewClient, client.DefaultNewRESTClient)
return restart(ctx, targetCluster, args...)
o := &RestartOptions{
term: ioutils.NewTerminal(cmd.InOrStdin, cmd.OutOrStdout),
newClient: client.DefaultNewClient,

Check warning on line 33 in pkg/cmd/adm/restart.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/adm/restart.go#L31-L33

Added lines #L31 - L33 were not covered by tests
}
return o.restart(cmd.Context(), targetCluster, args...)

Check warning on line 35 in pkg/cmd/adm/restart.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/adm/restart.go#L35

Added line #L35 was not covered by tests
},
}
command.Flags().StringVarP(&targetCluster, "target-cluster", "t", "", "The target cluster")
flags.MustMarkRequired(command, "target-cluster")
return command
}

func restart(ctx *clicontext.CommandContext, clusterName string, deployments ...string) error {
cfg, err := configuration.LoadClusterConfig(ctx, clusterName)
type RestartOptions struct {
term ioutils.Terminal
newClient clicontext.NewClientFunc
}

func (o *RestartOptions) restart(ctx context.Context, clusterName string, deployments ...string) error {
cfg, err := configuration.LoadClusterConfig(o.term, clusterName)
if err != nil {
return err
}
cl, err := ctx.NewClient(cfg.Token, cfg.ServerAPI)
cl, err := o.newClient(cfg.Token, cfg.ServerAPI)
if err != nil {
return err
}

if len(deployments) == 0 {
err := printExistingDeployments(ctx.Terminal, cl, cfg)
err := printExistingDeployments(o.term, cl, cfg)
if err != nil {
ctx.Terminal.Printlnf("\nERROR: Failed to list existing deployments\n :%s", err.Error())
o.term.Printlnf("\nERROR: Failed to list existing deployments\n :%s", err.Error())

Check warning on line 61 in pkg/cmd/adm/restart.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/adm/restart.go#L61

Added line #L61 was not covered by tests
}
return fmt.Errorf("at least one deployment name is required, include one or more of the above deployments to restart")
}
deploymentName := deployments[0]

if !ctx.AskForConfirmation(
if !o.term.AskForConfirmation(
ioutils.WithMessagef("restart the deployment '%s' in namespace '%s'", deploymentName, cfg.SandboxNamespace)) {
return nil
}
return restartDeployment(ctx, cl, cfg, deploymentName)
return restartDeployment(ctx, o.term, cl, cfg, deploymentName)
}

func restartDeployment(ctx *clicontext.CommandContext, cl runtimeclient.Client, cfg configuration.ClusterConfig, deploymentName string) error {
func restartDeployment(ctx context.Context, term ioutils.Terminal, cl runtimeclient.Client, cfg configuration.ClusterConfig, deploymentName string) error {
namespacedName := types.NamespacedName{
Namespace: cfg.SandboxNamespace,
Name: deploymentName,
}

originalReplicas, err := scaleToZero(cl, namespacedName)
originalReplicas, err := scaleToZero(ctx, cl, namespacedName)
if err != nil {
if apierrors.IsNotFound(err) {
ctx.Printlnf("\nERROR: The given deployment '%s' wasn't found.", deploymentName)
return printExistingDeployments(ctx, cl, cfg)
term.Printlnf("\nERROR: The given deployment '%s' wasn't found.", deploymentName)
return printExistingDeployments(term, cl, cfg)
}
return err
}
ctx.Println("The deployment was scaled to 0")
if err := scaleBack(ctx, cl, namespacedName, originalReplicas); err != nil {
ctx.Printlnf("Scaling the deployment '%s' in namespace '%s' back to '%d' replicas wasn't successful", originalReplicas)
ctx.Println("Please, try to contact administrators to scale the deployment back manually")
term.Println("The deployment was scaled to 0")
if err := scaleBack(term, cl, namespacedName, originalReplicas); err != nil {
term.Printlnf("Scaling the deployment '%s' in namespace '%s' back to '%d' replicas wasn't successful", originalReplicas)
term.Println("Please, try to contact administrators to scale the deployment back manually")

Check warning on line 91 in pkg/cmd/adm/restart.go

View check run for this annotation

Codecov / codecov/patch

pkg/cmd/adm/restart.go#L90-L91

Added lines #L90 - L91 were not covered by tests
return err
}

ctx.Printlnf("The deployment was scaled back to '%d'", originalReplicas)
term.Printlnf("The deployment was scaled back to '%d'", originalReplicas)
return nil
}

func restartHostOperator(ctx *clicontext.CommandContext, hostClient runtimeclient.Client, hostConfig configuration.ClusterConfig) error {
func restartHostOperator(ctx context.Context, term ioutils.Terminal, hostClient runtimeclient.Client, hostConfig configuration.ClusterConfig) error {
deployments := &appsv1.DeploymentList{}
if err := hostClient.List(context.TODO(), deployments,
runtimeclient.InNamespace(hostConfig.SandboxNamespace),
Expand All @@ -101,7 +108,7 @@ func restartHostOperator(ctx *clicontext.CommandContext, hostClient runtimeclien
"It's not possible to restart the Host Operator deployment", hostConfig.SandboxNamespace, len(deployments.Items))
}

return restartDeployment(ctx, hostClient, hostConfig, deployments.Items[0].Name)
return restartDeployment(ctx, term, hostClient, hostConfig, deployments.Items[0].Name)
}

func printExistingDeployments(term ioutils.Terminal, cl runtimeclient.Client, cfg configuration.ClusterConfig) error {
Expand All @@ -117,11 +124,11 @@ func printExistingDeployments(term ioutils.Terminal, cl runtimeclient.Client, cf
return nil
}

func scaleToZero(cl runtimeclient.Client, namespacedName types.NamespacedName) (int32, error) {
func scaleToZero(ctx context.Context, cl runtimeclient.Client, namespacedName types.NamespacedName) (int32, error) {

// get the deployment
deployment := &appsv1.Deployment{}
if err := cl.Get(context.TODO(), namespacedName, deployment); err != nil {
if err := cl.Get(ctx, namespacedName, deployment); err != nil {
return 0, err
}
// keep original number of replicas so we can bring it back
Expand All @@ -130,7 +137,7 @@ func scaleToZero(cl runtimeclient.Client, namespacedName types.NamespacedName) (
deployment.Spec.Replicas = &zero

// update the deployment so it scales to zero
return originalReplicas, cl.Update(context.TODO(), deployment)
return originalReplicas, cl.Update(ctx, deployment)
}

func scaleBack(term ioutils.Terminal, cl runtimeclient.Client, namespacedName types.NamespacedName, originalReplicas int32) error {
Expand Down
Loading

0 comments on commit 35a6fba

Please sign in to comment.