Skip to content

Commit

Permalink
Add an odo run command to manually execute command during odo dev (
Browse files Browse the repository at this point in the history
…#6857)

* Add a run command

* Check command name passed as arg

* Check platform is available

* Add a Run method to the DevClient

* Run command on cluster

* Add test with run command on cluster

* Implement and test run on podman

* Enhance test to check that command has been executed in container

* Fix `odo help` test

* Refactor common code for podman/cluster

* Test Apply commands on Kubernetes/Images

* Test  a msg is displayed when executing odo run without odo dev

* Review

* makes GetRunningPodFromSelector return only Running pods on Podman
  • Loading branch information
feloy authored Jun 2, 2023
1 parent b6c9c88 commit 330b724
Show file tree
Hide file tree
Showing 22 changed files with 574 additions and 34 deletions.
1 change: 1 addition & 0 deletions cmd/odo/help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Examples:
init Init bootstraps a new project
logs Show logs of all containers of the component
registry List all components from the Devfile registry
run Run a specific command in the Dev mode
`

Expand Down
6 changes: 1 addition & 5 deletions pkg/component/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,7 @@ func Log(platformClient platform.Client, componentName string, appName string, f

pod, err := platformClient.GetRunningPodFromSelector(odolabels.GetSelector(componentName, appName, odolabels.ComponentDevMode, false))
if err != nil {
return nil, fmt.Errorf("the component %s doesn't exist on the cluster", componentName)
}

if pod.Status.Phase != corev1.PodRunning {
return nil, fmt.Errorf("unable to show logs, component is not in running state. current status=%v", pod.Status.Phase)
return nil, fmt.Errorf("a running component %s doesn't exist on the cluster: %w", componentName, err)
}

containerName := command.Exec.Component
Expand Down
6 changes: 0 additions & 6 deletions pkg/component/delete/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,12 +212,6 @@ func (do *DeleteComponentClient) ExecutePreStopEvents(ctx context.Context, devfi
return fmt.Errorf("unable to determine if component %s exists; cause: %v", componentName, err.Error())
}

// do not fail Delete operation if if the pod is not running or if the event execution fails
if pod.Status.Phase != corev1.PodRunning {
klog.V(4).Infof("unable to execute preStop events, pod for component %q is not running", componentName)
return nil
}

klog.V(4).Infof("Executing %q event commands for component %q", libdevfile.PreStop, componentName)
// ignore the failures if any; delete should not fail because preStop events failed to execute
handler := component.NewRunHandler(
Expand Down
19 changes: 0 additions & 19 deletions pkg/component/delete/delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -700,25 +700,6 @@ func TestDeleteComponentClient_ExecutePreStopEvents(t *testing.T) {
},
wantErr: false,
},
{
name: "did not execute PreStopEvents because the pod is not in the running state",
fields: fields{
kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface {
client := kclient.NewMockClientInterface(ctrl)

selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentDevMode, false)
pod := odoTestingUtil.CreateFakePod(componentName, "mypod", "runtime")
pod.Status.Phase = corev1.PodFailed
client.EXPECT().GetRunningPodFromSelector(selector).Return(pod, nil)
return client
},
},
args: args{
devfileObj: devfileObjWithPreStopEvents,
appName: appName,
},
wantErr: false,
},
{
name: "failed to execute PreStopEvents because it failed to execute the command inside the container, but no error returned",
fields: fields{
Expand Down
53 changes: 53 additions & 0 deletions pkg/dev/common/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package common

import (
"context"
"fmt"

"github.com/redhat-developer/odo/pkg/component"
"github.com/redhat-developer/odo/pkg/configAutomount"
"github.com/redhat-developer/odo/pkg/devfile/image"
"github.com/redhat-developer/odo/pkg/exec"
"github.com/redhat-developer/odo/pkg/libdevfile"
odocontext "github.com/redhat-developer/odo/pkg/odo/context"
"github.com/redhat-developer/odo/pkg/platform"
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
)

func Run(
ctx context.Context,
commandName string,
platformClient platform.Client,
execClient exec.Client,
configAutomountClient configAutomount.Client,
filesystem filesystem.Filesystem,
) error {
var (
componentName = odocontext.GetComponentName(ctx)
devfileObj = odocontext.GetEffectiveDevfileObj(ctx)
devfilePath = odocontext.GetDevfilePath(ctx)
)

pod, err := platformClient.GetPodUsingComponentName(componentName)
if err != nil {
return fmt.Errorf("unable to get pod for component %s: %w. Please check the command 'odo dev' is running", componentName, err)
}

handler := component.NewRunHandler(
ctx,
platformClient,
execClient,
configAutomountClient,
pod.Name,
false,
component.GetContainersNames(pod),
"Executing command in container",

filesystem,
image.SelectBackend(ctx),
*devfileObj,
devfilePath,
)

return libdevfile.ExecuteCommandByName(ctx, *devfileObj, commandName, handler, false)
}
5 changes: 5 additions & 0 deletions pkg/dev/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ type Client interface {
options StartOptions,
) error

Run(
ctx context.Context,
commandName string,
) error

// CleanupResources deletes the component created using the context's devfile and writes any outputs to out
CleanupResources(ctx context.Context, out io.Writer) error
}
23 changes: 23 additions & 0 deletions pkg/dev/kubedev/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package kubedev

import (
"context"

"github.com/redhat-developer/odo/pkg/dev/common"
"k8s.io/klog"
)

func (o *DevClient) Run(
ctx context.Context,
commandName string,
) error {
klog.V(4).Infof("running command %q on cluster", commandName)
return common.Run(
ctx,
commandName,
o.kubernetesClient,
o.execClient,
o.configAutomountClient,
o.filesystem,
)
}
14 changes: 14 additions & 0 deletions pkg/dev/mock.go

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

23 changes: 23 additions & 0 deletions pkg/dev/podmandev/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package podmandev

import (
"context"

"github.com/redhat-developer/odo/pkg/dev/common"
"k8s.io/klog"
)

func (o *DevClient) Run(
ctx context.Context,
commandName string,
) error {
klog.V(4).Infof("running command %q on podman", commandName)
return common.Run(
ctx,
commandName,
o.podmanClient,
o.execClient,
nil, // TODO(feloy) set when running on new container is supported on podman
o.fs,
)
}
4 changes: 4 additions & 0 deletions pkg/exec/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ func (o fakePlatform) GetRunningPodFromSelector(selector string) (*corev1.Pod, e
panic("not implemented yet")
}

func (o fakePlatform) GetPodUsingComponentName(componentName string) (*corev1.Pod, error) {
panic("not implemented yet")
}

func TestExecuteCommand(t *testing.T) {
for _, tt := range []struct {
name string
Expand Down
3 changes: 3 additions & 0 deletions pkg/libdevfile/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ func (e NoCommandFoundError) Error() string {
if e.name == "" {
return fmt.Sprintf("no %s command found in devfile", e.kind)
}
if e.kind == "" {
return fmt.Sprintf("no command named %q found in devfile", e.name)
}
return fmt.Sprintf("no %s command with name %q found in Devfile", e.kind, e.name)
}

Expand Down
19 changes: 19 additions & 0 deletions pkg/libdevfile/libdevfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,25 @@ func ExecuteCommandByNameAndKind(ctx context.Context, devfileObj parser.DevfileO
return executeCommand(ctx, devfileObj, cmd, handler)
}

// ExecuteCommandByName executes the specified command cmdName in the Devfile.
// If ignoreCommandNotFound is true, nothing is executed if the command is not found and no error is returned.
func ExecuteCommandByName(ctx context.Context, devfileObj parser.DevfileObj, cmdName string, handler Handler, ignoreCommandNotFound bool) error {
commands, err := devfileObj.Data.GetCommands(
common.DevfileOptions{
FilterByName: cmdName,
},
)
if err != nil {
return err
}
if len(commands) != 1 {
return NewNoCommandFoundError("", cmdName)
}

cmd := commands[0]
return executeCommand(ctx, devfileObj, cmd, handler)
}

// executeCommand executes a specific command of a devfile using handler as backend
func executeCommand(ctx context.Context, devfileObj parser.DevfileObj, command v1alpha2.Command, handler Handler) error {
cmd, err := newCommand(devfileObj, command)
Expand Down
2 changes: 2 additions & 0 deletions pkg/odo/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"unicode"

"github.com/redhat-developer/odo/pkg/odo/cli/logs"
"github.com/redhat-developer/odo/pkg/odo/cli/run"
"github.com/redhat-developer/odo/pkg/odo/commonflags"

"github.com/redhat-developer/odo/pkg/log"
Expand Down Expand Up @@ -195,6 +196,7 @@ func odoRootCmd(ctx context.Context, name, fullName string) *cobra.Command {
set.NewCmdSet(set.RecommendedCommandName, util.GetFullName(fullName, set.RecommendedCommandName)),
logs.NewCmdLogs(logs.RecommendedCommandName, util.GetFullName(fullName, logs.RecommendedCommandName)),
completion.NewCmdCompletion(completion.RecommendedCommandName, util.GetFullName(fullName, completion.RecommendedCommandName)),
run.NewCmdRun(run.RecommendedCommandName, util.GetFullName(fullName, run.RecommendedCommandName)),
)

// Add all subcommands to base commands
Expand Down
14 changes: 14 additions & 0 deletions pkg/odo/cli/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ func (o NoCommandInDevfileError) Error() string {
return fmt.Sprintf("no command of kind %q found in the devfile", o.command)
}

type NoCommandNameInDevfileError struct {
name string
}

func NewNoCommandNameInDevfileError(name string) NoCommandNameInDevfileError {
return NoCommandNameInDevfileError{
name: name,
}
}

func (o NoCommandNameInDevfileError) Error() string {
return fmt.Sprintf("no command named %q found in the devfile", o.name)
}

type Warning struct {
msg string
err error
Expand Down
Loading

0 comments on commit 330b724

Please sign in to comment.