From 71d6c03ca7e8eac9d7fa2792287ca5760d178f7e Mon Sep 17 00:00:00 2001 From: Anbraten Date: Mon, 30 Jan 2023 20:18:48 +0100 Subject: [PATCH] Add agent no-schedule flag (#1567) This flag allows an agent owner / admin to stop the agent from taking new workflows / pipelines. --- server/api/agent.go | 6 ++++-- server/grpc/rpc.go | 8 ++++++++ server/model/agent.go | 1 + web/components.d.ts | 18 +----------------- web/src/assets/locales/en.json | 4 ++++ .../admin/settings/AdminAgentsTab.vue | 9 +++++++++ web/src/lib/api/types/agent.ts | 1 + 7 files changed, 28 insertions(+), 19 deletions(-) diff --git a/server/api/agent.go b/server/api/agent.go index c798b0f48..c1d3baa52 100644 --- a/server/api/agent.go +++ b/server/api/agent.go @@ -73,6 +73,7 @@ func PatchAgent(c *gin.Context) { return } agent.Name = in.Name + agent.NoSchedule = in.NoSchedule err = _store.AgentUpdate(agent) if err != nil { @@ -95,8 +96,9 @@ func PostAgent(c *gin.Context) { user := session.User(c) agent := &model.Agent{ - Name: in.Name, - OwnerID: user.ID, + Name: in.Name, + NoSchedule: in.NoSchedule, + OwnerID: user.ID, Token: base32.StdEncoding.EncodeToString( securecookie.GenerateRandomKey(32), ), diff --git a/server/grpc/rpc.go b/server/grpc/rpc.go index 2405a0c3b..e14c8ced7 100644 --- a/server/grpc/rpc.go +++ b/server/grpc/rpc.go @@ -70,6 +70,13 @@ func (s *RPC) Next(c context.Context, agentFilter rpc.Filter) (*rpc.Pipeline, er return nil, err } for { + agent, err := s.getAgentFromContext(c) + if err != nil { + return nil, err + } else if agent.NoSchedule { + return nil, nil + } + task, err := s.queue.Poll(c, fn) if err != nil { return nil, err @@ -82,6 +89,7 @@ func (s *RPC) Next(c context.Context, agentFilter rpc.Filter) (*rpc.Pipeline, er err = json.Unmarshal(task.Data, pipeline) return pipeline, err } + if err := s.Done(c, task.ID, rpc.State{}); err != nil { log.Error().Err(err).Msgf("mark task '%s' done failed", task.ID) } diff --git a/server/model/agent.go b/server/model/agent.go index 594b309b3..9ee3a1ad0 100644 --- a/server/model/agent.go +++ b/server/model/agent.go @@ -26,6 +26,7 @@ type Agent struct { Backend string `json:"backend" xorm:"VARCHAR(100)"` Capacity int32 `json:"capacity"` Version string `json:"version"` + NoSchedule bool `json:"no_schedule"` } // TableName return database table name for xorm diff --git a/web/components.d.ts b/web/components.d.ts index 8a8bd2f2f..375836573 100644 --- a/web/components.d.ts +++ b/web/components.d.ts @@ -21,10 +21,8 @@ declare module '@vue/runtime-core' { FluidContainer: typeof import('./src/components/layout/FluidContainer.vue')['default'] GeneralTab: typeof import('./src/components/repo/settings/GeneralTab.vue')['default'] Header: typeof import('./src/components/layout/scaffold/Header.vue')['default'] - IBiCheckCircle: typeof import('~icons/bi/check-circle')['default'] IBiCheckCircleFill: typeof import('~icons/bi/check-circle-fill')['default'] IBiCircle: typeof import('~icons/bi/circle')['default'] - IBiPauseCircleFill: typeof import('~icons/bi/pause-circle-fill')['default'] IBiPlayCircleFill: typeof import('~icons/bi/play-circle-fill')['default'] IBiSlashCircleFill: typeof import('~icons/bi/slash-circle-fill')['default'] IBiStopCircleFill: typeof import('~icons/bi/stop-circle-fill')['default'] @@ -33,13 +31,9 @@ declare module '@vue/runtime-core' { ICarbonCloseOutline: typeof import('~icons/carbon/close-outline')['default'] ICarbonInProgress: typeof import('~icons/carbon/in-progress')['default'] IClarityDeployLine: typeof import('~icons/clarity/deploy-line')['default'] - IClarityNoAccessSolid: typeof import('~icons/clarity/no-access-solid')['default'] IClaritySettingsSolid: typeof import('~icons/clarity/settings-solid')['default'] - IClaritySuccessStandardSolid: typeof import('~icons/clarity/success-standard-solid')['default'] - IClarityTimesCircleSolid: typeof import('~icons/clarity/times-circle-solid')['default'] Icon: typeof import('./src/components/atomic/Icon.vue')['default'] IconButton: typeof import('./src/components/atomic/IconButton.vue')['default'] - IEntypoDotsTwoVertical: typeof import('~icons/entypo/dots-two-vertical')['default'] IGgTrash: typeof import('~icons/gg/trash')['default'] IIcBaselineDarkMode: typeof import('~icons/ic/baseline-dark-mode')['default'] IIcBaselineDownloadForOffline: typeof import('~icons/ic/baseline-download-for-offline')['default'] @@ -67,24 +61,14 @@ declare module '@vue/runtime-core' { IMdiSync: typeof import('~icons/mdi/sync')['default'] IMdiTagOutline: typeof import('~icons/mdi/tag-outline')['default'] InputField: typeof import('./src/components/form/InputField.vue')['default'] - IOcticonSkip24: typeof import('~icons/octicon/skip24')['default'] - IPhCheckCircle: typeof import('~icons/ph/check-circle')['default'] IPhGitlabLogoSimpleFill: typeof import('~icons/ph/gitlab-logo-simple-fill')['default'] - IPhHand: typeof import('~icons/ph/hand')['default'] - IPhHourglass: typeof import('~icons/ph/hourglass')['default'] - IPhProhibit: typeof import('~icons/ph/prohibit')['default'] - IPhWarning: typeof import('~icons/ph/warning')['default'] - IPhXCircle: typeof import('~icons/ph/x-circle')['default'] ISimpleIconsGitea: typeof import('~icons/simple-icons/gitea')['default'] ITeenyiconsGitSolid: typeof import('~icons/teenyicons/git-solid')['default'] - IUiwCircleCheck: typeof import('~icons/uiw/circle-check')['default'] - IUiwCircleClose: typeof import('~icons/uiw/circle-close')['default'] - IUiwStop: typeof import('~icons/uiw/stop')['default'] + ITeenyiconsRefreshOutline: typeof import('~icons/teenyicons/refresh-outline')['default'] IVaadinQuestionCircleO: typeof import('~icons/vaadin/question-circle-o')['default'] ListItem: typeof import('./src/components/atomic/ListItem.vue')['default'] ManualPipelinePopup: typeof import('./src/components/layout/popups/ManualPipelinePopup.vue')['default'] Navbar: typeof import('./src/components/layout/header/Navbar.vue')['default'] - NavbarIcon: typeof import('./src/components/layout/header/NavbarIcon.vue')['default'] NumberField: typeof import('./src/components/form/NumberField.vue')['default'] OrgSecretsTab: typeof import('./src/components/org/settings/OrgSecretsTab.vue')['default'] Panel: typeof import('./src/components/layout/Panel.vue')['default'] diff --git a/web/src/assets/locales/en.json b/web/src/assets/locales/en.json index 529a43df2..974537171 100644 --- a/web/src/assets/locales/en.json +++ b/web/src/assets/locales/en.json @@ -336,6 +336,10 @@ "name": "Name", "placeholder": "Name of the agent" }, + "no_schedule": { + "name": "Disable agent", + "placeholder": "Stop agent from taking new tasks" + }, "token": "Token", "platform": "Platform", "backend": "Backend", diff --git a/web/src/components/admin/settings/AdminAgentsTab.vue b/web/src/components/admin/settings/AdminAgentsTab.vue index ab9348769..a3f5ff364 100644 --- a/web/src/components/admin/settings/AdminAgentsTab.vue +++ b/web/src/components/admin/settings/AdminAgentsTab.vue @@ -43,6 +43,14 @@ /> + + + +