Merge pull request #10221 from briancain/DOCKER-REPO-GIT

Docker provider build from repo
This commit is contained in:
Brian Cain 2018-09-20 09:16:22 -07:00 committed by GitHub
commit 3b7e37a2ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 229 additions and 35 deletions

View File

@ -17,9 +17,11 @@ module VagrantPlugins
machine = env[:machine] machine = env[:machine]
build_dir = env[:build_dir] build_dir = env[:build_dir]
build_dir ||= machine.provider_config.build_dir build_dir ||= machine.provider_config.build_dir
git_repo = env[:git_repo]
git_repo ||= machine.provider_config.git_repo
# If we're not building a container, then just skip this step # If we're not building a container, then just skip this step
return @app.call(env) if !build_dir return @app.call(env) if (!build_dir && !git_repo)
# Try to read the image ID from the cache file if we've # Try to read the image ID from the cache file if we've
# already built it. # already built it.
@ -41,18 +43,31 @@ module VagrantPlugins
args = machine.provider_config.build_args.clone args = machine.provider_config.build_args.clone
if machine.provider_config.dockerfile if machine.provider_config.dockerfile
dockerfile = machine.provider_config.dockerfile dockerfile = machine.provider_config.dockerfile
dockerfile_path = File.join(build_dir, dockerfile) dockerfile_path = build_dir ? File.join(build_dir, dockerfile) : dockerfile
args.push("--file").push(dockerfile_path) args.push("--file").push(dockerfile_path)
if build_dir
machine.ui.output( machine.ui.output(
I18n.t("docker_provider.building_named_dockerfile", I18n.t("docker_provider.building_named_dockerfile",
file: machine.provider_config.dockerfile)) file: machine.provider_config.dockerfile))
else else
machine.ui.output(
I18n.t("docker_provider.building_git_repo_named_dockerfile",
file: machine.provider_config.dockerfile,
repo: git_repo))
end
else
if build_dir
machine.ui.output(I18n.t("docker_provider.building")) machine.ui.output(I18n.t("docker_provider.building"))
else
machine.ui.output(
I18n.t("docker_provider.building_git_repo",
repo: git_repo))
end
end end
image = machine.provider.driver.build( image = machine.provider.driver.build(
build_dir, build_dir || git_repo,
extra_args: args) do |type, data| extra_args: args) do |type, data|
data = remove_ansi_escape_codes(data.chomp).chomp data = remove_ansi_escape_codes(data.chomp).chomp
env[:ui].detail(data) if data != "" env[:ui].detail(data) if data != ""

View File

@ -7,7 +7,7 @@ module VagrantPlugins
end end
def call(env) def call(env)
env[:result] = !!env[:machine].provider_config.build_dir env[:result] = (!!env[:machine].provider_config.build_dir || !!env[:machine].provider_config.git_repo)
@app.call(env) @app.call(env)
end end
end end

View File

