Skip to content

Commit

Permalink
bcs-webconsole持久化历史命令行
Browse files Browse the repository at this point in the history
  • Loading branch information
LidolLxf committed Oct 20, 2023
1 parent d30829b commit 2520726
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 0 deletions.
65 changes: 65 additions & 0 deletions bcs-services/bcs-webconsole/console/api/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/i18n"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/metrics"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/podmanager"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/repository"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/rest"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/sessions"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/tracing"
Expand Down Expand Up @@ -147,6 +148,14 @@ func (s *service) CreateWebConsoleSession(c *gin.Context) {
return
}

// 创建.bash_history文件
go func(podCtx *types.PodContext) {
errCreate := CreateBashHistory(podCtx)
if errCreate != nil {
logger.Warnf("create bash history fail: %s", errCreate.Error())
}
}(podCtx)

podCtx.ProjectId = authCtx.ProjectId
podCtx.Username = authCtx.Username
podCtx.Source = consoleQuery.Source
Expand Down Expand Up @@ -610,3 +619,59 @@ func APIError(c *gin.Context, msg string) { // nolint

c.AbortWithStatusJSON(http.StatusBadRequest, data)
}

// getBashHistory将文件放在本地 historyLocalDir
func getBashHistory(podName string) ([]byte, error) {
filename := podName + podmanager.HistoryFileName

// 使用cos存储的文件
storage, err := repository.NewProvider(config.G.Repository.StorageType)
if err != nil {
return nil, err
}

// 10 分钟下载时间
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*10)
defer cancel()

// 下载cos文件
fileInput, err := storage.DownloadFile(ctx, podmanager.HistoryRepoDir+filename)
if err != nil {
return nil, err
}

// 读取.bash_history内容byte格式
output, err := io.ReadAll(fileInput)
if err != nil {
return nil, err
}

return output, nil
}

// CreateBashHistory 创建.bash_history文件
func CreateBashHistory(podCtx *types.PodContext) error {
// 往容器写文件
pe, err := podCtx.NewPodExec()
if err != nil {
return err
}
pe.Command = []string{"cp", "/dev/stdin", "/root/.bash_history"}
stdin := &bytes.Buffer{}
pe.Stderr = &bytes.Buffer{}
// 读取保存的.bash_history文件
historyFileByte, err := getBashHistory(podCtx.PodName)
if err != nil {
return err
}
_, err = stdin.Write(historyFileByte)
if err != nil {
return err
}
pe.Stdin = stdin
err = pe.Exec()
if err != nil {
return err
}
return nil
}
59 changes: 59 additions & 0 deletions bcs-services/bcs-webconsole/console/podmanager/cleanup.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package podmanager

