-
Notifications
You must be signed in to change notification settings - Fork 243
/
info.go
157 lines (141 loc) · 5.15 KB
/
info.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package debug
import (
"encoding/json"
"errors"
"net"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"syscall"
"github.com/openshift/odo/pkg/testingutil/filesystem"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog"
)
type OdoDebugFile struct {
metav1.TypeMeta
metav1.ObjectMeta `json:"metadata"`
Spec OdoDebugFileSpec `json:"spec"`
}
type OdoDebugFileSpec struct {
App string `json:"app,omitempty"`
DebugProcessID int `json:"debugProcessID"`
RemotePort int `json:"remotePort"`
LocalPort int `json:"localPort"`
}
// GetDebugInfoFilePath gets the file path of the debug info file
func GetDebugInfoFilePath(componentName, appName string, projectName string) string {
tempDir := os.TempDir()
debugFileSuffix := "odo-debug.json"
var arr []string
if appName == "" {
arr = []string{projectName, componentName, debugFileSuffix}
} else {
arr = []string{projectName, appName, componentName, debugFileSuffix}
}
debugFileName := strings.Join(arr, "-")
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 {
return errors.New("port pair should be of the format localPort:RemotePort")
}
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{
Kind: "OdoDebugInfo",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: f.componentName,
Namespace: f.projectName,
},
Spec: OdoDebugFileSpec{
App: f.appName,
DebugProcessID: os.Getpid(),
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.componentName, f.appName, f.projectName), 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 gathers the information with regards to debugging information
func GetDebugInfo(f *DefaultPortForwarder) (OdoDebugFile, bool) {
return getDebugInfo(f, filesystem.DefaultFs{})
}
// getDebugInfo gets information regarding the debugging session of the component
// returns the OdoDebugFile from the debug info file
// returns true if debugging is running else false
func getDebugInfo(f *DefaultPortForwarder, fs filesystem.Filesystem) (OdoDebugFile, bool) {
// gets the debug info file path and reads/unmarshals it
debugInfoFilePath := GetDebugInfoFilePath(f.componentName, f.appName, f.projectName)
readFile, err := fs.ReadFile(debugInfoFilePath)
if err != nil {
klog.V(4).Infof("the debug %v is not present", debugInfoFilePath)
return OdoDebugFile{}, false
}
var odoDebugFileData OdoDebugFile
err = json.Unmarshal(readFile, &odoDebugFileData)
if err != nil {
klog.V(4).Infof("couldn't unmarshal the debug file %v", debugInfoFilePath)
return OdoDebugFile{}, false
}
// get the debug process id and send a signal 0 to check if it's alive or not
// according to https://golang.org/pkg/os/#FindProcess
// On Unix systems, FindProcess always succeeds and returns a Process for the given pid, regardless of whether the process exists.
// thus this step will pass on Unix systems and so for those systems and some others supporting signals
// we check if the process is alive or not by sending a signal 0 to the process
processInfo, err := os.FindProcess(odoDebugFileData.Spec.DebugProcessID)
if err != nil || processInfo == nil {
klog.V(4).Infof("error getting the process info for pid %v", odoDebugFileData.Spec.DebugProcessID)
return OdoDebugFile{}, false
}
// signal is not available on windows so we skip this step for windows
if runtime.GOOS != "windows" {
err = processInfo.Signal(syscall.Signal(0))
if err != nil {
klog.V(4).Infof("error sending signal 0 to pid %v, cause: %v", odoDebugFileData.Spec.DebugProcessID, err)
return OdoDebugFile{}, false
}
}
// gets the debug local port and tries to listen on it
// if error doesn't occur the debug port was free and thus no debug process was using the port
addressLook := "localhost:" + strconv.Itoa(odoDebugFileData.Spec.LocalPort)
listener, err := net.Listen("tcp", addressLook)
if err == nil {
klog.V(4).Infof("the debug port %v is free, thus debug is not running", odoDebugFileData.Spec.LocalPort)
err = listener.Close()
if err != nil {
klog.V(4).Infof("error occurred while closing the listener, cause :%v", err)
}
return OdoDebugFile{}, false
}
// returns the unmarshalled data
return odoDebugFileData, true
}