mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
* Add integration tests highlighting our expectations * Bump Devfile library to latest commitf041d79870* Expose preference that allows users to globally configure an image registry * Return the effective Devfile view by default from the initial context This is supposed to be read-only, so that tools can rely on it and to the operations they need to perform right away. Raw Devfile objects can still be obtained upon request if there is need to update them (for example via 'odo add/remove binding' commands. * Pass the image registry preference to the Devfile parser to build the effective view * Fix 'odo init' integration tests - The test spec was actually not doing what it was supposed to do - Now 'odo init' returns a complete Devfile, where the parent is flattened, because the goal of 'odo init' is to bootstrap a Devfile. Previously, 'odo init' would not download the parent referenced, making it hard to understand the resulting Devfile. * Document how odo now handles relative image names as selectors * fixup! Document how odo now handles relative image names as selectors Co-authored-by: Philippe Martin <phmartin@redhat.com> * Revert "Fix 'odo init' integration tests" This reverts commit78868b03fd. Co-authored-by: Philippe Martin <phmartin@redhat.com> * Do not make `odo init` return an effective Devfile as a result This would change the behavior of `odo init`. Furthermore, due to an issue [1] in the Devfile library, it is not possible to parse some Devfiles with parents linked as GitHub URLs (like GitHub release artifacts). [1] https://github.com/devfile/api/issues/1119 Co-authored-by: Philippe Martin <phmartin@redhat.com> * fixup! Document how odo now handles relative image names as selectors --------- Co-authored-by: Philippe Martin <phmartin@redhat.com>
176 lines
5.1 KiB
Go
176 lines
5.1 KiB
Go
package podmandev
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
|
"k8s.io/klog"
|
|
|
|
"github.com/redhat-developer/odo/pkg/dev"
|
|
"github.com/redhat-developer/odo/pkg/dev/common"
|
|
"github.com/redhat-developer/odo/pkg/devfile"
|
|
"github.com/redhat-developer/odo/pkg/devfile/location"
|
|
"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/podman"
|
|
"github.com/redhat-developer/odo/pkg/portForward"
|
|
"github.com/redhat-developer/odo/pkg/preference"
|
|
"github.com/redhat-developer/odo/pkg/state"
|
|
"github.com/redhat-developer/odo/pkg/sync"
|
|
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
|
|
"github.com/redhat-developer/odo/pkg/watch"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
)
|
|
|
|
const (
|
|
promptMessage = `
|
|
[Ctrl+c] - Exit and delete resources from podman
|
|
[p] - Manually apply local changes to the application on podman
|
|
`
|
|
)
|
|
|
|
type DevClient struct {
|
|
fs filesystem.Filesystem
|
|
|
|
podmanClient podman.Client
|
|
prefClient preference.Client
|
|
portForwardClient portForward.Client
|
|
syncClient sync.Client
|
|
execClient exec.Client
|
|
stateClient state.Client
|
|
watchClient watch.Client
|
|
|
|
deployedPod *corev1.Pod
|
|
usedPorts []int
|
|
}
|
|
|
|
var _ dev.Client = (*DevClient)(nil)
|
|
|
|
func NewDevClient(
|
|
fs filesystem.Filesystem,
|
|
podmanClient podman.Client,
|
|
prefClient preference.Client,
|
|
portForwardClient portForward.Client,
|
|
syncClient sync.Client,
|
|
execClient exec.Client,
|
|
stateClient state.Client,
|
|
watchClient watch.Client,
|
|
) *DevClient {
|
|
return &DevClient{
|
|
fs: fs,
|
|
podmanClient: podmanClient,
|
|
prefClient: prefClient,
|
|
portForwardClient: portForwardClient,
|
|
syncClient: syncClient,
|
|
execClient: execClient,
|
|
stateClient: stateClient,
|
|
watchClient: watchClient,
|
|
}
|
|
}
|
|
|
|
func (o *DevClient) Start(
|
|
ctx context.Context,
|
|
options dev.StartOptions,
|
|
) error {
|
|
klog.V(4).Infoln("Creating new adapter")
|
|
|
|
var (
|
|
componentStatus = watch.ComponentStatus{
|
|
ImageComponentsAutoApplied: make(map[string]devfilev1.ImageComponent),
|
|
}
|
|
)
|
|
|
|
klog.V(4).Infoln("Creating inner-loop resources for the component")
|
|
|
|
watchParameters := watch.WatchParameters{
|
|
StartOptions: options,
|
|
DevfileWatchHandler: o.watchHandler,
|
|
WatchCluster: false,
|
|
PromptMessage: promptMessage,
|
|
}
|
|
|
|
return o.watchClient.WatchAndPush(ctx, watchParameters, componentStatus)
|
|
}
|
|
|
|
// syncFiles syncs the local source files in path into the pod's source volume
|
|
func (o *DevClient) syncFiles(ctx context.Context, options dev.StartOptions, pod *corev1.Pod, path string) (bool, error) {
|
|
var (
|
|
devfileObj = odocontext.GetEffectiveDevfileObj(ctx)
|
|
componentName = odocontext.GetComponentName(ctx)
|
|
)
|
|
|
|
containerName, syncFolder, err := common.GetFirstContainerWithSourceVolume(pod.Spec.Containers)
|
|
if err != nil {
|
|
return false, fmt.Errorf("error while retrieving container from pod %s with a mounted project volume: %w", pod.GetName(), err)
|
|
}
|
|
|
|
compInfo := sync.ComponentInfo{
|
|
ComponentName: componentName,
|
|
ContainerName: containerName,
|
|
PodName: pod.GetName(),
|
|
SyncFolder: syncFolder,
|
|
}
|
|
|
|
cmdKind := devfilev1.RunCommandGroupKind
|
|
cmdName := options.RunCommand
|
|
if options.Debug {
|
|
cmdKind = devfilev1.DebugCommandGroupKind
|
|
cmdName = options.DebugCommand
|
|
}
|
|
devfileCmd, err := libdevfile.ValidateAndGetCommand(*devfileObj, cmdName, cmdKind)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
syncParams := sync.SyncParameters{
|
|
Path: path,
|
|
WatchFiles: nil,
|
|
WatchDeletedFiles: nil,
|
|
IgnoredFiles: options.IgnorePaths,
|
|
DevfileScanIndexForWatch: true,
|
|
|
|
CompInfo: compInfo,
|
|
ForcePush: true,
|
|
Files: common.GetSyncFilesFromAttributes(devfileCmd),
|
|
}
|
|
execRequired, err := o.syncClient.SyncFiles(ctx, syncParams)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return execRequired, nil
|
|
}
|
|
|
|
// checkVolumesFree checks that all persistent volumes declared in pod
|
|
// are not using an existing volume
|
|
func (o *DevClient) checkVolumesFree(pod *corev1.Pod) error {
|
|
existingVolumesSet, err := o.podmanClient.VolumeLs()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var problematicVolumes []string
|
|
for _, volume := range pod.Spec.Volumes {
|
|
if volume.PersistentVolumeClaim != nil && existingVolumesSet[volume.PersistentVolumeClaim.ClaimName] {
|
|
problematicVolumes = append(problematicVolumes, volume.PersistentVolumeClaim.ClaimName)
|
|
}
|
|
}
|
|
if len(problematicVolumes) > 0 {
|
|
return fmt.Errorf("volumes already exist, please remove them before to run odo dev: %s", strings.Join(problematicVolumes, ", "))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (o *DevClient) watchHandler(ctx context.Context, pushParams common.PushParameters, componentStatus *watch.ComponentStatus) error {
|
|
|
|
devObj, err := devfile.ParseAndValidateFromFileWithVariables(location.DevfileLocation(""), pushParams.StartOptions.Variables, o.prefClient.GetImageRegistry(), true)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to read devfile: %w", err)
|
|
}
|
|
pushParams.Devfile = devObj
|
|
|
|
return o.reconcile(ctx, pushParams, componentStatus)
|
|
}
|