This repository has been archived on 2023-05-06. You can view files and clone it, but cannot push or open issues or pull requests.
helix/internal/stacks/docker.go

201 lines
5.5 KiB
Go
Raw Normal View History

package stacks
import (
"context"
2021-09-01 22:04:40 +01:00
"embed"
"fmt"
"os"
"path/filepath"
"github.com/pulumi/pulumi/sdk/v3/go/auto"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optdestroy"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optpreview"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optup"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"forge.dananglin.me.uk/code/dananglin/helix/internal/config"
"forge.dananglin.me.uk/code/dananglin/helix/internal/docker"
)
// DockerStack is a stack for managing the containers
// for the forge platform.
type DockerStack struct {
Name string
Stack auto.Stack
}
2021-09-01 22:04:40 +01:00
//go:embed templates/*
var templates embed.FS
// newContainerStack creates the ContainerStack value.
func newDockerStack(ctx context.Context, project, stack string, c config.Config) (*DockerStack, error) {
deployFunc := deployDockerStack(project, c.Docker, c.Services)
s, err := createOrSelectStack(ctx, project, stack, deployFunc)
if err != nil {
return nil, fmt.Errorf("unable to initialise the '%s' stack...\n%w", stack, err)
}
d := DockerStack{
Name: stack,
Stack: s,
}
return &d, nil
}
2021-09-01 22:04:40 +01:00
// Preview the proposed changes to the docker stack.
func (c *DockerStack) Preview(ctx context.Context) error {
streamer := optpreview.ProgressStreams(os.Stdout)
_, err := c.Stack.Preview(ctx, streamer)
if err != nil {
return fmt.Errorf("unable to preview the '%s' stack...\n%w", c.Name, err)
}
return nil
}
2021-09-01 22:04:40 +01:00
// Update the docker stack.
func (c *DockerStack) Update(ctx context.Context) error {
streamer := optup.ProgressStreams(os.Stdout)
_, err := c.Stack.Up(ctx, streamer)
if err != nil {
return fmt.Errorf("unable to update '%s' stack...\n%w", c.Name, err)
}
return nil
}
2021-09-01 22:04:40 +01:00
// Destroy the docker stack.
func (c *DockerStack) Destroy(ctx context.Context) error {
streamer := optdestroy.ProgressStreams(os.Stdout)
_, err := c.Stack.Destroy(ctx, streamer)
if err != nil {
return fmt.Errorf("unable to destroy '%s' stack...\n%w", c.Name, err)
}
return nil
}
2021-09-01 22:04:40 +01:00
// deployDockerStack returns a Pulumi run function that is used to deploy the docker stack.
func deployDockerStack(project string, dockerConfig config.DockerConfig, services config.ServicesConfig) pulumi.RunFunc {
2021-09-01 22:04:40 +01:00
sharedVolumeMountPath := "/helix/shared"
groupId := 2239
services.Traefik.GroupId = groupId
services.Gitea.GroupId = groupId
services.Gitea.UserId = 2000
return func(ctx *pulumi.Context) error {
// TODO: Create the provider when we start playing with remote hosts
// Create the docker network
networkConfig := docker.DockerNetworkConfig{
Name: pulumi.String(dockerConfig.Network.Name),
Subnet: pulumi.String(dockerConfig.Network.Subnet),
Driver: pulumi.String(dockerConfig.Network.Driver),
}
network, err := docker.CreateNetwork(ctx, networkConfig)
if err != nil {
return err
}
// Create the shared volume
sharedVolumeInput := docker.DockerVolumeInput{
Name: pulumi.String(dockerConfig.SharedVolume.Name),
UniqueLabel: "shared",
}
sharedVolume, err := docker.CreateVolume(ctx, sharedVolumeInput)
if err != nil {
return err
}
2021-09-01 22:04:40 +01:00
baseCache, err := os.UserCacheDir()
if err != nil {
return fmt.Errorf("unable to get the base cache directory...\n%w", err)
}
2021-09-01 22:04:40 +01:00
projectCacheRoot := filepath.Join(baseCache, "helix", project)
2021-09-01 22:04:40 +01:00
// Traefik service.
if err = renderTemplates(services.Traefik, "traefik", projectCacheRoot); err != nil {
return err
}
2021-09-01 22:04:40 +01:00
traefikImageInput := docker.DockerImageInput{
BuildContext: pulumi.String(filepath.Join(projectCacheRoot, "traefik")),
Dockerfile: pulumi.String(filepath.Join(projectCacheRoot, "traefik", "Dockerfile")),
ImageName: pulumi.String("helix-traefik"),
ImageTag: pulumi.String(services.Traefik.Version),
UniqueLabel: "traefik-image",
}
2021-09-01 22:04:40 +01:00
traefikImage, err := docker.CreateImage(ctx, traefikImageInput)
if err != nil {
return err
}
traefikContainerInput := docker.DockerContainerInput{
Image: traefikImage.ImageName,
Ipv4Address: pulumi.String(services.Traefik.ContainerIp),
Name: pulumi.String("helix-traefik"),
Network: network.Name,
UniqueLabel: "traefik-container",
DockerVolumes: []docker.DockerVolume{
{
Name: sharedVolume.Name,
2021-09-01 22:04:40 +01:00
MountPath: pulumi.String(sharedVolumeMountPath),
},
},
}
if err = docker.CreateContainer(ctx, traefikContainerInput); err != nil {
return err
}
2021-09-01 22:04:40 +01:00
// Gitea service
if err = renderTemplates(services.Gitea, "gitea", projectCacheRoot); err != nil {
return err
}
giteaImageInput := docker.DockerImageInput{
BuildContext: pulumi.String(filepath.Join(projectCacheRoot, "gitea")),
Dockerfile: pulumi.String(filepath.Join(projectCacheRoot, "gitea", "Dockerfile")),
ImageName: pulumi.String("helix-gitea"),
ImageTag: pulumi.String(services.Gitea.Version),
UniqueLabel: "gitea-image",
}
giteaImage, err := docker.CreateImage(ctx, giteaImageInput)
if err != nil {
return err
}
giteaContainerInput := docker.DockerContainerInput{
Image: giteaImage.ImageName,
Ipv4Address: pulumi.String(services.Gitea.ContainerIp),
Name: pulumi.String("helix-gitea"),
Network: network.Name,
DockerVolumes: []docker.DockerVolume{
{
Name: sharedVolume.Name,
MountPath: pulumi.String(sharedVolumeMountPath),
},
},
HostPathVolumes: []docker.HostPathVolume{
{
HostPath: pulumi.String(services.Gitea.DataDirectory),
MountPath: pulumi.String("/helix/gitea/data"),
},
},
UniqueLabel: "gitea-container",
}
if err = docker.CreateContainer(ctx, giteaContainerInput); err != nil {
return err
}
return nil
}
}