Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use devstats.PID.json as devstate #6713

2 changes: 2 additions & 0 deletions cmd/odo/odo.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/redhat-developer/odo/pkg/log"
"github.com/redhat-developer/odo/pkg/odo/cli"
"github.com/redhat-developer/odo/pkg/odo/cli/version"
odocontext "github.com/redhat-developer/odo/pkg/odo/context"
"github.com/redhat-developer/odo/pkg/odo/util"
"github.com/redhat-developer/odo/pkg/odo/util/completion"
"github.com/redhat-developer/odo/pkg/preference"
Expand All @@ -31,6 +32,7 @@ func main() {
util.LogErrorAndExit(err, "")
}
ctx = envcontext.WithEnvConfig(ctx, *envConfig)
ctx = odocontext.WithPID(ctx, os.Getpid())

// create the complete command
klog.InitFlags(nil)
Expand Down
4 changes: 2 additions & 2 deletions pkg/dev/podmandev/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func (o *DevClient) reconcile(

if options.ForwardLocalhost {
// Port-forwarding is enabled by executing dedicated socat commands
err = o.portForwardClient.StartPortForwarding(*devfileObj, componentName, options.Debug, options.RandomPorts, out, errOut, fwPorts)
err = o.portForwardClient.StartPortForwarding(ctx, *devfileObj, componentName, options.Debug, options.RandomPorts, out, errOut, fwPorts)
if err != nil {
return adapters.NewErrPortForward(err)
}
Expand All @@ -153,7 +153,7 @@ func (o *DevClient) reconcile(
s := fmt.Sprintf("Forwarding from %s:%d -> %d", fwPort.LocalAddress, fwPort.LocalPort, fwPort.ContainerPort)
fmt.Fprintf(out, " - %s", log.SboldColor(color.FgGreen, s))
}
err = o.stateClient.SetForwardedPorts(fwPorts)
err = o.stateClient.SetForwardedPorts(ctx, fwPorts)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/devfile/adapters/kubernetes/component/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ func (a Adapter) Push(ctx context.Context, parameters adapters.PushParameters, c
fmt.Fprintln(log.GetStdout())
}

err = a.portForwardClient.StartPortForwarding(a.Devfile, a.ComponentName, parameters.Debug, parameters.RandomPorts, log.GetStdout(), parameters.ErrOut, parameters.CustomForwardedPorts)
err = a.portForwardClient.StartPortForwarding(ctx, a.Devfile, a.ComponentName, parameters.Debug, parameters.RandomPorts, log.GetStdout(), parameters.ErrOut, parameters.CustomForwardedPorts)
if err != nil {
return adapters.NewErrPortForward(err)
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/odo/cli/describe/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ func (o *ComponentOptions) describeDevfileComponent(ctx context.Context) (result
kubeClient = nil
}

allFwdPorts, err := o.clientset.StateClient.GetForwardedPorts()
// TODO(feloy) Pass PID with `--pid` flag
allFwdPorts, err := o.clientset.StateClient.GetForwardedPorts(ctx)
if err != nil {
return api.Component{}, nil, err
}
Expand Down
19 changes: 14 additions & 5 deletions pkg/odo/cli/dev/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@ import (
"strings"

"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"k8s.io/klog"

"github.com/redhat-developer/odo/pkg/api"

"github.com/spf13/cobra"
"k8s.io/klog/v2"
ktemplates "k8s.io/kubectl/pkg/util/templates"

"github.com/redhat-developer/odo/pkg/api"
"github.com/redhat-developer/odo/pkg/component"
"github.com/redhat-developer/odo/pkg/dev"
"github.com/redhat-developer/odo/pkg/kclient"
Expand All @@ -35,6 +33,7 @@ import (
odoutil "github.com/redhat-developer/odo/pkg/odo/util"
"github.com/redhat-developer/odo/pkg/podman"
scontext "github.com/redhat-developer/odo/pkg/segment/context"
"github.com/redhat-developer/odo/pkg/state"
"github.com/redhat-developer/odo/pkg/util"
"github.com/redhat-developer/odo/pkg/version"
)
Expand Down Expand Up @@ -231,6 +230,12 @@ func (o *DevOptions) Run(ctx context.Context) (err error) {

log.Sectionf("Running on %s in Dev mode", deployingTo)

err = o.clientset.StateClient.Init(ctx)
if err != nil {
err = fmt.Errorf("unable to save state file: %w", err)
return err
}

return o.clientset.DevClient.Start(
o.ctx,
o.out,
Expand Down Expand Up @@ -258,10 +263,14 @@ func (o *DevOptions) HandleSignal() error {
}

func (o *DevOptions) Cleanup(ctx context.Context, commandError error) {
if errors.As(commandError, &state.ErrAlreadyRunningOnPlatform{}) {
klog.V(4).Info("session already running, no need to cleanup")
return
}
if commandError != nil {
_ = o.clientset.DevClient.CleanupResources(ctx, log.GetStdout())
}
_ = o.clientset.StateClient.SaveExit()
_ = o.clientset.StateClient.SaveExit(ctx)
}

// NewCmdDev implements the odo dev command
Expand Down
19 changes: 19 additions & 0 deletions pkg/odo/context/odo.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
type (
applicationKeyType struct{}
cwdKeyType struct{}
pidKeyType struct{}
devfilePathKeyType struct{}
devfileObjKeyType struct{}
componentNameKeyType struct{}
Expand All @@ -17,6 +18,7 @@ type (
var (
applicationKey applicationKeyType
cwdKey cwdKeyType
pidKey pidKeyType
devfilePathKey devfilePathKeyType
devfileObjKey devfileObjKeyType
componentNameKey componentNameKeyType
Expand Down Expand Up @@ -57,6 +59,23 @@ func GetWorkingDirectory(ctx context.Context) string {
panic("this should not happen, either the original context is not passed or WithWorkingDirectory is not called as it should. Check that FILESYSTEM dependency is added to the command")
}

// WithPID sets the value of the PID in ctx
// This function must be used before calling GetPID
// Use this function only with a context obtained from Complete/Validate/Run/... methods of Runnable interface
func WithPID(ctx context.Context, val int) context.Context {
return context.WithValue(ctx, pidKey, val)
}

// GetPID gets the PID value in ctx
// This function will panic if the context does not contain the value
func GetPID(ctx context.Context) int {
value := ctx.Value(pidKey)
if cast, ok := value.(int); ok {
return cast
}
panic("this should not happen, either the original context is not passed or WithPID is not called as it should")
}

// WithDevfilePath sets the value of the devfile path in ctx
// This function must be called before using GetDevfilePath
func WithDevfilePath(ctx context.Context, val string) context.Context {
Expand Down
2 changes: 2 additions & 0 deletions pkg/portForward/interface.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package portForward

import (
"context"
"io"

"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
Expand All @@ -16,6 +17,7 @@ type Client interface {
// output will be written to errOut writer
// definedPorts allows callers to explicitly define the mapping they want to set.
StartPortForwarding(
ctx context.Context,
devFileObj parser.DevfileObj,
componentName string,
debug bool,
Expand Down
5 changes: 3 additions & 2 deletions pkg/portForward/kubeportforward/portForward.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kubeportforward

import (
"context"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -49,7 +50,7 @@ func NewPFClient(kubernetesClient kclient.ClientInterface, stateClient state.Cli
}
}

func (o *PFClient) StartPortForwarding(devFileObj parser.DevfileObj, componentName string, debug bool, randomPorts bool, out io.Writer, errOut io.Writer, definedPorts []api.ForwardedPort) error {
func (o *PFClient) StartPortForwarding(ctx context.Context, devFileObj parser.DevfileObj, componentName string, debug bool, randomPorts bool, out io.Writer, errOut io.Writer, definedPorts []api.ForwardedPort) error {
if randomPorts && len(definedPorts) != 0 {
return errors.New("cannot use randomPorts and custom definePorts together")
}
Expand Down Expand Up @@ -114,7 +115,7 @@ func (o *PFClient) StartPortForwarding(devFileObj parser.DevfileObj, componentNa

go func() {
portsBuf.Wait()
err = o.stateClient.SetForwardedPorts(portsBuf.GetForwardedPorts())
err = o.stateClient.SetForwardedPorts(ctx, portsBuf.GetForwardedPorts())
if err != nil {
err = fmt.Errorf("unable to save forwarded ports to state file: %v", err)
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/portForward/podmanportforward/portForward.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package podmanportforward

import (
"context"
"fmt"
"io"
"reflect"
Expand Down Expand Up @@ -36,6 +37,7 @@ func NewPFClient(execClient exec.Client) *PFClient {
}

func (o *PFClient) StartPortForwarding(
ctx context.Context,
devFileObj parser.DevfileObj,
componentName string,
debug bool,
Expand Down
8 changes: 4 additions & 4 deletions pkg/registry/mock.go

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

2 changes: 2 additions & 0 deletions pkg/state/const.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package state

const _dirpath = "./.odo"
const _filepath = "./.odo/devstate.json"
const _filepathPid = "./.odo/devstate.%d.json"
3 changes: 3 additions & 0 deletions pkg/state/doc.go
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
// Package state gives access to the state of the odo process stored in a local file
// The state of an instance is stored in a file .odo/devstate.${PID}.json.
// For compatibility with previous versions of odo, the `devstate.json` file contains
// the state of the first instance of odo.
package state
19 changes: 19 additions & 0 deletions pkg/state/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package state

import "fmt"

type ErrAlreadyRunningOnPlatform struct {
platform string
rm3l marked this conversation as resolved.
Show resolved Hide resolved
pid int
}

func NewErrAlreadyRunningOnPlatform(platform string, pid int) ErrAlreadyRunningOnPlatform {
return ErrAlreadyRunningOnPlatform{
platform: platform,
pid: pid,
}
}

func (e ErrAlreadyRunningOnPlatform) Error() string {
return fmt.Sprintf("a session with PID %d is already running on platform %q", e.pid, e.platform)
}
15 changes: 11 additions & 4 deletions pkg/state/interface.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package state

import "github.com/redhat-developer/odo/pkg/api"
import (
"context"

"github.com/redhat-developer/odo/pkg/api"
)

type Client interface {
// Init creates a devstate file for the process
Init(ctx context.Context) error

// SetForwardedPorts sets the forwarded ports in the state file and saves it to the file, updating the metadata
SetForwardedPorts(fwPorts []api.ForwardedPort) error
SetForwardedPorts(ctx context.Context, fwPorts []api.ForwardedPort) error

// GetForwardedPorts returns the ports forwarded by the current odo dev session
GetForwardedPorts() ([]api.ForwardedPort, error)
GetForwardedPorts(ctx context.Context) ([]api.ForwardedPort, error)

// SaveExit resets the state file to indicate odo is not running
SaveExit() error
SaveExit(ctx context.Context) error
}
38 changes: 38 additions & 0 deletions pkg/state/process_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos

package state

import (
"fmt"
"os"
"syscall"
)

func pidExists(pid int) (bool, error) {
if pid <= 0 {
return false, fmt.Errorf("invalid pid %v", pid)
}
proc, err := os.FindProcess(pid)
rm3l marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return false, nil
}
err = proc.Signal(syscall.Signal(0))
if err == nil {
return true, nil
}
if err.Error() == "os: process already finished" {
return false, nil
}
errno, ok := err.(syscall.Errno)
if !ok {
return false, err
}
switch errno {
case syscall.ESRCH:
return false, nil
case syscall.EPERM:
return true, nil
}
return false, err
}
17 changes: 17 additions & 0 deletions pkg/state/process_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package state

import (
"fmt"
"os"
)

func pidExists(pid int) (bool, error) {
if pid <= 0 {
return false, fmt.Errorf("invalid pid %v", pid)
}
_, err := os.FindProcess(pid)
if err != nil {
return false, nil
}
return true, nil
}
Loading