feat: add Timeweb Cloud provider for Woodpecker CI autoscaler

- Implement timewebcloud provider with DeployAgent, RemoveAgent, ListDeployedAgentNames
- Add minimal HTTP API client for Timeweb Cloud (create/list/delete servers)
- Register provider in main.go with CLI flags
- Add timeweb-list and timeweb-tester utilities
- Include Dockerfile and docker-compose.yml for deployment
- Update DEPLOY.md with verified OS/preset IDs
This commit is contained in:
2026-05-16 13:09:07 +03:00
commit 191cdd108f
34 changed files with 8651 additions and 0 deletions

View File

@@ -0,0 +1,215 @@
// Code generated by mockery; DO NOT EDIT.
// github.com/vektra/mockery
// template: testify
package mocks
import (
"context"
mock "github.com/stretchr/testify/mock"
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
)
// NewMockProvider creates a new instance of MockProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockProvider(t interface {
mock.TestingT
Cleanup(func())
}) *MockProvider {
mock := &MockProvider{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
// MockProvider is an autogenerated mock type for the Provider type
type MockProvider struct {
mock.Mock
}
type MockProvider_Expecter struct {
mock *mock.Mock
}
func (_m *MockProvider) EXPECT() *MockProvider_Expecter {
return &MockProvider_Expecter{mock: &_m.Mock}
}
// DeployAgent provides a mock function for the type MockProvider
func (_mock *MockProvider) DeployAgent(context1 context.Context, agent *woodpecker.Agent) error {
ret := _mock.Called(context1, agent)
if len(ret) == 0 {
panic("no return value specified for DeployAgent")
}
var r0 error
if returnFunc, ok := ret.Get(0).(func(context.Context, *woodpecker.Agent) error); ok {
r0 = returnFunc(context1, agent)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockProvider_DeployAgent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeployAgent'
type MockProvider_DeployAgent_Call struct {
*mock.Call
}
// DeployAgent is a helper method to define mock.On call
// - context1 context.Context
// - agent *woodpecker.Agent
func (_e *MockProvider_Expecter) DeployAgent(context1 interface{}, agent interface{}) *MockProvider_DeployAgent_Call {
return &MockProvider_DeployAgent_Call{Call: _e.mock.On("DeployAgent", context1, agent)}
}
func (_c *MockProvider_DeployAgent_Call) Run(run func(context1 context.Context, agent *woodpecker.Agent)) *MockProvider_DeployAgent_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
arg0 = args[0].(context.Context)
}
var arg1 *woodpecker.Agent
if args[1] != nil {
arg1 = args[1].(*woodpecker.Agent)
}
run(
arg0,
arg1,
)
})
return _c
}
func (_c *MockProvider_DeployAgent_Call) Return(err error) *MockProvider_DeployAgent_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockProvider_DeployAgent_Call) RunAndReturn(run func(context1 context.Context, agent *woodpecker.Agent) error) *MockProvider_DeployAgent_Call {
_c.Call.Return(run)
return _c
}
// ListDeployedAgentNames provides a mock function for the type MockProvider
func (_mock *MockProvider) ListDeployedAgentNames(context1 context.Context) ([]string, error) {
ret := _mock.Called(context1)
if len(ret) == 0 {
panic("no return value specified for ListDeployedAgentNames")
}
var r0 []string
var r1 error
if returnFunc, ok := ret.Get(0).(func(context.Context) ([]string, error)); ok {
return returnFunc(context1)
}
if returnFunc, ok := ret.Get(0).(func(context.Context) []string); ok {
r0 = returnFunc(context1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]string)
}
}
if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = returnFunc(context1)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockProvider_ListDeployedAgentNames_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListDeployedAgentNames'
type MockProvider_ListDeployedAgentNames_Call struct {
*mock.Call
}
// ListDeployedAgentNames is a helper method to define mock.On call
// - context1 context.Context
func (_e *MockProvider_Expecter) ListDeployedAgentNames(context1 interface{}) *MockProvider_ListDeployedAgentNames_Call {
return &MockProvider_ListDeployedAgentNames_Call{Call: _e.mock.On("ListDeployedAgentNames", context1)}
}
func (_c *MockProvider_ListDeployedAgentNames_Call) Run(run func(context1 context.Context)) *MockProvider_ListDeployedAgentNames_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
arg0 = args[0].(context.Context)
}
run(
arg0,
)
})
return _c
}
func (_c *MockProvider_ListDeployedAgentNames_Call) Return(strings []string, err error) *MockProvider_ListDeployedAgentNames_Call {
_c.Call.Return(strings, err)
return _c
}
func (_c *MockProvider_ListDeployedAgentNames_Call) RunAndReturn(run func(context1 context.Context) ([]string, error)) *MockProvider_ListDeployedAgentNames_Call {
_c.Call.Return(run)
return _c
}
// RemoveAgent provides a mock function for the type MockProvider
func (_mock *MockProvider) RemoveAgent(context1 context.Context, agent *woodpecker.Agent) error {
ret := _mock.Called(context1, agent)
if len(ret) == 0 {
panic("no return value specified for RemoveAgent")
}
var r0 error
if returnFunc, ok := ret.Get(0).(func(context.Context, *woodpecker.Agent) error); ok {
r0 = returnFunc(context1, agent)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockProvider_RemoveAgent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveAgent'
type MockProvider_RemoveAgent_Call struct {
*mock.Call
}
// RemoveAgent is a helper method to define mock.On call
// - context1 context.Context
// - agent *woodpecker.Agent
func (_e *MockProvider_Expecter) RemoveAgent(context1 interface{}, agent interface{}) *MockProvider_RemoveAgent_Call {
return &MockProvider_RemoveAgent_Call{Call: _e.mock.On("RemoveAgent", context1, agent)}
}
func (_c *MockProvider_RemoveAgent_Call) Run(run func(context1 context.Context, agent *woodpecker.Agent)) *MockProvider_RemoveAgent_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
arg0 = args[0].(context.Context)
}
var arg1 *woodpecker.Agent
if args[1] != nil {
arg1 = args[1].(*woodpecker.Agent)
}
run(
arg0,
arg1,
)
})
return _c
}
func (_c *MockProvider_RemoveAgent_Call) Return(err error) *MockProvider_RemoveAgent_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockProvider_RemoveAgent_Call) RunAndReturn(run func(context1 context.Context, agent *woodpecker.Agent) error) *MockProvider_RemoveAgent_Call {
_c.Call.Return(run)
return _c
}

13
engine/types/provider.go Normal file
View File

@@ -0,0 +1,13 @@
package types
import (
"context"
"go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker"
)
type Provider interface {
DeployAgent(context.Context, *woodpecker.Agent) error
RemoveAgent(context.Context, *woodpecker.Agent) error
ListDeployedAgentNames(context.Context) ([]string, error)
}