-
Notifications
You must be signed in to change notification settings - Fork 244
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
407 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package debug | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"github.com/golang/glog" | ||
"github.com/openshift/odo/pkg/occlient" | ||
"github.com/openshift/odo/pkg/testingutil/filesystem" | ||
"io/ioutil" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"net" | ||
"os" | ||
"path/filepath" | ||
"strconv" | ||
"strings" | ||
"syscall" | ||
) | ||
|
||
type OdoDebugFile struct { | ||
metav1.TypeMeta | ||
DebugProcessId int | ||
ProjectName string | ||
AppName string | ||
ComponentName string | ||
RemotePort int | ||
LocalPort int | ||
} | ||
|
||
// GetDebugInfoFilePath gets the file path of the debug info file | ||
func GetDebugInfoFilePath(client *occlient.Client, componentName, appName string) string { | ||
tempDir := os.TempDir() | ||
debugFilePrefix := "odo-debug.json" | ||
s := []string{client.Namespace, appName, componentName, debugFilePrefix} | ||
debugFileName := strings.Join(s, "-") | ||
return filepath.Join(tempDir, debugFileName) | ||
} | ||
|
||
func CreateDebugInfoFile(f *DefaultPortForwarder, portPair string) error { | ||
return createDebugInfoFile(f, portPair, filesystem.DefaultFs{}) | ||
} | ||
|
||
// createDebugInfoFile creates a file in the temp directory with information regarding the debugging session of a component | ||
func createDebugInfoFile(f *DefaultPortForwarder, portPair string, fs filesystem.Filesystem) error { | ||
portPairs := strings.Split(portPair, ":") | ||
if len(portPairs) > 2 || len(portPairs) < 2 { | ||
return errors.New("port pair should be of the format localPort:RemotePair") | ||
} | ||
|
||
localPort, err := strconv.Atoi(portPairs[0]) | ||
if err != nil { | ||
return errors.New("local port should be a int") | ||
} | ||
remotePort, err := strconv.Atoi(portPairs[1]) | ||
if err != nil { | ||
return errors.New("remote port should be a int") | ||
} | ||
|
||
odoDebugFile := OdoDebugFile{ | ||
TypeMeta: metav1.TypeMeta{}, | ||
DebugProcessId: os.Getpid(), | ||
ProjectName: f.client.Namespace, | ||
AppName: f.appName, | ||
ComponentName: f.componentName, | ||
RemotePort: remotePort, | ||
LocalPort: localPort, | ||
} | ||
odoDebugPathData, err := json.Marshal(odoDebugFile) | ||
if err != nil { | ||
return errors.New("error marshalling json data") | ||
} | ||
|
||
// writes the data to the debug info file | ||
file, err := fs.OpenFile(GetDebugInfoFilePath(f.client, f.componentName, f.appName), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) | ||
if err != nil { | ||
return err | ||
} | ||
_, err = file.Write(odoDebugPathData) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// GetDebugInfo gets information regarding the debugging session of the component | ||
func GetDebugInfo(f *DefaultPortForwarder) (int, bool) { | ||
// gets the debug info file path and reads/unmarshals it | ||
debugInfoFilePath := GetDebugInfoFilePath(f.client, f.componentName, f.appName) | ||
odoDebugFileRead, err := ioutil.ReadFile(debugInfoFilePath) | ||
if err != nil { | ||
glog.V(4).Infof("the debug %v is not present", debugInfoFilePath) | ||
return -1, false | ||
} | ||
|
||
var odoDebugFileData OdoDebugFile | ||
err = json.Unmarshal(odoDebugFileRead, &odoDebugFileData) | ||
if err != nil { | ||
glog.V(4).Infof("couldn't unmarshal the debug file %v", debugInfoFilePath) | ||
return -1, false | ||
} | ||
|
||
// get the debug process id and send a signal 0 to check if it's alive or not | ||
processInfo, err := os.FindProcess(odoDebugFileData.DebugProcessId) | ||
if err != nil { | ||
glog.V(4).Infof("error getting the process info for pid %v", odoDebugFileData.DebugProcessId) | ||
return -1, false | ||
} | ||
|
||
err = processInfo.Signal(syscall.Signal(0)) | ||
if err != nil { | ||
glog.V(4).Infof("error sending signal 0 to pid %v, cause: %v", odoDebugFileData.DebugProcessId, err) | ||
return -1, false | ||
} | ||
|
||
// gets the debug local port and dials it to check if the port is listening or not | ||
addressLook := "localhost:" + strconv.Itoa(odoDebugFileData.LocalPort) | ||
_, err = net.Dial("tcp", addressLook) | ||
if err != nil { | ||
glog.V(4).Infof("error dialing address %v, cause: %v", odoDebugFileData.DebugProcessId, err) | ||
return -1, false | ||
} | ||
|
||
// returns the local port for further processing | ||
return odoDebugFileData.LocalPort, true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package debug | ||
|
||
import ( | ||
"encoding/json" | ||
"github.com/openshift/odo/pkg/occlient" | ||
"github.com/openshift/odo/pkg/testingutil/filesystem" | ||
"os" | ||
"testing" | ||
) | ||
|
||
func Test_createDebugInfoFile(t *testing.T) { | ||
|
||
// create a fake fs in memory | ||
fs := filesystem.NewFakeFs() | ||
|
||
type args struct { | ||
defaultPortForwarder *DefaultPortForwarder | ||
portPair string | ||
fs filesystem.Filesystem | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
wantLocalPort int | ||
wantRemotePort int | ||
alreadyExistFile bool | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "case 1: normal json write to the debug file", | ||
args: args{ | ||
defaultPortForwarder: &DefaultPortForwarder{ | ||
componentName: "nodejs-ex", | ||
appName: "app", | ||
}, | ||
portPair: "5858:9001", | ||
fs: fs, | ||
}, | ||
wantLocalPort: 5858, | ||
wantRemotePort: 9001, | ||
alreadyExistFile: false, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "case 2: overwrite the debug file", | ||
args: args{ | ||
defaultPortForwarder: &DefaultPortForwarder{ | ||
componentName: "nodejs-ex", | ||
appName: "app", | ||
}, | ||
portPair: "5758:9004", | ||
fs: fs, | ||
}, | ||
wantLocalPort: 5758, | ||
wantRemotePort: 9004, | ||
alreadyExistFile: true, | ||
wantErr: false, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
|
||
// Fake the client with the appropriate arguments | ||
client, _ := occlient.FakeNew() | ||
client.Namespace = "testing-1" | ||
tt.args.defaultPortForwarder.client = client | ||
|
||
debugFilePath := GetDebugInfoFilePath(client, tt.args.defaultPortForwarder.componentName, tt.args.defaultPortForwarder.appName) | ||
if tt.alreadyExistFile { | ||
file, err := fs.Create(debugFilePath) | ||
if err != nil { | ||
t.Errorf("error happened while writing, cause: %v", err) | ||
} | ||
_, err = file.WriteString("blah") | ||
if err != nil { | ||
t.Errorf("error happened while writing, cause: %v", err) | ||
} | ||
} | ||
|
||
if err := createDebugInfoFile(tt.args.defaultPortForwarder, tt.args.portPair, tt.args.fs); (err != nil) != tt.wantErr { | ||
t.Errorf("createDebugInfoFile() error = %v, wantErr %v", err, tt.wantErr) | ||
} | ||
|
||
readBytes, err := fs.ReadFile(debugFilePath) | ||
if err != nil { | ||
t.Errorf("error while reading file, cause: %v", err) | ||
} | ||
var odoDebugFileData OdoDebugFile | ||
err = json.Unmarshal(readBytes, &odoDebugFileData) | ||
if err != nil { | ||
t.Errorf("error occured while unmarshalling json, cause: %v", err) | ||
} | ||
|
||
if odoDebugFileData.LocalPort != tt.wantLocalPort { | ||
t.Errorf("the local port on the file doesn't match, got %v, want %v", odoDebugFileData.LocalPort, tt.wantLocalPort) | ||
} | ||
if odoDebugFileData.RemotePort != tt.wantRemotePort { | ||
t.Errorf("the remote port on the file doesn't match, got %v, want %v", odoDebugFileData.RemotePort, tt.wantRemotePort) | ||
} | ||
if odoDebugFileData.DebugProcessId != os.Getpid() { | ||
t.Errorf("the debug process id on the file doesn't match, got %v, want %v", odoDebugFileData.DebugProcessId, os.Getpid()) | ||
} | ||
if odoDebugFileData.ComponentName != tt.args.defaultPortForwarder.componentName { | ||
t.Errorf("the component name on the file doesn't match, got %v, want %v", odoDebugFileData.ComponentName, tt.args.defaultPortForwarder.componentName) | ||
} | ||
if odoDebugFileData.AppName != tt.args.defaultPortForwarder.appName { | ||
t.Errorf("the app name on the file doesn't match, got %v, want %v", odoDebugFileData.AppName, tt.args.defaultPortForwarder.appName) | ||
} | ||
if odoDebugFileData.AppName != tt.args.defaultPortForwarder.appName { | ||
t.Errorf("the app name on the file doesn't match, got %v, want %v", odoDebugFileData.AppName, tt.args.defaultPortForwarder.appName) | ||
} | ||
if odoDebugFileData.ProjectName != tt.args.defaultPortForwarder.client.Namespace { | ||
t.Errorf("the app name on the file doesn't match, got %v, want %v", odoDebugFileData.AppName, tt.args.defaultPortForwarder.client.Namespace) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package debug | ||
|
||
import ( | ||
"github.com/openshift/odo/pkg/config" | ||
"github.com/openshift/odo/pkg/debug" | ||
"github.com/openshift/odo/pkg/log" | ||
"github.com/openshift/odo/pkg/odo/genericclioptions" | ||
"github.com/spf13/cobra" | ||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | ||
k8sgenclioptions "k8s.io/kubernetes/pkg/kubectl/genericclioptions" | ||
) | ||
|
||
// PortForwardOptions contains all the options for running the port-forward cli command. | ||
type InfoOptions struct { | ||
Namespace string | ||
PortForwarder *debug.DefaultPortForwarder | ||
*genericclioptions.Context | ||
localConfigInfo *config.LocalConfigInfo | ||
contextDir string | ||
} | ||
|
||
var ( | ||
infoLong = templates.LongDesc(` | ||
Gets information regarding any debug session of the component. | ||
`) | ||
|
||
infoExample = templates.Examples(` | ||
# Get information regarding any debug session of the component | ||
odo debug info | ||
`) | ||
) | ||
|
||
const ( | ||
infoCommandName = "info" | ||
) | ||
|
||
func NewInfoOptions() *InfoOptions { | ||
return &InfoOptions{} | ||
} | ||
|
||
// Complete completes all the required options for port-forward cmd. | ||
func (o *InfoOptions) Complete(name string, cmd *cobra.Command, args []string) (err error) { | ||
o.Context = genericclioptions.NewContext(cmd) | ||
cfg, err := config.NewLocalConfigInfo(o.contextDir) | ||
o.localConfigInfo = cfg | ||
|
||
// Using Discard streams because nothing important is logged | ||
o.PortForwarder = debug.NewDefaultPortForwarder(cfg.GetName(), cfg.GetApplication(), o.Client, k8sgenclioptions.NewTestIOStreamsDiscard()) | ||
|
||
return err | ||
} | ||
|
||
// Validate validates all the required options for port-forward cmd. | ||
func (o InfoOptions) Validate() error { | ||
return nil | ||
} | ||
|
||
// Run implements all the necessary functionality for port-forward cmd. | ||
func (o InfoOptions) Run() error { | ||
if localPort, debugging := debug.GetDebugInfo(o.PortForwarder); debugging { | ||
log.Infof("Debug is running for the component on the local port : %v\n", localPort) | ||
} else { | ||
log.Infof("Debug is not running for the component %v\n", o.localConfigInfo.GetName()) | ||
} | ||
return nil | ||
} | ||
|
||
// NewCmdInfo implements the debug info odo command | ||
func NewCmdInfo(name, fullName string) *cobra.Command { | ||
|
||
opts := NewInfoOptions() | ||
cmd := &cobra.Command{ | ||
Use: name, | ||
Short: "Displays debug info of a component", | ||
Long: infoLong, | ||
Example: infoExample, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
genericclioptions.GenericRun(opts, cmd, args) | ||
}, | ||
} | ||
genericclioptions.AddContextFlag(cmd, &opts.contextDir) | ||
|
||
return cmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.