feat: add environment support

Add support for deploying to different environments.
This commit is contained in:
Dan Anglin 2023-08-27 04:11:48 +01:00
parent f8c43f9709
commit a51db2d523
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
9 changed files with 63 additions and 50 deletions

View file

2
config

@ -1 +1 @@
Subproject commit 40b13ab1b1b52d617851f56d89c4017e0360c3b3 Subproject commit 4d9d8e21385c3c9fe481930ab157724f8d5d0dcc

View file

@ -6,13 +6,13 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"path/filepath"
) )
type config struct { type config struct {
RootDomain string `json:"rootDomain"` RootDomain string `json:"rootDomain"`
FlowGID int32 `json:"flowGID"` FlowGID int32 `json:"flowGID"`
DockerNetworkSubnet string `json:"dockerNetworkSubnet"` Docker dockerConfig `json:"docker"`
DockerHost string `json:"dockerHost"`
Traefik traefikConfig `json:"traefik"` Traefik traefikConfig `json:"traefik"`
Forgejo forgejoConfig `json:"forgejo"` Forgejo forgejoConfig `json:"forgejo"`
GoToSocial gotosocialConfig `json:"gotosocial"` GoToSocial gotosocialConfig `json:"gotosocial"`
@ -20,6 +20,16 @@ type config struct {
Landing landingConfig `json:"landing"` Landing landingConfig `json:"landing"`
} }
type dockerConfig struct {
Host string `json:"host"`
Network dockerNetworkConfig `json:"network"`
}
type dockerNetworkConfig struct {
Name string `json:"name"`
Subnet string `json:"subnet"`
}
type traefikConfig struct { type traefikConfig struct {
Version string `json:"version"` Version string `json:"version"`
CheckNewVersion bool `json:"checkNewVersion"` CheckNewVersion bool `json:"checkNewVersion"`
@ -108,14 +118,16 @@ type landingConfig struct {
} }
type landingConfigLinks struct { type landingConfigLinks struct {
Title string Title string `json:"title"`
URL string URL string `json:"url"`
Rel string Rel string `json:"rel"`
} }
func newConfig(path string) (config, error) { func newConfig(environment string) (config, error) {
var c config var c config
path := filepath.Join(configDir, environment, configFileName)
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
return c, fmt.Errorf("unable to open the file; %w", err) return c, fmt.Errorf("unable to open the file; %w", err)

View file

@ -3,7 +3,8 @@
package main package main
const ( const (
configFile string = "./config/services.json" configDir string = "./config/"
configFileName string = "services.json"
rootBuildDir string = "./build" rootBuildDir string = "./build"
templateExtension string = ".gotmpl" templateExtension string = ".gotmpl"
rootTemplatesDir string = "./templates" rootTemplatesDir string = "./templates"

View file

@ -11,25 +11,25 @@ import (
) )
// Deploy deploys the services to the Flow Platform. // Deploy deploys the services to the Flow Platform.
func Deploy(name string) error { func Deploy(environment, name string) error {
os.Setenv("MAGEFILE_VERBOSE", "true") os.Setenv("MAGEFILE_VERBOSE", "true")
mg.Deps( mg.Deps(
mg.F(Prepare, name), mg.F(Prepare, name),
) )
cfg, err := newConfig(configFile) cfg, err := newConfig(environment)
if err != nil { if err != nil {
return fmt.Errorf("unable to load the configuration; %w", err) return fmt.Errorf("unable to load the configuration; %w", err)
} }
os.Setenv("DOCKER_HOST", cfg.DockerHost) os.Setenv("DOCKER_HOST", cfg.Docker.Host)
command := []string{ command := []string{
"docker", "docker",
"compose", "compose",
"--project-directory", "--project-directory",
rootBuildDir+"/compose", fmt.Sprintf("%s/%s/compose", rootBuildDir, environment),
"up", "up",
"-d", "-d",
"--build", "--build",

View file

@ -14,23 +14,23 @@ import (
) )
// Download downloads the binaries for a given service. // Download downloads the binaries for a given service.
func Download(name string) error { func Download(environment, name string) error {
cfg, err := newConfig(configFile) cfg, err := newConfig(environment)
if err != nil { if err != nil {
return fmt.Errorf("unable to load the configuration; %v", err) return fmt.Errorf("unable to load the configuration; %v", err)
} }
switch name { switch name {
case "forgejo": case "forgejo":
if err := downloadForgejo(cfg.Forgejo.Version); err != nil { if err := downloadForgejo(environment, cfg.Forgejo.Version); err != nil {
return fmt.Errorf("an error occurred whilst getting the forgejo binary; %w", err) return fmt.Errorf("an error occurred whilst getting the forgejo binary; %w", err)
} }
case "gotosocial": case "gotosocial":
if err := downloadGoToSocial(cfg.GoToSocial.Version); err != nil { if err := downloadGoToSocial(environment, cfg.GoToSocial.Version); err != nil {
return fmt.Errorf("an error occurred whilst getting the packages for GoToSocial; %w", err) return fmt.Errorf("an error occurred whilst getting the packages for GoToSocial; %w", err)
} }
case "woodpecker": case "woodpecker":
if err := downloadWoodpecker(cfg.Woodpecker.Version); err != nil { if err := downloadWoodpecker(environment, cfg.Woodpecker.Version); err != nil {
return fmt.Errorf("an error occurred whilst getting the packages for Woodpecker; %w", err) return fmt.Errorf("an error occurred whilst getting the packages for Woodpecker; %w", err)
} }
default: default:
@ -41,8 +41,8 @@ func Download(name string) error {
} }
// downloadWoodpecker downloads and validates the files for the Woodpecker deployment. // downloadWoodpecker downloads and validates the files for the Woodpecker deployment.
func downloadWoodpecker(version string) error { func downloadWoodpecker(environment, version string) error {
destinationDir := filepath.Join(rootBuildDir, "woodpecker") destinationDir := filepath.Join(rootBuildDir, environment, "woodpecker")
binaryTarUrl := fmt.Sprintf( binaryTarUrl := fmt.Sprintf(
"https://github.com/woodpecker-ci/woodpecker/releases/download/v%s/woodpecker-server_linux_amd64.tar.gz", "https://github.com/woodpecker-ci/woodpecker/releases/download/v%s/woodpecker-server_linux_amd64.tar.gz",
@ -90,7 +90,7 @@ func downloadWoodpecker(version string) error {
} }
// downloadForgejo downloads and validates the Forgejo files. // downloadForgejo downloads and validates the Forgejo files.
func downloadForgejo(version string) error { func downloadForgejo(environment, version string) error {
var ( var (
forgejoBinaryFileFormat = "forgejo-%s-linux-amd64" forgejoBinaryFileFormat = "forgejo-%s-linux-amd64"
forgejoDigestExtension = ".sha256" forgejoDigestExtension = ".sha256"
@ -98,7 +98,7 @@ func downloadForgejo(version string) error {
forgejoJson = "./magefiles/forgejo.json" forgejoJson = "./magefiles/forgejo.json"
) )
destinationDir := filepath.Join(rootBuildDir, "forgejo") destinationDir := filepath.Join(rootBuildDir, environment, "forgejo")
binaryPath := filepath.Join( binaryPath := filepath.Join(
destinationDir, destinationDir,
@ -144,8 +144,8 @@ func downloadForgejo(version string) error {
} }
// downloadGoToSocial downloads and validates the files for GoToSocial. // downloadGoToSocial downloads and validates the files for GoToSocial.
func downloadGoToSocial(version string) error { func downloadGoToSocial(environment, version string) error {
destinationDir := filepath.Join(rootBuildDir, "gotosocial") destinationDir := filepath.Join(rootBuildDir, environment, "gotosocial")
binaryTarUrl := fmt.Sprintf( binaryTarUrl := fmt.Sprintf(
"https://github.com/superseriousbusiness/gotosocial/releases/download/v%s/gotosocial_%s_linux_amd64.tar.gz", "https://github.com/superseriousbusiness/gotosocial/releases/download/v%s/gotosocial_%s_linux_amd64.tar.gz",

View file

@ -16,8 +16,8 @@ import (
) )
// Prepare prepares the service's build directory. // Prepare prepares the service's build directory.
func Prepare(service string) error { func Prepare(environment, service string) error {
cfg, err := newConfig(configFile) cfg, err := newConfig(environment)
if err != nil { if err != nil {
return fmt.Errorf("unable to load the configuration; %v", err) return fmt.Errorf("unable to load the configuration; %v", err)
} }
@ -35,53 +35,53 @@ func Prepare(service string) error {
service := o.Name() service := o.Name()
buildDir := filepath.Join(rootBuildDir, service) buildDir := filepath.Join(rootBuildDir, environment, service)
if _, err := os.Stat(buildDir); err != nil { if _, err := os.Stat(buildDir); err != nil {
if err := os.Mkdir(buildDir, 0o700); err != nil { if err := os.MkdirAll(buildDir, 0o700); err != nil {
return fmt.Errorf("unable to make %s; %w", buildDir, err) return fmt.Errorf("unable to make %s; %w", buildDir, err)
} }
} }
if service != "compose" { if service != "compose" {
mg.Deps( mg.Deps(
mg.F(Download, service), mg.F(Download, environment, service),
) )
log.Printf("Copying assets for %s.\n", service) log.Printf("Copying assets for %s.\n", service)
if err := copyAssets(service); err != nil { if err := copyAssets(environment, service); err != nil {
return fmt.Errorf("unable to copy the assets for %s; %w", service, err) return fmt.Errorf("unable to copy the assets for %s; %w", service, err)
} }
} }
log.Printf("Rendering templates for %s.\n", service) log.Printf("Rendering templates for %s.\n", service)
if err := render(cfg, service); err != nil { if err := render(cfg, environment, service); err != nil {
return fmt.Errorf("unable to render templates for %s; %w", service, err) return fmt.Errorf("unable to render templates for %s; %w", service, err)
} }
} }
} else { } else {
buildDir := filepath.Join(rootBuildDir, service) buildDir := filepath.Join(rootBuildDir, environment, service)
if _, err := os.Stat(buildDir); err != nil { if _, err := os.Stat(buildDir); err != nil {
if err := os.Mkdir(buildDir, 0o700); err != nil { if err := os.MkdirAll(buildDir, 0o700); err != nil {
return fmt.Errorf("unable to make %s; %w", buildDir, err) return fmt.Errorf("unable to make %s; %w", buildDir, err)
} }
} }
if service != "compose" { if service != "compose" {
mg.Deps( mg.Deps(
mg.F(Download, service), mg.F(Download, environment, service),
mg.F(Prepare, "compose"), mg.F(Prepare, environment, "compose"),
) )
log.Printf("Copying assets for %s.\n", service) log.Printf("Copying assets for %s.\n", service)
if err := copyAssets(service); err != nil { if err := copyAssets(environment, service); err != nil {
return fmt.Errorf("unable to copy the assets for %s; %w", service, err) return fmt.Errorf("unable to copy the assets for %s; %w", service, err)
} }
} }
if err := render(cfg, service); err != nil { if err := render(cfg, environment, service); err != nil {
return fmt.Errorf("an error occurred whilst rendering the templates; %w", err) return fmt.Errorf("an error occurred whilst rendering the templates; %w", err)
} }
@ -90,8 +90,8 @@ func Prepare(service string) error {
return nil return nil
} }
func render(cfg config, component string) error { func render(cfg config, environment, component string) error {
buildDirName := filepath.Join(rootBuildDir, component) buildDirName := filepath.Join(rootBuildDir, environment, component)
templateDirName := filepath.Join(rootTemplatesDir, component) templateDirName := filepath.Join(rootTemplatesDir, component)
@ -147,7 +147,7 @@ func render(cfg config, component string) error {
return nil return nil
} }
func copyAssets(service string) error { func copyAssets(environment, service string) error {
assetsDirName := filepath.Join(rootAssetsDir, service) assetsDirName := filepath.Join(rootAssetsDir, service)
if _, err := os.Stat(assetsDirName); err != nil { if _, err := os.Stat(assetsDirName); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
@ -158,7 +158,7 @@ func copyAssets(service string) error {
return err return err
} }
buildDirName := filepath.Join(rootBuildDir, service, "assets") buildDirName := filepath.Join(rootBuildDir, environment, service, "assets")
walkDirFunc := func(path string, d fs.DirEntry, err error) error { walkDirFunc := func(path string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {

View file

@ -13,11 +13,11 @@ version: "3.9"
networks: networks:
flow: flow:
name: "flow" name: "{{ .Docker.Network.Name }}"
ipam: ipam:
driver: "default" driver: "default"
config: config:
- subnet: "{{ .DockerNetworkSubnet }}" - subnet: "{{ .Docker.Network.Subnet }}"
services: services:
# -- Traffic flow -- # -- Traffic flow --
@ -27,7 +27,7 @@ services:
build: build:
context: "../traefik" context: "../traefik"
networks: networks:
flow: {{ .Docker.Network.Name }}:
ipv4_address: "{{ .Traefik.ContainerIpv4Address }}" ipv4_address: "{{ .Traefik.ContainerIpv4Address }}"
ports: ports:
- target: 80 - target: 80
@ -59,7 +59,7 @@ services:
- "{{ .Forgejo.SshPort }}" - "{{ .Forgejo.SshPort }}"
- "{{ .Forgejo.HttpPort }}" - "{{ .Forgejo.HttpPort }}"
networks: networks:
flow: {{ .Docker.Network.Name }}:
ipv4_address: "{{ .Forgejo.ContainerIpv4Address }}" ipv4_address: "{{ .Forgejo.ContainerIpv4Address }}"
restart: "always" restart: "always"
volumes: volumes:
@ -79,7 +79,7 @@ services:
expose: expose:
- "{{ .GoToSocial.Port }}" - "{{ .GoToSocial.Port }}"
networks: networks:
flow: {{ .Docker.Network.Name }}:
ipv4_address: "{{ .GoToSocial.ContainerIpv4Address }}" ipv4_address: "{{ .GoToSocial.ContainerIpv4Address }}"
restart: "always" restart: "always"
volumes: volumes:
@ -114,7 +114,7 @@ services:
- "{{ .Woodpecker.HttpPort }}" - "{{ .Woodpecker.HttpPort }}"
- "{{ .Woodpecker.GrpcPort }}" - "{{ .Woodpecker.GrpcPort }}"
networks: networks:
flow: {{ .Docker.Network.Name }}:
ipv4_address: "{{ .Woodpecker.ContainerIpv4Address }}" ipv4_address: "{{ .Woodpecker.ContainerIpv4Address }}"
restart: "always" restart: "always"
volumes: volumes:
@ -138,7 +138,7 @@ services:
expose: expose:
- "{{ .Landing.Port }}" - "{{ .Landing.Port }}"
networks: networks:
flow: {{ .Docker.Network.Name }}:
ipv4_address: "{{ .Landing.ContainerIpv4Address }}" ipv4_address: "{{ .Landing.ContainerIpv4Address }}"
restart: "always" restart: "always"
volumes: volumes:

View file

@ -110,7 +110,7 @@ port: {{ .GoToSocial.Port }}
# Example: ["127.0.0.1/32", "172.20.0.1"] # Example: ["127.0.0.1/32", "172.20.0.1"]
# Default: ["127.0.0.1/32", "::1"] (localhost ipv4 + ipv6) # Default: ["127.0.0.1/32", "::1"] (localhost ipv4 + ipv6)
trusted-proxies: trusted-proxies:
- "{{ .DockerNetworkSubnet }}" - "{{ .Docker.Network.Subnet }}"
############################ ############################
##### DATABASE CONFIG ###### ##### DATABASE CONFIG ######