Files
Kevin Minehart 13f4cf162e CI: move grafana-build into pkg/build (#105640)
* move grafana-build into pkg/build
2025-05-20 10:48:00 -05:00

133 lines
4.1 KiB
Go

package containers
import (
"fmt"
"math/rand"
"os"
"path/filepath"
"strconv"
"dagger.io/dagger"
)
const GoogleCloudImage = "google/cloud-sdk:alpine"
// GCPAuthenticator injects authentication information into the provided container.
type GCPAuthenticator interface {
Authenticate(*dagger.Client, *dagger.Container) (*dagger.Container, error)
}
// GCPServiceAccount satisfies GCPAuthenticator and injects the provided ServiceAccount into the filesystem and adds a 'gcloud auth activate-service-account'
type GCPServiceAccount struct {
DaggerFile *dagger.File
JSONFile string
}
func (a *GCPServiceAccount) Authenticate(d *dagger.Client, c *dagger.Container) (*dagger.Container, error) {
if a.DaggerFile == nil && a.JSONFile == "" {
return nil, fmt.Errorf("GCPServiceAccount authentication missed JSONFile AND DaggerFile")
}
var container *dagger.Container
if a.JSONFile != "" {
container = c.WithMountedFile(
"/opt/service_account.json",
d.Host().Directory(filepath.Dir(a.JSONFile)).File(filepath.Base(a.JSONFile)),
)
}
if a.DaggerFile != nil {
container = c.WithMountedFile("/opt/service_account.json", a.DaggerFile)
}
return container.WithExec([]string{"gcloud", "auth", "activate-service-account", "--key-file", "/opt/service_account.json"}), nil
}
func NewGCPServiceAccount(filepath string) *GCPServiceAccount {
return &GCPServiceAccount{
JSONFile: filepath,
}
}
func NewGCPServiceAccountWithFile(file *dagger.File) *GCPServiceAccount {
return &GCPServiceAccount{
DaggerFile: file,
}
}
// InheritedServiceAccount uses `gcloud` command in the current shell to get the GCS credentials.
// This type should really only be used when running locally.
type GCPInheritedAuth struct{}
func (a *GCPInheritedAuth) Authenticate(d *dagger.Client, c *dagger.Container) (*dagger.Container, error) {
if val, ok := os.LookupEnv("GOOGLE_APPLICATION_CREDENTIALS"); ok {
return c.WithMountedDirectory("/auth/credentials.json", d.Host().Directory(val)).WithEnvVariable("GOOGLE_APPLICATION_CREDENTIALS", "/auth/credentials.json"), nil
}
cfg, err := os.UserHomeDir()
if err != nil {
return nil, err
}
return c.WithMountedDirectory("/root/.config/gcloud", d.Host().Directory(filepath.Join(cfg, ".config", "gcloud"))), nil
}
func GCSUploadDirectory(d *dagger.Client, image string, auth GCPAuthenticator, dir *dagger.Directory, dst string) (*dagger.Container, error) {
container := d.Container().From(image).
WithMountedDirectory("/src", dir)
var err error
container, err = auth.Authenticate(d, container)
if err != nil {
return nil, err
}
secret := d.SetSecret("gcs-destination", dst)
container = container.WithSecretVariable("GCS_DESTINATION", secret)
return container.WithExec([]string{"/bin/sh", "-c", "gcloud storage cp -r /src/* ${GCS_DESTINATION}"}), nil
}
func GCSDownloadFile(d *dagger.Client, image string, auth GCPAuthenticator, url string) (*dagger.File, error) {
var (
container = d.Container().From(image)
err error
r = rand.Int()
)
container, err = auth.Authenticate(d, container)
if err != nil {
return nil, err
}
secret := d.SetSecret("gcs-download-url", url)
file := container.
WithEnvVariable("RAND", strconv.Itoa(r)).
WithSecretVariable("GCS_DOWNLOAD_URL", secret).
WithExec([]string{"/bin/sh", "-c", "gcloud storage cp ${GCS_DOWNLOAD_URL} /src/file"}).
File("/src/file")
return file, nil
}
func GCSAuth(d *dagger.Client, opts *GCPOpts) GCPAuthenticator {
var auth GCPAuthenticator = &GCPInheritedAuth{}
// The order of operations:
// 1. Try to use base64 key.
// 2. Try to use gcp-service-account-key (path to a file).
// 3. Try mounting $XDG_CONFIG_HOME/gcloud
if key := opts.ServiceAccountKeyBase64; key != "" {
secret := d.SetSecret("gcp-sa-key-base64", key)
// Write key to a file in an alpine container...
file := d.Container().From("alpine").
WithSecretVariable("GCP_SERVICE_ACCOUNT_KEY_BASE64", secret).
WithExec([]string{"/bin/sh", "-c", "echo $GCP_SERVICE_ACCOUNT_KEY_BASE64 | base64 -d > /key.json"}).
File("/key.json")
auth = NewGCPServiceAccountWithFile(file)
} else if key := opts.ServiceAccountKey; key != "" {
auth = NewGCPServiceAccount(key)
}
return auth
}