-
Notifications
You must be signed in to change notification settings - Fork 30
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
0 parents
commit d6a4121
Showing
18 changed files
with
1,684 additions
and
0 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,51 @@ | ||
# Compiled Object files, Static and Dynamic libs (Shared Objects) | ||
*.o | ||
*.a | ||
*.so | ||
|
||
# Folders | ||
_obj | ||
_test | ||
.vagrant | ||
releases | ||
tmp | ||
.idea/ | ||
|
||
# Architecture specific extensions/prefixes | ||
trace.out | ||
*.out | ||
.DS_Store | ||
|
||
*.cgo1.go | ||
*.cgo2.c | ||
_cgo_defun.c | ||
_cgo_gotypes.go | ||
_cgo_export.* | ||
|
||
_testmain.go | ||
|
||
*.exe | ||
*.test | ||
*.prof | ||
profile.cov | ||
coverage.html | ||
|
||
# Emacs backup files | ||
*~ | ||
|
||
# ctags files | ||
tags | ||
|
||
# Project specific | ||
/chaosblade | ||
/blade | ||
/bin/java-agent*.jar | ||
/hack/chaosblade* | ||
/hack/lib/** | ||
/chaosblade.dat | ||
target | ||
coverage.txt | ||
vendor | ||
|
||
# Website | ||
site-build |
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,194 @@ | ||
/* | ||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package channel | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os/exec" | ||
"strings" | ||
"time" | ||
"os" | ||
"strconv" | ||
|
||
"github.com/sirupsen/logrus" | ||
|
||
"github.com/chaosblade-io/chaosblade-spec-go/spec" | ||
"github.com/chaosblade-io/chaosblade-spec-go/util" | ||
) | ||
|
||
// Run the script in the local with ctx and returns spec.Response | ||
func Run(ctx context.Context, script, args string) *spec.Response { | ||
return execScript(ctx, script, args) | ||
} | ||
|
||
// GetScriptPath returns the script path for running | ||
func GetScriptPath() string { | ||
return util.GetBinPath() | ||
} | ||
|
||
// execScript invokes exec.CommandContext | ||
func execScript(ctx context.Context, script, args string) *spec.Response { | ||
newCtx, cancel := context.WithTimeout(ctx, 60*time.Second) | ||
defer cancel() | ||
if ctx == context.Background() { | ||
ctx = newCtx | ||
} | ||
script = strings.Replace(script, " ", `\ `, -1) | ||
logrus.Debugf("script: %s %s", script, args) | ||
cmd := exec.CommandContext(ctx, "/bin/sh", "-c", script+" "+args) | ||
output, err := cmd.CombinedOutput() | ||
if err != nil { | ||
errMsg := fmt.Sprintf(string(output) + " " + err.Error()) | ||
return spec.ReturnFail(spec.Code[spec.ExecCommandError], errMsg) | ||
} | ||
result := string(output) | ||
return spec.ReturnSuccess(result) | ||
} | ||
|
||
// GetPidsByProcessCmdName returns the matched process other than the current process | ||
func GetPidsByProcessCmdName(processName string, ctx context.Context) ([]string, error) { | ||
excludeProcess := ctx.Value(ExcludeProcessKey) | ||
excludeGrepInfo := "" | ||
if excludeProcess != nil { | ||
excludeProcessString := excludeProcess.(string) | ||
if excludeProcessString != "" { | ||
excludeGrepInfo = fmt.Sprintf(`| grep -v -w %s`, excludeProcessString) | ||
} | ||
} | ||
response := Run(ctx, "pgrep", | ||
fmt.Sprintf(`-l %s %s | grep -v -w chaos_killprocess | grep -v -w chaos_stopprocess | awk '{print $1}' | tr '\n' ' '`, | ||
processName, excludeGrepInfo)) | ||
if !response.Success { | ||
return nil, fmt.Errorf(response.Err) | ||
} | ||
pidString := response.Result.(string) | ||
pids := strings.Fields(strings.TrimSpace(pidString)) | ||
currPid := strconv.Itoa(os.Getpid()) | ||
for idx, pid := range pids { | ||
if pid == currPid { | ||
return util.Remove(pids, idx), nil | ||
} | ||
} | ||
return pids, nil | ||
} | ||
|
||
// grep ${key} | ||
const ProcessKey = "process" | ||
const ExcludeProcessKey = "excludeProcess" | ||
|
||
// GetPidsByProcessName returns the matched process other than the current process | ||
func GetPidsByProcessName(processName string, ctx context.Context) ([]string, error) { | ||
psArgs := GetPsArgs() | ||
otherProcess := ctx.Value(ProcessKey) | ||
otherGrepInfo := "" | ||
if otherProcess != nil { | ||
processString := otherProcess.(string) | ||
if processString != "" { | ||
otherGrepInfo = fmt.Sprintf(`| grep "%s"`, processString) | ||
} | ||
} | ||
excludeProcess := ctx.Value(ExcludeProcessKey) | ||
excludeGrepInfo := "" | ||
if excludeProcess != nil { | ||
excludeProcessString := excludeProcess.(string) | ||
if excludeProcessString != "" { | ||
excludeGrepInfo = fmt.Sprintf(`| grep -v -w %s`, excludeProcessString) | ||
} | ||
} | ||
response := Run(ctx, "ps", | ||
fmt.Sprintf(`%s | grep "%s" %s %s | grep -v -w grep | grep -v -w chaos_killprocess | grep -v -w chaos_stopprocess | awk '{print $2}' | tr '\n' ' '`, | ||
psArgs, processName, otherGrepInfo, excludeGrepInfo)) | ||
if !response.Success { | ||
return nil, fmt.Errorf(response.Err) | ||
} | ||
pidString := strings.TrimSpace(response.Result.(string)) | ||
if pidString == "" { | ||
return make([]string, 0), nil | ||
} | ||
pids := strings.Fields(pidString) | ||
currPid := strconv.Itoa(os.Getpid()) | ||
for idx, pid := range pids { | ||
if pid == currPid { | ||
return util.Remove(pids, idx), nil | ||
} | ||
} | ||
return pids, nil | ||
} | ||
|
||
// GetPsArgs for querying the process info | ||
func GetPsArgs() string { | ||
var psArgs = "-eo user,pid,ppid,args" | ||
if isAlpinePlatform() { | ||
psArgs = "-o user,pid,ppid,args" | ||
} | ||
return psArgs | ||
} | ||
|
||
// isAlpinePlatform returns true if the os version is alpine. | ||
// If the /etc/os-release file doesn't exist, the function returns false. | ||
func isAlpinePlatform() bool { | ||
var osVer = "" | ||
if util.IsExist("/etc/os-release") { | ||
response := Run(context.TODO(), "awk", "-F '=' '{if ($1 == \"ID\") {print $2;exit 0}}' /etc/os-release") | ||
if response.Success { | ||
osVer = response.Result.(string) | ||
} | ||
} | ||
return strings.TrimSpace(osVer) == "alpine" | ||
} | ||
|
||
// IsCommandAvailable return true if the command exists | ||
func IsCommandAvailable(commandName string) bool { | ||
response := execScript(context.TODO(), "command", fmt.Sprintf("-v %s", commandName)) | ||
return response.Success | ||
} | ||
|
||
//ProcessExists returns true if the pid exists, otherwise return false. | ||
func ProcessExists(pid string) (bool, error) { | ||
if isAlpinePlatform() { | ||
response := Run(context.TODO(), "ps", fmt.Sprintf("-o pid | grep %s", pid)) | ||
if !response.Success { | ||
return false, fmt.Errorf(response.Err) | ||
} | ||
if strings.TrimSpace(response.Result.(string)) == "" { | ||
return false, nil | ||
} | ||
return true, nil | ||
} | ||
response := Run(context.TODO(), "ps", fmt.Sprintf("-p %s", pid)) | ||
return response.Success, nil | ||
} | ||
|
||
// GetPidUser returns the process user by pid | ||
func GetPidUser(pid string) (string, error) { | ||
var response *spec.Response | ||
if isAlpinePlatform() { | ||
response = Run(context.TODO(), "ps", fmt.Sprintf("-o user,pid | grep %s", pid)) | ||
|
||
} else { | ||
response = Run(context.TODO(), "ps", fmt.Sprintf("-o user,pid -p %s | grep %s", pid, pid)) | ||
} | ||
if !response.Success { | ||
return "", fmt.Errorf(response.Err) | ||
} | ||
result := strings.TrimSpace(response.Result.(string)) | ||
if result == "" { | ||
return "", fmt.Errorf("process user not found by pid") | ||
} | ||
return strings.Fields(result)[0], nil | ||
} |
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,39 @@ | ||
/* | ||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package channel | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/chaosblade-io/chaosblade-spec-go/spec" | ||
) | ||
|
||
type LocalChannel struct { | ||
} | ||
|
||
// NewLocalChannel returns a local channel for invoking the host command | ||
func NewLocalChannel() spec.Channel { | ||
return &LocalChannel{} | ||
} | ||
|
||
func (l *LocalChannel) Run(ctx context.Context, script, args string) *spec.Response { | ||
return Run(ctx, script, args) | ||
} | ||
|
||
func (l *LocalChannel) GetScriptPath() string { | ||
return GetScriptPath() | ||
} |
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,48 @@ | ||
/* | ||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package channel | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/chaosblade-io/chaosblade-spec-go/spec" | ||
) | ||
|
||
// MockLocalChannel for testing | ||
type MockLocalChannel struct { | ||
Response *spec.Response | ||
ScriptPath string | ||
ExpectedCommands []string | ||
InvokeTime int | ||
NoCheck bool | ||
T *testing.T | ||
} | ||
|
||
func (mlc *MockLocalChannel) Run(ctx context.Context, script, args string) *spec.Response { | ||
cmd := fmt.Sprintf("%s %s", script, args) | ||
if !mlc.NoCheck && mlc.ExpectedCommands[mlc.InvokeTime] != cmd { | ||
mlc.T.Errorf("unexpected command: %s, expected command: %s", cmd, mlc.ExpectedCommands[mlc.InvokeTime]) | ||
} | ||
mlc.InvokeTime++ | ||
return mlc.Response | ||
} | ||
|
||
func (mlc *MockLocalChannel) GetScriptPath() string { | ||
return mlc.ScriptPath | ||
} |
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,9 @@ | ||
module github.com/chaosblade-io/chaosblade-spec-go | ||
|
||
go 1.13 | ||
|
||
require ( | ||
github.com/sirupsen/logrus v1.4.2 | ||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 | ||
gopkg.in/yaml.v2 v2.2.4 | ||
) |
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,15 @@ | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= | ||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= | ||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= | ||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= | ||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= | ||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= | ||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= | ||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
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,30 @@ | ||
/* | ||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package spec | ||
|
||
import ( | ||
"context" | ||
) | ||
|
||
// Channel is an interface for command invocation | ||
type Channel interface { | ||
// Run script with args and returns response that wraps the result | ||
Run(ctx context.Context, script, args string) *Response | ||
|
||
// GetScriptPath return the script path | ||
GetScriptPath() string | ||
} |
Oops, something went wrong.