mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: implement agent process management (#9461)
- An opt-in feature has been added to the agent to allow deprioritizing non coder-related processes for CPU by setting their niceness level to 10. - Opting in to the feature requires setting CODER_PROC_PRIO_MGMT to a non-empty value.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
// Package agentproctest contains utility functions
|
||||
// for testing process management in the agent.
|
||||
package agentproctest
|
||||
|
||||
//go:generate mockgen -destination ./syscallermock.go -package agentproctest github.com/coder/coder/v2/agent/agentproc Syscaller
|
||||
@@ -0,0 +1,49 @@
|
||||
package agentproctest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/agent/agentproc"
|
||||
"github.com/coder/coder/v2/cryptorand"
|
||||
)
|
||||
|
||||
func GenerateProcess(t *testing.T, fs afero.Fs, muts ...func(*agentproc.Process)) agentproc.Process {
|
||||
t.Helper()
|
||||
|
||||
pid, err := cryptorand.Intn(1<<31 - 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
arg1, err := cryptorand.String(5)
|
||||
require.NoError(t, err)
|
||||
|
||||
arg2, err := cryptorand.String(5)
|
||||
require.NoError(t, err)
|
||||
|
||||
arg3, err := cryptorand.String(5)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmdline := fmt.Sprintf("%s\x00%s\x00%s", arg1, arg2, arg3)
|
||||
|
||||
process := agentproc.Process{
|
||||
CmdLine: cmdline,
|
||||
PID: int32(pid),
|
||||
}
|
||||
|
||||
for _, mut := range muts {
|
||||
mut(&process)
|
||||
}
|
||||
|
||||
process.Dir = fmt.Sprintf("%s/%d", "/proc", process.PID)
|
||||
|
||||
err = fs.MkdirAll(process.Dir, 0o555)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = afero.WriteFile(fs, fmt.Sprintf("%s/cmdline", process.Dir), []byte(process.CmdLine), 0o444)
|
||||
require.NoError(t, err)
|
||||
|
||||
return process
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/coder/coder/v2/agent/agentproc (interfaces: Syscaller)
|
||||
|
||||
// Package agentproctest is a generated GoMock package.
|
||||
package agentproctest
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
syscall "syscall"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockSyscaller is a mock of Syscaller interface.
|
||||
type MockSyscaller struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSyscallerMockRecorder
|
||||
}
|
||||
|
||||
// MockSyscallerMockRecorder is the mock recorder for MockSyscaller.
|
||||
type MockSyscallerMockRecorder struct {
|
||||
mock *MockSyscaller
|
||||
}
|
||||
|
||||
// NewMockSyscaller creates a new mock instance.
|
||||
func NewMockSyscaller(ctrl *gomock.Controller) *MockSyscaller {
|
||||
mock := &MockSyscaller{ctrl: ctrl}
|
||||
mock.recorder = &MockSyscallerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockSyscaller) EXPECT() *MockSyscallerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetPriority mocks base method.
|
||||
func (m *MockSyscaller) GetPriority(arg0 int32) (int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetPriority", arg0)
|
||||
ret0, _ := ret[0].(int)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetPriority indicates an expected call of GetPriority.
|
||||
func (mr *MockSyscallerMockRecorder) GetPriority(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPriority", reflect.TypeOf((*MockSyscaller)(nil).GetPriority), arg0)
|
||||
}
|
||||
|
||||
// Kill mocks base method.
|
||||
func (m *MockSyscaller) Kill(arg0 int32, arg1 syscall.Signal) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Kill", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Kill indicates an expected call of Kill.
|
||||
func (mr *MockSyscallerMockRecorder) Kill(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Kill", reflect.TypeOf((*MockSyscaller)(nil).Kill), arg0, arg1)
|
||||
}
|
||||
|
||||
// SetPriority mocks base method.
|
||||
func (m *MockSyscaller) SetPriority(arg0 int32, arg1 int) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetPriority", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetPriority indicates an expected call of SetPriority.
|
||||
func (mr *MockSyscallerMockRecorder) SetPriority(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPriority", reflect.TypeOf((*MockSyscaller)(nil).SetPriority), arg0, arg1)
|
||||
}
|
||||
Reference in New Issue
Block a user