Skip to content

Commit 9f03383

Browse files
authored
feat: Script within the container support the selection of users (#9170)
Refs #8766
1 parent 692c77e commit 9f03383

File tree

6 files changed

+80
-11
lines changed

6 files changed

+80
-11
lines changed

agent/app/api/v2/container.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,29 @@ func (b *BaseApi) SearchContainer(c *gin.Context) {
3535
})
3636
}
3737

38+
// @Tags Container
39+
// @Summary Load container users
40+
// @Accept json
41+
// @Param request body dto.OperationWithName true "request"
42+
// @Produce json
43+
// @Success 200 {array} string
44+
// @Security ApiKeyAuth
45+
// @Security Timestamp
46+
// @Router /containers/users [post]
47+
func (b *BaseApi) LoadContainerUsers(c *gin.Context) {
48+
var req dto.OperationWithName
49+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
50+
return
51+
}
52+
53+
list, err := containerService.LoadUsers(req)
54+
if err != nil {
55+
helper.InternalServer(c, err)
56+
return
57+
}
58+
helper.SuccessWithData(c, list)
59+
}
60+
3861
// @Tags Container
3962
// @Summary List containers
4063
// @Accept json

agent/app/service/container.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ type IContainerService interface {
8383
ComposeUpdate(req dto.ComposeUpdate) error
8484
Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error)
8585

86+
LoadUsers(req dto.OperationWithName) ([]string, error)
87+
8688
StreamLogs(ctx *gin.Context, params dto.StreamLog)
8789
}
8890

@@ -1083,6 +1085,21 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
10831085
return &data, nil
10841086
}
10851087

