Add optional support for docker-compose
Adds configuration switch to enable using docker-compose to create and manage docker containers.
This commit is contained in:
parent
eb0fd71baf
commit
deba93ce5c
|
@ -19,6 +19,8 @@ module VagrantPlugins
|
|||
# @return [String]
|
||||
attr_accessor :build_dir
|
||||
|
||||
attr_accessor :compose
|
||||
|
||||
# An optional file name of a Dockerfile to be used when building
|
||||
# the image. This requires Docker >1.5.0.
|
||||
#
|
||||
|
@ -138,6 +140,7 @@ module VagrantPlugins
|
|||
@build_args = []
|
||||
@build_dir = UNSET_VALUE
|
||||
@cmd = UNSET_VALUE
|
||||
@compose = UNSET_VALUE
|
||||
@create_args = UNSET_VALUE
|
||||
@dockerfile = UNSET_VALUE
|
||||
@env = {}
|
||||
|
@ -201,6 +204,7 @@ module VagrantPlugins
|
|||
@build_args = [] if @build_args == UNSET_VALUE
|
||||
@build_dir = nil if @build_dir == UNSET_VALUE
|
||||
@cmd = [] if @cmd == UNSET_VALUE
|
||||
@compose = false if @compose == UNSET_VALUE
|
||||
@create_args = [] if @create_args == UNSET_VALUE
|
||||
@dockerfile = nil if @dockerfile == UNSET_VALUE
|
||||
@env ||= {}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
require "json"
|
||||
|
||||
require "log4r"
|
||||
|
||||
require_relative "./driver/compose"
|
||||
|
||||
module VagrantPlugins
|
||||
module DockerProvider
|
||||
class Driver
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
require "json"
|
||||
require "log4r"
|
||||
|
||||
module VagrantPlugins
|
||||
module DockerProvider
|
||||
class Driver
|
||||
class Compose < Driver
|
||||
|
||||
# @return [String] Compose file format version
|
||||
COMPOSE_VERSION = "2".freeze
|
||||
|
||||
# @return [Pathname] data directory to store composition
|
||||
attr_reader :data_directory
|
||||
# @return [Vagrant::Machine]
|
||||
attr_reader :machine
|
||||
|
||||
# Create a new driver instance
|
||||
#
|
||||
# @param [Vagrant::Machine] machine Machine instance for this driver
|
||||
def initialize(machine)
|
||||
super()
|
||||
@machine = machine
|
||||
@data_directory = Pathname.new(machine.env.local_data_path).
|
||||
join("docker-compose")
|
||||
@data_directory.mkpath
|
||||
@logger = Log4r::Logger.new("vagrant::docker::driver::compose")
|
||||
@compose_lock = Mutex.new
|
||||
end
|
||||
|
||||
def build(dir, **opts, &block)
|
||||
update_composition do |composition|
|
||||
composition["build"] = dir
|
||||
end
|
||||
end
|
||||
|
||||
def create(params, **opts, &block)
|
||||
# NOTE: Use the direct machine name as we don't
|
||||
# need to worry about uniqueness with compose
|
||||
name = machine.name.to_s
|
||||
image = params.fetch(:image)
|
||||
links = params.fetch(:links)
|
||||
ports = Array(params[:ports])
|
||||
volumes = Array(params[:volumes])
|
||||
cmd = Array(params.fetch(:cmd))
|
||||
env = params.fetch(:env)
|
||||
expose = Array(params[:expose])
|
||||
|
||||
begin
|
||||
update_composition do |composition|
|
||||
services = composition["services"] ||= {}
|
||||
services[name] = {
|
||||
"image" => image,
|
||||
"environment" => env,
|
||||
"expose" => expose,
|
||||
"ports" => ports,
|
||||
"volumes" => volumes,
|
||||
"links" => links,
|
||||
"command" => cmd
|
||||
}
|
||||
end
|
||||
rescue
|
||||
update_composition(false) do |composition|
|
||||
composition["services"].delete(name)
|
||||
end
|
||||
raise
|
||||
end
|
||||
get_container_id(name)
|
||||
end
|
||||
|
||||
def rm(cid)
|
||||
if created?(cid)
|
||||
destroy = false
|
||||
compose_execute("rm", "-f", machine.name.to_s)
|
||||
update_composition do |composition|
|
||||
if composition["services"] && composition["services"].key?(machine.name.to_s)
|
||||
@logger.info("Removing container `#{machine.name}`")
|
||||
composition["services"].delete(machine.name.to_s)
|
||||
destroy = composition["services"].empty?
|
||||
end
|
||||
end
|
||||
if destroy
|
||||
@logger.info("No containers remain. Destroying full environment.")
|
||||
compose_execute("down", "--remove-orphans")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def created?(cid)
|
||||
result = super
|
||||
if !result
|
||||
composition = get_current_composition
|
||||
if composition["services"] && composition["services"].has_key?(machine.name.to_s)
|
||||
result = true
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Lookup the ID for the container with the given name
|
||||
#
|
||||
# @param [String] name Name of container
|
||||
# @return [String] Container ID
|
||||
def get_container_id(name)
|
||||
compose_execute("ps", "-q", name).chomp
|
||||
end
|
||||
|
||||
# Execute a `docker-compose` command
|
||||
def compose_execute(*cmd, **opts)
|
||||
@compose_lock.synchronize do
|
||||
execute("docker-compose", "-f", composition_path.to_s,
|
||||
"-p", machine.env.cwd.basename.to_s, *cmd, **opts)
|
||||
end
|
||||
end
|
||||
|
||||
# Apply any changes made to the composition
|
||||
def apply_composition!
|
||||
machine.env.lock("compose", retry: true) do
|
||||
compose_execute("up", "-d", "--remove-orphans")
|
||||
end
|
||||
end
|
||||
|
||||
# Update the composition and apply changes if requested
|
||||
#
|
||||
# @param [Boolean] apply Apply composition changes
|
||||
def update_composition(apply=true)
|
||||
machine.env.lock("compose", retry: true) do
|
||||
composition = get_current_composition
|
||||
yield composition
|
||||
write_composition(composition)
|
||||
apply_composition! if apply
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Hash] current composition contents
|
||||
def get_current_composition
|
||||
composition = {"version" => COMPOSE_VERSION.dup}
|
||||
if composition_path.exist?
|
||||
composition.merge!(
|
||||
YAML.load(composition_path.read)
|
||||
)
|
||||
end
|
||||
composition
|
||||
end
|
||||
|
||||
# Save the composition
|
||||
#
|
||||
# @param [Hash] composition New composition
|
||||
def write_composition(composition)
|
||||
tmp_file = Tempfile.new("vagrant-docker-compose")
|
||||
tmp_file.write(composition.to_yaml)
|
||||
tmp_file.close
|
||||
@compose_lock.synchronize do
|
||||
FileUtils.mv(tmp_file.path, composition_path.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Pathname] path to the docker-compose.yml file
|
||||
def composition_path
|
||||
data_directory.join("docker-compose.yml")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -31,11 +31,13 @@ module VagrantPlugins
|
|||
|
||||
# Returns the driver instance for this provider.
|
||||
def driver
|
||||
return @driver if @driver
|
||||
@driver = Driver.new
|
||||
|
||||
# If we are running on a host machine, then we set the executor
|
||||
# to execute remotely.
|
||||
if !@driver
|
||||
if @machine.provider_config.compose
|
||||
@driver = Driver::Compose.new(@machine)
|
||||
else
|
||||
@driver = Driver.new
|
||||
end
|
||||
end
|
||||
if host_vm?
|
||||
@driver.executor = Executor::Vagrant.new(host_vm)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue