woodpecker-autoscaler/internal/hetzner/hetzneragent.go

133 lines
4.1 KiB
Go
Raw Normal View History

2023-10-29 21:44:39 +00:00
package hetzner
import (
"bytes"
"context"
"errors"
"fmt"
2023-10-29 21:44:39 +00:00
"text/template"
"git.uploadfilter24.eu/covidnetes/woodpecker-autoscaler/internal/config"
"git.uploadfilter24.eu/covidnetes/woodpecker-autoscaler/internal/utils"
"github.com/hetznercloud/hcloud-go/hcloud"
log "github.com/sirupsen/logrus"
2023-10-29 21:44:39 +00:00
)
var USER_DATA_TEMPLATE = `
write_files:
- content: |
# docker-compose.yml
version: '3'
services:
woodpecker-agent:
image: {{ .Image }}
command: agent
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
{{- range $key, $val := .EnvConfig }}
- {{ $key }}: {{ $val }}
{{- end }}
path: /root/docker-compose.yml
runcmd:
- [ sh, -xc, "cd /root; docker run --rm --privileged multiarch/qemu-user-static --reset -p yes; docker compose up -d" ]
`
type UserDataConfig struct {
Image string
EnvConfig map[string]string
}
func generateConfig(cfg *config.Config, name string) (string, error) {
2023-10-29 21:44:39 +00:00
envConfig := map[string]string{}
envConfig["WOODPECKER_SERVER"] = cfg.WoodpeckerInstance
envConfig["WOODPECKER_AGENT_SECRET"] = cfg.WoodpeckerAgentSecret
envConfig["WOODPECKER_FILTER_LABELS"] = cfg.WoodpeckerLabelSelector
envConfig["WOODPECKER_HOSTNAME"] = name
2023-10-29 21:44:39 +00:00
config := UserDataConfig{
Image: "woodpeckerci/woodpecker-agent:latest",
EnvConfig: envConfig,
}
tmpl, err := template.New("userdata").Parse(USER_DATA_TEMPLATE)
2023-10-29 21:44:39 +00:00
if err != nil {
return "", errors.New(fmt.Sprintf("Errors in userdata template: %s", err.Error()))
2023-10-29 21:44:39 +00:00
}
var buf bytes.Buffer
err = tmpl.Execute(&buf, &config)
2023-10-29 21:44:39 +00:00
if err != nil {
return "", errors.New(fmt.Sprintf("Could not render userdata template: %s", err.Error()))
2023-10-29 21:44:39 +00:00
}
return buf.String(), nil
2023-10-29 21:44:39 +00:00
}
func CreateNewAgent(cfg *config.Config) (*hcloud.Server, error) {
client := hcloud.NewClient(hcloud.WithToken(cfg.HcloudToken))
name := fmt.Sprintf("woodpecker-autoscaler-agent-%s", utils.RandStringBytes(5))
userdata, err := generateConfig(cfg, name)
img, _, err := client.Image.GetByNameAndArchitecture(context.Background(), "docker-ce", "amd64")
loc, _, err := client.Location.GetByName(context.Background(), cfg.HcloudRegion)
pln, _, err := client.ServerType.GetByName(context.Background(), cfg.HcloudInstanceType)
key, _, err := client.SSHKey.GetByName(context.Background(), cfg.HcloudSSHKey)
dc, _, err := client.Datacenter.GetByName(context.Background(), cfg.HcloudDatacenter)
labels := map[string]string{}
labels["Role"] = "WoodpeckerAgent"
labels["ControledBy"] = "WoodpeckerAutoscaler"
if err != nil {
return nil, errors.New(fmt.Sprintf("Could not create new Agent: %s", err.Error()))
}
res, _, err := client.Server.Create(context.Background(), hcloud.ServerCreateOpts{
Name: name,
ServerType: pln,
Image: img,
SSHKeys: []*hcloud.SSHKey{key},
Location: loc,
Datacenter: dc,
UserData: userdata,
StartAfterCreate: utils.BoolPointer(true),
Labels: labels,
})
log.WithFields(log.Fields{
"Caller": "CreateNewAgent",
}).Infof("Created new Build Agent %s", res.Server.Name)
return res.Server, nil
}
func ListAgents(cfg *config.Config) ([]hcloud.Server, error) {
client := hcloud.NewClient(hcloud.WithToken(cfg.HcloudToken))
allServers, err := client.Server.All(context.Background())
if err != nil {
return nil, errors.New(fmt.Sprintf("Could not query Server list: %s", err.Error()))
}
myServers := []hcloud.Server{}
for _, server := range allServers {
val, exists := server.Labels["ControledBy"]
if exists && val == "WoodpeckerAutoscaler" {
myServers = append(myServers, *server)
log.WithFields(log.Fields{
"Caller": "ListAgents",
}).Debugf("Owning %s Hetzner node", server.Name)
}
}
return myServers, nil
}
func DecomNode(cfg *config.Config, server *hcloud.Server) error {
client := hcloud.NewClient(hcloud.WithToken(cfg.HcloudToken))
log.WithFields(log.Fields{
"Caller": "DecomNode",
}).Debugf("Deleting %s node", server.Name)
_, _, err := client.Server.DeleteWithResult(context.Background(), server)
if err != nil {
return errors.New(fmt.Sprintf("Could not delete Agent: %s", err.Error()))
}
return nil
}