Skip to content

Commit e0a63bf

Browse files
Abhishek Kashyapqiell
authored andcommitted
adds check for binary in current directory and path
- added function `BinPathFromPathEnv` which will give path for the supplied binary name - added test for above function - written two more functions `LogFatal` and `LogFatalf` in log package - added check for `minikube` and `kubectl` binary in the code - removed hardcoded strings for the above two Changes committed: modified: common/common.go modified: environments/minikube/general.go modified: environments/minikube/setup.go modified: utils/k8s/general.go modified: utils/k8s/k8s.go modified: utils/log/logger.go new file: utils/system/path_check_test.go new file: utils/system/path_check_unix.go Signed-off-by: Abhishek Kashyap <abhishek.kashyap@mayadata.io>
1 parent 9e0372d commit e0a63bf

File tree

8 files changed

+149
-5
lines changed

8 files changed

+149
-5
lines changed

common/common.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@ const (
1818
Minikube = "minikube"
1919
// Docker is the name of Docker which is "docker"
2020
Docker = "docker"
21+
// Kubectl is the name of Kubectl which is "kubectl"
22+
Kubectl = "kubectl"
2123
)

environments/minikube/general.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"strings"
1919
"time"
2020

21+
"github.com/golang/glog"
2122
"github.com/openebs/CITF/common"
2223
"github.com/openebs/CITF/utils/log"
2324
sysutil "github.com/openebs/CITF/utils/system"
@@ -32,6 +33,13 @@ var (
3233
)
3334

