-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3347 from mitchellh/f-docker-provider
New provider: Docker
- Loading branch information
Showing
31 changed files
with
1,017 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
module VagrantPlugins | ||
module DockerProvider | ||
module Action | ||
# Include the built-in modules so we can use them as top-level things. | ||
include Vagrant::Action::Builtin | ||
|
||
# This action brings the "machine" up from nothing, including creating the | ||
# container, configuring metadata, and booting. | ||
def self.action_up | ||
Vagrant::Action::Builder.new.tap do |b| | ||
b.use ConfigValidate | ||
b.use Call, IsState, :not_created do |env, b2| | ||
# If the VM is NOT created yet, then do the setup steps | ||
if env[:result] | ||
b2.use HandleBox | ||
b2.use EnvSet, :port_collision_repair => true | ||
b2.use HandleForwardedPortCollisions | ||
b2.use Provision | ||
b2.use PrepareNFSValidIds | ||
b2.use SyncedFolderCleanup | ||
b2.use SyncedFolders | ||
b2.use PrepareNFSSettings | ||
b2.use ForwardPorts | ||
# This will actually create and start, but that's fine | ||
b2.use Create | ||
b2.use action_boot | ||
else | ||
b2.use PrepareNFSValidIds | ||
b2.use SyncedFolderCleanup | ||
b2.use SyncedFolders | ||
b2.use PrepareNFSSettings | ||
b2.use action_start | ||
end | ||
end | ||
end | ||
end | ||
|
||
# This action just runs the provisioners on the machine. | ||
def self.action_provision | ||
Vagrant::Action::Builder.new.tap do |b| | ||
b.use ConfigValidate | ||
b.use Call, IsState, :not_created do |env, b2| | ||
if env[:result] | ||
b2.use Message, I18n.t("docker_provider.messages.not_created") | ||
next | ||
end | ||
|
||
b2.use Call, IsState, :running do |env2, b3| | ||
if !env2[:result] | ||
b3.use Message, I18n.t("docker_provider.messages.not_running") | ||
next | ||
end | ||
|
||
b3.use Provision | ||
end | ||
end | ||
end | ||
end | ||
|
||
# This is the action that is primarily responsible for halting | ||
# the virtual machine, gracefully or by force. | ||
def self.action_halt | ||
Vagrant::Action::Builder.new.tap do |b| | ||
b.use Call, IsState, :not_created do |env, b2| | ||
if env[:result] | ||
b2.use Message, I18n.t("docker_provider.messages.not_created") | ||
next | ||
end | ||
|
||
b2.use Call, GracefulHalt, :stopped, :running do |env2, b3| | ||
if !env2[:result] | ||
b3.use Stop | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
# This action is responsible for reloading the machine, which | ||
# brings it down, sucks in new configuration, and brings the | ||
# machine back up with the new configuration. | ||
def self.action_reload | ||
Vagrant::Action::Builder.new.tap do |b| | ||
b.use Call, IsState, :not_created do |env, b2| | ||
if env[:result] | ||
b2.use Message, I18n.t("docker_provider.messages.not_created") | ||
next | ||
end | ||
|
||
b2.use ConfigValidate | ||
b2.use action_halt | ||
b2.use action_start | ||
end | ||
end | ||
end | ||
|
||
# This is the action that is primarily responsible for completely | ||
# freeing the resources of the underlying virtual machine. | ||
def self.action_destroy | ||
Vagrant::Action::Builder.new.tap do |b| | ||
b.use Call, IsState, :not_created do |env, b2| | ||
if env[:result] | ||
b2.use Message, I18n.t("docker_provider.messages.not_created") | ||
next | ||
end | ||
|
||
b2.use Call, DestroyConfirm do |env2, b3| | ||
if env2[:result] | ||
b3.use ConfigValidate | ||
b3.use EnvSet, :force_halt => true | ||
b3.use action_halt | ||
b3.use Destroy | ||
b3.use ProvisionerCleanup | ||
else | ||
b3.use Message, I18n.t("docker_provider.messages.will_not_destroy") | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
# This is the action that will exec into an SSH shell. | ||
def self.action_ssh | ||
Vagrant::Action::Builder.new.tap do |b| | ||
b.use Call, IsState, :not_created do |env, b2| | ||
if env[:result] | ||
b2.use Message, I18n.t("docker_provider.messages.not_created") | ||
next | ||
end | ||
|
||
b2.use Call, IsState, :running do |env2, b3| | ||
if !env2[:result] | ||
b3.use Message, I18n.t("docker_provider.messages.not_running") | ||
next | ||
end | ||
b3.use SSHExec | ||
end | ||
end | ||
end | ||
end | ||
|
||
# This is the action that will run a single SSH command. | ||
def self.action_ssh_run | ||
Vagrant::Action::Builder.new.tap do |b| | ||
b.use Call, IsState, :not_created do |env, b2| | ||
if env[:result] | ||
b2.use Message, I18n.t("docker_provider.messages.not_created") | ||
next | ||
end | ||
|
||
b2.use Call, IsState, :running do |env2, b3| | ||
if !env2[:result] | ||
raise Vagrant::Errors::VMNotRunningError | ||
end | ||
|
||
b3.use SSHRun | ||
end | ||
end | ||
end | ||
end | ||
|
||
def self.action_start | ||
Vagrant::Action::Builder.new.tap do |b| | ||
b.use ConfigValidate | ||
b.use Call, IsState, :running do |env, b2| | ||
# If the container is running, then our work here is done, exit | ||
next if env[:result] | ||
|
||
b2.use Provision | ||
b2.use Message, I18n.t("docker_provider.messages.starting") | ||
b2.use action_boot | ||
end | ||
end | ||
end | ||
|
||
def self.action_boot | ||
Vagrant::Action::Builder.new.tap do |b| | ||
# TODO: b.use SetHostname | ||
b.use Start | ||
b.use WaitForCommunicator | ||
end | ||
end | ||
|
||
# The autoload farm | ||
action_root = Pathname.new(File.expand_path("../action", __FILE__)) | ||
autoload :Create, action_root.join("create") | ||
autoload :Destroy, action_root.join("destroy") | ||
autoload :ForwardPorts, action_root.join("forward_ports") | ||
autoload :Stop, action_root.join("stop") | ||
autoload :PrepareNFSValidIds, action_root.join("prepare_nfs_valid_ids") | ||
autoload :PrepareNFSSettings, action_root.join("prepare_nfs_settings") | ||
autoload :Start, action_root.join("start") | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
module VagrantPlugins | ||
module DockerProvider | ||
module Action | ||
class Create | ||
def initialize(app, env) | ||
@app = app | ||
@@mutex ||= Mutex.new | ||
end | ||
|
||
def call(env) | ||
@env = env | ||
@machine = env[:machine] | ||
@provider_config = @machine.provider_config | ||
@machine_config = @machine.config | ||
@driver = @machine.provider.driver | ||
|
||
guard_cmd_configured! | ||
|
||
cid = '' | ||
@@mutex.synchronize do | ||
cid = @driver.create(create_params) | ||
end | ||
|
||
@machine.id = cid | ||
@app.call(env) | ||
end | ||
|
||
def create_params | ||
container_name = "#{@env[:root_path].basename.to_s}_#{@machine.name}" | ||
container_name.gsub!(/[^-a-z0-9_]/i, "") | ||
container_name << "_#{Time.now.to_i}" | ||
|
||
{ | ||
image: @provider_config.image, | ||
cmd: @provider_config.cmd, | ||
ports: forwarded_ports, | ||
name: container_name, | ||
hostname: @machine_config.vm.hostname, | ||
volumes: @provider_config.volumes, | ||
privileged: @provider_config.privileged | ||
} | ||
end | ||
|
||
def forwarded_ports | ||
@env[:forwarded_ports].map do |fp| | ||
# TODO: Support for the protocol argument | ||
"#{fp[:host]}:#{fp[:guest]}" | ||
end.compact | ||
end | ||
|
||
def guard_cmd_configured! | ||
if ! @provider_config.image | ||
raise Errors::ImageNotConfiguredError, name: @machine.name | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
module VagrantPlugins | ||
module DockerProvider | ||
module Action | ||
class Destroy | ||
def initialize(app, env) | ||
@app = app | ||
end | ||
|
||
def call(env) | ||
env[:ui].info I18n.t("vagrant.actions.vm.destroy.destroying") | ||
|
||
machine = env[:machine] | ||
config = machine.provider_config | ||
driver = machine.provider.driver | ||
|
||
driver.rm(machine.id) | ||
machine.id = nil | ||
|
||
@app.call env | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
module VagrantPlugins | ||
module DockerProvider | ||
module Action | ||
class ForwardPorts | ||
def initialize(app, env) | ||
@app = app | ||
end | ||
|
||
def call(env) | ||
@env = env | ||
|
||
env[:forwarded_ports] = compile_forwarded_ports(env[:machine].config) | ||
|
||
if env[:forwarded_ports].any? | ||
env[:ui].info I18n.t("vagrant.actions.vm.forward_ports.forwarding") | ||
inform_forwarded_ports(env[:forwarded_ports]) | ||
end | ||
|
||
# FIXME: Check whether the container has already been created with | ||
# different exposed ports and let the user know about it | ||
|
||
@app.call env | ||
end | ||
|
||
def inform_forwarded_ports(ports) | ||
ports.each do |fp| | ||
message_attributes = { | ||
:adapter => 'eth0', | ||
:guest_port => fp[:guest], | ||
:host_port => fp[:host] | ||
} | ||
|
||
@env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.forwarding_entry", | ||
message_attributes)) | ||
end | ||
end | ||
|
||
private | ||
|
||
def compile_forwarded_ports(config) | ||
mappings = {} | ||
|
||
config.vm.networks.each do |type, options| | ||
if type == :forwarded_port && options[:id] != 'ssh' | ||
mappings[options[:host]] = options | ||
end | ||
end | ||
|
||
mappings.values | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
module VagrantPlugins | ||
module DockerProvider | ||
module Action | ||
class PrepareNFSSettings | ||
include Vagrant::Util::Retryable | ||
|
||
def initialize(app, env) | ||
@app = app | ||
@logger = Log4r::Logger.new("vagrant::action::vm::nfs") | ||
end | ||
|
||
def call(env) | ||
@machine = env[:machine] | ||
|
||
@app.call(env) | ||
|
||
if using_nfs? && !privileged_container? | ||
raise Errors::NfsWithoutPrivilegedError | ||
end | ||
|
||
if using_nfs? | ||
@logger.info("Using NFS, preparing NFS settings by reading host IP and machine IP") | ||
add_ips_to_env!(env) | ||
end | ||
end | ||
|
||
# We're using NFS if we have any synced folder with NFS configured. If | ||
# we are not using NFS we don't need to do the extra work to | ||
# populate these fields in the environment. | ||
def using_nfs? | ||
@machine.config.vm.synced_folders.any? { |_, opts| opts[:type] == :nfs } | ||
end | ||
|
||
def privileged_container? | ||
@machine.provider.driver.privileged?(@machine.id) | ||
end | ||
|
||
# Extracts the proper host and guest IPs for NFS mounts and stores them | ||
# in the environment for the SyncedFolder action to use them in | ||
# mounting. | ||
# | ||
# The ! indicates that this method modifies its argument. | ||
def add_ips_to_env!(env) | ||
provider = env[:machine].provider | ||
|
||
host_ip = provider.driver.docker_bridge_ip | ||
machine_ip = provider.ssh_info[:host] | ||
|
||
raise Vagrant::Errors::NFSNoHostonlyNetwork if !host_ip || !machine_ip | ||
|
||
env[:nfs_host_ip] = host_ip | ||
env[:nfs_machine_ip] = machine_ip | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.