mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
Wait when Build command fails (#6771)
* Same signature for reconcile in kubedev/podmandev * Do not call initial reconcile * Do not retry + filter deployment events * Integration tests * Move logs back to level 4 * Remove unnecessary files * Log state + Set state to ready when build fails
This commit is contained in:
@@ -61,12 +61,12 @@ func (o *DevClient) createComponents(ctx context.Context, parameters common.Push
|
||||
return false, err
|
||||
}
|
||||
|
||||
if componentStatus.State == watch.StateSyncOutdated {
|
||||
if componentStatus.GetState() == watch.StateSyncOutdated {
|
||||
// Clear the cache of image components already applied, hence forcing image components to be reapplied.
|
||||
componentStatus.ImageComponentsAutoApplied = make(map[string]devfilev1.ImageComponent)
|
||||
}
|
||||
|
||||
klog.V(4).Infof("component state: %q\n", componentStatus.State)
|
||||
klog.V(4).Infof("component state: %q\n", componentStatus.GetState())
|
||||
err = o.buildPushAutoImageComponents(ctx, o.filesystem, parameters.Devfile, componentStatus)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -78,7 +78,7 @@ func (o *DevClient) createComponents(ctx context.Context, parameters common.Push
|
||||
return false, err
|
||||
}
|
||||
|
||||
if componentStatus.State != watch.StateWaitDeployment && componentStatus.State != watch.StateReady {
|
||||
if componentStatus.GetState() != watch.StateWaitDeployment && componentStatus.GetState() != watch.StateReady {
|
||||
log.SpinnerNoSpin("Waiting for Kubernetes resources")
|
||||
}
|
||||
|
||||
@@ -132,14 +132,14 @@ func (o *DevClient) createComponents(ctx context.Context, parameters common.Push
|
||||
|
||||
if updated {
|
||||
klog.V(4).Infof("Deployment has been updated to generation %d. Waiting new event...\n", deployment.GetGeneration())
|
||||
componentStatus.State = watch.StateWaitDeployment
|
||||
componentStatus.SetState(watch.StateWaitDeployment)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
numberReplicas := deployment.Status.ReadyReplicas
|
||||
if numberReplicas != 1 {
|
||||
klog.V(4).Infof("Deployment has %d ready replicas. Waiting new event...\n", numberReplicas)
|
||||
componentStatus.State = watch.StateWaitDeployment
|
||||
componentStatus.SetState(watch.StateWaitDeployment)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ func (o *DevClient) createComponents(ctx context.Context, parameters common.Push
|
||||
}
|
||||
o.portsChanged = !reflect.DeepEqual(o.portsToForward, o.portForwardClient.GetForwardedPorts())
|
||||
|
||||
if componentStatus.State == watch.StateReady && !o.portsChanged {
|
||||
if componentStatus.GetState() == watch.StateReady && !o.portsChanged {
|
||||
// If the deployment is already in Ready State, no need to continue
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func (o *DevClient) innerloop(ctx context.Context, parameters common.PushParamet
|
||||
return fmt.Errorf("failed to validate devfile build and run commands: %w", err)
|
||||
}
|
||||
|
||||
podChanged := componentStatus.State == watch.StateWaitDeployment
|
||||
podChanged := componentStatus.GetState() == watch.StateWaitDeployment
|
||||
|
||||
// Get a sync adapter. Check if project files have changed and sync accordingly
|
||||
compInfo := sync.ComponentInfo{
|
||||
@@ -82,7 +82,7 @@ func (o *DevClient) innerloop(ctx context.Context, parameters common.PushParamet
|
||||
|
||||
execRequired, err := o.syncClient.SyncFiles(ctx, syncParams)
|
||||
if err != nil {
|
||||
componentStatus.State = watch.StateReady
|
||||
componentStatus.SetState(watch.StateReady)
|
||||
return fmt.Errorf("failed to sync to component with name %s: %w", componentName, err)
|
||||
}
|
||||
s.End(true)
|
||||
@@ -150,11 +150,13 @@ func (o *DevClient) innerloop(ctx context.Context, parameters common.PushParamet
|
||||
if running {
|
||||
if cmd.Exec == nil || !util.SafeGetBool(cmd.Exec.HotReloadCapable) {
|
||||
if err = doExecuteBuildCommand(); err != nil {
|
||||
componentStatus.SetState(watch.StateReady)
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err = doExecuteBuildCommand(); err != nil {
|
||||
componentStatus.SetState(watch.StateReady)
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -184,7 +186,7 @@ func (o *DevClient) innerloop(ctx context.Context, parameters common.PushParamet
|
||||
}
|
||||
componentStatus.EndpointsForwarded = o.portForwardClient.GetForwardedPorts()
|
||||
|
||||
componentStatus.State = watch.StateReady
|
||||
componentStatus.SetState(watch.StateReady)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/redhat-developer/odo/pkg/devfile/location"
|
||||
"github.com/redhat-developer/odo/pkg/exec"
|
||||
"github.com/redhat-developer/odo/pkg/kclient"
|
||||
odocontext "github.com/redhat-developer/odo/pkg/odo/context"
|
||||
"github.com/redhat-developer/odo/pkg/portForward"
|
||||
"github.com/redhat-developer/odo/pkg/preference"
|
||||
"github.com/redhat-developer/odo/pkg/sync"
|
||||
@@ -87,23 +86,12 @@ func (o *DevClient) Start(
|
||||
klog.V(4).Infoln("Creating new adapter")
|
||||
|
||||
var (
|
||||
devfileObj = odocontext.GetDevfileObj(ctx)
|
||||
componentStatus = watch.ComponentStatus{
|
||||
ImageComponentsAutoApplied: make(map[string]devfilev1.ImageComponent),
|
||||
}
|
||||
)
|
||||
|
||||
pushParameters := common.PushParameters{
|
||||
StartOptions: options,
|
||||
Devfile: *devfileObj,
|
||||
}
|
||||
|
||||
klog.V(4).Infoln("Creating inner-loop resources for the component")
|
||||
componentStatus := watch.ComponentStatus{
|
||||
ImageComponentsAutoApplied: make(map[string]devfilev1.ImageComponent),
|
||||
}
|
||||
err := o.reconcile(ctx, pushParameters, &componentStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
klog.V(4).Infoln("Successfully created inner-loop resources")
|
||||
|
||||
watchParameters := watch.WatchParameters{
|
||||
StartOptions: options,
|
||||
@@ -120,7 +108,7 @@ func (o *DevClient) regenerateAdapterAndPush(ctx context.Context, pushParams com
|
||||
|
||||
devObj, err := devfile.ParseAndValidateFromFileWithVariables(location.DevfileLocation(""), pushParams.StartOptions.Variables)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to generate component from watch parameters: %w", err)
|
||||
return fmt.Errorf("unable to read devfile: %w", err)
|
||||
}
|
||||
|
||||
pushParams.Devfile = devObj
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
@@ -77,21 +76,15 @@ func (o *DevClient) Start(
|
||||
ctx context.Context,
|
||||
options dev.StartOptions,
|
||||
) error {
|
||||
var (
|
||||
devfilePath = odocontext.GetDevfilePath(ctx)
|
||||
path = filepath.Dir(devfilePath)
|
||||
klog.V(4).Infoln("Creating new adapter")
|
||||
|
||||
var (
|
||||
componentStatus = watch.ComponentStatus{
|
||||
ImageComponentsAutoApplied: make(map[string]devfilev1.ImageComponent),
|
||||
}
|
||||
)
|
||||
|
||||
err := o.reconcile(ctx, options, &componentStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
watch.PrintInfoMessage(options.Out, path, options.WatchFiles, promptMessage)
|
||||
klog.V(4).Infoln("Creating inner-loop resources for the component")
|
||||
|
||||
watchParameters := watch.WatchParameters{
|
||||
StartOptions: options,
|
||||
@@ -171,8 +164,9 @@ func (o *DevClient) checkVolumesFree(pod *corev1.Pod) error {
|
||||
}
|
||||
|
||||
func (o *DevClient) watchHandler(ctx context.Context, pushParams common.PushParameters, componentStatus *watch.ComponentStatus) error {
|
||||
pushParams.Devfile = *odocontext.GetDevfileObj(ctx) // TOO reload devfile from disk
|
||||
printWarningsOnDevfileChanges(ctx, pushParams.StartOptions)
|
||||
return o.reconcile(ctx, pushParams.StartOptions, componentStatus)
|
||||
return o.reconcile(ctx, pushParams, componentStatus)
|
||||
}
|
||||
|
||||
func printWarningsOnDevfileChanges(ctx context.Context, options dev.StartOptions) {
|
||||
|
||||
@@ -31,20 +31,21 @@ import (
|
||||
|
||||
func (o *DevClient) reconcile(
|
||||
ctx context.Context,
|
||||
options dev.StartOptions,
|
||||
parameters common.PushParameters,
|
||||
componentStatus *watch.ComponentStatus,
|
||||
) error {
|
||||
var (
|
||||
appName = odocontext.GetApplication(ctx)
|
||||
componentName = odocontext.GetComponentName(ctx)
|
||||
devfileObj = odocontext.GetDevfileObj(ctx)
|
||||
devfilePath = odocontext.GetDevfilePath(ctx)
|
||||
path = filepath.Dir(devfilePath)
|
||||
options = parameters.StartOptions
|
||||
devfileObj = parameters.Devfile
|
||||
)
|
||||
|
||||
o.warnAboutK8sComponents(*devfileObj)
|
||||
o.warnAboutK8sComponents(devfileObj)
|
||||
|
||||
err := o.buildPushAutoImageComponents(ctx, *devfileObj)
|
||||
err := o.buildPushAutoImageComponents(ctx, devfileObj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -54,6 +55,7 @@ func (o *DevClient) reconcile(
|
||||
return err
|
||||
}
|
||||
o.deployedPod = pod
|
||||
componentStatus.SetState(watch.StateReady)
|
||||
|
||||
execRequired, err := o.syncFiles(ctx, options, pod, path)
|
||||
if err != nil {
|
||||
@@ -62,7 +64,7 @@ func (o *DevClient) reconcile(
|
||||
|
||||
// PostStart events from the devfile will only be executed when the component
|
||||
// didn't previously exist
|
||||
if !componentStatus.PostStartEventsDone && libdevfile.HasPostStartEvents(*devfileObj) {
|
||||
if !componentStatus.PostStartEventsDone && libdevfile.HasPostStartEvents(devfileObj) {
|
||||
execHandler := component.NewExecHandler(
|
||||
o.podmanClient,
|
||||
o.execClient,
|
||||
@@ -72,7 +74,7 @@ func (o *DevClient) reconcile(
|
||||
"Executing post-start command in container",
|
||||
false, /* TODO */
|
||||
)
|
||||
err = libdevfile.ExecPostStartEvents(ctx, *devfileObj, execHandler)
|
||||
err = libdevfile.ExecPostStartEvents(ctx, devfileObj, execHandler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -90,7 +92,7 @@ func (o *DevClient) reconcile(
|
||||
"Building your application in container",
|
||||
false, /* TODO */
|
||||
)
|
||||
return libdevfile.Build(ctx, *devfileObj, options.BuildCommand, execHandler)
|
||||
return libdevfile.Build(ctx, devfileObj, options.BuildCommand, execHandler)
|
||||
}
|
||||
err = doExecuteBuildCommand()
|
||||
if err != nil {
|
||||
@@ -113,7 +115,7 @@ func (o *DevClient) reconcile(
|
||||
appName: appName,
|
||||
componentName: componentName,
|
||||
}
|
||||
err = libdevfile.ExecuteCommandByNameAndKind(ctx, *devfileObj, cmdName, cmdKind, &cmdHandler, false)
|
||||
err = libdevfile.ExecuteCommandByNameAndKind(ctx, devfileObj, cmdName, cmdKind, &cmdHandler, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -140,7 +142,7 @@ func (o *DevClient) reconcile(
|
||||
|
||||
if options.ForwardLocalhost {
|
||||
// Port-forwarding is enabled by executing dedicated socat commands
|
||||
err = o.portForwardClient.StartPortForwarding(ctx, *devfileObj, componentName, options.Debug, options.RandomPorts, options.Out, options.ErrOut, fwPorts)
|
||||
err = o.portForwardClient.StartPortForwarding(ctx, devfileObj, componentName, options.Debug, options.RandomPorts, options.Out, options.ErrOut, fwPorts)
|
||||
if err != nil {
|
||||
return common.NewErrPortForward(err)
|
||||
}
|
||||
@@ -155,7 +157,7 @@ func (o *DevClient) reconcile(
|
||||
return err
|
||||
}
|
||||
|
||||
componentStatus.State = watch.StateReady
|
||||
componentStatus.SetState(watch.StateReady)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package watch
|
||||
|
||||
import "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
import (
|
||||
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
type State string
|
||||
|
||||
@@ -16,7 +19,7 @@ const (
|
||||
)
|
||||
|
||||
type ComponentStatus struct {
|
||||
State State
|
||||
state State
|
||||
PostStartEventsDone bool
|
||||
// RunExecuted is set to true when the run command has been executed
|
||||
// Used for HotReload capability
|
||||
@@ -27,6 +30,15 @@ type ComponentStatus struct {
|
||||
ImageComponentsAutoApplied map[string]v1alpha2.ImageComponent
|
||||
}
|
||||
|
||||
func (o *ComponentStatus) SetState(s State) {
|
||||
klog.V(4).Infof("setting inner loop State %q", s)
|
||||
o.state = s
|
||||
}
|
||||
|
||||
func (o *ComponentStatus) GetState() State {
|
||||
return o.state
|
||||
}
|
||||
|
||||
func componentCanSyncFile(state State) bool {
|
||||
return state == StateReady
|
||||
}
|
||||
|
||||
@@ -47,6 +47,10 @@ type WatchClient struct {
|
||||
|
||||
// true to force sync, used when manual sync
|
||||
forceSync bool
|
||||
|
||||
// deploymentGeneration indicates the generation of the latest observed Deployment
|
||||
deploymentGeneration int64
|
||||
readyReplicas int32
|
||||
}
|
||||
|
||||
var _ Client = (*WatchClient)(nil)
|
||||
@@ -83,7 +87,7 @@ type evaluateChangesFunc func(events []fsnotify.Event, path string, fileIgnores
|
||||
|
||||
// processEventsFunc processes the events received on the watcher. It uses the WatchParameters to trigger watch handler and writes to out
|
||||
// It returns a Duration after which to recall in case of error
|
||||
type processEventsFunc func(ctx context.Context, parameters WatchParameters, changedFiles, deletedPaths []string, componentStatus *ComponentStatus, backoff *ExpBackoff) (*time.Duration, error)
|
||||
type processEventsFunc func(ctx context.Context, parameters WatchParameters, changedFiles, deletedPaths []string, componentStatus *ComponentStatus) error
|
||||
|
||||
func (o *WatchClient) WatchAndPush(ctx context.Context, parameters WatchParameters, componentStatus ComponentStatus) error {
|
||||
var (
|
||||
@@ -159,6 +163,12 @@ func (o *WatchClient) WatchAndPush(ctx context.Context, parameters WatchParamete
|
||||
}
|
||||
|
||||
o.keyWatcher = getKeyWatcher(ctx, parameters.StartOptions.Out)
|
||||
|
||||
err = o.processEvents(ctx, parameters, nil, nil, &componentStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return o.eventWatcher(ctx, parameters, evaluateFileChanges, o.processEvents, componentStatus)
|
||||
}
|
||||
|
||||
@@ -181,8 +191,6 @@ func (o *WatchClient) eventWatcher(
|
||||
out = parameters.StartOptions.Out
|
||||
)
|
||||
|
||||
expBackoff := NewExpBackoff()
|
||||
|
||||
var events []fsnotify.Event
|
||||
|
||||
// sourcesTimer helps collect multiple events that happen in a quick succession. We start with 1ms as we don't care much
|
||||
@@ -202,10 +210,6 @@ func (o *WatchClient) eventWatcher(
|
||||
deployTimer := time.NewTimer(time.Millisecond)
|
||||
<-deployTimer.C
|
||||
|
||||
// retryTimer is a timer used to retry later a sync that has failed
|
||||
retryTimer := time.NewTimer(time.Millisecond)
|
||||
<-retryTimer.C
|
||||
|
||||
podsPhases := NewPodPhases()
|
||||
|
||||
for {
|
||||
@@ -217,8 +221,8 @@ func (o *WatchClient) eventWatcher(
|
||||
|
||||
case <-sourcesTimer.C:
|
||||
// timer has fired
|
||||
if !componentCanSyncFile(componentStatus.State) {
|
||||
klog.V(4).Infof("State of component is %q, don't sync sources", componentStatus.State)
|
||||
if !componentCanSyncFile(componentStatus.GetState()) {
|
||||
klog.V(4).Infof("State of component is %q, don't sync sources", componentStatus.GetState())
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -232,25 +236,18 @@ func (o *WatchClient) eventWatcher(
|
||||
}
|
||||
}
|
||||
|
||||
componentStatus.State = StateSyncOutdated
|
||||
componentStatus.SetState(StateSyncOutdated)
|
||||
fmt.Fprintf(out, "Pushing files...\n\n")
|
||||
retry, err := processEventsHandler(ctx, parameters, changedFiles, deletedPaths, &componentStatus, expBackoff)
|
||||
err := processEventsHandler(ctx, parameters, changedFiles, deletedPaths, &componentStatus)
|
||||
o.forceSync = false
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// empty the events to receive new events
|
||||
if componentStatus.State == StateReady {
|
||||
if componentStatus.GetState() == StateReady {
|
||||
events = []fsnotify.Event{} // empty the events slice to capture new events
|
||||
}
|
||||
|
||||
if retry != nil {
|
||||
retryTimer.Reset(*retry)
|
||||
} else {
|
||||
retryTimer.Reset(time.Millisecond)
|
||||
<-retryTimer.C
|
||||
}
|
||||
|
||||
case watchErr := <-o.sourcesWatcher.Errors:
|
||||
return watchErr
|
||||
|
||||
@@ -263,53 +260,33 @@ func (o *WatchClient) eventWatcher(
|
||||
case ev := <-o.deploymentWatcher.ResultChan():
|
||||
switch obj := ev.Object.(type) {
|
||||
case *appsv1.Deployment:
|
||||
klog.V(4).Infof("deployment watcher Event: Type: %s, name: %s, rv: %s, pods: %d\n",
|
||||
ev.Type, obj.GetName(), obj.GetResourceVersion(), obj.Status.ReadyReplicas)
|
||||
deployTimer.Reset(300 * time.Millisecond)
|
||||
klog.V(4).Infof("deployment watcher Event: Type: %s, name: %s, rv: %s, generation: %d, pods: %d\n",
|
||||
ev.Type, obj.GetName(), obj.GetResourceVersion(), obj.GetGeneration(), obj.Status.ReadyReplicas)
|
||||
if obj.GetGeneration() > o.deploymentGeneration || obj.Status.ReadyReplicas != o.readyReplicas {
|
||||
o.deploymentGeneration = obj.GetGeneration()
|
||||
o.readyReplicas = obj.Status.ReadyReplicas
|
||||
deployTimer.Reset(300 * time.Millisecond)
|
||||
}
|
||||
|
||||
case *metav1.Status:
|
||||
klog.V(4).Infof("Status: %+v\n", obj)
|
||||
}
|
||||
|
||||
case <-deployTimer.C:
|
||||
retry, err := processEventsHandler(ctx, parameters, nil, nil, &componentStatus, expBackoff)
|
||||
err := processEventsHandler(ctx, parameters, nil, nil, &componentStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if retry != nil {
|
||||
retryTimer.Reset(*retry)
|
||||
} else {
|
||||
retryTimer.Reset(time.Millisecond)
|
||||
<-retryTimer.C
|
||||
}
|
||||
|
||||
case <-o.devfileWatcher.Events:
|
||||
devfileTimer.Reset(100 * time.Millisecond)
|
||||
|
||||
case <-devfileTimer.C:
|
||||
fmt.Fprintf(out, "Updating Component...\n\n")
|
||||
retry, err := processEventsHandler(ctx, parameters, nil, nil, &componentStatus, expBackoff)
|
||||
err := processEventsHandler(ctx, parameters, nil, nil, &componentStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if retry != nil {
|
||||
retryTimer.Reset(*retry)
|
||||
} else {
|
||||
retryTimer.Reset(time.Millisecond)
|
||||
<-retryTimer.C
|
||||
}
|
||||
|
||||
case <-retryTimer.C:
|
||||
retry, err := processEventsHandler(ctx, parameters, nil, nil, &componentStatus, expBackoff)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if retry != nil {
|
||||
retryTimer.Reset(*retry)
|
||||
} else {
|
||||
retryTimer.Reset(time.Millisecond)
|
||||
<-retryTimer.C
|
||||
}
|
||||
|
||||
case ev := <-o.podWatcher.ResultChan():
|
||||
switch ev.Type {
|
||||
@@ -421,8 +398,7 @@ func (o *WatchClient) processEvents(
|
||||
parameters WatchParameters,
|
||||
changedFiles, deletedPaths []string,
|
||||
componentStatus *ComponentStatus,
|
||||
backoff *ExpBackoff,
|
||||
) (*time.Duration, error) {
|
||||
) error {
|
||||
var (
|
||||
devfilePath = odocontext.GetDevfilePath(ctx)
|
||||
path = filepath.Dir(devfilePath)
|
||||
@@ -447,7 +423,7 @@ func (o *WatchClient) processEvents(
|
||||
err := parameters.DevfileWatchHandler(ctx, pushParams, componentStatus)
|
||||
if err != nil {
|
||||
if isFatal(err) {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
klog.V(4).Infof("Error from Push: %v", err)
|
||||
// Log and output, but intentionally not exiting on error here.
|
||||
@@ -462,22 +438,17 @@ func (o *WatchClient) processEvents(
|
||||
fmt.Fprintf(out, "Updated Kubernetes config\n")
|
||||
}
|
||||
} else {
|
||||
if parameters.StartOptions.WatchFiles {
|
||||
fmt.Fprintf(out, "%s - %s\n\n", PushErrorString, err.Error())
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Fprintf(out, "%s - %s\n\n", PushErrorString, err.Error())
|
||||
PrintInfoMessage(out, path, parameters.StartOptions.WatchFiles, parameters.PromptMessage)
|
||||
}
|
||||
wait := backoff.Delay()
|
||||
return &wait, nil
|
||||
return nil
|
||||
}
|
||||
backoff.Reset()
|
||||
if oldStatus.State != StateReady && componentStatus.State == StateReady ||
|
||||
if oldStatus.GetState() != StateReady && componentStatus.GetState() == StateReady ||
|
||||
!reflect.DeepEqual(oldStatus.EndpointsForwarded, componentStatus.EndpointsForwarded) {
|
||||
|
||||
PrintInfoMessage(out, path, parameters.StartOptions.WatchFiles, parameters.PromptMessage)
|
||||
}
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func shouldIgnoreEvent(event fsnotify.Event) (ignoreEvent bool) {
|
||||
|
||||
@@ -42,9 +42,9 @@ func evaluateChangesHandler(events []fsnotify.Event, path string, fileIgnores []
|
||||
return changedFiles, deletedPaths
|
||||
}
|
||||
|
||||
func processEventsHandler(ctx context.Context, params WatchParameters, changedFiles, deletedPaths []string, componentStatus *ComponentStatus, backo *ExpBackoff) (*time.Duration, error) {
|
||||
func processEventsHandler(ctx context.Context, params WatchParameters, changedFiles, deletedPaths []string, componentStatus *ComponentStatus) error {
|
||||
fmt.Fprintf(params.StartOptions.Out, "changedFiles %s deletedPaths %s\n", changedFiles, deletedPaths)
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeWatcher struct{}
|
||||
@@ -136,9 +136,8 @@ func Test_eventWatcher(t *testing.T) {
|
||||
cancel()
|
||||
}()
|
||||
|
||||
componentStatus := ComponentStatus{
|
||||
State: StateReady,
|
||||
}
|
||||
componentStatus := ComponentStatus{}
|
||||
componentStatus.SetState(StateReady)
|
||||
|
||||
o := WatchClient{
|
||||
sourcesWatcher: watcher,
|
||||
|
||||
@@ -120,6 +120,7 @@ type DevSessionOpts struct {
|
||||
RunOnPodman bool
|
||||
TimeoutInSeconds int
|
||||
NoRandomPorts bool
|
||||
NoWatch bool
|
||||
}
|
||||
|
||||
// StartDevMode starts a dev session with `odo dev`
|
||||
@@ -139,6 +140,9 @@ func StartDevMode(options DevSessionOpts) (devSession DevSession, out []byte, er
|
||||
if !options.NoRandomPorts {
|
||||
args = append(args, "--random-ports")
|
||||
}
|
||||
if options.NoWatch {
|
||||
args = append(args, "--no-watch")
|
||||
}
|
||||
args = append(args, options.CmdlineArgs...)
|
||||
cmd := Cmd("odo", args...)
|
||||
cmd.Cmd.Stdin = c.Tty()
|
||||
|
||||
@@ -2447,31 +2447,48 @@ CMD ["npm", "start"]
|
||||
}
|
||||
|
||||
for _, podman := range []bool{false, true} {
|
||||
podman := podman
|
||||
When("running odo dev --no-watch and build command throws an error", helper.LabelPodmanIf(podman, func() {
|
||||
var stderr string
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(
|
||||
filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"),
|
||||
filepath.Join(commonVar.Context, "devfile.yaml"),
|
||||
helper.DevfileMetadataNameSetter(cmpName))
|
||||
helper.ReplaceString(filepath.Join(commonVar.Context, "devfile.yaml"), "npm install", "npm install-does-not-exist")
|
||||
args := []string{"dev", "--no-watch", "--random-ports"}
|
||||
if podman {
|
||||
args = append(args, "--platform", "podman")
|
||||
}
|
||||
cmd := helper.Cmd("odo", args...)
|
||||
stderr = cmd.ShouldFail().Err()
|
||||
})
|
||||
for _, noWatch := range []bool{false, true} {
|
||||
podman := podman
|
||||
noWatch := noWatch
|
||||
noWatchFlag := ""
|
||||
if noWatch {
|
||||
noWatchFlag = " --no-watch"
|
||||
}
|
||||
title := fmt.Sprintf("running odo dev%s and build command throws an error", noWatchFlag)
|
||||
When(title, helper.LabelPodmanIf(podman, func() {
|
||||
var session helper.DevSession
|
||||
var stdout, stderr []byte
|
||||
BeforeEach(func() {
|
||||
helper.CopyExampleDevFile(
|
||||
filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"),
|
||||
filepath.Join(commonVar.Context, "devfile.yaml"),
|
||||
helper.DevfileMetadataNameSetter(cmpName))
|
||||
helper.ReplaceString(filepath.Join(commonVar.Context, "devfile.yaml"), "npm install", "npm install-does-not-exist")
|
||||
|
||||
It("should error out with some log", func() {
|
||||
helper.MatchAllInOutput(stderr, []string{
|
||||
"unable to exec command",
|
||||
"Usage: npm <command>",
|
||||
"Did you mean one of these?",
|
||||
var err error
|
||||
session, stdout, stderr, _, err = helper.StartDevMode(helper.DevSessionOpts{
|
||||
RunOnPodman: podman,
|
||||
NoWatch: noWatch,
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
}))
|
||||
|
||||
AfterEach(func() {
|
||||
session.Stop()
|
||||
session.WaitEnd()
|
||||
})
|
||||
|
||||
It("should error out with some log", func() {
|
||||
helper.MatchAllInOutput(string(stdout), []string{
|
||||
"unable to exec command",
|
||||
})
|
||||
helper.MatchAllInOutput(string(stderr), []string{
|
||||
"Usage: npm <command>",
|
||||
"Did you mean one of these?",
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
for _, podman := range []bool{false, true} {
|
||||
@@ -2644,24 +2661,33 @@ CMD ["npm", "start"]
|
||||
|
||||
It("should error out on an invalid command", func() {
|
||||
By("calling with an invalid build command", func() {
|
||||
args := []string{"dev", "--random-ports", "--build-command", "build-command-does-not-exist"}
|
||||
if podman {
|
||||
args = append(args, "--platform", "podman")
|
||||
}
|
||||
cmd := helper.Cmd("odo", args...)
|
||||
output := cmd.ShouldFail().Err()
|
||||
Expect(output).To(ContainSubstring("no build command with name \"build-command-does-not-exist\" found in Devfile"))
|
||||
|
||||
session, stdout, _, _, err := helper.StartDevMode(helper.DevSessionOpts{
|
||||
RunOnPodman: podman,
|
||||
CmdlineArgs: []string{"--build-command", "build-command-does-not-exist"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer func() {
|
||||
session.Stop()
|
||||
session.WaitEnd()
|
||||
}()
|
||||
|
||||
Expect(string(stdout)).To(ContainSubstring("no build command with name \"build-command-does-not-exist\" found in Devfile"))
|
||||
})
|
||||
|
||||
By("calling with a command of another kind (not build)", func() {
|
||||
// devrun is a valid run command, not a build command
|
||||
args := []string{"dev", "--random-ports", "--build-command", "devrun"}
|
||||
if podman {
|
||||
args = append(args, "--platform", "podman")
|
||||
}
|
||||
cmd := helper.Cmd("odo", args...)
|
||||
output := cmd.ShouldFail().Err()
|
||||
Expect(output).To(ContainSubstring("no build command with name \"devrun\" found in Devfile"))
|
||||
session, stdout, _, _, err := helper.StartDevMode(helper.DevSessionOpts{
|
||||
RunOnPodman: podman,
|
||||
CmdlineArgs: []string{"--build-command", "devrun"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer func() {
|
||||
session.Stop()
|
||||
session.WaitEnd()
|
||||
}()
|
||||
|
||||
Expect(string(stdout)).To(ContainSubstring("no build command with name \"devrun\" found in Devfile"))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2705,24 +2731,32 @@ CMD ["npm", "start"]
|
||||
|
||||
It("should error out on an invalid command", func() {
|
||||
By("calling with an invalid run command", func() {
|
||||
args := []string{"dev", "--random-ports", "--run-command", "run-command-does-not-exist"}
|
||||
if podman {
|
||||
args = append(args, "--platform", "podman")
|
||||
}
|
||||
cmd := helper.Cmd("odo", args...)
|
||||
output := cmd.ShouldFail().Err()
|
||||
Expect(output).To(ContainSubstring("no run command with name \"run-command-does-not-exist\" found in Devfile"))
|
||||
session, stdout, _, _, err := helper.StartDevMode(helper.DevSessionOpts{
|
||||
RunOnPodman: podman,
|
||||
CmdlineArgs: []string{"--run-command", "run-command-does-not-exist"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer func() {
|
||||
session.Stop()
|
||||
session.WaitEnd()
|
||||
}()
|
||||
|
||||
Expect(string(stdout)).To(ContainSubstring("no run command with name \"run-command-does-not-exist\" found in Devfile"))
|
||||
})
|
||||
|
||||
By("calling with a command of another kind (not run)", func() {
|
||||
// devbuild is a valid build command, not a run command
|
||||
args := []string{"dev", "--random-ports", "--run-command", "devbuild"}
|
||||
if podman {
|
||||
args = append(args, "--platform", "podman")
|
||||
}
|
||||
cmd := helper.Cmd("odo", args...)
|
||||
output := cmd.ShouldFail().Err()
|
||||
Expect(output).To(ContainSubstring("no run command with name \"devbuild\" found in Devfile"))
|
||||
session, stdout, _, _, err := helper.StartDevMode(helper.DevSessionOpts{
|
||||
RunOnPodman: podman,
|
||||
CmdlineArgs: []string{"--run-command", "devbuild"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer func() {
|
||||
session.Stop()
|
||||
session.WaitEnd()
|
||||
}()
|
||||
|
||||
Expect(string(stdout)).To(ContainSubstring("no run command with name \"devbuild\" found in Devfile"))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3665,11 +3699,17 @@ CMD ["npm", "start"]
|
||||
helper.DevfileMetadataNameSetter(cmpName))
|
||||
helper.ReplaceString(filepath.Join(commonVar.Context, "devfile.yaml"), "registry.access.redhat.com/ubi8/nodejs", "registry.access.redhat.com/ubi8/nose")
|
||||
})
|
||||
It("should fail with an error and cleanup resources", func() {
|
||||
errContents := helper.Cmd("odo", "dev", "--platform=podman").ShouldFail().Err()
|
||||
helper.MatchAllInOutput(errContents, []string{"Complete Podman output", "registry.access.redhat.com/ubi8/nose", "Repo not found"})
|
||||
component := helper.NewComponent(cmpName, "app", labels.ComponentDevMode, commonVar.Project, commonVar.CliRunner)
|
||||
component.ExpectIsNotDeployed()
|
||||
It("should fail with an error", func() {
|
||||
session, stdout, _, _, err := helper.StartDevMode(helper.DevSessionOpts{
|
||||
RunOnPodman: true,
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer func() {
|
||||
session.Stop()
|
||||
session.WaitEnd()
|
||||
}()
|
||||
|
||||
helper.MatchAllInOutput(string(stdout), []string{"Complete Podman output", "registry.access.redhat.com/ubi8/nose", "Repo not found"})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3765,7 +3805,14 @@ CMD ["npm", "start"]
|
||||
})
|
||||
|
||||
It("should error out if not ignoring localhost", func() {
|
||||
stderr := helper.Cmd("odo", "dev", "--random-ports", "--platform", "podman").ShouldFail().Err()
|
||||
session, _, stderr, _, err := helper.StartDevMode(helper.DevSessionOpts{
|
||||
RunOnPodman: true,
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer func() {
|
||||
session.Stop()
|
||||
session.WaitEnd()
|
||||
}()
|
||||
Expect(stderr).Should(ContainSubstring("Detected that the following port(s) can be reached only via the container loopback interface: admin (3001)"))
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user