Skip to content

Commit

Permalink
feat: cmd alias config file support special (#232)
Browse files Browse the repository at this point in the history
  • Loading branch information
wencaiwulue authored Apr 27, 2024
1 parent ada4b51 commit f93b06e
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 6 deletions.
30 changes: 24 additions & 6 deletions cmd/kubevpn/cmds/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
yaml "sigs.k8s.io/yaml/goyaml.v3"

"github.com/wencaiwulue/kubevpn/v2/pkg/daemon"
"github.com/wencaiwulue/kubevpn/v2/pkg/util"
)

// CmdAlias
Expand All @@ -36,6 +37,7 @@ Flags:
- --extra-hosts xxx.com
*/
func CmdAlias(f cmdutil.Factory) *cobra.Command {
var localFile, remoteAddr string
cmd := &cobra.Command{
Use: "alias",
Short: "Config file alias to execute command simply",
Expand Down Expand Up @@ -68,29 +70,43 @@ Config file support three field: Name,Needs,Flags
kubevpn alias jumper
`)),
PreRunE: func(cmd *cobra.Command, args []string) (err error) {
_, err = os.Stat(daemon.GetConfigFilePath())
if localFile != "" {
_, err = os.Stat(localFile)
}
return err
},
Args: cobra.MatchAll(cobra.ExactArgs(1)),
RunE: func(cmd *cobra.Command, args []string) error {
file, err := os.ReadFile(daemon.GetConfigFilePath())
var content []byte
var err error
var path string
if localFile != "" {
path = localFile
content, err = os.ReadFile(path)
} else if remoteAddr != "" {
path = remoteAddr
content, err = util.DownloadFileStream(path)
} else {
path = daemon.GetConfigFilePath()
content, err = os.ReadFile(path)
}
if err != nil {
return err
}
configList, err := ParseConfig(file)
configList, err := ParseConfig(content)
if err != nil {
return err
}
configs, err := GetConfigs(configList, args[0])
if len(configs) == 0 {
return fmt.Errorf("can not found any alias for name %s, please check your config file %s", args[0], daemon.GetConfigFilePath())
return fmt.Errorf("can not found any alias for name %s, please check your config file %s", args[0], path)
}
path, err := os.Executable()
name, err := os.Executable()
if err != nil {
return err
}
for _, config := range configs {
c := exec.Command(path, strings.Split(strings.Join(config.Flags, " "), " ")...)
c := exec.Command(name, strings.Split(strings.Join(config.Flags, " "), " ")...)
c.Stdout = os.Stdout
c.Stdin = os.Stdin
c.Stderr = os.Stderr
Expand All @@ -103,6 +119,8 @@ Config file support three field: Name,Needs,Flags
return nil
},
}
cmd.Flags().StringVarP(&localFile, "file", "f", daemon.GetConfigFilePath(), "Config file location")
cmd.Flags().StringVarP(&remoteAddr, "remote", "r", "", "Remote config file, eg: https://raw.githubusercontent.com/kubenetworks/kubevpn/master/pkg/config/config.yaml")
return cmd
}

Expand Down
106 changes: 106 additions & 0 deletions pkg/util/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package util

import (
"fmt"
"io"
"math"
"net/http"
"os"
"path/filepath"
"time"

"github.com/sirupsen/logrus"
)

func DownloadFileWithName(uri, name string) (string, error) {
resp, err := getWithRetry(uri)
if err != nil {
return "", err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("downloading file %s failed. status code: %d, expected: %d", uri, resp.StatusCode, http.StatusOK)
}

dir, err := os.MkdirTemp("", "")
if err != nil {
return "", err
}

file := filepath.Join(dir, name)
out, err := os.Create(file)
if err != nil {
return "", err
}
defer out.Close()

_, err = io.Copy(out, resp.Body)
if err != nil {
return "", fmt.Errorf("failed to save file %s. error: %v", file, err)
}

logrus.Infof("downloaded file %s", file)
return file, nil
}

func DownloadFileStream(uri string) ([]byte, error) {
resp, err := getWithRetry(uri)
if err != nil {
return nil, err
}

defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("downloading file %s failed. status code: %d, expected: %d", uri, resp.StatusCode, http.StatusOK)
}
return io.ReadAll(resp.Body)
}

func DownloadFile(uri string) (string, error) {
return DownloadFileWithName(uri, fmt.Sprintf("%d", time.Now().Unix()))
}

const (
maxRetries = 4
retryWaitMin = 2 * time.Second
retryWaitMax = 10 * time.Second
)

func getWithRetry(uri string) (*http.Response, error) {
var resp *http.Response
var err error

for i := 0; i < maxRetries; i++ {
resp, err = http.Get(uri)
shouldRetry := checkRetry(resp, err)
if !shouldRetry {
break
}

drainBody(resp.Body)
wait := backoff(retryWaitMin, retryWaitMax, i)
<-time.After(wait)
}

return resp, err
}

func checkRetry(resp *http.Response, err error) bool {
return resp != nil && resp.StatusCode == http.StatusNotFound
}

func drainBody(b io.ReadCloser) {
defer b.Close()
io.Copy(io.Discard, io.LimitReader(b, int64(4096)))
}

func backoff(min, max time.Duration, attemptNum int) time.Duration {
mult := math.Pow(2, float64(attemptNum)) * float64(min)
sleep := time.Duration(mult)
if float64(sleep) != mult || sleep > max {
sleep = max
}
return sleep
}

0 comments on commit f93b06e

Please sign in to comment.