本文主要是介绍k8s 将k8s作为module使用,进行二开,解决k8s replace的staging本地依赖问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
go版本,相比bash版本加强了并发能力
/** hack-go-get-kubernetes-version-xx.xx.xx.go* example:* go run $s4y/hack-go-get-kubernetes-version-xx.xx.xx.go v1.22.6* 1. 依赖的kubernetes版本号*/// Package main is the entry of script.
package mainimport ("bytes""errors""fmt""os""os/exec""strconv""strings""sync""syscall"
)func main() {fmt.Println("hack-go-get-kubernetes-version-xx.xx.xx begin")defer fmt.Println("hack-go-get-kubernetes-version-xx.xx.xx end")var err errorvar strExample = "go run $s4y/hack-go-get-kubernetes-version-xx.xx.xx.go v1.22.6"defer func() { fmt.Printf("err: %v, example: %s\n", err, strExample) }()var errParamWrong = errors.New("param wrong")// 获取当前目录var pwd stringif pwd, err = os.Getwd(); err != nil {return}fmt.Printf("pwd: %s\n", pwd)// 获取命令行参数var lenOsArgs = len(os.Args)fmt.Printf("command-args-cnt: %d, command-args: %v\n", lenOsArgs, os.Args)if lenOsArgs != 2 {err = errors.New("lenOsArgs != 2")return}// 获取依赖的kubernetes版本号var version = os.Args[1]var idxV = strings.IndexByte(version, 'v')if idxV == -1 {err = errParamWrongreturn}var versionTrimV = version[idxV+1:]// 解析k8s的go.mod文件var strCmd = fmt.Sprintf(`curl -x $http_proxy -sS https://raw.githubusercontent.com/kubernetes/kubernetes/v%s/go.mod | grep "staging" | sed -n 's|.*k8s.io/\(.*\) => ./staging/src/k8s.io/.*|k8s.io/\1|p'`, versionTrimV)var cmd = NewCommand(strCmd)if err = cmd.Exec(); err != nil {return}var stdOut = cmd.GetStdOut()if stdOut == "" {err = fmt.Errorf("%s stdOut is null", strCmd)return}var stageRepos = strings.Split(stdOut, "\n")var lenStageRepos = len(stageRepos)var stageVersions = make([]string, lenStageRepos)// 并发下载k8s依赖的包缓存到本地var wg sync.WaitGroupwg.Add(lenStageRepos)for idx, repo := range stageRepos {go func(idx int, repo string) {defer wg.Done()if repo == "" {return}var strCmd = fmt.Sprintf(`go mod download -json "%s@kubernetes-%s" | grep "Version" | sed -n 's|.*"Version": "\(.*\)".*|\1|p'`, repo, versionTrimV)var cmd = NewCommand(strCmd)if err := cmd.Exec(); err != nil {fmt.Printf("strCmd: %s, err: %s\n", strCmd, err.Error())return}var stdOut = cmd.GetStdOut()if stdOut == "" {fmt.Printf("strCmd: %s, stdOut is null\n", strCmd)return}stageVersions[idx] = fmt.Sprintf("\t%s => %s %s\n",repo, repo, stdOut,)}(idx, repo)}wg.Wait()// 以追加方式写入到go.mod文件末尾, 并获取k8s包var strToWrite strings.BuilderstrToWrite.Grow(1024)strToWrite.WriteString("\nreplace(\n")for _, str := range stageVersions {strToWrite.WriteString(str)}strToWrite.WriteString(")\n")fmt.Printf("write to %s/go.mod\n", pwd)strCmd = fmt.Sprintf(`echo "%s" >> ./go.mod && go get "k8s.io/kubernetes@v%s"`, strToWrite.String(), versionTrimV)cmd = NewCommand(strCmd)err = cmd.Exec()fmt.Println(cmd.StringWithExecErr(err))return
}//Command defines commands to be executed and captures std out and std error
type Command struct {Cmd *exec.CmdStdOut []byteStdErr []byteExitCode int
}func NewCommand(command string) *Command {return &Command{Cmd: exec.Command("bash", "-c", command)}
}// Exec run command and exit formatted error, callers can print err directly
// Any running error or non-zero exitcode is consider as error
func (cmd *Command) Exec() error {var stdoutBuf, stderrBuf bytes.Buffercmd.Cmd.Stdout = &stdoutBufcmd.Cmd.Stderr = &stderrBuferrString := fmt.Sprintf("failed to exec '%s'", cmd.GetCommand())err := cmd.Cmd.Start()if err != nil {errString = fmt.Sprintf("%s, err: %v", errString, err)return errors.New(errString)}err = cmd.Cmd.Wait()if err != nil {cmd.StdErr = stderrBuf.Bytes()if exit, ok := err.(*exec.ExitError); ok {cmd.ExitCode = exit.Sys().(syscall.WaitStatus).ExitStatus()errString = fmt.Sprintf("%s, err: %s", errString, stderrBuf.Bytes())} else {cmd.ExitCode = 1}errString = fmt.Sprintf("%s, err: %v", errString, err)return errors.New(errString)}cmd.StdOut, cmd.StdErr = stdoutBuf.Bytes(), stderrBuf.Bytes()return nil
}func (cmd Command) GetCommand() string {return strings.Join(cmd.Cmd.Args, " ")
}func (cmd Command) GetStdOut() string {if len(cmd.StdOut) != 0 {return strings.TrimSuffix(string(cmd.StdOut), "\n")}return ""
}func (cmd Command) GetStdErr() string {if len(cmd.StdErr) != 0 {return strings.TrimSuffix(string(cmd.StdErr), "\n")}return ""
}func (cmd Command) StringWithExecErr(errExec error) (res string) {var resBuild strings.BuilderresBuild.Grow(1024)// 写入执行的命令resBuild.WriteString("strCmd: ")for _, args := range cmd.Cmd.Args {resBuild.WriteByte(' ')resBuild.WriteString(args)}resBuild.WriteByte('\n')// 写入执行的errif errExec == nil {resBuild.WriteString("err: nil\n")} else {resBuild.WriteString("err: ")resBuild.WriteString(errExec.Error())resBuild.WriteByte('\n')}// 写入stdOutif len(cmd.StdOut) == 0 {resBuild.WriteString("stdOut is null\n")} else {resBuild.WriteString("stdOut: ")resBuild.Write(cmd.StdOut)}// 写入stdErrif len(cmd.StdErr) == 0 {resBuild.WriteString("stdErr is null\n")} else {resBuild.WriteString("stdErr: ")resBuild.Write(cmd.StdErr)}// 写入exitCoderesBuild.WriteString("exitCode: ")resBuild.WriteString(strconv.Itoa(cmd.ExitCode))res = resBuild.String()return
}
bash版本
#########################################################################
# File Name: hack-go-get-kubernetes-version-xx.xx.xx.sh
# Author: xiaoyang.chen
# mail: xiaoyang.chen@???.com
# Created Time: 五 3/25 17:01:05 2022
#########################################################################
#!/bin/bash# using example: hack-go-get-kubernetes-version-xx.xx.xx.sh v1.22.6
# from https://github.com/kubernetes/kubernetes/issues/79384
# abursavich commented on 15 Aug 2019# '-e': 当一个命令失败时, 立即退出
# '-u': 遇到未定义的变量, 报错并立即退出
# '-o pipefail': 在运行脚本时, 通常我们只看最后一个命令的退出码, 例如'invalid_command || echo "invalid command"', 我们获得退出码为0, 因为我们获得整个管道的最后一个命令, 加上'-o pipefail', 则会根据整个管道链的退出码来判断, 只有所有退出码为0, 退出码才会为0
set -euo pipefailVERSION=${1#"v"}
# -z True if the length of $VERSION is zero.
if [ -z "$VERSION" ]; thenecho "Must specify version!"exit 1
fi
# curl -sS -s silent, -S with -s, will print error message when curl fail
# in k8s go.mod:
# k8s.io/api => ./staging/src/k8s.io/api
# k8s.io/apiextensions-apiserver => ./staging/src/k8s.io/apiextensions-apiserver
# k8s.io/apimachinery => ./staging/src/k8s.io/apimachinery
# k8s.io/apiserver => ./staging/src/k8s.io/apiserver
# s为substitution替换, |为分界符, p指仅将替换后的行输出到标准输出, 其他不输出
# \1是()中匹配到的内容的第一个匹配项, ()会将匹配到的内容保存进缓冲区, 缓冲区编号从1开始, 最多可存储99个捕获的子表达式, 每个缓冲区都可以使用\n访问, 其中n为一个标识特定缓冲区的一位或两位十进制数
# 解析k8s的go.mod文件
MODS=($(curl -x $http_proxy -sS https://raw.githubusercontent.com/kubernetes/kubernetes/v${VERSION}/go.mod | grep "staging" | sed -n 's|.*k8s.io/\(.*\) => ./staging/src/k8s.io/.*|k8s.io/\1|p'
))
# 并发下载k8s依赖的包缓存到本地
declare -a versions
for MOD in "${MODS[@]}"; doversions+=("$MOD => $MOD `go mod download -json "${MOD}@kubernetes-${VERSION}" | grep "Version" | sed -n 's|.*"Version": "\(.*\)".*|\1|p' &`");
done
wait
# 以追加方式写入到go.mod文件末尾
stringToWrite="\nreplace(\n"
for v in "${versions[@]}"; dostringToWrite+="\t$v\n";
done
stringToWrite+=")\n"
echo "write to `pwd`/go.mod";
echo "$stringToWrite" >> ./go.mod;
go get "k8s.io/kubernetes@v${VERSION}"
这篇关于k8s 将k8s作为module使用,进行二开,解决k8s replace的staging本地依赖问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!