Files
odo/pkg/component/handler.go
Philippe Martin 6bc30110ba Display outputs when executing odo run (#6865)
* Change NewRunHandler params with Options

* Pass an options to RunHandler to show logs

* Hide spinner and std output since outputs are displayed

* Integration tests with failing command

* Fix outputs

* use raw terminal and local standard i/o streams

* Fix podman i/o

* Fix stdout/err

* Test if in/out are terminal

* command reference doc
2023-06-12 10:45:31 -04:00

170 lines
5.7 KiB
Go

package component
import (
"context"
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/devfile/library/v2/pkg/devfile/parser"
"k8s.io/klog"
envcontext "github.com/redhat-developer/odo/pkg/config/context"
"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/kclient"
odolabels "github.com/redhat-developer/odo/pkg/labels"
"github.com/redhat-developer/odo/pkg/libdevfile"
"github.com/redhat-developer/odo/pkg/log"
odocontext "github.com/redhat-developer/odo/pkg/odo/context"
"github.com/redhat-developer/odo/pkg/platform"
"github.com/redhat-developer/odo/pkg/remotecmd"
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
)
type runHandler struct {
ctx context.Context
platformClient platform.Client
execClient exec.Client
configAutomountClient configAutomount.Client
podName string
ComponentExists bool
containersRunning []string
msg string
directRun bool
fs filesystem.Filesystem
imageBackend image.Backend
devfile parser.DevfileObj
path string
}
var _ libdevfile.Handler = (*runHandler)(nil)
type HandlerOptions struct {
PodName string
ComponentExists bool
ContainersRunning []string
Msg string
DirectRun bool
// For apply Kubernetes / Openshift
Devfile parser.DevfileObj
Path string
}
func NewRunHandler(
ctx context.Context,
platformClient platform.Client,
execClient exec.Client,
configAutomountClient configAutomount.Client,
// For building images
fs filesystem.Filesystem,
imageBackend image.Backend,
options HandlerOptions,
) *runHandler {
return &runHandler{
ctx: ctx,
platformClient: platformClient,
execClient: execClient,
configAutomountClient: configAutomountClient,
podName: options.PodName,
ComponentExists: options.ComponentExists,
containersRunning: options.ContainersRunning,
msg: options.Msg,
directRun: options.DirectRun,
fs: fs,
imageBackend: imageBackend,
devfile: options.Devfile,
path: options.Path,
}
}
func (a *runHandler) ApplyImage(img devfilev1.Component) error {
return image.BuildPushSpecificImage(a.ctx, a.imageBackend, a.fs, img, envcontext.GetEnvConfig(a.ctx).PushImages)
}
func (a *runHandler) ApplyKubernetes(kubernetes devfilev1.Component, kind v1alpha2.CommandGroupKind) error {
var (
componentName = odocontext.GetComponentName(a.ctx)
appName = odocontext.GetApplication(a.ctx)
)
mode := odolabels.ComponentDevMode
if kind == v1alpha2.DeployCommandGroupKind {
mode = odolabels.ComponentDeployMode
}
switch platform := a.platformClient.(type) {
case kclient.ClientInterface:
return ApplyKubernetes(mode, appName, componentName, a.devfile, kubernetes, platform, a.path)
default:
klog.V(4).Info("apply kubernetes/Openshift commands are not implemented on podman")
log.Warningf("Apply Kubernetes/Openshift components are not supported on Podman. Skipping: %v.", kubernetes.Name)
return nil
}
}
func (a *runHandler) ApplyOpenShift(openshift devfilev1.Component, kind v1alpha2.CommandGroupKind) error {
return a.ApplyKubernetes(openshift, kind)
}
func (a *runHandler) ExecuteNonTerminatingCommand(ctx context.Context, command devfilev1.Command) error {
var (
componentName = odocontext.GetComponentName(a.ctx)
appName = odocontext.GetApplication(a.ctx)
)
if isContainerRunning(command.Exec.Component, a.containersRunning) {
return ExecuteRunCommand(ctx, a.execClient, a.platformClient, command, a.ComponentExists, a.podName, appName, componentName)
}
switch platform := a.platformClient.(type) {
case kclient.ClientInterface:
return ExecuteInNewContainer(ctx, platform, a.configAutomountClient, a.devfile, componentName, appName, command)
default:
klog.V(4).Info("executing a command in a new container is not implemented on podman")
log.Warningf("executing a command in a new container is not implemented on podman. Skipping: %v.", command.Id)
return nil
}
}
func (a *runHandler) ExecuteTerminatingCommand(ctx context.Context, command devfilev1.Command) error {
var (
componentName = odocontext.GetComponentName(a.ctx)
appName = odocontext.GetApplication(a.ctx)
)
if isContainerRunning(command.Exec.Component, a.containersRunning) {
return ExecuteTerminatingCommand(ctx, a.execClient, a.platformClient, command, a.ComponentExists, a.podName, appName, componentName, a.msg, a.directRun)
}
switch platform := a.platformClient.(type) {
case kclient.ClientInterface:
return ExecuteInNewContainer(ctx, platform, a.configAutomountClient, a.devfile, componentName, appName, command)
default:
klog.V(4).Info("executing a command in a new container is not implemented on podman")
log.Warningf("executing a command in a new container is not implemented on podman. Skipping: %v.", command.Id)
return nil
}
}
// IsRemoteProcessForCommandRunning returns true if the command is running
func (a *runHandler) IsRemoteProcessForCommandRunning(ctx context.Context, command devfilev1.Command, podName string) (bool, error) {
remoteProcess, err := remotecmd.NewKubeExecProcessHandler(a.execClient).GetProcessInfoForCommand(ctx, remotecmd.CommandDefinition{Id: command.Id}, podName, command.Exec.Component)
if err != nil {
return false, err
}
return remoteProcess.Status == remotecmd.Running, nil
}
func isContainerRunning(container string, containers []string) bool {
for _, cnt := range containers {
if container == cnt {
return true
}
}
return false
}