3435
func init() {
36+
// Check if `minikube` is present
37+
minikubePath, err := sysutil.BinPathFromPathEnv(common.Minikube)
38+
if minikubePath == "" {
39+
logger.LogFatalf(err, "%q not found in current directory or in directories represented by PATH environment variable", common.Minikube)
40+
}
41+
glog.Infof("%q found on path: %q", common.Minikube, minikubePath)
42+
3543
// `sudo` use detection
3644
useSudoEnv := strings.ToLower(strings.TrimSpace(os.Getenv("USE_SUDO")))
3745
if useSudoEnv == "true" { // If it is mentioned in the environment variable to use sudo

environments/minikube/setup.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ package minikube
1616
import (
1717
"fmt"
1818
"os"
19+
20+
"github.com/openebs/CITF/common"
1921
)
2022

2123
// runPostStartCommandsForMinikube runs the commands required when run minikube as --vm-driver=none
@@ -42,7 +44,7 @@ func (minikube Minikube) runPostStartCommandsForMinikubeNoneDriver() {
4244

4345
// StartMinikube method starts minikube with `--vm-driver=none` option.
4446
func (minikube Minikube) StartMinikube() error {
45-
err := runCommand("minikube start --vm-driver=none")
47+
err := runCommand(common.Minikube + " start --vm-driver=none")
4648
// We can also use following:
4749
// "minikube start --vm-driver=none --feature-gates=MountPropagation=true --cpus=1 --memory=1024 --v=3 --alsologtostderr"
4850
if err != nil {
@@ -75,7 +77,7 @@ func (minikube Minikube) Setup() error {
7577
minikubeStatus, err := minikube.Status()
7678

7779
logger.PrintfDebugMessageIfError(err, "error occurred while checking minikube status")
78-
logger.PrintfDebugMessageIfNotError(err, "minikube status: %q", minikubeStatus)
80+
logger.PrintfDebugMessageIfNotError(err, common.Minikube+" status: %q", minikubeStatus)
7981

8082
teardownRequired := false
8183
startRequired := false

utils/k8s/general.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ package k8s
1616
import (
1717
"fmt"
1818

19+
"github.com/golang/glog"
20+
"github.com/openebs/CITF/common"
1921
"github.com/openebs/CITF/config"
2022
"github.com/openebs/CITF/utils/log"
23+
sysutil "github.com/openebs/CITF/utils/system"
2124
api_core_v1 "k8s.io/api/core/v1"
2225
"k8s.io/client-go/kubernetes"
2326
"k8s.io/client-go/rest"
@@ -34,6 +37,16 @@ type K8S struct {
3437
Clientset *kubernetes.Clientset
3538
}
3639

40+
func init() {
41+
// check if `kubectl` is present
42+
kubectlPath, err := sysutil.BinPathFromPathEnv(common.Kubectl)
43+
if kubectlPath == "" {
44+
// we don't want to exit here because k8s package may be used as a wrapper over client-go as well
45+
glog.Errorf("%q not found in current directory or in directories represented by PATH environment variable: %+v", common.Kubectl, err)
46+
}
47+
glog.Infof("%q found on path: %q", common.Kubectl, kubectlPath)
48+
}
49+
3750
// NewK8S returns K8S struct
3851
func NewK8S() (K8S, error) {
3952
config, err := GetClientConfig()

utils/k8s/k8s.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"errors"
2727

2828
"github.com/golang/glog"
29+
"github.com/openebs/CITF/common"
2930
strutil "github.com/openebs/CITF/utils/string"
3031
sysutil "github.com/openebs/CITF/utils/system"
3132
core_v1 "k8s.io/api/core/v1"
@@ -414,7 +415,7 @@ func (k8s K8S) GetDaemonsetStructFromYamlBytes(yamlBytes []byte) (v1beta1.Daemon
414415
func (k8s K8S) YAMLApply(yamlPath string) error {
415416
// TODO: Try using API call first. i.e. Using client-go
416417

417-
err := sysutil.RunCommand("kubectl apply -f " + yamlPath)
418+
err := sysutil.RunCommand(common.Kubectl + " apply -f " + yamlPath)
418419
logger.LogErrorf(err, "error occurred while applying the %s", yamlPath)
419420
if err != nil {
420421
return fmt.Errorf("failed applying %s", yamlPath)
@@ -489,7 +490,7 @@ func (k8s K8S) ExecToPodThroughAPI(command, containerName, podName, namespace st
489490
// :return: string: Output of the command. (STDOUT)
490491
// error: If any error has occurred otherwise `nil`
491492
func (k8s K8S) ExecToPodThroughKubectl(command, containerName, podName, namespace string) (string, error) {
492-
kubectlCommand := "kubectl"
493+
kubectlCommand := common.Kubectl
493494

494495
// adding namespace if namespace is not blank string
495496
if len(namespace) != 0 {
@@ -561,7 +562,7 @@ func (k8s K8S) GetLog(podName, namespace string) (string, error) {
561562
use_kubectl:
562563
glog.Errorf("Error while getting log with API call. Error: %+v", err)
563564

564-
return sysutil.ExecCommand("kubectl -n " + namespace + " logs " + podName)
565+
return sysutil.ExecCommand(common.Kubectl + " -n " + namespace + " logs " + podName)
565566
}
566567

567568
// BlockUntilPodIsUp blocks until all containers of the given pod is ready

utils/log/logger.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,22 @@ func (logger Logger) LogNonErrorf(err error, message string, a ...interface{}) {
7777
}
7878
}
7979

80+
// LogFatal logs error using `glog.Error` only when err is not nil.
81+
// Please follow convensions for error message e.g. start with lowercase, don't end with period etc.
82+
func (logger Logger) LogFatal(err error, message string) {
83+
if err != nil {
84+
glog.Fatal(message+":", err)
85+
}
86+
}
87+
88+
// LogFatalf formats according to a format specifier and logs error using `glog.Error` only when err is not nil.
89+
// Please follow convensions for error message e.g. start with lowercase, don't end with period etc.
90+
func (logger Logger) LogFatalf(err error, message string, a ...interface{}) {
91+
if err != nil {
92+
glog.Fatal(fmt.Sprintf(message, a...)+":", err)
93+
}
94+
}
95+
8096
// PrintError wtires error message to os.StdErr only when err is not nil.
8197
// Spaces are always added between operands and a newline is appended.
8298
// It returns the number of bytes written and any write error encountered.

utils/system/path_check_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// +build linux darwin
2+
3+
package system
4+
5+
import (
6+
"os"
7+
"strings"
8+
"testing"
9+
)
10+
11+
func TestBinPathFromPathEnv(t *testing.T) {
12+
type args struct {
13+
BinName string
14+
}
15+
16+
tests := []struct {
17+
Name string
18+
Args args
19+
}{
20+
{
21+
Name: "check path of minikube",
22+
Args: args{
23+
BinName: "minikube",
24+
},
25+
},
26+
{
27+
Name: "check path of kubectl",
28+
Args: args{
29+
BinName: "kubectl",
30+
},
31+
},
32+
{
33+
Name: "check path of some-radom-binary",
34+
Args: args{
35+
BinName: "some-radom-binary",
36+
},
37+
},
38+
}
39+
40+
os.Setenv("PATH", "~/front:"+os.Getenv("PATH")+":~/back")
41+
for _, tt := range tests {
42+
t.Run(tt.Name, func(t *testing.T) {
43+
t.Log("os.Getenv(\"PATH\")=", os.Getenv("PATH"))
44+
// Assumption: `which` is present in the system
45+
want, _ := ExecCommand("which " + tt.Args.BinName)
46+
want = strings.TrimSpace(want)
47+
48+
get, err := BinPathFromPathEnv(tt.Args.BinName)
49+
if err != nil {
50+
t.Errorf("error occurred while getting path for %q: %+v", tt.Args.BinName, err)
51+
}
52+
get = strings.TrimSpace(get)
53+
54+
if get != want {
55+
t.Errorf("BinPathFromPathEnv(%q)=%q; want=%q", tt.Args.BinName, get, want)
56+
}
57+
})
58+
}
59+
}

utils/system/path_check_unix.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// +build linux darwin
2+
3+
package system
4+
5+
import (
6+
"fmt"
7+
"io/ioutil"
8+
"os"
9+
"path/filepath"
10+
"strings"
11+
)
12+
13+
// BinPathFromPathEnv returns absolute file path of the binary which name is supplied from argument
14+
// if that file found in current directory itself or directories represented by PATH variable,
15+
// it returns error if any error occurres during the process or empty string otherwise for path otherwise.
16+
func BinPathFromPathEnv(binName string) (string, error) {
17+
var err error
18+
pwd, err := os.Getwd()
19+
if err != nil {
20+
return "", fmt.Errorf("error getting current path: %+v", err)
21+
}
22+
23+
pathDirs := strings.Split(os.Getenv("PATH"), ":")
24+
pathDirs = append([]string{pwd}, pathDirs...)
25+
26+
// PATH variable is scanned from left to right so no need of reversal of the slice
27+
var files []os.FileInfo
28+
for _, pathDir := range pathDirs {
29+
files, err = ioutil.ReadDir(pathDir)
30+
logger.PrintfDebugMessageIfError(err, "error reading directory entries for directory: %q", pathDir)
31+
32+
// if error wont be nil, then files will be empty slice so below for will automatically be ignored,
33+
// no need of continue statement here
34+
for _, file := range files {
35+
if !file.IsDir() && file.Name() == binName {
36+
return filepath.Join(pathDir, file.Name()), nil
37+
}
38+
}
39+
40+
}
41+
42+
return "", nil
43+
}

0 commit comments

Comments
 (0)