Skip to content

Commit

Permalink
Merge remote-tracking branch 'github-bk-bcs/master'
Browse files Browse the repository at this point in the history
* github-bk-bcs/master:
  bcs-webconsole持久化历史命令行 (#2679)
  fix:修复部分空间样式和交互问题 (#2705)
  optimize: 服务导入模板时选择的模版版本按创建时间逆向排序 (#2702)
  • Loading branch information
wenxinlee2015 committed Oct 25, 2023
2 parents 17f2432 + 3df0e1f commit 66b6357
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 25 deletions.
4 changes: 2 additions & 2 deletions bcs-services/bcs-bscp/pkg/dal/dao/template_revision.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,15 @@ func (dao *templateRevisionDao) ListByTemplateIDs(kit *kit.Kit, bizID uint32, te
[]*table.TemplateRevision, error) {
m := dao.genQ.TemplateRevision
q := dao.genQ.TemplateRevision.WithContext(kit.Ctx)
return q.Where(m.BizID.Eq(bizID), m.TemplateID.In(templateIDs...)).Find()
return q.Where(m.BizID.Eq(bizID), m.TemplateID.In(templateIDs...)).Order(m.ID.Desc()).Find()
}

// ListByTemplateIDsWithTx list template revisions by template ids with transaction.
func (dao *templateRevisionDao) ListByTemplateIDsWithTx(
kit *kit.Kit, tx *gen.QueryTx, bizID uint32, templateIDs []uint32) ([]*table.TemplateRevision, error) {
m := tx.TemplateRevision
q := tx.TemplateRevision.WithContext(kit.Ctx)
return q.Where(m.BizID.Eq(bizID), m.TemplateID.In(templateIDs...)).Find()
return q.Where(m.BizID.Eq(bizID), m.TemplateID.In(templateIDs...)).Order(m.ID.Desc()).Find()
}

// DeleteForTmplWithTx delete template revision for one template with transaction.
Expand Down
2 changes: 1 addition & 1 deletion bcs-services/bcs-bscp/ui/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const routes = [
const { spaceList } = useGlobalStore();
const firstHasPermSpace = spaceList.find((item: ISpaceDetail) => item.permission);
const spaceId = firstHasPermSpace ? firstHasPermSpace.space_id : spaceList[0]?.space_id;
return { name: 'service-mine', params: { spaceId } };
return { name: 'service-all', params: { spaceId } };
},
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -713,4 +713,10 @@ const goToIAM = () => {
display: none;
}
}
.delete-service-dialog {
.bk-modal-footer {
background-color: #fff !important;
border-top: none !important;
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
</bk-form-item>
<bk-form-item class="radio-group-form" label="分组规则" required property="rules">
<div v-for="(rule, index) in formData.rules" class="rule-config" :key="index">
<bk-input v-model="rule.key" style="width: 176px" placeholder="" @change="ruleChange"></bk-input>
<bk-input v-model="rule.key" style="width: 174px" placeholder="" @change="ruleChange"></bk-input>
<bk-select
:model-value="rule.op"
style="width: 120px"
style="width: 72px"
:clearable="false"
@change="handleLogicChange(index, $event)"
>
Expand Down Expand Up @@ -271,7 +271,7 @@ defineExpose({
cursor: pointer;
}
.value-input {
width: 250px;
width: 280px;
}
}
.action-btns {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,20 @@
</bk-form-item>
<bk-form-item class="fixed-width-form" property="tag" label="分类标签">
<!-- <bk-input v-model="formData.tag" /> -->
<bk-select
v-model="formData.tag"
<bk-tag-input
v-model="selectTags"
placeholder="请选择标签或输入新标签按Enter结束"
:loading="tagsLoading"
display-key="tag"
save-key="tag"
search-key="tag"
:max-data="1"
:list="tagsData"
:allow-create="true"
:filterable="true"
>
<bk-option
v-for="option in tagsData"
:key="option.tag"
:value="option.tag"
:label="option.tag"
></bk-option>
</bk-select>
trigger="focus"
/>
</bk-form-item>
<bk-form-item class="fixed-width-form" property="memo" label="脚本描述">
<bk-input v-model="formData.memo" type="textarea" :rows="3" :maxlength="200" :resize="false"/>
<bk-input v-model="formData.memo" type="textarea" :rows="3" :maxlength="200" :resize="false" />
</bk-form-item>
<bk-form-item label="脚本内容" property="content" required>
<div class="script-content-wrapper">
Expand Down Expand Up @@ -74,17 +71,18 @@ const SCRIPT_TYPE = [
{ id: EScriptType.Python, name: 'Python' },
];
const formRef = ref();
const pending = ref(false);
const tagsLoading = ref(false);
const tagsData = ref<IScriptTagItem[]>([]);
const selectTags = ref<string[]>([]);
const formData = ref<IScriptEditingForm>({
name: '',
tag: '',
memo: '',
type: EScriptType.Shell,
content: '',
});
const formRef = ref();
const pending = ref(false);
const tagsLoading = ref(false);
const tagsData = ref<IScriptTagItem[]>([]);
onMounted(() => {
getTags();
Expand All @@ -102,6 +100,7 @@ const handleCreate = async () => {
await formRef.value.validate();
try {
pending.value = true;
formData.value.tag = selectTags.value[0];
await createScript(spaceId.value, formData.value);
BkMessage({
theme: 'success',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ const rules = {
message: '文件权限 不能为空',
trigger: 'change',
},
{
validator: () => {
const privilege = parseInt(privilegeInputVal.value[0]);
return privilege >= 4;
},
message: '文件own必须有读取权限',
trigger: 'blur',
},
],
path: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const handleValidateEditor = () => {
errorInfo: '请检查是否已正确使用分隔符',
lineNumber: index + 1,
});
} else if (!key.startsWith('bk_bscp_')) {
} else if (!key.startsWith('bk_bscp_') && !key.startsWith('BK_BSCP_')) {
errorLine.value.push({
errorInfo: '变量必须以bk_bscp_开头',
lineNumber: index + 1,
Expand All @@ -134,7 +134,7 @@ const handleValidateEditor = () => {
errorInfo: '类型必须为 string 或者 number',
lineNumber: index + 1,
});
} else if (type === 'number' && !/^\d+$/.test(value)) {
} else if (type === 'number' && !/^\d+(\.\d+)?$/.test(value)) {
errorLine.value.push({
errorInfo: '类型为number 值不为number',
lineNumber: index + 1,
Expand Down
63 changes: 63 additions & 0 deletions bcs-services/bcs-webconsole/console/api/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,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 @@ -138,6 +139,12 @@ func (s *service) CreateWebConsoleSession(c *gin.Context) {
return
}

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

podCtx.ProjectId = authCtx.ProjectId
podCtx.Username = authCtx.Username
podCtx.Source = consoleQuery.Source
Expand Down Expand Up @@ -546,3 +553,59 @@ func makeWebSocketURL(sessionId, lang string, withScheme bool) string {
func (s *service) CreateClusterPortalSession(c *gin.Context) {
rest.APIError(c, "Not implemented")
}

// getBashHistory直接读取存储在远程repo中的文件
func getBashHistory(podName string) ([]byte, error) {
filename := podName + podmanager.HistoryFileName

// 使用系统对象存储
storage, err := repository.NewProvider(config.G.Repository.StorageType)
if err != nil {
return nil, err
}

// 5秒下载时间
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()

// 下载对象储存文件
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
}
61 changes: 61 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
}

// 命令行持久化保存
if errCommand := persistenceCommand(
k8sClient, pod.Name, pod.Namespace, pod.Spec.Containers[0].Name, clusterId); 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,56 @@ 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

// 上传远程repo对象存储
storage, err := repository.NewProvider(config.G.Repository.StorageType)
if err != nil {
return err
}

// 10秒上传超时时间
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()

// 推送至远程repo对象存储
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)
blog.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 66b6357

Please sign in to comment.