You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ke...@apache.org on 2021/08/12 08:29:32 UTC
[skywalking-infra-e2e] 01/01: Propagate environment variables from
user command to parent process
This is an automated email from the ASF dual-hosted git repository.
kezhenxu94 pushed a commit to branch enhancement/env-var
in repository https://gitbox.apache.org/repos/asf/skywalking-infra-e2e.git
commit 33088ee7c4f8c15ff0c3a735eff87b204a32eefb
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Thu Aug 12 16:28:59 2021 +0800
Propagate environment variables from user command to parent process
And some other enhancements:
- Replace linter `golint` to `revive` as the former is deprecated, and fix code styles found by `revive`.
- Polish the logs to make it not too lengthy.
- Add log level configuration.
- Bump up Go version to 1.16.
- Propagate environment variables from user command (sub-process) to parent process to make it available to other sub-processes.
---
.golangci.yml | 5 +--
Makefile | 2 +-
commands/root.go | 30 ++++++++++++++-
commands/verify/verify.go | 12 +++---
go.mod | 2 +-
internal/components/cleanup/kind.go | 6 +--
internal/components/setup/common.go | 9 +++--
internal/components/trigger/http.go | 4 +-
internal/logger/log.go | 2 +-
internal/util/config.go | 5 ++-
internal/util/hook.sh | 21 +++++++++++
internal/util/{config.go => io.go} | 34 ++++++++---------
internal/util/utils.go | 74 ++++++++++++++++++++++++++++++++++---
13 files changed, 156 insertions(+), 50 deletions(-)
diff --git a/.golangci.yml b/.golangci.yml
index 617deaf..f3d33b5 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -24,7 +24,7 @@ run:
linters-settings:
govet:
check-shadowing: true
- golint:
+ revive:
min-confidence: 0
gocyclo:
min-complexity: 15
@@ -108,12 +108,11 @@ linters:
- gocyclo
- gofmt
- goimports
- - golint
+ - revive
- gosec
- gosimple
- govet
- ineffassign
- - interfacer
- lll
- misspell
- nakedret
diff --git a/Makefile b/Makefile
index 1eee4be..e0f675b 100644
--- a/Makefile
+++ b/Makefile
@@ -40,7 +40,7 @@ all: clean lint test build
.PHONY: lint
lint:
- $(GO_LINT) version || curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GO_PATH)/bin
+ $(GO_LINT) version || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GO_PATH)/bin
$(GO_LINT) run -v --timeout 5m ./...
.PHONY: fix-lint
diff --git a/commands/root.go b/commands/root.go
index 8b5fe6c..ff625db 100644
--- a/commands/root.go
+++ b/commands/root.go
@@ -18,9 +18,12 @@
package commands
import (
+ "os"
+
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
- "github.com/apache/skywalking-infra-e2e/internal/util"
+ "github.com/apache/skywalking-infra-e2e/internal/logger"
"github.com/apache/skywalking-infra-e2e/commands/cleanup"
"github.com/apache/skywalking-infra-e2e/commands/run"
@@ -29,6 +32,11 @@ import (
"github.com/apache/skywalking-infra-e2e/commands/verify"
"github.com/apache/skywalking-infra-e2e/internal/config"
"github.com/apache/skywalking-infra-e2e/internal/constant"
+ "github.com/apache/skywalking-infra-e2e/internal/util"
+)
+
+var (
+ verbosity string
)
// Root represents the base command when called without any subcommands
@@ -38,8 +46,24 @@ var Root = &cobra.Command{
Version: version,
SilenceErrors: true,
SilenceUsage: true,
- PersistentPreRun: func(cmd *cobra.Command, args []string) {
+ PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
config.ReadGlobalConfigFile()
+
+ level, err := logrus.ParseLevel(verbosity)
+ if err != nil {
+ return err
+ }
+ logger.Log.SetLevel(level)
+
+ util.WorkDir = util.ExpandFilePath(util.WorkDir)
+ if _, err := os.Stat(util.WorkDir); os.IsNotExist(err) {
+ if err := os.MkdirAll(util.WorkDir, os.ModePerm); err != nil {
+ logger.Log.Warnf("failed to create working directory %v", util.WorkDir)
+ return err
+ }
+ }
+
+ return nil
},
}
@@ -52,6 +76,8 @@ func Execute() error {
Root.AddCommand(verify.Verify)
Root.AddCommand(cleanup.Cleanup)
+ Root.PersistentFlags().StringVarP(&verbosity, "verbosity", "v", logrus.InfoLevel.String(), "log level (debug, info, warn, error, fatal, panic")
+ Root.PersistentFlags().StringVarP(&util.WorkDir, "work-dir", "w", "~/.skywalking-infra-e2e", "the working directory for skywalking-infra-e2e")
Root.PersistentFlags().StringVarP(&util.CfgFile, "config", "c", constant.E2EDefaultFile, "the config file")
return Root.Execute()
diff --git a/commands/verify/verify.go b/commands/verify/verify.go
index e979b41..776510b 100644
--- a/commands/verify/verify.go
+++ b/commands/verify/verify.go
@@ -59,7 +59,7 @@ func verifySingleCase(expectedFile, actualFile, query string) error {
return fmt.Errorf("failed to read the expected data file: %v", err)
}
- var actualData, sourceName string
+ var actualData, sourceName, stderr string
if actualFile != "" {
sourceName = actualFile
actualData, err = util.ReadFileContent(actualFile)
@@ -68,19 +68,19 @@ func verifySingleCase(expectedFile, actualFile, query string) error {
}
} else if query != "" {
sourceName = query
- actualData, err = util.ExecuteCommand(query)
+ actualData, stderr, err = util.ExecuteCommand(query)
if err != nil {
- return fmt.Errorf("failed to execute the query: %s, output: %s, error: %v", query, actualData, err)
+ return fmt.Errorf("failed to execute the query: %s, output: %s, error: %v", query, actualData, stderr)
}
}
if err = verifier.Verify(actualData, expectedData); err != nil {
if me, ok := err.(*verifier.MismatchError); ok {
- return fmt.Errorf("failed to verify the output: %s, error: %v", sourceName, me.Error())
+ return fmt.Errorf("failed to verify the output: %s, error:\n%v", sourceName, me.Error())
}
- return fmt.Errorf("failed to verify the output: %s, error: %v", sourceName, err)
+ return fmt.Errorf("failed to verify the output: %s, error:\n%v", sourceName, err)
}
- logger.Log.Infof("verified the output: %s\n", sourceName)
+ logger.Log.Infof("verified the output: %s", sourceName)
return nil
}
diff --git a/go.mod b/go.mod
index ce51fdd..004f535 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/apache/skywalking-infra-e2e
-go 1.13
+go 1.16
require (
github.com/docker/docker v20.10.7+incompatible
diff --git a/internal/components/cleanup/kind.go b/internal/components/cleanup/kind.go
index 1e19072..3e5f8f1 100644
--- a/internal/components/cleanup/kind.go
+++ b/internal/components/cleanup/kind.go
@@ -86,9 +86,5 @@ func cleanKindCluster(kindConfigFilePath string) error {
args := []string{"delete", "cluster", "--name", clusterName}
logger.Log.Debugf("cluster delete commands: %s %s", constant.KindCommand, strings.Join(args, " "))
- if err := kind.Run(kindcmd.NewLogger(), kindcmd.StandardIOStreams(), args); err != nil {
- return err
- }
-
- return nil
+ return kind.Run(kindcmd.NewLogger(), kindcmd.StandardIOStreams(), args)
}
diff --git a/internal/components/setup/common.go b/internal/components/setup/common.go
index 1e93b9d..e220fa8 100644
--- a/internal/components/setup/common.go
+++ b/internal/components/setup/common.go
@@ -22,6 +22,7 @@ import (
"fmt"
"io/ioutil"
"os"
+ "strings"
"time"
"k8s.io/client-go/dynamic"
@@ -170,13 +171,13 @@ func executeCommandsAndWait(commands string, waits []config.Wait, waitSet *util.
defer waitSet.WaitGroup.Done()
// executes commands
- logger.Log.Infof("executing commands [%s]", commands)
- result, err := util.ExecuteCommand(commands)
+ logger.Log.Infof("executing commands [%s]", strings.ReplaceAll(commands, "\n", "\\n"))
+ result, stderr, err := util.ExecuteCommand(commands)
if err != nil {
- err = fmt.Errorf("commands: [%s] runs error: %s", commands, err)
+ err = fmt.Errorf("commands: [%s] runs error: %s", strings.ReplaceAll(commands, "\n", "\\n"), stderr)
waitSet.ErrChan <- err
}
- logger.Log.Infof("executed commands [%s], result: %s", commands, result)
+ logger.Log.Infof("executed commands [%s], result: %s", strings.ReplaceAll(commands, "\n", "\\n"), result)
// waits for conditions meet
for idx := range waits {
diff --git a/internal/components/trigger/http.go b/internal/components/trigger/http.go
index ce4cbe2..2af36a3 100644
--- a/internal/components/trigger/http.go
+++ b/internal/components/trigger/http.go
@@ -113,9 +113,9 @@ func (h *httpAction) executeOnce(client *http.Client, req *http.Request) error {
logger.Log.Errorf("do request error %v", err)
return err
}
- response.Body.Close()
+ _ = response.Body.Close()
- logger.Log.Infof("do request %v response http code %v", h.url, response.StatusCode)
+ logger.Log.Debugf("do request %v response http code %v", h.url, response.StatusCode)
if response.StatusCode == http.StatusOK {
logger.Log.Debugf("do http action %+v success.", *h)
return nil
diff --git a/internal/logger/log.go b/internal/logger/log.go
index 7fc102e..1c641e8 100644
--- a/internal/logger/log.go
+++ b/internal/logger/log.go
@@ -29,7 +29,7 @@ func init() {
if Log == nil {
Log = logrus.New()
}
- Log.Level = logrus.DebugLevel
+ Log.Level = logrus.InfoLevel
Log.SetOutput(os.Stdout)
Log.SetFormatter(&logrus.TextFormatter{
DisableTimestamp: true,
diff --git a/internal/util/config.go b/internal/util/config.go
index 15e38e1..c34eecb 100644
--- a/internal/util/config.go
+++ b/internal/util/config.go
@@ -25,7 +25,10 @@ import (
"github.com/apache/skywalking-infra-e2e/internal/logger"
)
-var CfgFile string
+var (
+ CfgFile string
+ WorkDir string
+)
// ResolveAbs resolves the relative path (relative to CfgFile) to an absolute file path.
func ResolveAbs(p string) string {
diff --git a/internal/util/hook.sh b/internal/util/hook.sh
new file mode 100644
index 0000000..0a09eda
--- /dev/null
+++ b/internal/util/hook.sh
@@ -0,0 +1,21 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you 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.
+#
+function finish {
+ printenv > {{ .EnvFile }}
+}
+trap finish EXIT
diff --git a/internal/util/config.go b/internal/util/io.go
similarity index 62%
copy from internal/util/config.go
copy to internal/util/io.go
index 15e38e1..733f552 100644
--- a/internal/util/config.go
+++ b/internal/util/io.go
@@ -19,29 +19,27 @@
package util
import (
- "path"
- "path/filepath"
+ "os/user"
+ "strings"
"github.com/apache/skywalking-infra-e2e/internal/logger"
)
-var CfgFile string
-
-// ResolveAbs resolves the relative path (relative to CfgFile) to an absolute file path.
-func ResolveAbs(p string) string {
- if p == "" {
- return p
- }
-
- if path.IsAbs(p) {
- return p
+// UserHomeDir returns the current user's home directory absolute path,
+// which is usually represented as `~` in most shells
+func UserHomeDir() string {
+ if currentUser, err := user.Current(); err != nil {
+ logger.Log.Warnln("Cannot obtain user home directory")
+ } else {
+ return currentUser.HomeDir
}
+ return ""
+}
- abs, err := filepath.Abs(CfgFile)
- if err != nil {
- logger.Log.Warnf("failed to resolve the absolute file path of %v\n", CfgFile)
- return p
+// ExpandFilePath expands the leading `~` to absolute path
+func ExpandFilePath(path string) string {
+ if strings.HasPrefix(path, "~") {
+ return strings.Replace(path, "~", UserHomeDir(), 1)
}
-
- return filepath.Join(filepath.Dir(abs), p)
+ return path
}
diff --git a/internal/util/utils.go b/internal/util/utils.go
index 1e84ea1..5dc7a55 100644
--- a/internal/util/utils.go
+++ b/internal/util/utils.go
@@ -20,10 +20,16 @@ package util
import (
"bytes"
+ _ "embed"
"errors"
"io/ioutil"
"os"
"os/exec"
+ "path/filepath"
+ "strings"
+ "text/template"
+
+ "github.com/apache/skywalking-infra-e2e/internal/logger"
)
// PathExist checks if a file/directory is exist.
@@ -48,16 +54,72 @@ func ReadFileContent(filename string) (string, error) {
}
// ExecuteCommand executes the given command and returns the result.
-func ExecuteCommand(cmd string) (string, error) {
+func ExecuteCommand(cmd string) (stdout, stderr string, err error) {
+ hookScript, err := hookScript()
+ if err != nil {
+ return "", "", err
+ }
+
+ // Propagate the env vars from sub-process back to parent process
+ defer exportEnvVars()
+
+ cmd = hookScript + "\n" + cmd
+
command := exec.Command("bash", "-ec", cmd)
- outinfo := bytes.Buffer{}
- command.Stdout = &outinfo
+ sout, serr := bytes.Buffer{}, bytes.Buffer{}
+ command.Stdout, command.Stderr = &sout, &serr
if err := command.Start(); err != nil {
- return outinfo.String(), err
+ return sout.String(), serr.String(), err
}
if err := command.Wait(); err != nil {
- return outinfo.String(), err
+ return sout.String(), serr.String(), err
+ }
+ return sout.String(), serr.String(), nil
+}
+
+//go:embed hook.sh
+var hookScriptTemplate string
+
+type HookScriptTemplate struct {
+ EnvFile string
+}
+
+func hookScript() (string, error) {
+ hookScript := bytes.Buffer{}
+
+ parse, err := template.New("hookScriptTemplate").Parse(hookScriptTemplate)
+ if err != nil {
+ return "", err
+ }
+
+ envFile := filepath.Join(WorkDir, ".env")
+ scriptData := HookScriptTemplate{EnvFile: envFile}
+ if err := parse.Execute(&hookScript, scriptData); err != nil {
+ return "", err
+ }
+ return hookScript.String(), nil
+}
+
+func exportEnvVars() {
+ envFile := filepath.Join(WorkDir, ".env")
+ b, err := ioutil.ReadFile(envFile)
+ if err != nil {
+ logger.Log.Warnf("failed to export environment variables, %v", err)
+ return
+ }
+ s := string(b)
+
+ lines := strings.Split(s, "\n")
+ for _, line := range lines {
+ kv := strings.SplitN(line, "=", 2)
+ if len(kv) != 2 {
+ continue
+ }
+ key, val := kv[0], kv[1]
+ // should only export env vars that are not already exist in parent process (Go process)
+ if err := os.Setenv(key, val); err != nil {
+ logger.Log.Warnf("failed to export environment variable %v=%v, %v", key, val, err)
+ }
}
- return outinfo.String(), nil
}