From 9f0338382fa6754a57c3480fb9ed7db2c6c75bcf Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:46:58 +0800 Subject: [PATCH] feat: Script within the container support the selection of users (#9170) Refs #8766 --- agent/app/api/v2/container.go | 23 +++++++++++++ agent/app/service/container.go | 17 ++++++++++ agent/app/service/cronjob_helper.go | 12 ++++++- agent/router/ro_container.go | 2 ++ frontend/src/api/modules/container.ts | 3 ++ .../views/cronjob/cronjob/operate/index.vue | 34 +++++++++++++------ 6 files changed, 80 insertions(+), 11 deletions(-) diff --git a/agent/app/api/v2/container.go b/agent/app/api/v2/container.go index 5d554c2f8..f8e4953b6 100644 --- a/agent/app/api/v2/container.go +++ b/agent/app/api/v2/container.go @@ -35,6 +35,29 @@ func (b *BaseApi) SearchContainer(c *gin.Context) { }) } +// @Tags Container +// @Summary Load container users +// @Accept json +// @Param request body dto.OperationWithName true "request" +// @Produce json +// @Success 200 {array} string +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /containers/users [post] +func (b *BaseApi) LoadContainerUsers(c *gin.Context) { + var req dto.OperationWithName + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + + list, err := containerService.LoadUsers(req) + if err != nil { + helper.InternalServer(c, err) + return + } + helper.SuccessWithData(c, list) +} + // @Tags Container // @Summary List containers // @Accept json diff --git a/agent/app/service/container.go b/agent/app/service/container.go index d9c142d45..dbc489478 100644 --- a/agent/app/service/container.go +++ b/agent/app/service/container.go @@ -83,6 +83,8 @@ type IContainerService interface { ComposeUpdate(req dto.ComposeUpdate) error Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error) + LoadUsers(req dto.OperationWithName) ([]string, error) + StreamLogs(ctx *gin.Context, params dto.StreamLog) } @@ -1083,6 +1085,21 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error return &data, nil } +func (u *ContainerService) LoadUsers(req dto.OperationWithName) ([]string, error) { + std, err := cmd.RunDefaultWithStdoutBashCf("docker exec %s cat /etc/passwd", req.Name) + if err != nil { + return nil, err + } + var users []string + lines := strings.Split(string(std), "\n") + for _, line := range lines { + if strings.Contains(line, ":") { + users = append(users, strings.Split(line, ":")[0]) + } + } + return users, nil +} + func stringsToMap(list []string) map[string]string { var labelMap = make(map[string]string) for _, label := range list { diff --git a/agent/app/service/cronjob_helper.go b/agent/app/service/cronjob_helper.go index 913faa190..c8540ca3f 100644 --- a/agent/app/service/cronjob_helper.go +++ b/agent/app/service/cronjob_helper.go @@ -118,11 +118,21 @@ func (u *CronjobService) handleShell(cronjob model.Cronjob, taskItem *task.Task) cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*taskItem)) taskItem.AddSubTaskWithOps(i18n.GetWithName("HandleShell", cronjob.Name), func(t *task.Task) error { if len(cronjob.ContainerName) != 0 { + scriptItem := cronjob.Script + if cronjob.ScriptMode == "select" { + scriptItem = path.Join("/tmp", path.Base(cronjob.Script)) + if err := cmdMgr.Run("docker", "cp", cronjob.Script, cronjob.ContainerName+":"+scriptItem); err != nil { + return err + } + } command := "sh" if len(cronjob.Command) != 0 { command = cronjob.Command } - return cmdMgr.Run("docker", "exec", cronjob.ContainerName, command, "-c", strings.ReplaceAll(cronjob.Script, "\"", "\\\"")) + if len(cronjob.User) != 0 { + return cmdMgr.Run("docker", "exec", "-u", cronjob.User, cronjob.ContainerName, command, "-c", strings.ReplaceAll(scriptItem, "\"", "\\\"")) + } + return cmdMgr.Run("docker", "exec", cronjob.ContainerName, command, "-c", strings.ReplaceAll(scriptItem, "\"", "\\\"")) } if len(cronjob.Executor) == 0 { cronjob.Executor = "bash" diff --git a/agent/router/ro_container.go b/agent/router/ro_container.go index dbd4f9e60..cc8821bc2 100644 --- a/agent/router/ro_container.go +++ b/agent/router/ro_container.go @@ -33,6 +33,8 @@ func (s *ContainerRouter) InitRouter(Router *gin.RouterGroup) { baRouter.POST("/operate", baseApi.ContainerOperation) baRouter.POST("/prune", baseApi.ContainerPrune) + baRouter.POST("/users", baseApi.LoadContainerUsers) + baRouter.GET("/repo", baseApi.ListRepo) baRouter.POST("/repo/status", baseApi.CheckRepoStatus) baRouter.POST("/repo/search", baseApi.SearchRepo) diff --git a/frontend/src/api/modules/container.ts b/frontend/src/api/modules/container.ts index 9c7983a63..f5e25b95a 100644 --- a/frontend/src/api/modules/container.ts +++ b/frontend/src/api/modules/container.ts @@ -9,6 +9,9 @@ export const searchContainer = (params: Container.ContainerSearch) => { export const listContainer = () => { return http.post>(`/containers/list`, {}); }; +export const loadContainerUsers = (name: string) => { + return http.post>(`/containers/users`, { name: name }); +}; export const loadContainerStatus = () => { return http.get(`/containers/status`); }; diff --git a/frontend/src/views/cronjob/cronjob/operate/index.vue b/frontend/src/views/cronjob/cronjob/operate/index.vue index c00576cd0..4a7e9995d 100644 --- a/frontend/src/views/cronjob/cronjob/operate/index.vue +++ b/frontend/src/views/cronjob/cronjob/operate/index.vue @@ -343,7 +343,7 @@ - + {{ $t('cronjob.containerCheckBox') }} @@ -351,7 +351,10 @@ - + @@ -390,7 +393,7 @@ - + @@ -400,7 +403,7 @@ - + {{ $t('container.custom') }} @@ -693,6 +696,7 @@ import { weekOptions, } from '../helper'; import { loadUsers } from '@/api/modules/toolbox'; +import { loadContainerUsers } from '@/api/modules/container'; import { storeToRefs } from 'pinia'; import { GlobalStore } from '@/store'; import LicenseImport from '@/components/license-import/index.vue'; @@ -784,13 +788,13 @@ const search = async () => { form.scriptMode = res.data.scriptMode; form.containerName = res.data.containerName; + form.user = res.data.user; if (form.containerName.length !== 0) { form.inContainer = true; form.command = res.data.command || 'sh'; form.isCustom = form.command !== 'sh' && form.command !== 'bash' && form.command !== 'ash'; } else { form.executor = res.data.executor || 'bash'; - form.user = res.data.user; form.isCustom = form.executor !== 'sh' && form.executor !== 'bash' && @@ -846,7 +850,7 @@ const search = async () => { } loadBackups(); loadAppInstalls(); - loadShellUsers(); + loadUserOptions(true); loadWebsites(); loadContainers(); loadScripts(); @@ -1205,9 +1209,19 @@ const changeAccount = async () => { } }; -const loadShellUsers = async () => { - const res = await loadUsers(); - userOptions.value = res.data || []; +const loadUserOptions = async (isInit: boolean) => { + if (!form.inContainer) { + const res = await loadUsers(); + userOptions.value = res.data || []; + } else { + if (!isInit) { + form.user = ''; + } + if (form.containerName) { + const res = await loadContainerUsers(form.containerName); + userOptions.value = res.data || []; + } + } }; const loadAppInstalls = async () => {