import (
"bytes"
"context"
"fmt"
"strconv"
Expand All @@ -23,10 +24,14 @@ import (
"github.com/go-redis/redis/v8"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/tools/remotecommand"

"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/components/k8sclient"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/config"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/metrics"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/repository"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/sessions"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/storage"
"github.com/Tencent/bk-bcs/bcs-services/bcs-webconsole/console/types"
Expand Down Expand Up @@ -164,6 +169,12 @@ func (p *CleanUpManager) cleanUserPodByCluster(clusterId string, namespace strin
continue
}

// 命令行持久化保存
errCommand := persistenceCommand(k8sClient, pod.Name, pod.Namespace, pod.Spec.Containers[0].Name, clusterId)
if errCommand != nil {
logger.Errorf("persistenceCommand, err: %s", errCommand)
}

// 删除pod
if err := k8sClient.CoreV1().Pods(namespace).Delete(p.ctx, pod.Name, metav1.DeleteOptions{}); err != nil {
logger.Errorf("delete pod(%s) failed, err: %s", pod.Name, err)
Expand All @@ -176,6 +187,54 @@ func (p *CleanUpManager) cleanUserPodByCluster(clusterId string, namespace strin
return nil
}

// persistenceCommand 命令行持久化保存
func persistenceCommand(k8sClient *kubernetes.Clientset, podName, namespace, containerName, clusterId string) error {
req := k8sClient.CoreV1().RESTClient().Post().Resource("pods").Name(podName).Namespace(namespace).
SubResource("exec")

req.VersionedParams(&v1.PodExecOptions{
Command: []string{"/bin/bash", "-c", "cat /root/.bash_history"},
Container: containerName,
Stdin: false,
Stdout: true,
Stderr: true, // kubectl 默认 stderr 未设置, virtual-kubelet 节点 stderr 和 tty 不能同时为 true
TTY: false,
}, scheme.ParameterCodec)

k8sConfig := k8sclient.GetK8SConfigByClusterId(clusterId)
executor, err := remotecommand.NewSPDYExecutor(k8sConfig, "POST", req.URL())
if err != nil {
return err
}

stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
err = executor.Stream(remotecommand.StreamOptions{
Stdout: stdout,
Stderr: stderr,
})
if err != nil {
return err
}

// 文件名
filename := podName + HistoryFileName

// 上传cos
storage, err := repository.NewProvider(config.G.Repository.StorageType)
if err != nil {
return err
}

ctx := context.Background()

// 推送至cos存储桶
err = storage.UploadFileByReader(ctx, stdout, HistoryRepoDir+filename)
if err != nil {
return err
}
return nil
}

// cleanConfigMap 清理configmap
func (p *CleanUpManager) cleanConfigMap(clusterId string, namespace string, alivePodMap map[string]struct{}) error {
k8sClient, err := k8sclient.GetK8SClientByClusterId(clusterId)
Expand Down
5 changes: 5 additions & 0 deletions bcs-services/bcs-webconsole/console/podmanager/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,9 @@ const (
// UserCtxExpireTime Context 过期时间, 12个小时
UserCtxExpireTime = 3600 * 12
clusterExpireSeconds = 3600 * 24 * 7

// HistoryFileName .bash_history文件结尾
HistoryFileName = "-history.txt"
// HistoryRepoDir .bash_history repo远程存放的目录
HistoryRepoDir = "/bash-history/latest/"
)
25 changes: 25 additions & 0 deletions bcs-services/bcs-webconsole/console/repository/bkrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,31 @@ func (b *bkrepoStorage) UploadFile(ctx context.Context, localFile, filePath stri
return nil
}

// UploadFileByReader upload file to bkRepo by Reader
func (b *bkrepoStorage) UploadFileByReader(ctx context.Context, r io.Reader, filePath string) error {
// 上传文件API PUT /generic/{project}/{repoName}/{fullPath}
rawURL := fmt.Sprintf("%s/generic/%s/%s/%s", config.G.Repository.Bkrepo.Endpoint,
config.G.Repository.Bkrepo.Project, config.G.Repository.Bkrepo.Repo, filePath)

req, err := http.NewRequestWithContext(ctx, http.MethodPut, rawURL, r)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/octet-stream")
req.Header.Set("X-BKREPO-OVERWRITE", "true")

resp, err := b.client.Do(req)
if err != nil {
return err
}
if resp.StatusCode != 200 {
body, _ := io.ReadAll(resp.Body)
klog.Errorf("Upload file failed, resp: %s\n", string(body))
return fmt.Errorf("upload file failed, Err code: %v", resp.StatusCode)
}
return nil
}

// IsExist 是否存在
func (b *bkrepoStorage) IsExist(ctx context.Context, filePath string) (bool, error) {
rawURL := fmt.Sprintf("%s/generic/%s/%s%s", config.G.Repository.Bkrepo.Endpoint,
Expand Down
10 changes: 10 additions & 0 deletions bcs-services/bcs-webconsole/console/repository/cos.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ func (c *cosStorage) UploadFile(ctx context.Context, localFile, filePath string)
return nil
}

// UploadFileByReader upload file to cos by Reader
func (c *cosStorage) UploadFileByReader(ctx context.Context, r io.Reader, filePath string) error {
_, err := c.client.Object.Put(ctx, filePath, r, nil)
if err != nil {
return fmt.Errorf("upload file failed: %v", err)
}

return nil
}

// ListFile list current folder files
func (c *cosStorage) ListFile(ctx context.Context, folderName string) ([]string, error) {
var marker string
Expand Down
1 change: 1 addition & 0 deletions bcs-services/bcs-webconsole/console/repository/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
// Provider 对象存储接口
type Provider interface {
UploadFile(ctx context.Context, localFile, filePath string) error
UploadFileByReader(ctx context.Context, r io.Reader, filePath string) error
ListFile(ctx context.Context, folderName string) ([]string, error)
ListFolders(ctx context.Context, folderName string) ([]string, error)
IsExist(ctx context.Context, filePath string) (bool, error)
Expand Down

0 comments on commit 2520726

Please sign in to comment.