providers/docker: support building Dockerfiles
This commit is contained in:
parent
3ba0ca3562
commit
81df70eee0
|
@ -34,7 +34,6 @@ module Vagrant
|
|||
# If this is our scope, then override
|
||||
if parts[0] == scope
|
||||
result[parts[1].to_sym] = value
|
||||
result.delete(key)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@ module VagrantPlugins
|
|||
|
||||
b2.use ConfigValidate
|
||||
b2.use action_halt
|
||||
b2.use EnvSet, build_rebuild: true
|
||||
b2.use action_start
|
||||
end
|
||||
end
|
||||
|
@ -202,18 +203,18 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
# We only want to actually sync folder differences if
|
||||
# we're not created.
|
||||
b2.use Call, IsState, :not_created do |env2, b3|
|
||||
if !env2[:result]
|
||||
b3.use EnvSet, host_machine_sync_folders: false
|
||||
end
|
||||
end
|
||||
|
||||
b2.use HostMachineBuildDir
|
||||
b2.use HostMachineSyncFolders
|
||||
b2.use PrepareNFSValidIds
|
||||
b2.use SyncedFolderCleanup
|
||||
b2.use PrepareNFSSettings
|
||||
b2.use Build
|
||||
|
||||
# If the VM is NOT created yet, then do some setup steps
|
||||
# necessary for creating it.
|
||||
|
@ -245,11 +246,13 @@ module VagrantPlugins
|
|||
|
||||
# The autoload farm
|
||||
action_root = Pathname.new(File.expand_path("../action", __FILE__))
|
||||
autoload :Build, action_root.join("build")
|
||||
autoload :CompareSyncedFolders, action_root.join("compare_synced_folders")
|
||||
autoload :Create, action_root.join("create")
|
||||
autoload :Destroy, action_root.join("destroy")
|
||||
autoload :HasSSH, action_root.join("has_ssh")
|
||||
autoload :HostMachine, action_root.join("host_machine")
|
||||
autoload :HostMachineBuildDir, action_root.join("host_machine_build_dir")
|
||||
autoload :HostMachinePortChecker, action_root.join("host_machine_port_checker")
|
||||
autoload :HostMachinePortWarning, action_root.join("host_machine_port_warning")
|
||||
autoload :HostMachineRequired, action_root.join("host_machine_required")
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
require "log4r"
|
||||
|
||||
module VagrantPlugins
|
||||
module DockerProvider
|
||||
module Action
|
||||
class Build
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::docker::build")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
machine = env[:machine]
|
||||
build_dir = env[:build_dir]
|
||||
build_dir ||= machine.provider_config.build_dir
|
||||
|
||||
# If we're not building a container, then just skip this step
|
||||
return @app.call(env) if !build_dir
|
||||
|
||||
# Try to read the image ID from the cache file if we've
|
||||
# already built it.
|
||||
image_file = machine.data_dir.join("docker_build_image")
|
||||
image = nil
|
||||
if image_file.file?
|
||||
image = image_file.read.chomp
|
||||
end
|
||||
|
||||
# If we have no image or we're rebuilding, we rebuild
|
||||
if !image || env[:build_rebuild]
|
||||
# Build it
|
||||
machine.ui.output(I18n.t("docker_provider.building"))
|
||||
image = machine.provider.driver.build(build_dir)
|
||||
|
||||
# Store the image ID
|
||||
image_file.open("w") do |f|
|
||||
f.binmode
|
||||
f.write("#{image}\n")
|
||||
end
|
||||
else
|
||||
machine.ui.output(I18n.t("docker_provider.already_built"))
|
||||
end
|
||||
|
||||
# Set the image for creation
|
||||
env[:create_image] = image
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -50,6 +50,9 @@ module VagrantPlugins
|
|||
container_name << "_#{Time.now.to_i}"
|
||||
end
|
||||
|
||||
image = @env[:create_image]
|
||||
image ||= @provider_config.image
|
||||
|
||||
links = {}
|
||||
@provider_config._links.each do |link|
|
||||
parts = link.split(":", 2)
|
||||
|
@ -61,7 +64,7 @@ module VagrantPlugins
|
|||
env: @provider_config.env,
|
||||
extra_args: @provider_config.create_args,
|
||||
hostname: @machine_config.vm.hostname,
|
||||
image: @provider_config.image,
|
||||
image: image,
|
||||
links: links,
|
||||
name: container_name,
|
||||
ports: forwarded_ports,
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
require "digest/md5"
|
||||
|
||||
require "log4r"
|
||||
|
||||
module VagrantPlugins
|
||||
module DockerProvider
|
||||
module Action
|
||||
class HostMachineBuildDir
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::docker::hostmachinebuilddir")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
machine = env[:machine]
|
||||
build_dir = machine.provider_config.build_dir
|
||||
|
||||
# If we're not building a Dockerfile, ignore
|
||||
return @app.call(env) if !build_dir
|
||||
|
||||
# If we're building a docker file, expand the directory
|
||||
build_dir = File.expand_path(build_dir, env[:machine].env.root_path)
|
||||
env[:build_dir] = build_dir
|
||||
|
||||
# If we're not on a host VM, we're done
|
||||
return @app.call(env) if !machine.provider.host_vm?
|
||||
|
||||
# We're on a host VM, so we need to move our build dir to
|
||||
# that machine. We do this by putting the synced folder on
|
||||
# ourself and letting HostMachineSyncFolders handle it.
|
||||
new_build_dir = "/mnt/docker_build_#{Digest::MD5.hexdigest(build_dir)}"
|
||||
options = {
|
||||
docker__ignore: true,
|
||||
docker__exact: true,
|
||||
}
|
||||
machine.config.vm.synced_folder(build_dir, new_build_dir, options)
|
||||
|
||||
# Set the build dir to be the correct one
|
||||
env[:build_dir] = new_build_dir
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -91,15 +91,23 @@ module VagrantPlugins
|
|||
# Generate an ID that is deterministic based on our machine
|
||||
# and Vagrantfile path...
|
||||
id = Digest::MD5.hexdigest(
|
||||
"#{env[:machine].env.root_path}#{env[:machine].name}")
|
||||
"#{env[:machine].env.root_path}" +
|
||||
"#{data[:hostpath]}" +
|
||||
"#{data[:guestpath]}" +
|
||||
"#{env[:machine].name}")
|
||||
|
||||
# Generate a new guestpath
|
||||
data[:docker_guestpath] = data[:guestpath]
|
||||
data[:docker_sfid] = id
|
||||
data[:docker_host_sfid] = host_sfid
|
||||
data[:guestpath] = "/mnt/docker_#{Time.now.to_i}_#{rand(100000)}"
|
||||
data[:id] = id[0...6] + rand(10000).to_s
|
||||
|
||||
# If we specify exact then we know what we're doing
|
||||
if !data[:docker__exact]
|
||||
data[:guestpath] =
|
||||
"/mnt/docker_#{Time.now.to_i}_#{rand(100000)}"
|
||||
end
|
||||
|
||||
# Add this synced folder onto the new config if we haven't
|
||||
# already shared it before.
|
||||
if !existing_ids.has_key?(id)
|
||||
|
|
|
@ -3,6 +3,12 @@ module VagrantPlugins
|
|||
class Config < Vagrant.plugin("2", :config)
|
||||
attr_accessor :image, :cmd, :ports, :volumes, :privileged
|
||||
|
||||
# The directory with a Dockerfile to build and use as the basis
|
||||
# for this container. If this is set, "image" should not be set.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :build_dir
|
||||
|
||||
# Additional arguments to pass to `docker run` when creating
|
||||
# the container for the first time. This is an array of args.
|
||||
#
|
||||
|
@ -54,6 +60,7 @@ module VagrantPlugins
|
|||
attr_accessor :vagrant_vagrantfile
|
||||
|
||||
def initialize
|
||||
@build_dir = UNSET_VALUE
|
||||
@cmd = UNSET_VALUE
|
||||
@create_args = []
|
||||
@env = {}
|
||||
|
@ -87,6 +94,7 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def finalize!
|
||||
@build_dir = nil if @build_dir == UNSET_VALUE
|
||||
@cmd = [] if @cmd == UNSET_VALUE
|
||||
@create_args = [] if @create_args == UNSET_VALUE
|
||||
@env ||= {}
|
||||
|
|
|
@ -14,6 +14,17 @@ module VagrantPlugins
|
|||
@executor = Executor::Local.new
|
||||
end
|
||||
|
||||
def build(dir, **opts)
|
||||
result = execute('docker', 'build', dir)
|
||||
regexp = /Successfully built (.+)$/i
|
||||
match = regexp.match(result)
|
||||
if !match
|
||||
# TODO: error
|
||||
end
|
||||
|
||||
match[1]
|
||||
end
|
||||
|
||||
def create(params)
|
||||
image = params.fetch(:image)
|
||||
links = params.fetch(:links)
|
||||
|
|
|
@ -16,9 +16,9 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def prepare(machine, folders, _opts)
|
||||
# FIXME: Check whether the container has already been created with
|
||||
# different synced folders and let the user know about it
|
||||
folders.each do |id, data|
|
||||
next if data[:ignore]
|
||||
|
||||
host_path = data[:hostpath]
|
||||
guest_path = data[:guestpath]
|
||||
machine.provider_config.volumes << "#{host_path}:#{guest_path}"
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
en:
|
||||
docker_provider:
|
||||
already_built: |-
|
||||
Image is already built from the Dockerfile. `vagrant reload` to rebuild.
|
||||
building: |-
|
||||
Building the container from a Dockerfile...
|
||||
creating: |-
|
||||
Creating the container...
|
||||
created: |-
|
||||
|
|
|
@ -24,6 +24,7 @@ describe VagrantPlugins::DockerProvider::Config do
|
|||
describe "defaults" do
|
||||
before { subject.finalize! }
|
||||
|
||||
its(:build_dir) { should be_nil }
|
||||
its(:cmd) { should eq([]) }
|
||||
its(:env) { should eq({}) }
|
||||
its(:image) { should be_nil }
|
||||
|
|
|
@ -25,7 +25,8 @@ describe Vagrant::Util::ScopedHashOverride do
|
|||
}
|
||||
|
||||
expected = {
|
||||
:key => "replaced"
|
||||
:key => "replaced",
|
||||
:scope__key => "replaced"
|
||||
}
|
||||
|
||||
expect(klass.scoped_hash_override(original, "scope")).to eq(expected)
|
||||
|
@ -40,6 +41,7 @@ describe Vagrant::Util::ScopedHashOverride do
|
|||
|
||||
expected = {
|
||||
:key => "replaced",
|
||||
:scope__key => "replaced",
|
||||
:another__key => "value"
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue