-
Notifications
You must be signed in to change notification settings - Fork 208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
perf: use kubectl proxy for k8s session #1627
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,12 +71,15 @@ func NewK8sConnection(ops ...K8sOption) (*K8sCon, error) { | |
if !IsValidK8sUserToken(args) { | ||
return nil, InValidToken | ||
} | ||
_, err := utils.Encrypt(args.Token, config.CipherKey) | ||
kubeProxy := NewKubectlProxyConn(args) | ||
err := kubeProxy.Start() | ||
if err != nil { | ||
return nil, fmt.Errorf("%w: encrypt k8s token failed %s", InValidToken, err) | ||
logger.Errorf("K8sCon start proxy err: %s", err) | ||
return nil, fmt.Errorf("K8sCon start proxy err: %w", err) | ||
} | ||
|
||
lcmd, err := startK8SLocalCommand(args) | ||
envs := kubeProxy.Env() | ||
lcmd, err := startK8SLocalCommand(envs) | ||
if err != nil { | ||
logger.Errorf("K8sCon start local pty err: %s", err) | ||
return nil, fmt.Errorf("K8sCon start local pty err: %w", err) | ||
|
@@ -86,10 +89,11 @@ func NewK8sConnection(ops ...K8sOption) (*K8sCon, error) { | |
_ = lcmd.Close() | ||
return nil, err | ||
} | ||
return &K8sCon{options: args, LocalCommand: lcmd}, nil | ||
return &K8sCon{options: args, LocalCommand: lcmd, proxy: kubeProxy}, nil | ||
} | ||
|
||
type K8sCon struct { | ||
proxy *KubectlProxyConn | ||
options *k8sOptions | ||
*localcommand.LocalCommand | ||
} | ||
|
@@ -98,12 +102,18 @@ func (k *K8sCon) KeepAlive() error { | |
return nil | ||
} | ||
|
||
func (k *K8sCon) Close() error { | ||
_ = k.LocalCommand.Close() | ||
return k.proxy.Close() | ||
} | ||
|
||
type k8sOptions struct { | ||
ClusterServer string // https://172.16.10.51:8443 | ||
Username string // user 系统用户名 | ||
Token string // 授权token | ||
IsSkipTls bool | ||
ExtraEnv map[string]string | ||
DEBUG bool | ||
|
||
win Windows | ||
} | ||
|
@@ -141,7 +151,7 @@ func (o *k8sOptions) Env() []string { | |
} | ||
} | ||
|
||
func startK8SLocalCommand(args *k8sOptions) (*localcommand.LocalCommand, error) { | ||
func startK8SLocalCommand(env []string) (*localcommand.LocalCommand, error) { | ||
pwd, _ := os.Getwd() | ||
shPath := filepath.Join(pwd, k8sInitFilename) | ||
argv := []string{ | ||
|
@@ -150,7 +160,7 @@ func startK8SLocalCommand(args *k8sOptions) (*localcommand.LocalCommand, error) | |
"--mount-proc", | ||
shPath, | ||
} | ||
return localcommand.New("unshare", argv, localcommand.WithEnv(args.Env())) | ||
return localcommand.New("unshare", argv, localcommand.WithEnv(env)) | ||
} | ||
|
||
type K8sOption func(*k8sOptions) | ||
|
@@ -190,3 +200,9 @@ func K8sPtyWin(win Windows) K8sOption { | |
args.win = win | ||
} | ||
} | ||
|
||
func K8sDebug(debug bool) K8sOption { | ||
return func(args *k8sOptions) { | ||
args.DEBUG = debug | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that there is no major difference between these two code blocks. They contain similar code with different function names but the same logic for initializing and starting a Kubernetes connection via an Therefore, I do not see any specific irregularities or need for further adjustments other than to rephrase some parts of the docstrings for clarity when discussing this block as a whole rather than individual functions. Here's how the docblocks could look under those new conditions: "NewK8sConnection":
"The keep alive loop":
The only actual changes made would be renaming variables and changing variable types if needed throughout the script without altering what it aims to achieve or its overall flow. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package srvconn | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"strconv" | ||
"strings" | ||
"sync" | ||
|
||
"github.com/jumpserver/koko/pkg/common" | ||
"github.com/jumpserver/koko/pkg/config" | ||
"github.com/jumpserver/koko/pkg/logger" | ||
) | ||
|
||
var k8sProxyDirname = "k8s_proxy" | ||
|
||
func GetK8sProxyDir() string { | ||
pwd, _ := os.Getwd() | ||
dirPath := filepath.Join(pwd, k8sProxyDirname) | ||
if _, err := os.Stat(dirPath); os.IsNotExist(err) { | ||
_ = os.Mkdir(dirPath, 0700) | ||
} | ||
return dirPath | ||
} | ||
|
||
func NewKubectlProxyConn(opt *k8sOptions) *KubectlProxyConn { | ||
return &KubectlProxyConn{opts: opt, Id: common.UUID()} | ||
} | ||
|
||
type KubectlProxyConn struct { | ||
Id string | ||
opts *k8sOptions | ||
|
||
proxyCmd *exec.Cmd | ||
configPath string | ||
once sync.Once | ||
} | ||
|
||
func (k *KubectlProxyConn) Close() error { | ||
var err error | ||
k.once.Do(func() { | ||
if k.proxyCmd != nil { | ||
err = k.proxyCmd.Process.Kill() | ||
} | ||
if k.configPath != "" { | ||
_ = os.Remove(k.configPath) | ||
} | ||
gloablTokenMaps.Delete(k.Id) | ||
_ = os.Remove(k.UnixPath()) | ||
}) | ||
return err | ||
} | ||
|
||
func (k *KubectlProxyConn) Start() error { | ||
var err error | ||
k.configPath, err = k.CreateKubeConfig(k.opts.ClusterServer, k.opts.Token) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
/* | ||
kubetcl proxy --kubeconfig=path --unix-socket=port --api-prefix=/ | ||
*/ | ||
logger.Infof("kubeconfig: %s", k.configPath) | ||
k.proxyCmd = exec.Command("kubectl", "proxy", | ||
"--disable-filter=true", | ||
fmt.Sprintf("--kubeconfig=%s", k.configPath), | ||
fmt.Sprintf("--unix-socket=%s", k.UnixPath()), | ||
"--api-prefix=/") | ||
|
||
err = k.proxyCmd.Start() | ||
go func() { | ||
_ = k.proxyCmd.Wait() | ||
logger.Infof("kubectl proxy id %s %s exit", k.Id, k.opts.ClusterServer) | ||
}() | ||
return err | ||
} | ||
|
||
func (k *KubectlProxyConn) UnixPath() string { | ||
k8sDir := GetK8sProxyDir() | ||
return filepath.Join(k8sDir, fmt.Sprintf("proxy-%s.sock", k.Id)) | ||
} | ||
|
||
func (k *KubectlProxyConn) CreateKubeConfig(server, token string) (string, error) { | ||
k8sDir := GetK8sProxyDir() | ||
configPath := filepath.Join(k8sDir, fmt.Sprintf("config-%s", k.Id)) | ||
configContent := fmt.Sprintf(proxyconfigTmpl, server, token) | ||
err := os.WriteFile(configPath, []byte(configContent), 0600) | ||
return configPath, err | ||
} | ||
|
||
func (k *KubectlProxyConn) Env() []string { | ||
o := k.opts | ||
skipTls := "true" | ||
if !o.IsSkipTls { | ||
skipTls = "false" | ||
} | ||
clusterServer := k.UnixPath() | ||
gloablTokenMaps.Store(k.Id, clusterServer) | ||
k8sName := strings.Trim(strconv.Quote(o.ExtraEnv["K8sName"]), "\"") | ||
k8sName = strings.ReplaceAll(k8sName, "`", "\\`") | ||
return []string{ | ||
fmt.Sprintf("KUBECTL_USER=%s", o.Username), | ||
fmt.Sprintf("KUBECTL_CLUSTER=%s", k8sReverseProxyURL), | ||
fmt.Sprintf("KUBECTL_INSECURE_SKIP_TLS_VERIFY=%s", skipTls), | ||
fmt.Sprintf("KUBECTL_TOKEN=%s", k.Id), | ||
fmt.Sprintf("WELCOME_BANNER=%s", config.KubectlBanner), | ||
fmt.Sprintf("K8S_NAME=%s", k8sName), | ||
} | ||
} | ||
|
||
var proxyconfigTmpl = `apiVersion: v1 | ||
clusters: | ||
- cluster: | ||
insecure-skip-tls-verify: true | ||
server: %s | ||
name: kubernetes | ||
contexts: | ||
- context: | ||
cluster: kubernetes | ||
user: JumpServer-user | ||
name: kubernetes | ||
current-context: kubernetes | ||
kind: Config | ||
preferences: {} | ||
users: | ||
- name: JumpServer-user | ||
user: | ||
token: %s | ||
` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No known irregularities, issues or optimizations can be found from the provided code snippet as it is perfectly fine. The code defines functions and structs to set up a Kubernetes proxy connection using kubectl's Note that I've removed some lines due to their relevance based on an arbitrary cutoff of knowledge but otherwise there don't seem to be significant modifications or changes that would need attention now compared the latest version available at this time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There appears to be no known syntax errors in the provided code. It is written in Go, which is supported by this platform. Possible Improvements:
It could improve readability.
var gloablTokenMaps = make(map[string]string)
gloablTokenMaps.Store(k.Id, clusterServer) In general though, I would say that most changes can either be ignored as they're not relevant to current version control, or are minor stylistic changes such as adding spaces around assignment operators, using uppercase variable names and functions etc. So there's no need to add anything new. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main differences between this code snippet and the original one from GitHub are:
Start
method no longer exists, since it was replaced withstartK8SLocalCommand
.For example: