mirror of
https://github.com/actions/actions-runner-controller.git
synced 2025-12-11 03:57:01 +00:00
feat: HorizontalRunnerAutoscaler Webhook server (#282)
* feat: HorizontalRunnerAutoscaler Webhook server This introduces a Webhook server that responds GitHub `check_run`, `pull_request`, and `push` events by scaling up matched HorizontalRunnerAutoscaler by 1 replica. This allows you to immediately add "resource slack" for future GitHub Actions job runs, without waiting next sync period to add insufficient runners. This feature is highly inspired by https://github.com/philips-labs/terraform-aws-github-runner. terraform-aws-github-runner can manage one set of runners per deployment, where actions-runner-controller with this feature can manage as many sets of runners as you declare with HorizontalRunnerAutoscaler and RunnerDeployment pairs. On each GitHub event received, the webhook server queries repository-wide and organizational runners from the cluster and searches for the single target to scale up. The webhook server tries to match HorizontalRunnerAutoscaler.Spec.ScaleUpTriggers[].GitHubEvent.[CheckRun|Push|PullRequest] against the event and if it finds only one HRA, it is the scale target. If none or two or more targets are found for repository-wide runners, it does the same on organizational runners. Changes: * Fix integration test * Update manifests * chart: Add support for github webhook server * dockerfile: Include github-webhook-server binary * Do not import unversioned go-github * Update README
This commit is contained in:
@@ -24,6 +24,16 @@ const (
|
||||
`
|
||||
)
|
||||
|
||||
type ListRunnersHandler struct {
|
||||
Status int
|
||||
Body string
|
||||
}
|
||||
|
||||
func (h *ListRunnersHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(h.Status)
|
||||
fmt.Fprintf(w, h.Body)
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
Status int
|
||||
Body string
|
||||
@@ -94,10 +104,7 @@ func NewServer(opts ...Option) *httptest.Server {
|
||||
},
|
||||
|
||||
// For ListRunners
|
||||
"/repos/test/valid/actions/runners": &Handler{
|
||||
Status: http.StatusOK,
|
||||
Body: RunnersListBody,
|
||||
},
|
||||
"/repos/test/valid/actions/runners": config.FixedResponses.ListRunners,
|
||||
"/repos/test/invalid/actions/runners": &Handler{
|
||||
Status: http.StatusNoContent,
|
||||
Body: "",
|
||||
@@ -159,3 +166,10 @@ func NewServer(opts ...Option) *httptest.Server {
|
||||
|
||||
return httptest.NewServer(mux)
|
||||
}
|
||||
|
||||
func DefaultListRunnersHandler() *ListRunnersHandler {
|
||||
return &ListRunnersHandler{
|
||||
Status: http.StatusOK,
|
||||
Body: RunnersListBody,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package fake
|
||||
|
||||
import "net/http"
|
||||
|
||||
type FixedResponses struct {
|
||||
ListRepositoryWorkflowRuns *Handler
|
||||
ListWorkflowJobs *MapHandler
|
||||
ListRunners http.Handler
|
||||
}
|
||||
|
||||
type Option func(*ServerConfig)
|
||||
@@ -25,6 +28,15 @@ func WithListWorkflowJobsResponse(status int, bodies map[int]string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func WithListRunnersResponse(status int, body string) Option {
|
||||
return func(c *ServerConfig) {
|
||||
c.FixedResponses.ListRunners = &ListRunnersHandler{
|
||||
Status: status,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithFixedResponses(responses *FixedResponses) Option {
|
||||
return func(c *ServerConfig) {
|
||||
c.FixedResponses = responses
|
||||
|
||||
@@ -29,15 +29,15 @@ func (r *RunnersList) Add(runner *github.Runner) {
|
||||
func (r *RunnersList) GetServer() *httptest.Server {
|
||||
router := mux.NewRouter()
|
||||
|
||||
router.Handle("/repos/{owner}/{repo}/actions/runners", r.handleList())
|
||||
router.Handle("/repos/{owner}/{repo}/actions/runners", r.HandleList())
|
||||
router.Handle("/repos/{owner}/{repo}/actions/runners/{id}", r.handleRemove())
|
||||
router.Handle("/orgs/{org}/actions/runners", r.handleList())
|
||||
router.Handle("/orgs/{org}/actions/runners", r.HandleList())
|
||||
router.Handle("/orgs/{org}/actions/runners/{id}", r.handleRemove())
|
||||
|
||||
return httptest.NewServer(router)
|
||||
}
|
||||
|
||||
func (r *RunnersList) handleList() http.HandlerFunc {
|
||||
func (r *RunnersList) HandleList() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, res *http.Request) {
|
||||
j, err := json.Marshal(github.Runners{
|
||||
TotalCount: len(r.runners),
|
||||
|
||||
@@ -32,7 +32,10 @@ func newTestClient() *Client {
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
server = fake.NewServer()
|
||||
res := &fake.FixedResponses{
|
||||
ListRunners: fake.DefaultListRunnersHandler(),
|
||||
}
|
||||
server = fake.NewServer(fake.WithFixedResponses(res))
|
||||
defer server.Close()
|
||||
m.Run()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user