garm-provider-edge-connect/internal/spec/spec.go
Richard Robert Reitz 40dec1b6fd
Some checks failed
build / build (push) Successful in 1m9s
Go Tests / go-tests (push) Failing after 1m14s
feat(edge): Enabled the buildkit docker driver for rootless operation, but with appamor requirement instead
2025-10-28 15:30:10 +01:00

223 lines
5 KiB
Go

package spec
import (
"encoding/json"
"fmt"
"net/url"
"strings"
"github.com/cloudbase/garm-provider-common/params"
corev1 "k8s.io/api/core/v1"
)
type GitHubScopeDetails struct {
BaseURL string
Repo string
Org string
Enterprise string
}
type RunnerExtraSpecs struct {
RunnerWorkDir string `json:"runner_workdir"`
DisableRunnerUpdate *bool `json:"disable_runner_update"`
RunnerEphemeral *bool `json:"runner_ephemeral"`
PodSpec *corev1.PodSpec `json:"pod_spec,omitempty"`
}
func ExtractGitHubScopeDetails(gitRepoURL string) (GitHubScopeDetails, error) {
if gitRepoURL == "" {
return GitHubScopeDetails{}, fmt.Errorf("no gitRepoURL supplied")
}
u, err := url.Parse(gitRepoURL)
if err != nil {
return GitHubScopeDetails{}, fmt.Errorf("invalid URL: %w", err)
}
if u.Scheme == "" || u.Host == "" {
return GitHubScopeDetails{}, fmt.Errorf("invalid URL: %s", gitRepoURL)
}
pathParts := strings.Split(strings.Trim(u.Path, "/"), "/")
scope := GitHubScopeDetails{
BaseURL: u.Scheme + "://" + u.Host,
}
switch {
case len(pathParts) == 1:
scope.Org = pathParts[0]
case len(pathParts) == 2 && pathParts[0] == "enterprises":
scope.Enterprise = pathParts[1]
case len(pathParts) == 2:
scope.Org = pathParts[0]
scope.Repo = pathParts[1]
default:
return GitHubScopeDetails{}, fmt.Errorf("URL does not match the expected patterns")
}
return scope, nil
}
func ParseExtraSpecs(bootstrapParams params.BootstrapInstance) RunnerExtraSpecs {
var extraSpecs RunnerExtraSpecs
if len(bootstrapParams.ExtraSpecs) > 0 {
_ = json.Unmarshal(bootstrapParams.ExtraSpecs, &extraSpecs)
}
return extraSpecs
}
func GetRunnerEnvs(gitHubScope GitHubScopeDetails, bootstrapParams params.BootstrapInstance) []corev1.EnvVar {
extraSpecs := ParseExtraSpecs(bootstrapParams)
runnerWorkDir := extraSpecs.RunnerWorkDir
if runnerWorkDir == "" {
runnerWorkDir = "/runner/_work/"
}
disableRunnerUpdate := "true"
if extraSpecs.DisableRunnerUpdate != nil {
disableRunnerUpdate = fmt.Sprintf("%t", *extraSpecs.DisableRunnerUpdate)
}
runnerEphemeral := "true"
if extraSpecs.RunnerEphemeral != nil {
runnerEphemeral = fmt.Sprintf("%t", *extraSpecs.RunnerEphemeral)
}
return []corev1.EnvVar{
{
Name: "RUNNER_GITEA_INSTANCE",
Value: bootstrapParams.RepoURL,
},
{
Name: "RUNNER_GROUP",
Value: bootstrapParams.GitHubRunnerGroup,
},
{
Name: "RUNNER_NAME",
Value: bootstrapParams.Name,
},
{
Name: "RUNNER_LABELS",
Value: strings.Join(bootstrapParams.Labels, ","),
},
{
Name: "RUNNER_NO_DEFAULT_LABELS",
Value: "true",
},
{
Name: "DISABLE_RUNNER_UPDATE",
Value: disableRunnerUpdate,
},
{
Name: "RUNNER_WORKDIR",
Value: runnerWorkDir,
},
{
Name: "GITHUB_URL",
Value: gitHubScope.BaseURL,
},
{
Name: "RUNNER_EPHEMERAL",
Value: runnerEphemeral,
},
{
Name: "RUNNER_TOKEN",
Value: "dummy",
},
{
Name: "METADATA_URL",
Value: bootstrapParams.MetadataURL,
},
{
Name: "BEARER_TOKEN",
Value: bootstrapParams.InstanceToken,
},
{
Name: "CALLBACK_URL",
Value: bootstrapParams.CallbackURL,
},
{
Name: "JIT_CONFIG_ENABLED",
Value: fmt.Sprintf("%t", bootstrapParams.JitConfigEnabled),
},
}
}
func GetPodSpec(gitHubScope GitHubScopeDetails, bootstrapParams params.BootstrapInstance) corev1.PodSpec {
extraSpecs := ParseExtraSpecs(bootstrapParams)
if extraSpecs.PodSpec != nil {
return *extraSpecs.PodSpec
}
envs := GetRunnerEnvs(gitHubScope, bootstrapParams)
return corev1.PodSpec{
RestartPolicy: corev1.RestartPolicyAlways,
Containers: []corev1.Container{
{
Name: "runner",
Image: bootstrapParams.Image,
ImagePullPolicy: "Always",
Env: envs,
VolumeMounts: []corev1.VolumeMount{
{
Name: "buildkitd",
MountPath: "/run/user/1000/buildkit",
SubPath: "buildkitd.sock",
},
{
Name: "runner",
MountPath: "/runner",
},
},
},
{
Name: "buildkitd",
Image: "moby/buildkit:v0.25.1-rootless",
Args: []string{
"--allow-insecure-entitlement=network.host",
"--oci-worker-no-process-sandbox",
},
ImagePullPolicy: corev1.PullIfNotPresent,
ReadinessProbe: &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
Exec: &corev1.ExecAction{
Command: []string{
"buildctl",
"debug",
"workers",
},
},
},
FailureThreshold: 3,
PeriodSeconds: 10,
SuccessThreshold: 1,
TimeoutSeconds: 1,
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "buildkitd",
MountPath: "/run/user/1000/buildkit",
SubPath: "buildkitd.sock",
},
},
},
},
Volumes: []corev1.Volume{
{
Name: "buildkitd",
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
{
Name: "runner",
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
},
}
}