1088+
func (u *ContainerService) LoadUsers(req dto.OperationWithName) ([]string, error) {
1089+
std, err := cmd.RunDefaultWithStdoutBashCf("docker exec %s cat /etc/passwd", req.Name)
1090+
if err != nil {
1091+
return nil, err
1092+
}
1093+
var users []string
1094+
lines := strings.Split(string(std), "\n")
1095+
for _, line := range lines {
1096+
if strings.Contains(line, ":") {
1097+
users = append(users, strings.Split(line, ":")[0])
1098+
}
1099+
}
1100+
return users, nil
1101+
}
1102+
10861103
func stringsToMap(list []string) map[string]string {
10871104
var labelMap = make(map[string]string)
10881105
for _, label := range list {

agent/app/service/cronjob_helper.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,21 @@ func (u *CronjobService) handleShell(cronjob model.Cronjob, taskItem *task.Task)
118118
cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*taskItem))
119119
taskItem.AddSubTaskWithOps(i18n.GetWithName("HandleShell", cronjob.Name), func(t *task.Task) error {
120120
if len(cronjob.ContainerName) != 0 {
121+
scriptItem := cronjob.Script
122+
if cronjob.ScriptMode == "select" {
123+
scriptItem = path.Join("/tmp", path.Base(cronjob.Script))
124+
if err := cmdMgr.Run("docker", "cp", cronjob.Script, cronjob.ContainerName+":"+scriptItem); err != nil {
125+
return err
126+
}
127+
}
121128
command := "sh"
122129
if len(cronjob.Command) != 0 {
123130
command = cronjob.Command
124131
}
125-
return cmdMgr.Run("docker", "exec", cronjob.ContainerName, command, "-c", strings.ReplaceAll(cronjob.Script, "\"", "\\\""))
132+
if len(cronjob.User) != 0 {
133+
return cmdMgr.Run("docker", "exec", "-u", cronjob.User, cronjob.ContainerName, command, "-c", strings.ReplaceAll(scriptItem, "\"", "\\\""))
134+
}
135+
return cmdMgr.Run("docker", "exec", cronjob.ContainerName, command, "-c", strings.ReplaceAll(scriptItem, "\"", "\\\""))
126136
}
127137
if len(cronjob.Executor) == 0 {
128138
cronjob.Executor = "bash"

agent/router/ro_container.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ func (s *ContainerRouter) InitRouter(Router *gin.RouterGroup) {
3333
baRouter.POST("/operate", baseApi.ContainerOperation)
3434
baRouter.POST("/prune", baseApi.ContainerPrune)
3535

36+
baRouter.POST("/users", baseApi.LoadContainerUsers)
37+
3638
baRouter.GET("/repo", baseApi.ListRepo)
3739
baRouter.POST("/repo/status", baseApi.CheckRepoStatus)
3840
baRouter.POST("/repo/search", baseApi.SearchRepo)

frontend/src/api/modules/container.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ export const searchContainer = (params: Container.ContainerSearch) => {
99
export const listContainer = () => {
1010
return http.post<Array<string>>(`/containers/list`, {});
1111
};
12+
export const loadContainerUsers = (name: string) => {
13+
return http.post<Array<string>>(`/containers/users`, { name: name });
14+
};
1215
export const loadContainerStatus = () => {
1316
return http.get<Container.ContainerStatus>(`/containers/status`);
1417
};

frontend/src/views/cronjob/cronjob/operate/index.vue

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -343,15 +343,18 @@
343343
<el-row :gutter="20">
344344
<el-col :span="24" v-if="hasScript()">
345345
<el-form-item>
346-
<el-checkbox v-model="form.inContainer">
346+
<el-checkbox @change="loadUserOptions(false)" v-model="form.inContainer">
347347
{{ $t('cronjob.containerCheckBox') }}
348348
</el-checkbox>
349349
</el-form-item>
350350

351351
<el-row :gutter="20" v-if="form.inContainer">
352352
<LayoutCol>
353353
<el-form-item :label="$t('cronjob.containerName')" prop="containerName">
354-
<el-select v-model="form.containerName">
354+
<el-select
355+
@change="loadUserOptions(false)"
356+
v-model="form.containerName"
357+
>
355358
<el-option
356359
v-for="item in containerOptions"
357360
:key="item"
@@ -363,7 +366,7 @@
363366
</LayoutCol>
364367
<LayoutCol>
365368
<el-form-item
366-
:label="$t('container.command') + 123"
369+
:label="$t('container.command')"
367370
prop="command"
368371
:rules="Rules.requiredInput"
369372
>
@@ -390,7 +393,7 @@
390393
</el-form-item>
391394
</LayoutCol>
392395
</el-row>
393-
<el-row :gutter="20" v-if="!form.inContainer">
396+
<el-row :gutter="20">
394397
<LayoutCol>
395398
<el-form-item :label="$t('commons.table.user')" prop="user">
396399
<el-select filterable v-model="form.user">
@@ -400,7 +403,7 @@
400403
</el-select>
401404
</el-form-item>
402405
</LayoutCol>
403-
<LayoutCol>
406+
<LayoutCol v-if="!form.inContainer">
404407
<el-form-item :label="$t('cronjob.executor')" prop="executor">
405408
<el-checkbox border v-model="form.isCustom">
406409
{{ $t('container.custom') }}
@@ -693,6 +696,7 @@ import {
693696
weekOptions,
694697
} from '../helper';
695698
import { loadUsers } from '@/api/modules/toolbox';
699+
import { loadContainerUsers } from '@/api/modules/container';
696700
import { storeToRefs } from 'pinia';
697701
import { GlobalStore } from '@/store';
698702
import LicenseImport from '@/components/license-import/index.vue';
@@ -784,13 +788,13 @@ const search = async () => {
784788
form.scriptMode = res.data.scriptMode;
785789
786790
form.containerName = res.data.containerName;
791+
form.user = res.data.user;
787792
if (form.containerName.length !== 0) {
788793
form.inContainer = true;
789794
form.command = res.data.command || 'sh';
790795
form.isCustom = form.command !== 'sh' && form.command !== 'bash' && form.command !== 'ash';
791796
} else {
792797
form.executor = res.data.executor || 'bash';
793-
form.user = res.data.user;
794798
form.isCustom =
795799
form.executor !== 'sh' &&
796800
form.executor !== 'bash' &&
@@ -846,7 +850,7 @@ const search = async () => {
846850
}
847851
loadBackups();
848852
loadAppInstalls();
849-
loadShellUsers();
853+
loadUserOptions(true);
850854
loadWebsites();
851855
loadContainers();
852856
loadScripts();
@@ -1205,9 +1209,19 @@ const changeAccount = async () => {
12051209
}
12061210
};
12071211
1208-
const loadShellUsers = async () => {
1209-
const res = await loadUsers();
1210-
userOptions.value = res.data || [];
1212+
const loadUserOptions = async (isInit: boolean) => {
1213+
if (!form.inContainer) {
1214+
const res = await loadUsers();
1215+
userOptions.value = res.data || [];
1216+
} else {
1217+
if (!isInit) {
1218+
form.user = '';
1219+
}
1220+
if (form.containerName) {
1221+
const res = await loadContainerUsers(form.containerName);
1222+
userOptions.value = res.data || [];
1223+
}
1224+
}
12111225
};
12121226
12131227
const loadAppInstalls = async () => {

0 commit comments

Comments
 (0)