@ -14,11 +14,19 @@ module VagrantPlugins
attr_accessor :build_args attr_accessor :build_args
# The directory with a Dockerfile to build and use as the basis # The directory with a Dockerfile to build and use as the basis
# for this container. If this is set, "image" should not be set. # for this container. If this is set, neither "image" nor "git_repo"
# should be set.
# #
# @return [String] # @return [String]
attr_accessor :build_dir attr_accessor :build_dir
# The URL for a git repository with a Dockerfile to build and use
# as the basis for this container. If this is set, neither "image"
# nor "build_dir" should be set.
#
# @return [String]
attr_accessor :git_repo
# Use docker-compose to manage the lifecycle and environment for # Use docker-compose to manage the lifecycle and environment for
# containers instead of using docker directly. # containers instead of using docker directly.
# #
@ -149,6 +157,7 @@ module VagrantPlugins
def initialize def initialize
@build_args = [] @build_args = []
@build_dir = UNSET_VALUE @build_dir = UNSET_VALUE
@git_repo = UNSET_VALUE
@cmd = UNSET_VALUE @cmd = UNSET_VALUE
@compose = UNSET_VALUE @compose = UNSET_VALUE
@compose_configuration = {} @compose_configuration = {}
@ -185,15 +194,40 @@ module VagrantPlugins
super.tap do |result| super.tap do |result|
# This is a bit confusing. The tests explain the purpose of this # This is a bit confusing. The tests explain the purpose of this
# better than the code lets on, I believe. # better than the code lets on, I believe.
if (other.image != UNSET_VALUE || other.build_dir != UNSET_VALUE) && has_image = (other.image != UNSET_VALUE)
(other.image == UNSET_VALUE || other.build_dir == UNSET_VALUE) has_build_dir = (other.build_dir != UNSET_VALUE)
if other.image != UNSET_VALUE && @build_dir != UNSET_VALUE has_git_repo = (other.git_repo != UNSET_VALUE)
if (has_image ^ has_build_dir ^ has_git_repo) && !(has_image && has_build_dir && has_git_repo)
# image
if has_image
if @build_dir != UNSET_VALUE
result.build_dir = nil result.build_dir = nil
end end
if @git_repo != UNSET_VALUE
result.git_repo = nil
end
end
if other.build_dir != UNSET_VALUE && @image != UNSET_VALUE # build_dir
if has_build_dir
if @image != UNSET_VALUE
result.image = nil result.image = nil
end end
if @git_repo != UNSET_VALUE
result.git_repo = nil
end
end
# git_repo
if has_git_repo
if @build_dir != UNSET_VALUE
result.build_dir = nil
end
if @image != UNSET_VALUE
result.image = nil
end
end
end end
env = {} env = {}
@ -214,6 +248,7 @@ module VagrantPlugins
def finalize! def finalize!
@build_args = [] if @build_args == UNSET_VALUE @build_args = [] if @build_args == UNSET_VALUE
@build_dir = nil if @build_dir == UNSET_VALUE @build_dir = nil if @build_dir == UNSET_VALUE
@git_repo = nil if @git_repo == UNSET_VALUE
@cmd = [] if @cmd == UNSET_VALUE @cmd = [] if @cmd == UNSET_VALUE
@compose = false if @compose == UNSET_VALUE @compose = false if @compose == UNSET_VALUE
@create_args = [] if @create_args == UNSET_VALUE @create_args = [] if @create_args == UNSET_VALUE
@ -262,11 +297,11 @@ module VagrantPlugins
def validate(machine) def validate(machine)
errors = _detected_errors errors = _detected_errors
if @build_dir && @image if [@build_dir, @git_repo, @image].compact.size > 1
errors << I18n.t("docker_provider.errors.config.both_build_and_image") errors << I18n.t("docker_provider.errors.config.both_build_and_image_and_git")
end end
if !@build_dir && !@image if !@build_dir && !@git_repo && !@image
errors << I18n.t("docker_provider.errors.config.build_dir_or_image") errors << I18n.t("docker_provider.errors.config.build_dir_or_image")
end end
@ -277,6 +312,11 @@ module VagrantPlugins
end end
end end
# Comparison logic taken directly from docker's urlutil.go
if @git_repo && !( @git_repo =~ /^http(?:s)?:\/\/.*.git(?:#.+)?$/ || @git_repo =~ /^git(?:hub\.com|@|:\/\/)/)
errors << I18n.t("docker_provider.errors.config.git_repo_invalid")
end
if !@compose_configuration.is_a?(Hash) if !@compose_configuration.is_a?(Hash)
errors << I18n.t("docker_provider.errors.config.compose_configuration_hash") errors << I18n.t("docker_provider.errors.config.compose_configuration_hash")
end end

View File

@ -12,8 +12,12 @@ en:
Build image no longer exists. Rebuilding... Build image no longer exists. Rebuilding...
building: |- building: |-
Building the container from a Dockerfile... Building the container from a Dockerfile...
building_git_repo: |-
Building the container from the git repository: %{repo}...
building_named_dockerfile: |- building_named_dockerfile: |-
Building the container from the named Dockerfile: %{file}... Building the container from the named Dockerfile: %{file}...
building_git_repo_named_dockerfile: |-
Building the container from the named Dockerfile: %{file} in the git repository: %{repo}...
creating: |- creating: |-
Creating the container... Creating the container...
created: |- created: |-
@ -137,16 +141,20 @@ en:
and notify them to not use this communicator for anything except the and notify them to not use this communicator for anything except the
"docker" provider. "docker" provider.
config: config:
both_build_and_image: |- both_build_and_image_and_git: |-
Only one of "build_dir" or "image" can be set Only one of "build_dir", "git_repo" or "image" can be set
build_dir_invalid: |- build_dir_invalid: |-
"build_dir" must exist and contain a Dockerfile "build_dir" must exist and contain a Dockerfile
git_repo_invalid: |-
"git_repo" must be a valid repository URL
build_dir_or_image: |- build_dir_or_image: |-
One of "build_dir" or "image" must be set One of "build_dir", "git_repo" or "image" must be set
compose_configuration_hash: |- compose_configuration_hash: |-
"compose_configuration" must be a hash "compose_configuration" must be a hash
compose_force_vm: |- compose_force_vm: |-
Docker compose is not currently supported from within proxy VM. Docker compose is not currently supported from within proxy VM.
git_repo_invalid: |-
"git_repo" must be a valid git URL
create_args_array: |- create_args_array: |-
"create_args" must be an array "create_args" must be an array
invalid_link: |- invalid_link: |-

View File

@ -43,6 +43,7 @@ describe VagrantPlugins::DockerProvider::Config do
before { subject.finalize! } before { subject.finalize! }
its(:build_dir) { should be_nil } its(:build_dir) { should be_nil }
its(:git_repo) { should be_nil }
its(:expose) { should eq([]) } its(:expose) { should eq([]) }
its(:cmd) { should eq([]) } its(:cmd) { should eq([]) }
its(:env) { should eq({}) } its(:env) { should eq({}) }
@ -67,16 +68,44 @@ describe VagrantPlugins::DockerProvider::Config do
allow(Vagrant::Util::Platform).to receive(:linux?).and_return(true) allow(Vagrant::Util::Platform).to receive(:linux?).and_return(true)
end end
it "should be invalid if both build dir and image are set" do describe "should be invalid if any two or more of build dir, git repo and image are set" do
it "build dir and image" do
subject.build_dir = build_dir subject.build_dir = build_dir
subject.image = "foo" subject.image = "foo"
subject.git_repo = nil
subject.finalize!
assert_invalid
end
it "build dir and git repo" do
subject.build_dir = build_dir
subject.git_repo = "http://someone.com/something.git#branch:dir"
subject.image = nil
subject.finalize!
assert_invalid
end
it "git repo dir and image" do
subject.build_dir = nil
subject.git_repo = "http://someone.com/something.git#branch:dir"
subject.image = "foo"
subject.finalize! subject.finalize!
assert_invalid assert_invalid
end end
it "build dir, git repo and image" do
subject.build_dir = build_dir
subject.git_repo = "http://someone.com/something.git#branch:dir"
subject.image = "foo"
subject.finalize!
assert_invalid
end
end
describe "#build_dir" do describe "#build_dir" do
it "should be valid if not set with image" do it "should be valid if not set with image or git repo" do
subject.build_dir = nil subject.build_dir = nil
subject.git_repo = nil
subject.image = "foo" subject.image = "foo"
subject.finalize! subject.finalize!
assert_valid assert_valid
@ -89,6 +118,52 @@ describe VagrantPlugins::DockerProvider::Config do
end end
end end
describe "#git_repo" do
it "should be valid if not set with image or build dir" do
subject.build_dir = nil
subject.git_repo = "http://someone.com/something.git#branch:dir"
subject.image = nil
subject.finalize!
assert_valid
end
it "should be valid with a http git url" do
subject.git_repo = "http://someone.com/something.git#branch:dir"
subject.finalize!
assert_valid
end
it "should be valid with a git@ url" do
subject.git_repo = "git@someone.com:somebody/something"
subject.finalize!
assert_valid
end
it "should be valid with a git:// url" do
subject.git_repo = "git://someone.com/something"
subject.finalize!
assert_valid
end
it "should be valid with a short url beginning with github.com url" do
subject.git_repo = "github.com/somebody/something"
subject.finalize!
assert_valid
end
it "should be invalid with an non-git url" do
subject.git_repo = "http://foo.bar.com"
subject.finalize!
assert_invalid
end
it "should be invalid with an non url" do
subject.git_repo = "http||://foo.bar.com sdfs"
subject.finalize!
assert_invalid
end
end
describe "#compose" do describe "#compose" do
before do before do
valid_defaults valid_defaults
@ -179,7 +254,7 @@ describe VagrantPlugins::DockerProvider::Config do
subject { one.merge(two) } subject { one.merge(two) }
context "#build_dir and #image" do context "#build_dir, #git_repo and #image" do
it "overrides image if build_dir is set previously" do it "overrides image if build_dir is set previously" do
one.build_dir = "foo" one.build_dir = "foo"
two.image = "bar" two.image = "bar"
@ -188,21 +263,71 @@ describe VagrantPlugins::DockerProvider::Config do
expect(subject.image).to eq("bar") expect(subject.image).to eq("bar")
end end
it "overrides image if build_dir is set previously" do it "overrides image if git_repo is set previously" do
one.git_repo = "foo"
two.image = "bar"
expect(subject.image).to eq("bar")
expect(subject.git_repo).to be_nil
end
it "overrides build_dir if image is set previously" do
one.image = "foo" one.image = "foo"
two.build_dir = "bar" two.build_dir = "bar"
expect(subject.image).to be_nil
expect(subject.build_dir).to eq("bar") expect(subject.build_dir).to eq("bar")
expect(subject.image).to be_nil
end end
it "preserves if both set" do it "overrides build_dir if git_repo is set previously" do
one.git_repo = "foo"
two.build_dir = "bar"
expect(subject.build_dir).to eq("bar")
expect(subject.git_repo).to be_nil
end
it "overrides git_repo if build_dir is set previously" do
one.build_dir = "foo"
two.git_repo = "bar"
expect(subject.build_dir).to be_nil
expect(subject.git_repo).to eq("bar")
end
it "overrides git_repo if image is set previously" do
one.image = "foo"
two.git_repo = "bar"
expect(subject.image).to be_nil
expect(subject.git_repo).to eq("bar")
end
it "preserves if both image and build_dir are set" do
one.image = "foo" one.image = "foo"
two.image = "baz" two.image = "baz"
two.build_dir = "bar" two.build_dir = "bar"
expect(subject.image).to eq("baz")
expect(subject.build_dir).to eq("bar") expect(subject.build_dir).to eq("bar")
expect(subject.image).to eq("baz")
end
it "preserves if both image and git_repo are set" do
one.image = "foo"
two.image = "baz"
two.git_repo = "bar"
expect(subject.image).to eq("baz")
expect(subject.git_repo).to eq("bar")
end
it "preserves if both build_dir and git_repo are set" do
one.build_dir = "foo"
two.build_dir = "baz"
two.git_repo = "bar"
expect(subject.build_dir).to eq("baz")
expect(subject.git_repo).to eq("bar")
end end
end end

View File

@ -14,11 +14,17 @@ you may set. A complete reference is shown below.
### Required ### Required
One of the following settings is required when using the Docker provider:
* `build_dir` (string) - The path to a directory containing a Dockerfile. * `build_dir` (string) - The path to a directory containing a Dockerfile.
One of this or `image` is required.
* `image` (string) - The image to launch, specified by the image ID or a name * `image` (string) - The image to launch, specified by the image ID or a name
such as `ubuntu:12.04`. One of this or `build_dir` is required. such as `ubuntu:12.04`.
* `git_repo` (string) - The URL of a git repository to build the image from.
Supports pulling specific tags, branches and revision, consult the
[docker documenation](https://docs.docker.com/engine/reference/commandline/build/#/git-repositories)
for more information.
### Optional ### Optional