mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 23:52:19 +08:00
266 lines
7.6 KiB
Go
266 lines
7.6 KiB
Go
package artifacts
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"strings"
|
|
|
|
"dagger.io/dagger"
|
|
"github.com/grafana/grafana/pkg/build/daggerbuild/arguments"
|
|
"github.com/grafana/grafana/pkg/build/daggerbuild/backend"
|
|
"github.com/grafana/grafana/pkg/build/daggerbuild/docker"
|
|
"github.com/grafana/grafana/pkg/build/daggerbuild/flags"
|
|
"github.com/grafana/grafana/pkg/build/daggerbuild/packages"
|
|
"github.com/grafana/grafana/pkg/build/daggerbuild/pipeline"
|
|
)
|
|
|
|
var (
|
|
DockerArguments = arguments.Join(
|
|
TargzArguments,
|
|
[]pipeline.Argument{
|
|
arguments.DockerRegistry,
|
|
arguments.DockerOrg,
|
|
arguments.AlpineImage,
|
|
arguments.UbuntuImage,
|
|
arguments.TagFormat,
|
|
arguments.UbuntuTagFormat,
|
|
arguments.BoringTagFormat,
|
|
},
|
|
)
|
|
DockerFlags = flags.JoinFlags(
|
|
TargzFlags,
|
|
flags.DockerFlags,
|
|
)
|
|
)
|
|
|
|
var DockerInitializer = Initializer{
|
|
InitializerFunc: NewDockerFromString,
|
|
Arguments: DockerArguments,
|
|
}
|
|
|
|
// PacakgeDocker uses a built tar.gz package to create a docker image from the Dockerfile in the tar.gz
|
|
type Docker struct {
|
|
Name packages.Name
|
|
Version string
|
|
BuildID string
|
|
Distro backend.Distribution
|
|
Enterprise bool
|
|
|
|
Ubuntu bool
|
|
Registry string
|
|
Repositories []string
|
|
Org string
|
|
BaseImage string
|
|
TagFormat string
|
|
|
|
Tarball *pipeline.Artifact
|
|
|
|
// Src is the Grafana source code for running e2e tests when validating.
|
|
// The grafana source should not be used for anything else when building a docker image. All files in the Docker image, including the Dockerfile, should be
|
|
// from the tar.gz file.
|
|
Src *dagger.Directory
|
|
YarnCache *dagger.CacheVolume
|
|
}
|
|
|
|
func (d *Docker) Dependencies(ctx context.Context) ([]*pipeline.Artifact, error) {
|
|
return []*pipeline.Artifact{
|
|
d.Tarball,
|
|
}, nil
|
|
}
|
|
|
|
func (d *Docker) Builder(ctx context.Context, opts *pipeline.ArtifactContainerOpts) (*dagger.Container, error) {
|
|
targz, err := opts.Store.File(ctx, d.Tarball)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return docker.Builder(opts.Client, opts.Client.Host().UnixSocket("/var/run/docker.sock"), targz), nil
|
|
}
|
|
|
|
func (d *Docker) BuildFile(ctx context.Context, builder *dagger.Container, opts *pipeline.ArtifactContainerOpts) (*dagger.File, error) {
|
|
// Unlike most other things we push to, docker image tags do not support all characters.
|
|
// Specifically, the `+` character used in the `buildmetadata` section of semver.
|
|
version := strings.ReplaceAll(d.Version, "+", "-")
|
|
|
|
tags, err := docker.Tags(d.Org, d.Registry, d.Repositories, d.TagFormat, packages.NameOpts{
|
|
Name: d.Name,
|
|
Version: version,
|
|
BuildID: d.BuildID,
|
|
Distro: d.Distro,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
buildOpts := &docker.BuildOpts{
|
|
// Tags are provided as the '-t' argument, and can include the registry domain as well as the repository.
|
|
// Docker build supports building the same image with multiple tags.
|
|
// You might want to also include a 'latest' version of the tag.
|
|
Tags: tags,
|
|
Platform: backend.Platform(d.Distro),
|
|
BuildArgs: []string{
|
|
"GRAFANA_TGZ=grafana.tar.gz",
|
|
"GO_SRC=tgz-builder",
|
|
"JS_SRC=tgz-builder",
|
|
fmt.Sprintf("BASE_IMAGE=%s", d.BaseImage),
|
|
},
|
|
}
|
|
|
|
b := docker.Build(opts.Client, builder, buildOpts)
|
|
|
|
return docker.Save(b, buildOpts), nil
|
|
}
|
|
|
|
func (d *Docker) BuildDir(ctx context.Context, builder *dagger.Container, opts *pipeline.ArtifactContainerOpts) (*dagger.Directory, error) {
|
|
panic("This artifact does not produce directories")
|
|
}
|
|
|
|
func (d *Docker) Publisher(ctx context.Context, opts *pipeline.ArtifactContainerOpts) (*dagger.Container, error) {
|
|
socket := opts.Client.Host().UnixSocket("/var/run/docker.sock")
|
|
return opts.Client.Container().From("docker").WithUnixSocket("/var/run/docker.sock", socket), nil
|
|
}
|
|
|
|
func (d *Docker) PublishFile(ctx context.Context, opts *pipeline.ArtifactPublishFileOpts) error {
|
|
panic("not implemented")
|
|
}
|
|
|
|
func (d *Docker) PublishDir(ctx context.Context, opts *pipeline.ArtifactPublishDirOpts) error {
|
|
panic("This artifact does not produce directories")
|
|
}
|
|
|
|
// Filename should return a deterministic file or folder name that this build will produce.
|
|
// This filename is used as a map key for caching, so implementers need to ensure that arguments or flags that affect the output
|
|
// also affect the filename to ensure that there are no collisions.
|
|
// For example, the backend for `linux/amd64` and `linux/arm64` should not both produce a `bin` folder, they should produce a
|
|
// `bin/linux-amd64` folder and a `bin/linux-arm64` folder. Callers can mount this as `bin` or whatever if they want.
|
|
func (d *Docker) Filename(ctx context.Context) (string, error) {
|
|
ext := "docker.tar.gz"
|
|
if d.Ubuntu {
|
|
ext = "ubuntu.docker.tar.gz"
|
|
}
|
|
|
|
return packages.FileName(d.Name, d.Version, d.BuildID, d.Distro, ext)
|
|
}
|
|
|
|
func (d *Docker) VerifyFile(ctx context.Context, client *dagger.Client, file *dagger.File) error {
|
|
// Currently verifying riscv64 is unsupported (because alpine and ubuntu don't have riscv64 images yet)
|
|
if _, arch := backend.OSAndArch(d.Distro); arch == "riscv64" {
|
|
return nil
|
|
}
|
|
|
|
return docker.Verify(ctx, client, file, d.Src, d.YarnCache, d.Distro)
|
|
}
|
|
|
|
func (d *Docker) VerifyDirectory(ctx context.Context, client *dagger.Client, dir *dagger.Directory) error {
|
|
panic("not implemented") // TODO: Implement
|
|
}
|
|
|
|
func NewDockerFromString(ctx context.Context, log *slog.Logger, artifact string, state pipeline.StateHandler) (*pipeline.Artifact, error) {
|
|
options, err := pipeline.ParseFlags(artifact, DockerFlags)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
p, err := GetPackageDetails(ctx, options, state)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tarball, err := NewTarballFromString(ctx, log, artifact, state)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ubuntu, err := options.Bool(flags.Ubuntu)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Ubuntu Version to use as the base for the Grafana docker image (if this is a ubuntu artifact)
|
|
// This shouldn't fail if it's not set by the user, instead it'll default to 22.04 or something.
|
|
ubuntuImage, err := state.String(ctx, arguments.UbuntuImage)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Same for Alpine
|
|
alpineImage, err := state.String(ctx, arguments.AlpineImage)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
registry, err := state.String(ctx, arguments.DockerRegistry)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
org, err := state.String(ctx, arguments.DockerOrg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
repos, err := options.StringSlice(flags.DockerRepositories)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
format, err := state.String(ctx, arguments.TagFormat)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ubuntuFormat, err := state.String(ctx, arguments.UbuntuTagFormat)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
boringFormat, err := state.String(ctx, arguments.BoringTagFormat)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
base := alpineImage
|
|
if ubuntu {
|
|
format = ubuntuFormat
|
|
base = ubuntuImage
|
|
}
|
|
|
|
if p.Name == packages.PackageEnterpriseBoring {
|
|
format = boringFormat
|
|
}
|
|
|
|
src, err := state.Directory(ctx, arguments.GrafanaDirectory)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
yarnCache, err := state.CacheVolume(ctx, arguments.YarnCacheDirectory)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
log.Info("initializing Docker artifact", "Org", org, "registry", registry, "repos", repos, "tag", format)
|
|
|
|
return pipeline.ArtifactWithLogging(ctx, log, &pipeline.Artifact{
|
|
ArtifactString: artifact,
|
|
Handler: &Docker{
|
|
Name: p.Name,
|
|
Version: p.Version,
|
|
BuildID: p.BuildID,
|
|
Distro: p.Distribution,
|
|
Enterprise: p.Enterprise,
|
|
Tarball: tarball,
|
|
|
|
Ubuntu: ubuntu,
|
|
BaseImage: base,
|
|
Registry: registry,
|
|
Org: org,
|
|
Repositories: repos,
|
|
TagFormat: format,
|
|
|
|
Src: src,
|
|
YarnCache: yarnCache,
|
|
},
|
|
Type: pipeline.ArtifactTypeFile,
|
|
Flags: DockerFlags,
|
|
})
|
|
}
|