summaryrefslogtreecommitdiff
path: root/config
diff options
context:
space:
mode:
authorDan Duvall <dduvall@wikimedia.org>2017-08-30 09:47:41 -0700
committerDan Duvall <dduvall@wikimedia.org>2017-09-07 10:01:34 -0700
commit410085e1f5be759b6a2bfbe08a51dca84aa18e3c (patch)
tree9c0b1e24953082cfe96e84b0924ba0ac90c67100 /config
parent2a19f04679b042567dd7ed9c0208eacbb63b8d26 (diff)
downloadblubber-410085e1f5be759b6a2bfbe08a51dca84aa18e3c.tar.gz
Support `copies` config entry for multi-stage builds
Summary: Support a `copies` variant config entry that will result in a multi-stage build, copying both shared library files and application directory from a previously defined variant. This is essentially a shorthand for two `artifacts` entries that are likely to be idiomatic to multi-stage build/prod configurations. Defined a new abstract `build.CopyFrom` instruction and corresponding `docker.DockerCopyFrom` instruction and refactored the writing of these Dockerfile lines to be accomplished using an `InstructionsForPhase` method on `config.ArtifactsConfig`. Implemented new support for `copies` configuration in `config.VariantConfig` and an `InstructionsForPhase` method that returns `build.CopyFrom` instructions for both the shared library and application directories. Fixes T174622 Depends on D759 Test Plan: Run `go test ./...`. Run `blubber blubber.example.yaml production` and ensure the right `COPY --from` lines are included for the final stage. Reviewers: thcipriani, mobrovac, hashar, mmodell, #release-engineering-team Reviewed By: thcipriani, #release-engineering-team Tags: #release-engineering-team Maniphest Tasks: T174622 Differential Revision: https://phabricator.wikimedia.org/D768
Diffstat (limited to 'config')
-rw-r--r--config/artifacts.go15
-rw-r--r--config/artifacts_test.go31
-rw-r--r--config/variant.go55
-rw-r--r--config/variant_test.go66
4 files changed, 167 insertions, 0 deletions
diff --git a/config/artifacts.go b/config/artifacts.go
index a8108d0..c3fad69 100644
--- a/config/artifacts.go
+++ b/config/artifacts.go
@@ -1,7 +1,22 @@
package config
+import (
+ "phabricator.wikimedia.org/source/blubber.git/build"
+)
+
type ArtifactsConfig struct {
From string `yaml:"from"`
Source string `yaml:"source"`
Destination string `yaml:"destination"`
}
+
+func (ac ArtifactsConfig) InstructionsForPhase(phase build.Phase) []build.Instruction {
+ switch phase {
+ case build.PhasePostInstall:
+ return []build.Instruction{
+ build.CopyFrom{ac.From, build.Copy{[]string{ac.Source}, ac.Destination}},
+ }
+ }
+
+ return []build.Instruction{}
+}
diff --git a/config/artifacts_test.go b/config/artifacts_test.go
index 09f2ae4..9198d96 100644
--- a/config/artifacts_test.go
+++ b/config/artifacts_test.go
@@ -5,6 +5,7 @@ import (
"gopkg.in/stretchr/testify.v1/assert"
+ "phabricator.wikimedia.org/source/blubber.git/build"
"phabricator.wikimedia.org/source/blubber.git/config"
)
@@ -38,3 +39,33 @@ func TestArtifactsConfig(t *testing.T) {
config.ArtifactsConfig{From: "build", Source: "/bar/src", Destination: "/bar/dst"},
)
}
+
+func TestArtifactsConfigInstructions(t *testing.T) {
+ cfg := config.ArtifactsConfig{
+ From: "foo",
+ Source: "/source/path",
+ Destination: "/destination/path",
+ }
+
+ t.Run("PhasePrivileged", func(t *testing.T) {
+ assert.Empty(t, cfg.InstructionsForPhase(build.PhasePrivileged))
+ })
+
+ t.Run("PhasePrivilegeDropped", func(t *testing.T) {
+ assert.Empty(t, cfg.InstructionsForPhase(build.PhasePrivilegeDropped))
+ })
+
+ t.Run("PhasePreInstall", func(t *testing.T) {
+ assert.Empty(t, cfg.InstructionsForPhase(build.PhasePreInstall))
+ })
+
+ t.Run("PhasePostInstall", func(t *testing.T) {
+ assert.Equal(t,
+ []build.Instruction{build.CopyFrom{
+ "foo",
+ build.Copy{[]string{"/source/path"}, "/destination/path"},
+ }},
+ cfg.InstructionsForPhase(build.PhasePostInstall),
+ )
+ })
+}
diff --git a/config/variant.go b/config/variant.go
index 9309b9d..cc2cbdb 100644
--- a/config/variant.go
+++ b/config/variant.go
@@ -1,12 +1,67 @@
package config
+import (
+ "phabricator.wikimedia.org/source/blubber.git/build"
+)
+
type VariantConfig struct {
Includes []string `yaml:"includes"`
+ Copies string `yaml:"copies"`
Artifacts []ArtifactsConfig `yaml:"artifacts"`
CommonConfig `yaml:",inline"`
}
func (vc *VariantConfig) Merge(vc2 VariantConfig) {
+ vc.Copies = vc2.Copies
vc.Artifacts = append(vc.Artifacts, vc2.Artifacts...)
vc.CommonConfig.Merge(vc2.CommonConfig)
}
+
+func (vc *VariantConfig) InstructionsForPhase(phase build.Phase) []build.Instruction {
+ instructions := vc.CommonConfig.InstructionsForPhase(phase)
+ ainstructions := []build.Instruction{}
+
+ for _, artifact := range vc.allArtifacts() {
+ ainstructions = append(ainstructions, artifact.InstructionsForPhase(phase)...)
+ }
+
+ return append(ainstructions, instructions...)
+}
+
+func (vc *VariantConfig) VariantDependencies() []string {
+ // get unique set of variant dependencies based on artifacts
+ existing := map[string]bool{}
+ dependencies := []string{}
+
+ for _, artifact := range vc.allArtifacts() {
+ if dependency := artifact.From; dependency != "" && !existing[dependency] {
+ existing[dependency] = true
+ dependencies = append(dependencies, dependency)
+ }
+ }
+
+ return dependencies
+}
+
+func (vc *VariantConfig) allArtifacts() []ArtifactsConfig {
+ return append(vc.defaultArtifacts(), vc.Artifacts...)
+}
+
+func (vc *VariantConfig) defaultArtifacts() []ArtifactsConfig {
+ if vc.Copies != "" {
+ return []ArtifactsConfig{
+ {
+ From: vc.Copies,
+ Source: vc.CommonConfig.Runs.In,
+ Destination: vc.CommonConfig.Runs.In,
+ },
+ {
+ From: vc.Copies,
+ Source: LocalLibPrefix,
+ Destination: LocalLibPrefix,
+ },
+ }
+ }
+
+ return []ArtifactsConfig{}
+}
diff --git a/config/variant_test.go b/config/variant_test.go
new file mode 100644
index 0000000..0a98828
--- /dev/null
+++ b/config/variant_test.go
@@ -0,0 +1,66 @@
+package config_test
+
+import (
+ "testing"
+
+ "gopkg.in/stretchr/testify.v1/assert"
+
+ "phabricator.wikimedia.org/source/blubber.git/build"
+ "phabricator.wikimedia.org/source/blubber.git/config"
+)
+
+func TestVariantConfig(t *testing.T) {
+ cfg, err := config.ReadConfig([]byte(`---
+ variants:
+ build: {}
+ production:
+ copies: build
+ artifacts:
+ - from: build
+ source: /foo/src
+ destination: /foo/dst
+ - from: build
+ source: /bar/src
+ destination: /bar/dst`))
+
+ assert.Nil(t, err)
+
+ variant, err := config.ExpandVariant(cfg, "production")
+
+ assert.Nil(t, err)
+
+ assert.Equal(t, "build", variant.Copies)
+ assert.Len(t, variant.Artifacts, 2)
+}
+
+func TestVariantDependencies(t *testing.T) {
+ cfg := config.VariantConfig{
+ Copies: "foo",
+ Artifacts: []config.ArtifactsConfig{
+ {From: "build", Source: "/foo/src", Destination: "/foo/dst"},
+ },
+ }
+
+ assert.Equal(t, []string{"foo", "build"}, cfg.VariantDependencies())
+}
+
+func TestVariantConfigInstructions(t *testing.T) {
+ cfg := config.VariantConfig{
+ CommonConfig: config.CommonConfig{Runs: config.RunsConfig{In: "/srv/service"}},
+ Copies: "foo",
+ Artifacts: []config.ArtifactsConfig{
+ {From: "build", Source: "/foo/src", Destination: "/foo/dst"},
+ },
+ }
+
+ t.Run("PhasePostInstall", func(t *testing.T) {
+ assert.Equal(t,
+ []build.Instruction{
+ build.CopyFrom{"foo", build.Copy{[]string{"/srv/service"}, "/srv/service"}},
+ build.CopyFrom{"foo", build.Copy{[]string{config.LocalLibPrefix}, config.LocalLibPrefix}},
+ build.CopyFrom{"build", build.Copy{[]string{"/foo/src"}, "/foo/dst"}},
+ },
+ cfg.InstructionsForPhase(build.PhasePostInstall),
+ )
+ })
+}