From d9a53a4728c20e98ca3eb80892cb1b9ade8539cd Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 20:32:31 -0300 Subject: [PATCH 01/17] provisioners/docker: Change to VagrantPlugins::DockerProvisioner namespace --- .../docker/cap/debian/docker_configure_auto_start.rb | 2 +- plugins/provisioners/docker/cap/debian/docker_install.rb | 2 +- plugins/provisioners/docker/cap/debian/docker_start_service.rb | 2 +- .../docker/cap/linux/docker_configure_vagrant_user.rb | 2 +- plugins/provisioners/docker/cap/linux/docker_installed.rb | 2 +- .../docker/cap/redhat/docker_configure_auto_start.rb | 2 +- plugins/provisioners/docker/cap/redhat/docker_install.rb | 2 +- plugins/provisioners/docker/cap/redhat/docker_start_service.rb | 2 +- plugins/provisioners/docker/client.rb | 2 +- plugins/provisioners/docker/config.rb | 2 +- plugins/provisioners/docker/installer.rb | 2 +- plugins/provisioners/docker/plugin.rb | 2 +- plugins/provisioners/docker/provisioner.rb | 2 +- test/unit/plugins/provisioners/docker/config_test.rb | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/plugins/provisioners/docker/cap/debian/docker_configure_auto_start.rb b/plugins/provisioners/docker/cap/debian/docker_configure_auto_start.rb index 8a04e6cc577..1e85f4071e8 100644 --- a/plugins/provisioners/docker/cap/debian/docker_configure_auto_start.rb +++ b/plugins/provisioners/docker/cap/debian/docker_configure_auto_start.rb @@ -1,5 +1,5 @@ module VagrantPlugins - module Docker + module DockerProvisioner module Cap module Debian module DockerConfigureAutoStart diff --git a/plugins/provisioners/docker/cap/debian/docker_install.rb b/plugins/provisioners/docker/cap/debian/docker_install.rb index 22c7eee78a4..23f3b43eff4 100644 --- a/plugins/provisioners/docker/cap/debian/docker_install.rb +++ b/plugins/provisioners/docker/cap/debian/docker_install.rb @@ -1,5 +1,5 @@ module VagrantPlugins - module Docker + module DockerProvisioner module Cap module Debian module DockerInstall diff --git a/plugins/provisioners/docker/cap/debian/docker_start_service.rb b/plugins/provisioners/docker/cap/debian/docker_start_service.rb index a97bade8b31..63c1e318334 100644 --- a/plugins/provisioners/docker/cap/debian/docker_start_service.rb +++ b/plugins/provisioners/docker/cap/debian/docker_start_service.rb @@ -1,5 +1,5 @@ module VagrantPlugins - module Docker + module DockerProvisioner module Cap module Debian module DockerStartService diff --git a/plugins/provisioners/docker/cap/linux/docker_configure_vagrant_user.rb b/plugins/provisioners/docker/cap/linux/docker_configure_vagrant_user.rb index e65a33d4f01..7a3d87e947d 100644 --- a/plugins/provisioners/docker/cap/linux/docker_configure_vagrant_user.rb +++ b/plugins/provisioners/docker/cap/linux/docker_configure_vagrant_user.rb @@ -1,5 +1,5 @@ module VagrantPlugins - module Docker + module DockerProvisioner module Cap module Linux module DockerConfigureVagrantUser diff --git a/plugins/provisioners/docker/cap/linux/docker_installed.rb b/plugins/provisioners/docker/cap/linux/docker_installed.rb index f5d6935014e..f1d05fa2f39 100644 --- a/plugins/provisioners/docker/cap/linux/docker_installed.rb +++ b/plugins/provisioners/docker/cap/linux/docker_installed.rb @@ -1,5 +1,5 @@ module VagrantPlugins - module Docker + module DockerProvisioner module Cap module Linux module DockerInstalled diff --git a/plugins/provisioners/docker/cap/redhat/docker_configure_auto_start.rb b/plugins/provisioners/docker/cap/redhat/docker_configure_auto_start.rb index 696d946fc31..aaae9d78793 100644 --- a/plugins/provisioners/docker/cap/redhat/docker_configure_auto_start.rb +++ b/plugins/provisioners/docker/cap/redhat/docker_configure_auto_start.rb @@ -1,5 +1,5 @@ module VagrantPlugins - module Docker + module DockerProvisioner module Cap module Redhat module DockerConfigureAutoStart diff --git a/plugins/provisioners/docker/cap/redhat/docker_install.rb b/plugins/provisioners/docker/cap/redhat/docker_install.rb index a7374696dc1..a0ef03cb04f 100644 --- a/plugins/provisioners/docker/cap/redhat/docker_install.rb +++ b/plugins/provisioners/docker/cap/redhat/docker_install.rb @@ -1,5 +1,5 @@ module VagrantPlugins - module Docker + module DockerProvisioner module Cap module Redhat module DockerInstall diff --git a/plugins/provisioners/docker/cap/redhat/docker_start_service.rb b/plugins/provisioners/docker/cap/redhat/docker_start_service.rb index 263b2c3edc8..2e7662f0083 100644 --- a/plugins/provisioners/docker/cap/redhat/docker_start_service.rb +++ b/plugins/provisioners/docker/cap/redhat/docker_start_service.rb @@ -1,5 +1,5 @@ module VagrantPlugins - module Docker + module DockerProvisioner module Cap module Redhat module DockerStartService diff --git a/plugins/provisioners/docker/client.rb b/plugins/provisioners/docker/client.rb index 5feb3712bee..fdcf0555626 100644 --- a/plugins/provisioners/docker/client.rb +++ b/plugins/provisioners/docker/client.rb @@ -1,7 +1,7 @@ require 'digest/sha1' module VagrantPlugins - module Docker + module DockerProvisioner class Client def initialize(machine) @machine = machine diff --git a/plugins/provisioners/docker/config.rb b/plugins/provisioners/docker/config.rb index e38d607b4e7..c96e9730522 100644 --- a/plugins/provisioners/docker/config.rb +++ b/plugins/provisioners/docker/config.rb @@ -1,7 +1,7 @@ require 'set' module VagrantPlugins - module Docker + module DockerProvisioner class Config < Vagrant.plugin("2", :config) attr_reader :images attr_accessor :version diff --git a/plugins/provisioners/docker/installer.rb b/plugins/provisioners/docker/installer.rb index 8f2fbf2b055..01028f5c013 100644 --- a/plugins/provisioners/docker/installer.rb +++ b/plugins/provisioners/docker/installer.rb @@ -1,5 +1,5 @@ module VagrantPlugins - module Docker + module DockerProvisioner class Installer def initialize(machine, version) @machine = machine diff --git a/plugins/provisioners/docker/plugin.rb b/plugins/provisioners/docker/plugin.rb index 3c73279ac06..52db5178745 100644 --- a/plugins/provisioners/docker/plugin.rb +++ b/plugins/provisioners/docker/plugin.rb @@ -1,7 +1,7 @@ require "vagrant" module VagrantPlugins - module Docker + module DockerProvisioner class Plugin < Vagrant.plugin("2") name "docker" description <<-DESC diff --git a/plugins/provisioners/docker/provisioner.rb b/plugins/provisioners/docker/provisioner.rb index d378b2d9ab7..8b9d609a387 100644 --- a/plugins/provisioners/docker/provisioner.rb +++ b/plugins/provisioners/docker/provisioner.rb @@ -2,7 +2,7 @@ require_relative "installer" module VagrantPlugins - module Docker + module DockerProvisioner class DockerError < Vagrant::Errors::VagrantError error_namespace("vagrant.provisioners.docker") end diff --git a/test/unit/plugins/provisioners/docker/config_test.rb b/test/unit/plugins/provisioners/docker/config_test.rb index 282e7af4041..e34c24bbadb 100644 --- a/test/unit/plugins/provisioners/docker/config_test.rb +++ b/test/unit/plugins/provisioners/docker/config_test.rb @@ -2,7 +2,7 @@ require Vagrant.source_root.join("plugins/provisioners/docker/config") -describe VagrantPlugins::Docker::Config do +describe VagrantPlugins::DockerProvisioner::Config do subject { described_class.new } describe "#build_image" do From 1fc663bd880d9e371e70ae02a92ac580129503fd Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 20:45:46 -0300 Subject: [PATCH 02/17] providers/docker: Import code from https://github.com/fgrehm/docker-provider with some initial tweaks --- plugins/providers/docker/README.md | 206 ++++++++++++++++++ plugins/providers/docker/lib/action.rb | 175 +++++++++++++++ .../docker/lib/action/check_running.rb | 25 +++ plugins/providers/docker/lib/action/create.rb | 59 +++++ .../providers/docker/lib/action/created.rb | 18 ++ .../providers/docker/lib/action/destroy.rb | 24 ++ .../docker/lib/action/forward_ports.rb | 54 +++++ .../providers/docker/lib/action/is_running.rb | 20 ++ .../providers/docker/lib/action/message.rb | 23 ++ .../docker/lib/action/prepare_nfs_settings.rb | 59 +++++ .../lib/action/prepare_nfs_valid_ids.rb | 19 ++ plugins/providers/docker/lib/action/start.rb | 18 ++ plugins/providers/docker/lib/action/stop.rb | 21 ++ plugins/providers/docker/lib/config.rb | 35 +++ plugins/providers/docker/lib/driver.rb | 138 ++++++++++++ plugins/providers/docker/lib/errors.rb | 14 ++ plugins/providers/docker/lib/plugin.rb | 31 +++ plugins/providers/docker/lib/provider.rb | 61 ++++++ plugins/providers/docker/lib/synced_folder.rb | 20 ++ templates/locales/providers_docker.yml | 32 +++ .../plugins/providers/docker/driver_spec.rb | 202 +++++++++++++++++ 21 files changed, 1254 insertions(+) create mode 100644 plugins/providers/docker/README.md create mode 100644 plugins/providers/docker/lib/action.rb create mode 100644 plugins/providers/docker/lib/action/check_running.rb create mode 100644 plugins/providers/docker/lib/action/create.rb create mode 100644 plugins/providers/docker/lib/action/created.rb create mode 100644 plugins/providers/docker/lib/action/destroy.rb create mode 100644 plugins/providers/docker/lib/action/forward_ports.rb create mode 100644 plugins/providers/docker/lib/action/is_running.rb create mode 100644 plugins/providers/docker/lib/action/message.rb create mode 100644 plugins/providers/docker/lib/action/prepare_nfs_settings.rb create mode 100644 plugins/providers/docker/lib/action/prepare_nfs_valid_ids.rb create mode 100644 plugins/providers/docker/lib/action/start.rb create mode 100644 plugins/providers/docker/lib/action/stop.rb create mode 100644 plugins/providers/docker/lib/config.rb create mode 100644 plugins/providers/docker/lib/driver.rb create mode 100644 plugins/providers/docker/lib/errors.rb create mode 100644 plugins/providers/docker/lib/plugin.rb create mode 100644 plugins/providers/docker/lib/provider.rb create mode 100644 plugins/providers/docker/lib/synced_folder.rb create mode 100644 templates/locales/providers_docker.yml create mode 100644 test/unit/plugins/providers/docker/driver_spec.rb diff --git a/plugins/providers/docker/README.md b/plugins/providers/docker/README.md new file mode 100644 index 00000000000..e83e5efae5b --- /dev/null +++ b/plugins/providers/docker/README.md @@ -0,0 +1,206 @@ +# docker-provider + +[![Build Status](https://travis-ci.org/fgrehm/docker-provider.png?branch=master)](https://travis-ci.org/fgrehm/docker-provider) [![Gem Version](https://badge.fury.io/rb/docker-provider.png)](http://badge.fury.io/rb/docker-provider) [![Gittip](http://img.shields.io/gittip/fgrehm.svg)](https://www.gittip.com/fgrehm/) + +A [Docker](http://www.docker.io/) provider for [Vagrant](http://www.vagrantup.com/) +1.4+. + + +## Warning + +This is experimental, expect things to break. + + +## Requirements + +* Vagrant 1.4+ +* Docker 0.7.0+ + + +## Features + +* Support for Vagrant's `up`, `destroy`, `halt`, `reload` and `ssh` commands +* Port forwarding +* Synced / shared folders support +* Set container hostnames from Vagrantfiles +* Provision Docker containers with any built-in Vagrant provisioner (as long as the container has a SSH server running) + +You can see the plugin in action by watching the following asciicasts I published +prior to releasing 0.0.1: + +* http://asciinema.org/a/6162 +* http://asciinema.org/a/6177 + + +## Getting started + +If you are on a Mac / Windows machine, please fire up a x64 Linux VM with Docker + +Vagrant 1.4+ installed or use [this Vagrantfile](https://gist.github.com/fgrehm/fc48fb51ec7df64439e4) +and follow the instructions from within the VM. + +_It is likely that the plugin works with [boot2docker](http://boot2docker.github.io/) +but I personally haven't tried that yet. If you are able to give it a go please +[let me know](https://github.com/fgrehm/docker-provider/issues/new)._ + +### Initial setup + +_If you are trying things out from a Vagrant VM using the `Vagrantfile` gisted +above, you can skip to the next section_ + +The plugin requires Docker's executable to be available on current user's `PATH` +and that the current user has been added to the `docker` group since we are not +using `sudo` when interacting with Docker's CLI. For more information on setting +this up please check [this page](http://docs.docker.io/en/latest/installation/ubuntulinux/#giving-non-root-access). + +### `vagrant up` + +On its current state, the plugin is not "user friendly" and won't provide any kind +of feedback about the process of downloading Docker images, so before you add a +`docker-provider` [base box](http://docs.vagrantup.com/v2/boxes.html) it is recommended +that you `docker pull` the associated base box images prior to spinning up `docker-provider` +containers (otherwise you'll be staring at a blinking cursor without any progress +information for a while). + +Assuming you have Vagrant 1.4+ and Docker 0.7.0+ installed just sing that same +old song: + +```sh +vagrant plugin install docker-provider +docker pull fgrehm/vagrant-ubuntu:precise +vagrant box add precise64 http://bit.ly/vagrant-docker-precise +vagrant init precise64 +vagrant up --provider=docker +``` + +Under the hood, that base box will [configure](#configuration) `docker-provider` +to use the [`fgrehm/vagrant-ubuntu:precise`](https://index.docker.io/u/fgrehm/vagrant-ubuntu/) +image that approximates a standard Vagrant box (`vagrant` user, default SSH key, +etc.) and you should be good to go. + + +## Using custom images + +If you want to use a custom Docker image without creating a Vagrant base box, +you can use a "dummy" box and configure things from your `Vagrantfile` like +in [vagrant-digitalocean](https://github.com/smdahlen/vagrant-digitalocean#configure) +or [vagrant-aws](https://github.com/mitchellh/vagrant-aws#quick-start): + +```ruby +Vagrant.configure("2") do |config| + config.vm.box = "dummy" + config.vm.box_url = "http://bit.ly/vagrant-docker-dummy" + config.vm.provider :docker do |docker| + docker.image = "your/image:tag" + end +end +``` + + +## Configuration + +This provider exposes a few provider-specific configuration options +that are passed on to `docker run` under the hood when the container +is being created: + +* `image` - Docker image to run (required) +* `privileged` - Give extended privileges to the container (defaults to false) +* `cmd` - An array of strings that makes up for the command to run the container (defaults to what has been set on your `Dockerfile` as `CMD` or `ENTRYPOINT`) +* `ports` - An array of strings that makes up for the mapped network ports +* `volumes` - An array of strings that makes up for the data volumes used by the container + +These can be set like typical provider-specific configuration: + +```ruby +Vagrant.configure("2") do |config| + # ... other stuff + + config.vm.provider :docker do |docker| + docker.image = 'fgrehm/vagrant-ubuntu-dind:precise' + docker.privileged = true + docker.cmd = ['/dind', '/sbin/init'] + + docker.ports << '1234:22' + docker.volumes << '/var/lib/docker' + end +end +``` + + +## Networks + +Networking features in the form of `config.vm.network` are not supported with +`docker-provider` apart from [forwarded ports](). +If any of [`:private_network`](http://docs.vagrantup.com/v2/networking/private_network.html) +or [`:public_network`](http://docs.vagrantup.com/v2/networking/public_network.html) +are specified, Vagrant **won't** emit a warning. + +The same applies to changes on forwarded ports after the container has been +created, Vagrant **won't** emit a warning to let you know that the ports specified +on your `Vagrantfile` differs from what has been passed on to `docker run` when +creating the container. + +_At some point the plugin will emit warnings on the scenarios described above, but +not on its current state. Pull Requests are encouraged ;)_ + + +## Synced Folders + +There is support for synced folders on the form of [Docker volumes](http://docs.docker.io/en/latest/use/working_with_volumes/#mount-a-host-directory-as-a-container-volume) +but as with forwarded ports, you won't be able to change them after the container +has been created. [NFS](http://docs.vagrantup.com/v2/synced-folders/nfs.html) +synced folders are also supported (as long as you set the `privileged` +[config](#configuration) to true so that `docker-provider` can mount it on the +guest container) and are capable of being reconfigured between `vagrant reload`s +(different from Docker volumes). + +This is good enough for all built-in Vagrant provisioners (shell, +chef, and puppet) to work! + +_At some point the plugin will emit warnings when the configured `Vagrantfile` +synced folders / volumes differs from the ones used upon the container creation, +but not on its current state. Pull Requests are encouraged ;)_ + + +## Box format + +Every provider in Vagrant must introduce a custom box format. This provider introduces +`docker` boxes and you can view some examples in the [`boxes`](boxes) directory. +That directory also contains instructions on how to build them. + +The box format is basically just the required `metadata.json` file along with a +`Vagrantfile` that does default settings for the provider-specific configuration +for this provider. + + +## Available base boxes + +| LINK | DESCRIPTION | +| --- | --- | +| http://bit.ly/vagrant-docker-precise | Ubuntu 12.04 Precise x86_64 with Puppet and Chef preinstalled and configured to run `/sbin/init` | +| http://bit.ly/vagrant-docker-precise-dind | Ubuntu 12.04 Precise x86_64 based on the box above and ready to run [DinD](https://github.com/jpetazzo/dind) | + + +## Limitations + +As explained on the [networks](#networks) and [synced folder](#synced-folders) +sections above, there are some "gotchas" when using the plugin that you need to have +in mind before you start to pull your hair out. + +For instance, forwarded ports, synced folders and containers' hostnames will not be +reconfigured on `vagrant reload`s if they have changed and the plugin **_will not +give you any kind of warning or message_**. As an example, if you change your Puppet +manifests / Chef cookbooks paths (which are shared / synced folders under the hood), +**_you'll need to start from scratch_** (unless you make them NFS shared folders). +This is due to a limitation in Docker itself as we can't change those parameters +after the container has been created. + +Forwarded ports automatic collision handling is **_not supported as well_**. + + +## Contributing + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request diff --git a/plugins/providers/docker/lib/action.rb b/plugins/providers/docker/lib/action.rb new file mode 100644 index 00000000000..d09838c18de --- /dev/null +++ b/plugins/providers/docker/lib/action.rb @@ -0,0 +1,175 @@ +module VagrantPlugins + module DockerProvider + module Action + # Shortcuts + Builtin = Vagrant::Action::Builtin + Builder = Vagrant::Action::Builder + + # This action brings the "machine" up from nothing, including creating the + # container, configuring metadata, and booting. + def self.action_up + Builder.new.tap do |b| + b.use Builtin::ConfigValidate + b.use Builtin::Call, Created do |env, b2| + if !env[:result] + b2.use Builtin::HandleBoxUrl + # TODO: Find out where this fits into the process + # b2.use Builtin::EnvSet, :port_collision_repair => true + # b2.use Builtin::HandleForwardedPortCollisions + b2.use Builtin::Provision + b2.use PrepareNFSValidIds + b2.use Builtin::SyncedFolderCleanup + b2.use Builtin::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 Builtin::SyncedFolderCleanup + b2.use Builtin::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 + Builder.new.tap do |b| + b.use Builtin::ConfigValidate + b.use Builtin::Call, Created do |env1, b2| + if !env1[:result] + b2.use Message, :not_created + next + end + + b2.use Builtin::Call, IsRunning do |env2, b3| + if !env2[:result] + b3.use Message, :not_running + next + end + + b3.use Builtin::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 + Builder.new.tap do |b| + b.use Builtin::Call, Created do |env, b2| + if env[:result] + b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3| + if !env2[:result] + b3.use Stop + end + end + else + b2.use Message, :not_created + 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 + Builder.new.tap do |b| + b.use Builtin::Call, Created do |env1, b2| + if !env1[:result] + b2.use Message, :not_created + next + end + + b2.use Builtin::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 + Builder.new.tap do |b| + b.use Builtin::Call, Created do |env1, b2| + if !env1[:result] + b2.use Message, :not_created + next + end + + b2.use Builtin::Call, Builtin::DestroyConfirm do |env2, b3| + if env2[:result] + b3.use Builtin::ConfigValidate + b3.use Builtin::EnvSet, :force_halt => true + b3.use action_halt + b3.use Destroy + b3.use Builtin::ProvisionerCleanup + else + b3.use Message, :will_not_destroy + end + end + end + end + end + + # This is the action that will exec into an SSH shell. + def self.action_ssh + Builder.new.tap do |b| + b.use CheckRunning + b.use Builtin::SSHExec + end + end + + # This is the action that will run a single SSH command. + def self.action_ssh_run + Builder.new.tap do |b| + b.use CheckRunning + b.use Builtin::SSHRun + end + end + + def self.action_start + Builder.new.tap do |b| + b.use Builtin::ConfigValidate + b.use Builtin::Call, IsRunning do |env, b2| + # If the container is running, then our work here is done, exit + next if env[:result] + + b2.use Builtin::Provision + b2.use Message, :starting + b2.use action_boot + end + end + end + + def self.action_boot + Builder.new.tap do |b| + # TODO: b.use Builtin::SetHostname + b.use Start + b.use Builtin::WaitForCommunicator + end + end + + # The autoload farm + action_root = Pathname.new(File.expand_path("../action", __FILE__)) + autoload :CheckRunning, action_root.join("check_running") + autoload :Created, action_root.join("created") + 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 :Message, action_root.join("message") + autoload :PrepareNFSValidIds, action_root.join("prepare_nfs_valid_ids") + autoload :PrepareNFSSettings, action_root.join("prepare_nfs_settings") + autoload :IsRunning, action_root.join("is_running") + autoload :Start, action_root.join("start") + end + end +end diff --git a/plugins/providers/docker/lib/action/check_running.rb b/plugins/providers/docker/lib/action/check_running.rb new file mode 100644 index 00000000000..75224096d63 --- /dev/null +++ b/plugins/providers/docker/lib/action/check_running.rb @@ -0,0 +1,25 @@ +module VagrantPlugins + module DockerProvider + module Action + class CheckRunning + def initialize(app, env) + @app = app + end + + def call(env) + if env[:machine].state.id == :not_created + raise Vagrant::Errors::VMNotCreatedError + end + + if env[:machine].state.id == :stopped + raise Vagrant::Errors::VMNotRunningError + end + + # Call the next if we have one (but we shouldn't, since this + # middleware is built to run with the Call-type middlewares) + @app.call(env) + end + end + end + end +end diff --git a/plugins/providers/docker/lib/action/create.rb b/plugins/providers/docker/lib/action/create.rb new file mode 100644 index 00000000000..a8ea7fe6d29 --- /dev/null +++ b/plugins/providers/docker/lib/action/create.rb @@ -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 diff --git a/plugins/providers/docker/lib/action/created.rb b/plugins/providers/docker/lib/action/created.rb new file mode 100644 index 00000000000..39da1abdcdb --- /dev/null +++ b/plugins/providers/docker/lib/action/created.rb @@ -0,0 +1,18 @@ +module VagrantPlugins + module DockerProvider + module Action + class Created + def initialize(app, env) + @app = app + end + + def call(env) + machine = env[:machine] + driver = machine.provider.driver + env[:result] = machine.id && driver.created?(machine.id) + @app.call(env) + end + end + end + end +end diff --git a/plugins/providers/docker/lib/action/destroy.rb b/plugins/providers/docker/lib/action/destroy.rb new file mode 100644 index 00000000000..aba1cbf18f3 --- /dev/null +++ b/plugins/providers/docker/lib/action/destroy.rb @@ -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 diff --git a/plugins/providers/docker/lib/action/forward_ports.rb b/plugins/providers/docker/lib/action/forward_ports.rb new file mode 100644 index 00000000000..5051e7ab323 --- /dev/null +++ b/plugins/providers/docker/lib/action/forward_ports.rb @@ -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 diff --git a/plugins/providers/docker/lib/action/is_running.rb b/plugins/providers/docker/lib/action/is_running.rb new file mode 100644 index 00000000000..3357bb7dd6b --- /dev/null +++ b/plugins/providers/docker/lib/action/is_running.rb @@ -0,0 +1,20 @@ +module VagrantPlugins + module DockerProvider + module Action + class IsRunning + def initialize(app, env) + @app = app + end + + def call(env) + machine = env[:machine] + driver = machine.provider.driver + + env[:result] = driver.running?(machine.id) + + @app.call(env) + end + end + end + end +end diff --git a/plugins/providers/docker/lib/action/message.rb b/plugins/providers/docker/lib/action/message.rb new file mode 100644 index 00000000000..59a7bbfa70e --- /dev/null +++ b/plugins/providers/docker/lib/action/message.rb @@ -0,0 +1,23 @@ +module VagrantPlugins + module DockerProvider + module Action + # XXX: Is this really needed? Should we contribute this back to Vagrant's core? + class Message + def initialize(app, env, msg_key, type = :info) + @app = app + @msg_key = msg_key + @type = type + end + + def call(env) + machine = env[:machine] + message = I18n.t("docker_provider.messages.#{@msg_key}", name: machine.name) + + env[:ui].send @type, message + + @app.call env + end + end + end + end +end diff --git a/plugins/providers/docker/lib/action/prepare_nfs_settings.rb b/plugins/providers/docker/lib/action/prepare_nfs_settings.rb new file mode 100644 index 00000000000..5d437f472c1 --- /dev/null +++ b/plugins/providers/docker/lib/action/prepare_nfs_settings.rb @@ -0,0 +1,59 @@ +require_relative '../errors' + +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 diff --git a/plugins/providers/docker/lib/action/prepare_nfs_valid_ids.rb b/plugins/providers/docker/lib/action/prepare_nfs_valid_ids.rb new file mode 100644 index 00000000000..6bc79f3b31e --- /dev/null +++ b/plugins/providers/docker/lib/action/prepare_nfs_valid_ids.rb @@ -0,0 +1,19 @@ +module VagrantPlugins + module DockerProvider + module Action + class PrepareNFSValidIds + def initialize(app, env) + @app = app + @logger = Log4r::Logger.new("vagrant::action::vm::nfs") + end + + def call(env) + machine = env[:machine] + env[:nfs_valid_ids] = machine.provider.driver.all_containers + + @app.call(env) + end + end + end + end +end diff --git a/plugins/providers/docker/lib/action/start.rb b/plugins/providers/docker/lib/action/start.rb new file mode 100644 index 00000000000..e748adff696 --- /dev/null +++ b/plugins/providers/docker/lib/action/start.rb @@ -0,0 +1,18 @@ +module VagrantPlugins + module DockerProvider + module Action + class Start + def initialize(app, env) + @app = app + end + + def call(env) + machine = env[:machine] + driver = machine.provider.driver + driver.start(machine.id) + @app.call(env) + end + end + end + end +end diff --git a/plugins/providers/docker/lib/action/stop.rb b/plugins/providers/docker/lib/action/stop.rb new file mode 100644 index 00000000000..f743c8b6cef --- /dev/null +++ b/plugins/providers/docker/lib/action/stop.rb @@ -0,0 +1,21 @@ +module VagrantPlugins + module DockerProvider + module Action + class Stop + def initialize(app, env) + @app = app + end + + def call(env) + machine = env[:machine] + driver = machine.provider.driver + if driver.running?(machine.id) + env[:ui].info I18n.t("docker_provider.messages.stopping") + driver.stop(machine.id) + end + @app.call(env) + end + end + end + end +end diff --git a/plugins/providers/docker/lib/config.rb b/plugins/providers/docker/lib/config.rb new file mode 100644 index 00000000000..2b2c7198ed5 --- /dev/null +++ b/plugins/providers/docker/lib/config.rb @@ -0,0 +1,35 @@ +module VagrantPlugins + module DockerProvider + class Config < Vagrant.plugin("2", :config) + attr_accessor :image, :cmd, :ports, :volumes, :privileged + + def initialize + @image = nil + @cmd = UNSET_VALUE + @ports = [] + @privileged = UNSET_VALUE + @volumes = [] + end + + def finalize! + @cmd = [] if @cmd == UNSET_VALUE + @privileged = false if @privileged == UNSET_VALUE + end + + def validate(machine) + errors = _detected_errors + + # TODO: Detect if base image has a CMD / ENTRYPOINT set before erroring out + errors << I18n.t("docker_provider.errors.config.cmd_not_set") if @cmd == UNSET_VALUE + + { "docker-provider" => errors } + end + + private + + def using_nfs?(machine) + machine.config.vm.synced_folders.any? { |_, opts| opts[:type] == :nfs } + end + end + end +end diff --git a/plugins/providers/docker/lib/driver.rb b/plugins/providers/docker/lib/driver.rb new file mode 100644 index 00000000000..9a4a39e501d --- /dev/null +++ b/plugins/providers/docker/lib/driver.rb @@ -0,0 +1,138 @@ +require "vagrant/util/busy" +require "vagrant/util/subprocess" +require "vagrant/util/retryable" + +require 'log4r' +require 'json' + +module VagrantPlugins + module DockerProvider + class Driver + include Vagrant::Util::Retryable + + def initialize + @logger = Log4r::Logger.new("vagrant::docker::driver") + end + + def create(params) + image = params.fetch(:image) + ports = Array(params[:ports]) + volumes = Array(params[:volumes]) + name = params.fetch(:name) + cmd = Array(params.fetch(:cmd)) + + run_cmd = %W(docker run -name #{name} -d) + run_cmd += ports.map { |p| ['-p', p.to_s] } + run_cmd += volumes.map { |v| ['-v', v.to_s] } + run_cmd += %W(-privileged) if params[:privileged] + run_cmd += %W(-h #{params[:hostname]}) if params[:hostname] + run_cmd += [image, cmd] + + retryable(tries: 10, sleep: 1) do + execute(*run_cmd.flatten).chomp + end + end + + def state(cid) + case + when running?(cid) + :running + when created?(cid) + :stopped + else + :not_created + end + end + + def created?(cid) + result = execute('docker', 'ps', '-a', '-q', '-notrunc').to_s + result =~ /^#{Regexp.escape cid}$/ + end + + def running?(cid) + result = execute('docker', 'ps', '-q', '-notrunc') + result =~ /^#{Regexp.escape cid}$/m + end + + def privileged?(cid) + inspect_container(cid)['HostConfig']['Privileged'] + end + + def start(cid) + unless running?(cid) + execute('docker', 'start', cid) + # This resets the cached information we have around, allowing `vagrant reload`s + # to work properly + # TODO: Add spec to verify this behavior + @data = nil + end + end + + def stop(cid) + if running?(cid) + execute('docker', 'stop', '-t', '1', cid) + end + end + + def rm(cid) + if created?(cid) + execute('docker', 'rm', '-v', cid) + end + end + + def inspect_container(cid) + # DISCUSS: Is there a chance that this json will change after the container + # has been brought up? + @data ||= JSON.parse(execute('docker', 'inspect', cid)).first + end + + def all_containers + execute('docker', 'ps', '-a', '-q', '-notrunc').to_s.split + end + + def docker_bridge_ip + output = execute('/sbin/ip', '-4', 'addr', 'show', 'scope', 'global', 'docker0') + if output =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/ + return $1.to_s + else + # TODO: Raise an user friendly message + raise 'Unable to fetch docker bridge IP!' + end + end + + private + + def execute(*cmd, &block) + result = raw(*cmd, &block) + + if result.exit_code != 0 + if @interrupted + @logger.info("Exit code != 0, but interrupted. Ignoring.") + else + msg = result.stdout.gsub("\r\n", "\n") + msg << result.stderr.gsub("\r\n", "\n") + raise "#{cmd.inspect}\n#{msg}" #Errors::ExecuteError, :command => command.inspect + end + end + + # Return the output, making sure to replace any Windows-style + # newlines with Unix-style. + result.stdout.gsub("\r\n", "\n") + end + + def raw(*cmd, &block) + int_callback = lambda do + @interrupted = true + @logger.info("Interrupted.") + end + + # Append in the options for subprocess + cmd << { :notify => [:stdout, :stderr] } + + Vagrant::Util::Busy.busy(int_callback) do + Vagrant::Util::Subprocess.execute(*cmd, &block) + end + end + end + end +end diff --git a/plugins/providers/docker/lib/errors.rb b/plugins/providers/docker/lib/errors.rb new file mode 100644 index 00000000000..68b3fbd7102 --- /dev/null +++ b/plugins/providers/docker/lib/errors.rb @@ -0,0 +1,14 @@ +require 'vagrant/errors' + +module VagrantPlugins + module DockerProvider + module Errors + class ImageNotConfiguredError < Vagrant::Errors::VagrantError + error_key(:docker_provider_image_not_configured) + end + class NfsWithoutPrivilegedError < Vagrant::Errors::VagrantError + error_key(:docker_provider_nfs_without_privileged) + end + end + end +end diff --git a/plugins/providers/docker/lib/plugin.rb b/plugins/providers/docker/lib/plugin.rb new file mode 100644 index 00000000000..abe8ae6c28b --- /dev/null +++ b/plugins/providers/docker/lib/plugin.rb @@ -0,0 +1,31 @@ +# TODO: Switch to Vagrant.require_version before 1.0.0 +# see: https://github.com/mitchellh/vagrant/blob/bc55081e9ffaa6820113e449a9f76b293a29b27d/lib/vagrant.rb#L202-L228 +unless Gem::Requirement.new('>= 1.4.0').satisfied_by?(Gem::Version.new(Vagrant::VERSION)) + raise 'docker-provider requires Vagrant >= 1.4.0 in order to work!' +end + +I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml') +I18n.reload! + +module VagrantPlugins + module DockerProvider + class Plugin < Vagrant.plugin("2") + name "docker-provider" + + provider(:docker, parallel: true) do + require_relative 'provider' + Provider + end + + config(:docker, :provider) do + require_relative 'config' + Config + end + + synced_folder(:docker) do + require File.expand_path("../synced_folder", __FILE__) + SyncedFolder + end + end + end +end diff --git a/plugins/providers/docker/lib/provider.rb b/plugins/providers/docker/lib/provider.rb new file mode 100644 index 00000000000..fcc48230fd0 --- /dev/null +++ b/plugins/providers/docker/lib/provider.rb @@ -0,0 +1,61 @@ +require "log4r" + +require_relative 'driver' +require_relative 'action' + +module VagrantPlugins + module DockerProvider + class Provider < Vagrant.plugin("2", :provider) + attr_reader :driver + + def initialize(machine) + @logger = Log4r::Logger.new("vagrant::provider::docker") + @machine = machine + @driver = Driver.new + end + + # @see Vagrant::Plugin::V2::Provider#action + def action(name) + action_method = "action_#{name}" + return Action.send(action_method) if Action.respond_to?(action_method) + nil + end + + # Returns the SSH info for accessing the Container. + def ssh_info + # If the Container is not created then we cannot possibly SSH into it, so + # we return nil. + return nil if state == :not_created + + network = @driver.inspect_container(@machine.id)['NetworkSettings'] + ip = network['IPAddress'] + + # If we were not able to identify the container's IP, we return nil + # here and we let Vagrant core deal with it ;) + return nil unless ip + + { + :host => ip, + :port => @machine.config.ssh.guest_port + } + end + + def state + state_id = nil + state_id = :not_created if !@machine.id || !@driver.created?(@machine.id) + state_id = @driver.state(@machine.id) if @machine.id && !state_id + state_id = :unknown if !state_id + + short = state_id.to_s.gsub("_", " ") + long = I18n.t("vagrant.commands.status.#{state_id}") + + Vagrant::MachineState.new(state_id, short, long) + end + + def to_s + id = @machine.id ? @machine.id : "new container" + "Docker (#{id})" + end + end + end +end diff --git a/plugins/providers/docker/lib/synced_folder.rb b/plugins/providers/docker/lib/synced_folder.rb new file mode 100644 index 00000000000..9aad24761d7 --- /dev/null +++ b/plugins/providers/docker/lib/synced_folder.rb @@ -0,0 +1,20 @@ +module VagrantPlugins + module DockerProvider + class SyncedFolder < Vagrant.plugin("2", :synced_folder) + def usable?(machine) + # These synced folders only work if the provider is Docker + machine.provider_name == :docker + 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| + host_path = File.expand_path(data[:hostpath], machine.env.root_path) + guest_path = data[:guestpath] + machine.provider_config.volumes << "#{host_path}:#{guest_path}" + end + end + end + end +end diff --git a/templates/locales/providers_docker.yml b/templates/locales/providers_docker.yml new file mode 100644 index 00000000000..04db785ebfd --- /dev/null +++ b/templates/locales/providers_docker.yml @@ -0,0 +1,32 @@ +en: + docker_provider: + messages: + not_created: |- + The container hasn't been created yet. + not_running: |- + The container is not currently running. + will_not_destroy: |- + The container '%{name}' will not be destroyed, since the confirmation + was declined. + starting: |- + Starting container... + stopping: |- + Stopping container... + container_ready: |- + Container started and ready for use! + + errors: + config: + cmd_not_set: |- + The Docker command has not been set! + + vagrant: + errors: + docker_provider_nfs_without_privileged: |- + You've configured a NFS synced folder but didn't enable privileged + mode for the container. Please set the `privileged` option to true + on the provider block from your Vagrantfile, recreate the container + and try again. + + docker_provider_image_not_configured: |- + The base Docker image has not been set for the '%{name}' VM! diff --git a/test/unit/plugins/providers/docker/driver_spec.rb b/test/unit/plugins/providers/docker/driver_spec.rb new file mode 100644 index 00000000000..b057d0d0eae --- /dev/null +++ b/test/unit/plugins/providers/docker/driver_spec.rb @@ -0,0 +1,202 @@ +require_relative "../../../base" + +require Vagrant.source_root.join("plugins/providers/docker/driver") + +describe VagrantPlugins::DockerProvider::Driver do + let(:cmd_executed) { @cmd } + let(:cid) { 'side-1-song-10' } + + before do + subject.stub(:execute) { |*args| @cmd = args.join(' ') } + end + + describe '#create' do + let(:params) { { + image: 'jimi/hendrix:eletric-ladyland', + cmd: ['play', 'voodoo-chile'], + ports: '8080:80', + volumes: '/host/path:guest/path', + name: cid, + hostname: 'jimi-hendrix', + privileged: true + } } + + before { subject.create(params) } + + it 'runs a detached docker image' do + expect(cmd_executed).to match(/^docker run .+ -d .+ #{Regexp.escape params[:image]}/) + end + + it 'sets container name' do + expect(cmd_executed).to match(/-name #{Regexp.escape params[:name]}/) + end + + it 'forwards ports' do + expect(cmd_executed).to match(/-p #{params[:ports]} .+ #{Regexp.escape params[:image]}/) + end + + it 'shares folders' do + expect(cmd_executed).to match(/-v #{params[:volumes]} .+ #{Regexp.escape params[:image]}/) + end + + it 'is able to run a privileged container' do + expect(cmd_executed).to match(/-privileged .+ #{Regexp.escape params[:image]}/) + end + + it 'sets the hostname if specified' do + expect(cmd_executed).to match(/-h #{params[:hostname]} #{Regexp.escape params[:image]}/) + end + + it 'executes the provided command' do + expect(cmd_executed).to match(/#{Regexp.escape params[:image]} #{Regexp.escape params[:cmd].join(' ')}/) + end + end + + describe '#created?' do + let(:result) { subject.created?(cid) } + + it 'performs the check on all containers list' do + subject.created?(cid) + expect(cmd_executed).to match(/docker ps \-a \-q/) + end + + context 'when container exists' do + before { subject.stub(execute: "foo\n#{cid}\nbar") } + it { expect(result).to be_true } + end + + context 'when container does not exist' do + before { subject.stub(execute: "foo\n#{cid}extra\nbar") } + it { expect(result).to be_false } + end + end + + describe '#running?' do + let(:result) { subject.running?(cid) } + + it 'performs the check on the running containers list' do + subject.running?(cid) + expect(cmd_executed).to match(/docker ps \-q/) + expect(cmd_executed).to_not include('-a') + end + + context 'when container exists' do + before { subject.stub(execute: "foo\n#{cid}\nbar") } + it { expect(result).to be_true } + end + + context 'when container does not exist' do + before { subject.stub(execute: "foo\n#{cid}extra\nbar") } + it { expect(result).to be_false } + end + end + + describe '#privileged?' do + it 'identifies privileged containers' do + subject.stub(inspect_container: {'HostConfig' => {"Privileged" => true}}) + expect(subject).to be_privileged(cid) + end + + it 'identifies unprivileged containers' do + subject.stub(inspect_container: {'HostConfig' => {"Privileged" => false}}) + expect(subject).to_not be_privileged(cid) + end + end + + describe '#start' do + context 'when container is running' do + before { subject.stub(running?: true) } + + it 'does not start the container' do + subject.should_not_receive(:execute).with('docker', 'start', cid) + subject.start(cid) + end + end + + context 'when container is not running' do + before { subject.stub(running?: false) } + + it 'starts the container' do + subject.should_receive(:execute).with('docker', 'start', cid) + subject.start(cid) + end + end + end + + describe '#stop' do + context 'when container is running' do + before { subject.stub(running?: true) } + + it 'stops the container' do + subject.should_receive(:execute).with('docker', 'stop', '-t', '1', cid) + subject.stop(cid) + end + end + + context 'when container is not running' do + before { subject.stub(running?: false) } + + it 'does not stop container' do + subject.should_not_receive(:execute).with('docker', 'stop', '-t', '1', cid) + subject.stop(cid) + end + end + end + + describe '#rm' do + context 'when container has been created' do + before { subject.stub(created?: true) } + + it 'removes the container' do + subject.should_receive(:execute).with('docker', 'rm', '-v', cid) + subject.rm(cid) + end + end + + context 'when container has not been created' do + before { subject.stub(created?: false) } + + it 'does not attempt to remove the container' do + subject.should_not_receive(:execute).with('docker', 'rm', '-v', cid) + subject.rm(cid) + end + end + end + + describe '#inspect_container' do + let(:data) { '[{"json": "value"}]' } + + before { subject.stub(execute: data) } + + it 'inspects the container' do + subject.should_receive(:execute).with('docker', 'inspect', cid) + subject.inspect_container(cid) + end + + it 'parses the json output' do + expect(subject.inspect_container(cid)).to eq('json' => 'value') + end + end + + describe '#all_containers' do + let(:containers) { "container1\ncontainer2" } + + before { subject.stub(execute: containers) } + + it 'returns an array of all known containers' do + subject.should_receive(:execute).with('docker', 'ps', '-a', '-q', '-notrunc') + expect(subject.all_containers).to eq(['container1', 'container2']) + end + end + + describe '#docker_bridge_ip' do + let(:containers) { " inet 123.456.789.012/16 " } + + before { subject.stub(execute: containers) } + + it 'returns an array of all known containers' do + subject.should_receive(:execute).with('/sbin/ip', '-4', 'addr', 'show', 'scope', 'global', 'docker0') + expect(subject.docker_bridge_ip).to eq('123.456.789.012') + end + end +end From 6387af2c298b272ecc4e990c2e7fa6433970c073 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 20:59:51 -0300 Subject: [PATCH 03/17] providers/docker: Move code out of lib dir so that Vagrant can pick it up --- plugins/providers/docker/{lib => }/action.rb | 0 plugins/providers/docker/{lib => }/action/check_running.rb | 0 plugins/providers/docker/{lib => }/action/create.rb | 0 plugins/providers/docker/{lib => }/action/created.rb | 0 plugins/providers/docker/{lib => }/action/destroy.rb | 0 plugins/providers/docker/{lib => }/action/forward_ports.rb | 0 plugins/providers/docker/{lib => }/action/is_running.rb | 0 plugins/providers/docker/{lib => }/action/message.rb | 0 plugins/providers/docker/{lib => }/action/prepare_nfs_settings.rb | 0 .../providers/docker/{lib => }/action/prepare_nfs_valid_ids.rb | 0 plugins/providers/docker/{lib => }/action/start.rb | 0 plugins/providers/docker/{lib => }/action/stop.rb | 0 plugins/providers/docker/{lib => }/config.rb | 0 plugins/providers/docker/{lib => }/driver.rb | 0 plugins/providers/docker/{lib => }/errors.rb | 0 plugins/providers/docker/{lib => }/plugin.rb | 0 plugins/providers/docker/{lib => }/provider.rb | 0 plugins/providers/docker/{lib => }/synced_folder.rb | 0 18 files changed, 0 insertions(+), 0 deletions(-) rename plugins/providers/docker/{lib => }/action.rb (100%) rename plugins/providers/docker/{lib => }/action/check_running.rb (100%) rename plugins/providers/docker/{lib => }/action/create.rb (100%) rename plugins/providers/docker/{lib => }/action/created.rb (100%) rename plugins/providers/docker/{lib => }/action/destroy.rb (100%) rename plugins/providers/docker/{lib => }/action/forward_ports.rb (100%) rename plugins/providers/docker/{lib => }/action/is_running.rb (100%) rename plugins/providers/docker/{lib => }/action/message.rb (100%) rename plugins/providers/docker/{lib => }/action/prepare_nfs_settings.rb (100%) rename plugins/providers/docker/{lib => }/action/prepare_nfs_valid_ids.rb (100%) rename plugins/providers/docker/{lib => }/action/start.rb (100%) rename plugins/providers/docker/{lib => }/action/stop.rb (100%) rename plugins/providers/docker/{lib => }/config.rb (100%) rename plugins/providers/docker/{lib => }/driver.rb (100%) rename plugins/providers/docker/{lib => }/errors.rb (100%) rename plugins/providers/docker/{lib => }/plugin.rb (100%) rename plugins/providers/docker/{lib => }/provider.rb (100%) rename plugins/providers/docker/{lib => }/synced_folder.rb (100%) diff --git a/plugins/providers/docker/lib/action.rb b/plugins/providers/docker/action.rb similarity index 100% rename from plugins/providers/docker/lib/action.rb rename to plugins/providers/docker/action.rb diff --git a/plugins/providers/docker/lib/action/check_running.rb b/plugins/providers/docker/action/check_running.rb similarity index 100% rename from plugins/providers/docker/lib/action/check_running.rb rename to plugins/providers/docker/action/check_running.rb diff --git a/plugins/providers/docker/lib/action/create.rb b/plugins/providers/docker/action/create.rb similarity index 100% rename from plugins/providers/docker/lib/action/create.rb rename to plugins/providers/docker/action/create.rb diff --git a/plugins/providers/docker/lib/action/created.rb b/plugins/providers/docker/action/created.rb similarity index 100% rename from plugins/providers/docker/lib/action/created.rb rename to plugins/providers/docker/action/created.rb diff --git a/plugins/providers/docker/lib/action/destroy.rb b/plugins/providers/docker/action/destroy.rb similarity index 100% rename from plugins/providers/docker/lib/action/destroy.rb rename to plugins/providers/docker/action/destroy.rb diff --git a/plugins/providers/docker/lib/action/forward_ports.rb b/plugins/providers/docker/action/forward_ports.rb similarity index 100% rename from plugins/providers/docker/lib/action/forward_ports.rb rename to plugins/providers/docker/action/forward_ports.rb diff --git a/plugins/providers/docker/lib/action/is_running.rb b/plugins/providers/docker/action/is_running.rb similarity index 100% rename from plugins/providers/docker/lib/action/is_running.rb rename to plugins/providers/docker/action/is_running.rb diff --git a/plugins/providers/docker/lib/action/message.rb b/plugins/providers/docker/action/message.rb similarity index 100% rename from plugins/providers/docker/lib/action/message.rb rename to plugins/providers/docker/action/message.rb diff --git a/plugins/providers/docker/lib/action/prepare_nfs_settings.rb b/plugins/providers/docker/action/prepare_nfs_settings.rb similarity index 100% rename from plugins/providers/docker/lib/action/prepare_nfs_settings.rb rename to plugins/providers/docker/action/prepare_nfs_settings.rb diff --git a/plugins/providers/docker/lib/action/prepare_nfs_valid_ids.rb b/plugins/providers/docker/action/prepare_nfs_valid_ids.rb similarity index 100% rename from plugins/providers/docker/lib/action/prepare_nfs_valid_ids.rb rename to plugins/providers/docker/action/prepare_nfs_valid_ids.rb diff --git a/plugins/providers/docker/lib/action/start.rb b/plugins/providers/docker/action/start.rb similarity index 100% rename from plugins/providers/docker/lib/action/start.rb rename to plugins/providers/docker/action/start.rb diff --git a/plugins/providers/docker/lib/action/stop.rb b/plugins/providers/docker/action/stop.rb similarity index 100% rename from plugins/providers/docker/lib/action/stop.rb rename to plugins/providers/docker/action/stop.rb diff --git a/plugins/providers/docker/lib/config.rb b/plugins/providers/docker/config.rb similarity index 100% rename from plugins/providers/docker/lib/config.rb rename to plugins/providers/docker/config.rb diff --git a/plugins/providers/docker/lib/driver.rb b/plugins/providers/docker/driver.rb similarity index 100% rename from plugins/providers/docker/lib/driver.rb rename to plugins/providers/docker/driver.rb diff --git a/plugins/providers/docker/lib/errors.rb b/plugins/providers/docker/errors.rb similarity index 100% rename from plugins/providers/docker/lib/errors.rb rename to plugins/providers/docker/errors.rb diff --git a/plugins/providers/docker/lib/plugin.rb b/plugins/providers/docker/plugin.rb similarity index 100% rename from plugins/providers/docker/lib/plugin.rb rename to plugins/providers/docker/plugin.rb diff --git a/plugins/providers/docker/lib/provider.rb b/plugins/providers/docker/provider.rb similarity index 100% rename from plugins/providers/docker/lib/provider.rb rename to plugins/providers/docker/provider.rb diff --git a/plugins/providers/docker/lib/synced_folder.rb b/plugins/providers/docker/synced_folder.rb similarity index 100% rename from plugins/providers/docker/lib/synced_folder.rb rename to plugins/providers/docker/synced_folder.rb From 8eed0df8ec6e42650d8e269e3f1c2a2bbc1ba45b Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 21:00:41 -0300 Subject: [PATCH 04/17] providers/docker: Get rid of vagrant version check from old plugin --- plugins/providers/docker/plugin.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/plugins/providers/docker/plugin.rb b/plugins/providers/docker/plugin.rb index abe8ae6c28b..1420eed9fec 100644 --- a/plugins/providers/docker/plugin.rb +++ b/plugins/providers/docker/plugin.rb @@ -1,9 +1,3 @@ -# TODO: Switch to Vagrant.require_version before 1.0.0 -# see: https://github.com/mitchellh/vagrant/blob/bc55081e9ffaa6820113e449a9f76b293a29b27d/lib/vagrant.rb#L202-L228 -unless Gem::Requirement.new('>= 1.4.0').satisfied_by?(Gem::Version.new(Vagrant::VERSION)) - raise 'docker-provider requires Vagrant >= 1.4.0 in order to work!' -end - I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml') I18n.reload! From 091378bc0801990aa35b35243be67ddb1e98fc57 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 21:01:34 -0300 Subject: [PATCH 05/17] providers/docker: Lazy load locales --- plugins/providers/docker/plugin.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/plugins/providers/docker/plugin.rb b/plugins/providers/docker/plugin.rb index 1420eed9fec..05d3b8fab39 100644 --- a/plugins/providers/docker/plugin.rb +++ b/plugins/providers/docker/plugin.rb @@ -1,6 +1,3 @@ -I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml') -I18n.reload! - module VagrantPlugins module DockerProvider class Plugin < Vagrant.plugin("2") @@ -8,11 +5,13 @@ class Plugin < Vagrant.plugin("2") provider(:docker, parallel: true) do require_relative 'provider' + init! Provider end config(:docker, :provider) do require_relative 'config' + init! Config end @@ -20,6 +19,16 @@ class Plugin < Vagrant.plugin("2") require File.expand_path("../synced_folder", __FILE__) SyncedFolder end + + protected + + def self.init! + return if defined?(@_init) + I18n.load_path << File.expand_path( + "templates/locales/providers_docker.yml", Vagrant.source_root) + I18n.reload! + @_init = true + end end end end From 17e51248c3b1302fa3b74b450c13bd557f9da8af Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 21:04:15 -0300 Subject: [PATCH 06/17] providers/docker: Get rid of some explicit requires in favor of autoloading --- plugins/providers/docker/action/prepare_nfs_settings.rb | 2 -- plugins/providers/docker/errors.rb | 2 -- plugins/providers/docker/plugin.rb | 4 ++++ plugins/providers/docker/provider.rb | 3 --- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/plugins/providers/docker/action/prepare_nfs_settings.rb b/plugins/providers/docker/action/prepare_nfs_settings.rb index 5d437f472c1..860d69facb4 100644 --- a/plugins/providers/docker/action/prepare_nfs_settings.rb +++ b/plugins/providers/docker/action/prepare_nfs_settings.rb @@ -1,5 +1,3 @@ -require_relative '../errors' - module VagrantPlugins module DockerProvider module Action diff --git a/plugins/providers/docker/errors.rb b/plugins/providers/docker/errors.rb index 68b3fbd7102..77824b265e1 100644 --- a/plugins/providers/docker/errors.rb +++ b/plugins/providers/docker/errors.rb @@ -1,5 +1,3 @@ -require 'vagrant/errors' - module VagrantPlugins module DockerProvider module Errors diff --git a/plugins/providers/docker/plugin.rb b/plugins/providers/docker/plugin.rb index 05d3b8fab39..4f67b2a19ab 100644 --- a/plugins/providers/docker/plugin.rb +++ b/plugins/providers/docker/plugin.rb @@ -1,5 +1,9 @@ module VagrantPlugins module DockerProvider + autoload :Action, File.expand_path("../action", __FILE__) + autoload :Driver, File.expand_path("../driver", __FILE__) + autoload :Errors, File.expand_path("../errors", __FILE__) + class Plugin < Vagrant.plugin("2") name "docker-provider" diff --git a/plugins/providers/docker/provider.rb b/plugins/providers/docker/provider.rb index fcc48230fd0..c18a7438d30 100644 --- a/plugins/providers/docker/provider.rb +++ b/plugins/providers/docker/provider.rb @@ -1,8 +1,5 @@ require "log4r" -require_relative 'driver' -require_relative 'action' - module VagrantPlugins module DockerProvider class Provider < Vagrant.plugin("2", :provider) From d8dce00e642e2c8dc64b28a7b6a115801ea38ecc Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 21:04:35 -0300 Subject: [PATCH 07/17] providers/docker: Add description --- plugins/providers/docker/plugin.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/providers/docker/plugin.rb b/plugins/providers/docker/plugin.rb index 4f67b2a19ab..9e6c4f9c733 100644 --- a/plugins/providers/docker/plugin.rb +++ b/plugins/providers/docker/plugin.rb @@ -6,6 +6,10 @@ module DockerProvider class Plugin < Vagrant.plugin("2") name "docker-provider" + description <<-EOF + The Docker provider allows Vagrant to manage and control + Docker containers. + EOF provider(:docker, parallel: true) do require_relative 'provider' From e013b8d1a4e2fccb5af600e89f62c13fe258a5ae Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 21:14:25 -0300 Subject: [PATCH 08/17] providers/docker: Remove Vagrant::Action shortcuts as we are on core now --- plugins/providers/docker/action.rb | 82 +++++++++++++++--------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/plugins/providers/docker/action.rb b/plugins/providers/docker/action.rb index d09838c18de..701dc148447 100644 --- a/plugins/providers/docker/action.rb +++ b/plugins/providers/docker/action.rb @@ -1,25 +1,23 @@ module VagrantPlugins module DockerProvider module Action - # Shortcuts - Builtin = Vagrant::Action::Builtin - Builder = Vagrant::Action::Builder + include Vagrant::Action::Builtin # This action brings the "machine" up from nothing, including creating the # container, configuring metadata, and booting. def self.action_up - Builder.new.tap do |b| - b.use Builtin::ConfigValidate - b.use Builtin::Call, Created do |env, b2| + Vagrant::Action::Builder.new.tap do |b| + b.use ConfigValidate + b.use Call, Created do |env, b2| if !env[:result] - b2.use Builtin::HandleBoxUrl + b2.use HandleBoxUrl # TODO: Find out where this fits into the process - # b2.use Builtin::EnvSet, :port_collision_repair => true - # b2.use Builtin::HandleForwardedPortCollisions - b2.use Builtin::Provision + # b2.use EnvSet, :port_collision_repair => true + # b2.use HandleForwardedPortCollisions + b2.use Provision b2.use PrepareNFSValidIds - b2.use Builtin::SyncedFolderCleanup - b2.use Builtin::SyncedFolders + b2.use SyncedFolderCleanup + b2.use SyncedFolders b2.use PrepareNFSSettings b2.use ForwardPorts # This will actually create and start, but that's fine @@ -27,8 +25,8 @@ def self.action_up b2.use action_boot else b2.use PrepareNFSValidIds - b2.use Builtin::SyncedFolderCleanup - b2.use Builtin::SyncedFolders + b2.use SyncedFolderCleanup + b2.use SyncedFolders b2.use PrepareNFSSettings b2.use action_start end @@ -38,21 +36,21 @@ def self.action_up # This action just runs the provisioners on the machine. def self.action_provision - Builder.new.tap do |b| - b.use Builtin::ConfigValidate - b.use Builtin::Call, Created do |env1, b2| + Vagrant::Action::Builder.new.tap do |b| + b.use ConfigValidate + b.use Call, Created do |env1, b2| if !env1[:result] b2.use Message, :not_created next end - b2.use Builtin::Call, IsRunning do |env2, b3| + b2.use Call, IsRunning do |env2, b3| if !env2[:result] b3.use Message, :not_running next end - b3.use Builtin::Provision + b3.use Provision end end end @@ -61,10 +59,10 @@ def self.action_provision # This is the action that is primarily responsible for halting # the virtual machine, gracefully or by force. def self.action_halt - Builder.new.tap do |b| - b.use Builtin::Call, Created do |env, b2| + Vagrant::Action::Builder.new.tap do |b| + b.use Call, Created do |env, b2| if env[:result] - b2.use Builtin::Call, Builtin::GracefulHalt, :stopped, :running do |env2, b3| + b2.use Call, GracefulHalt, :stopped, :running do |env2, b3| if !env2[:result] b3.use Stop end @@ -80,14 +78,14 @@ def self.action_halt # brings it down, sucks in new configuration, and brings the # machine back up with the new configuration. def self.action_reload - Builder.new.tap do |b| - b.use Builtin::Call, Created do |env1, b2| + Vagrant::Action::Builder.new.tap do |b| + b.use Call, Created do |env1, b2| if !env1[:result] b2.use Message, :not_created next end - b2.use Builtin::ConfigValidate + b2.use ConfigValidate b2.use action_halt b2.use action_start end @@ -97,20 +95,20 @@ def self.action_reload # This is the action that is primarily responsible for completely # freeing the resources of the underlying virtual machine. def self.action_destroy - Builder.new.tap do |b| - b.use Builtin::Call, Created do |env1, b2| + Vagrant::Action::Builder.new.tap do |b| + b.use Call, Created do |env1, b2| if !env1[:result] b2.use Message, :not_created next end - b2.use Builtin::Call, Builtin::DestroyConfirm do |env2, b3| + b2.use Call, DestroyConfirm do |env2, b3| if env2[:result] - b3.use Builtin::ConfigValidate - b3.use Builtin::EnvSet, :force_halt => true + b3.use ConfigValidate + b3.use EnvSet, :force_halt => true b3.use action_halt b3.use Destroy - b3.use Builtin::ProvisionerCleanup + b3.use ProvisionerCleanup else b3.use Message, :will_not_destroy end @@ -121,28 +119,28 @@ def self.action_destroy # This is the action that will exec into an SSH shell. def self.action_ssh - Builder.new.tap do |b| + Vagrant::Action::Builder.new.tap do |b| b.use CheckRunning - b.use Builtin::SSHExec + b.use SSHExec end end # This is the action that will run a single SSH command. def self.action_ssh_run - Builder.new.tap do |b| + Vagrant::Action::Builder.new.tap do |b| b.use CheckRunning - b.use Builtin::SSHRun + b.use SSHRun end end def self.action_start - Builder.new.tap do |b| - b.use Builtin::ConfigValidate - b.use Builtin::Call, IsRunning do |env, b2| + Vagrant::Action::Builder.new.tap do |b| + b.use ConfigValidate + b.use Call, IsRunning do |env, b2| # If the container is running, then our work here is done, exit next if env[:result] - b2.use Builtin::Provision + b2.use Provision b2.use Message, :starting b2.use action_boot end @@ -150,10 +148,10 @@ def self.action_start end def self.action_boot - Builder.new.tap do |b| - # TODO: b.use Builtin::SetHostname + Vagrant::Action::Builder.new.tap do |b| + # TODO: b.use SetHostname b.use Start - b.use Builtin::WaitForCommunicator + b.use WaitForCommunicator end end From 897ed3a08f6858d81c9ccfe32eec61a09371a73c Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 21:16:27 -0300 Subject: [PATCH 09/17] providers/docker: Switch to new HandleBox middleware --- plugins/providers/docker/action.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/providers/docker/action.rb b/plugins/providers/docker/action.rb index 701dc148447..aeccc9a563f 100644 --- a/plugins/providers/docker/action.rb +++ b/plugins/providers/docker/action.rb @@ -10,7 +10,7 @@ def self.action_up b.use ConfigValidate b.use Call, Created do |env, b2| if !env[:result] - b2.use HandleBoxUrl + b2.use HandleBox # TODO: Find out where this fits into the process # b2.use EnvSet, :port_collision_repair => true # b2.use HandleForwardedPortCollisions From 3ca1f3d3224158d4d53616a651278b63f771968c Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 21:21:40 -0300 Subject: [PATCH 10/17] providers/docker: Remove custom Action::Message --- plugins/providers/docker/action.rb | 15 +++++++------- plugins/providers/docker/action/message.rb | 23 ---------------------- 2 files changed, 7 insertions(+), 31 deletions(-) delete mode 100644 plugins/providers/docker/action/message.rb diff --git a/plugins/providers/docker/action.rb b/plugins/providers/docker/action.rb index aeccc9a563f..9f8c7717663 100644 --- a/plugins/providers/docker/action.rb +++ b/plugins/providers/docker/action.rb @@ -40,13 +40,13 @@ def self.action_provision b.use ConfigValidate b.use Call, Created do |env1, b2| if !env1[:result] - b2.use Message, :not_created + b2.use Message, I18n.t("docker_provider.messages.not_created") next end b2.use Call, IsRunning do |env2, b3| if !env2[:result] - b3.use Message, :not_running + b3.use Message, I18n.t("docker_provider.messages.not_running") next end @@ -68,7 +68,7 @@ def self.action_halt end end else - b2.use Message, :not_created + b2.use Message, I18n.t("docker_provider.messages.not_created") end end end @@ -81,7 +81,7 @@ def self.action_reload Vagrant::Action::Builder.new.tap do |b| b.use Call, Created do |env1, b2| if !env1[:result] - b2.use Message, :not_created + b2.use Message, I18n.t("docker_provider.messages.not_created") next end @@ -98,7 +98,7 @@ def self.action_destroy Vagrant::Action::Builder.new.tap do |b| b.use Call, Created do |env1, b2| if !env1[:result] - b2.use Message, :not_created + b2.use Message, I18n.t("docker_provider.messages.not_created") next end @@ -110,7 +110,7 @@ def self.action_destroy b3.use Destroy b3.use ProvisionerCleanup else - b3.use Message, :will_not_destroy + b3.use Message, I18n.t("docker_provider.messages.will_not_destroy") end end end @@ -141,7 +141,7 @@ def self.action_start next if env[:result] b2.use Provision - b2.use Message, :starting + b2.use Message, I18n.t("docker_provider.messages.starting") b2.use action_boot end end @@ -163,7 +163,6 @@ def self.action_boot autoload :Destroy, action_root.join("destroy") autoload :ForwardPorts, action_root.join("forward_ports") autoload :Stop, action_root.join("stop") - autoload :Message, action_root.join("message") autoload :PrepareNFSValidIds, action_root.join("prepare_nfs_valid_ids") autoload :PrepareNFSSettings, action_root.join("prepare_nfs_settings") autoload :IsRunning, action_root.join("is_running") diff --git a/plugins/providers/docker/action/message.rb b/plugins/providers/docker/action/message.rb deleted file mode 100644 index 59a7bbfa70e..00000000000 --- a/plugins/providers/docker/action/message.rb +++ /dev/null @@ -1,23 +0,0 @@ -module VagrantPlugins - module DockerProvider - module Action - # XXX: Is this really needed? Should we contribute this back to Vagrant's core? - class Message - def initialize(app, env, msg_key, type = :info) - @app = app - @msg_key = msg_key - @type = type - end - - def call(env) - machine = env[:machine] - message = I18n.t("docker_provider.messages.#{@msg_key}", name: machine.name) - - env[:ui].send @type, message - - @app.call env - end - end - end - end -end From ee5b7e56616cff9f95d82bdca0a6bea5d6f14df8 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 21:51:58 -0300 Subject: [PATCH 11/17] providers/docker: Make use of Action::Builtin::IsState and remove provider specific actions --- plugins/providers/docker/action.rb | 72 ++++++++++++------- .../providers/docker/action/check_running.rb | 25 ------- plugins/providers/docker/action/created.rb | 18 ----- plugins/providers/docker/action/is_running.rb | 20 ------ 4 files changed, 48 insertions(+), 87 deletions(-) delete mode 100644 plugins/providers/docker/action/check_running.rb delete mode 100644 plugins/providers/docker/action/created.rb delete mode 100644 plugins/providers/docker/action/is_running.rb diff --git a/plugins/providers/docker/action.rb b/plugins/providers/docker/action.rb index 9f8c7717663..70f46b86ac6 100644 --- a/plugins/providers/docker/action.rb +++ b/plugins/providers/docker/action.rb @@ -1,6 +1,7 @@ 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 @@ -8,8 +9,9 @@ module Action def self.action_up Vagrant::Action::Builder.new.tap do |b| b.use ConfigValidate - b.use Call, Created do |env, b2| - if !env[:result] + 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 # TODO: Find out where this fits into the process # b2.use EnvSet, :port_collision_repair => true @@ -38,13 +40,13 @@ def self.action_up def self.action_provision Vagrant::Action::Builder.new.tap do |b| b.use ConfigValidate - b.use Call, Created do |env1, b2| - if !env1[:result] + 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, IsRunning do |env2, b3| + b2.use Call, IsState, :running do |env2, b3| if !env2[:result] b3.use Message, I18n.t("docker_provider.messages.not_running") next @@ -60,15 +62,16 @@ def self.action_provision # the virtual machine, gracefully or by force. def self.action_halt Vagrant::Action::Builder.new.tap do |b| - b.use Call, Created do |env, b2| + b.use Call, IsState, :not_created do |env, b2| if env[:result] - b2.use Call, GracefulHalt, :stopped, :running do |env2, b3| - if !env2[:result] - b3.use Stop - end - end - else 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 @@ -79,8 +82,8 @@ def self.action_halt # machine back up with the new configuration. def self.action_reload Vagrant::Action::Builder.new.tap do |b| - b.use Call, Created do |env1, b2| - if !env1[:result] + b.use Call, IsState, :not_created do |env, b2| + if env[:result] b2.use Message, I18n.t("docker_provider.messages.not_created") next end @@ -96,8 +99,8 @@ def self.action_reload # freeing the resources of the underlying virtual machine. def self.action_destroy Vagrant::Action::Builder.new.tap do |b| - b.use Call, Created do |env1, b2| - if !env1[:result] + b.use Call, IsState, :not_created do |env, b2| + if env[:result] b2.use Message, I18n.t("docker_provider.messages.not_created") next end @@ -120,23 +123,47 @@ def self.action_destroy # This is the action that will exec into an SSH shell. def self.action_ssh Vagrant::Action::Builder.new.tap do |b| - b.use CheckRunning - b.use SSHExec + 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 CheckRunning - b.use SSHRun + 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, IsRunning do |env, b2| + b.use Call, IsState, :running do |env, b2| # If the container is running, then our work here is done, exit next if env[:result] @@ -157,15 +184,12 @@ def self.action_boot # The autoload farm action_root = Pathname.new(File.expand_path("../action", __FILE__)) - autoload :CheckRunning, action_root.join("check_running") - autoload :Created, action_root.join("created") 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 :IsRunning, action_root.join("is_running") autoload :Start, action_root.join("start") end end diff --git a/plugins/providers/docker/action/check_running.rb b/plugins/providers/docker/action/check_running.rb deleted file mode 100644 index 75224096d63..00000000000 --- a/plugins/providers/docker/action/check_running.rb +++ /dev/null @@ -1,25 +0,0 @@ -module VagrantPlugins - module DockerProvider - module Action - class CheckRunning - def initialize(app, env) - @app = app - end - - def call(env) - if env[:machine].state.id == :not_created - raise Vagrant::Errors::VMNotCreatedError - end - - if env[:machine].state.id == :stopped - raise Vagrant::Errors::VMNotRunningError - end - - # Call the next if we have one (but we shouldn't, since this - # middleware is built to run with the Call-type middlewares) - @app.call(env) - end - end - end - end -end diff --git a/plugins/providers/docker/action/created.rb b/plugins/providers/docker/action/created.rb deleted file mode 100644 index 39da1abdcdb..00000000000 --- a/plugins/providers/docker/action/created.rb +++ /dev/null @@ -1,18 +0,0 @@ -module VagrantPlugins - module DockerProvider - module Action - class Created - def initialize(app, env) - @app = app - end - - def call(env) - machine = env[:machine] - driver = machine.provider.driver - env[:result] = machine.id && driver.created?(machine.id) - @app.call(env) - end - end - end - end -end diff --git a/plugins/providers/docker/action/is_running.rb b/plugins/providers/docker/action/is_running.rb deleted file mode 100644 index 3357bb7dd6b..00000000000 --- a/plugins/providers/docker/action/is_running.rb +++ /dev/null @@ -1,20 +0,0 @@ -module VagrantPlugins - module DockerProvider - module Action - class IsRunning - def initialize(app, env) - @app = app - end - - def call(env) - machine = env[:machine] - driver = machine.provider.driver - - env[:result] = driver.running?(machine.id) - - @app.call(env) - end - end - end - end -end From 1dc92144cd5b4aed64a9acacd525e241c66ef1f4 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 26 Mar 2014 21:52:47 -0300 Subject: [PATCH 12/17] providers/docker: Remove unused locale parameter --- templates/locales/providers_docker.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/templates/locales/providers_docker.yml b/templates/locales/providers_docker.yml index 04db785ebfd..62b30a2c6e7 100644 --- a/templates/locales/providers_docker.yml +++ b/templates/locales/providers_docker.yml @@ -6,8 +6,7 @@ en: not_running: |- The container is not currently running. will_not_destroy: |- - The container '%{name}' will not be destroyed, since the confirmation - was declined. + The container will not be destroyed, since the confirmation was declined. starting: |- Starting container... stopping: |- From c63d535e142c5b41f8e0b0898f41f96abd8b157d Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 27 Mar 2014 20:09:13 -0300 Subject: [PATCH 13/17] providers/docker: Remove old README --- plugins/providers/docker/README.md | 206 ----------------------------- 1 file changed, 206 deletions(-) delete mode 100644 plugins/providers/docker/README.md diff --git a/plugins/providers/docker/README.md b/plugins/providers/docker/README.md deleted file mode 100644 index e83e5efae5b..00000000000 --- a/plugins/providers/docker/README.md +++ /dev/null @@ -1,206 +0,0 @@ -# docker-provider - -[![Build Status](https://travis-ci.org/fgrehm/docker-provider.png?branch=master)](https://travis-ci.org/fgrehm/docker-provider) [![Gem Version](https://badge.fury.io/rb/docker-provider.png)](http://badge.fury.io/rb/docker-provider) [![Gittip](http://img.shields.io/gittip/fgrehm.svg)](https://www.gittip.com/fgrehm/) - -A [Docker](http://www.docker.io/) provider for [Vagrant](http://www.vagrantup.com/) -1.4+. - - -## Warning - -This is experimental, expect things to break. - - -## Requirements - -* Vagrant 1.4+ -* Docker 0.7.0+ - - -## Features - -* Support for Vagrant's `up`, `destroy`, `halt`, `reload` and `ssh` commands -* Port forwarding -* Synced / shared folders support -* Set container hostnames from Vagrantfiles -* Provision Docker containers with any built-in Vagrant provisioner (as long as the container has a SSH server running) - -You can see the plugin in action by watching the following asciicasts I published -prior to releasing 0.0.1: - -* http://asciinema.org/a/6162 -* http://asciinema.org/a/6177 - - -## Getting started - -If you are on a Mac / Windows machine, please fire up a x64 Linux VM with Docker + -Vagrant 1.4+ installed or use [this Vagrantfile](https://gist.github.com/fgrehm/fc48fb51ec7df64439e4) -and follow the instructions from within the VM. - -_It is likely that the plugin works with [boot2docker](http://boot2docker.github.io/) -but I personally haven't tried that yet. If you are able to give it a go please -[let me know](https://github.com/fgrehm/docker-provider/issues/new)._ - -### Initial setup - -_If you are trying things out from a Vagrant VM using the `Vagrantfile` gisted -above, you can skip to the next section_ - -The plugin requires Docker's executable to be available on current user's `PATH` -and that the current user has been added to the `docker` group since we are not -using `sudo` when interacting with Docker's CLI. For more information on setting -this up please check [this page](http://docs.docker.io/en/latest/installation/ubuntulinux/#giving-non-root-access). - -### `vagrant up` - -On its current state, the plugin is not "user friendly" and won't provide any kind -of feedback about the process of downloading Docker images, so before you add a -`docker-provider` [base box](http://docs.vagrantup.com/v2/boxes.html) it is recommended -that you `docker pull` the associated base box images prior to spinning up `docker-provider` -containers (otherwise you'll be staring at a blinking cursor without any progress -information for a while). - -Assuming you have Vagrant 1.4+ and Docker 0.7.0+ installed just sing that same -old song: - -```sh -vagrant plugin install docker-provider -docker pull fgrehm/vagrant-ubuntu:precise -vagrant box add precise64 http://bit.ly/vagrant-docker-precise -vagrant init precise64 -vagrant up --provider=docker -``` - -Under the hood, that base box will [configure](#configuration) `docker-provider` -to use the [`fgrehm/vagrant-ubuntu:precise`](https://index.docker.io/u/fgrehm/vagrant-ubuntu/) -image that approximates a standard Vagrant box (`vagrant` user, default SSH key, -etc.) and you should be good to go. - - -## Using custom images - -If you want to use a custom Docker image without creating a Vagrant base box, -you can use a "dummy" box and configure things from your `Vagrantfile` like -in [vagrant-digitalocean](https://github.com/smdahlen/vagrant-digitalocean#configure) -or [vagrant-aws](https://github.com/mitchellh/vagrant-aws#quick-start): - -```ruby -Vagrant.configure("2") do |config| - config.vm.box = "dummy" - config.vm.box_url = "http://bit.ly/vagrant-docker-dummy" - config.vm.provider :docker do |docker| - docker.image = "your/image:tag" - end -end -``` - - -## Configuration - -This provider exposes a few provider-specific configuration options -that are passed on to `docker run` under the hood when the container -is being created: - -* `image` - Docker image to run (required) -* `privileged` - Give extended privileges to the container (defaults to false) -* `cmd` - An array of strings that makes up for the command to run the container (defaults to what has been set on your `Dockerfile` as `CMD` or `ENTRYPOINT`) -* `ports` - An array of strings that makes up for the mapped network ports -* `volumes` - An array of strings that makes up for the data volumes used by the container - -These can be set like typical provider-specific configuration: - -```ruby -Vagrant.configure("2") do |config| - # ... other stuff - - config.vm.provider :docker do |docker| - docker.image = 'fgrehm/vagrant-ubuntu-dind:precise' - docker.privileged = true - docker.cmd = ['/dind', '/sbin/init'] - - docker.ports << '1234:22' - docker.volumes << '/var/lib/docker' - end -end -``` - - -## Networks - -Networking features in the form of `config.vm.network` are not supported with -`docker-provider` apart from [forwarded ports](). -If any of [`:private_network`](http://docs.vagrantup.com/v2/networking/private_network.html) -or [`:public_network`](http://docs.vagrantup.com/v2/networking/public_network.html) -are specified, Vagrant **won't** emit a warning. - -The same applies to changes on forwarded ports after the container has been -created, Vagrant **won't** emit a warning to let you know that the ports specified -on your `Vagrantfile` differs from what has been passed on to `docker run` when -creating the container. - -_At some point the plugin will emit warnings on the scenarios described above, but -not on its current state. Pull Requests are encouraged ;)_ - - -## Synced Folders - -There is support for synced folders on the form of [Docker volumes](http://docs.docker.io/en/latest/use/working_with_volumes/#mount-a-host-directory-as-a-container-volume) -but as with forwarded ports, you won't be able to change them after the container -has been created. [NFS](http://docs.vagrantup.com/v2/synced-folders/nfs.html) -synced folders are also supported (as long as you set the `privileged` -[config](#configuration) to true so that `docker-provider` can mount it on the -guest container) and are capable of being reconfigured between `vagrant reload`s -(different from Docker volumes). - -This is good enough for all built-in Vagrant provisioners (shell, -chef, and puppet) to work! - -_At some point the plugin will emit warnings when the configured `Vagrantfile` -synced folders / volumes differs from the ones used upon the container creation, -but not on its current state. Pull Requests are encouraged ;)_ - - -## Box format - -Every provider in Vagrant must introduce a custom box format. This provider introduces -`docker` boxes and you can view some examples in the [`boxes`](boxes) directory. -That directory also contains instructions on how to build them. - -The box format is basically just the required `metadata.json` file along with a -`Vagrantfile` that does default settings for the provider-specific configuration -for this provider. - - -## Available base boxes - -| LINK | DESCRIPTION | -| --- | --- | -| http://bit.ly/vagrant-docker-precise | Ubuntu 12.04 Precise x86_64 with Puppet and Chef preinstalled and configured to run `/sbin/init` | -| http://bit.ly/vagrant-docker-precise-dind | Ubuntu 12.04 Precise x86_64 based on the box above and ready to run [DinD](https://github.com/jpetazzo/dind) | - - -## Limitations - -As explained on the [networks](#networks) and [synced folder](#synced-folders) -sections above, there are some "gotchas" when using the plugin that you need to have -in mind before you start to pull your hair out. - -For instance, forwarded ports, synced folders and containers' hostnames will not be -reconfigured on `vagrant reload`s if they have changed and the plugin **_will not -give you any kind of warning or message_**. As an example, if you change your Puppet -manifests / Chef cookbooks paths (which are shared / synced folders under the hood), -**_you'll need to start from scratch_** (unless you make them NFS shared folders). -This is due to a limitation in Docker itself as we can't change those parameters -after the container has been created. - -Forwarded ports automatic collision handling is **_not supported as well_**. - - -## Contributing - -1. Fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Add some feature'`) -4. Push to the branch (`git push origin my-new-feature`) -5. Create new Pull Request From 7f07298db72f755ff2d201ea20fcee189b1dcfba Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 27 Mar 2014 20:51:44 -0300 Subject: [PATCH 14/17] providers/docker: Update driver to docker 0.9 --- plugins/providers/docker/driver.rb | 10 +++++----- test/unit/plugins/providers/docker/driver_spec.rb | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/providers/docker/driver.rb b/plugins/providers/docker/driver.rb index 9a4a39e501d..5aea34054ac 100644 --- a/plugins/providers/docker/driver.rb +++ b/plugins/providers/docker/driver.rb @@ -21,10 +21,10 @@ def create(params) name = params.fetch(:name) cmd = Array(params.fetch(:cmd)) - run_cmd = %W(docker run -name #{name} -d) + run_cmd = %W(docker run --name #{name} -d) run_cmd += ports.map { |p| ['-p', p.to_s] } run_cmd += volumes.map { |v| ['-v', v.to_s] } - run_cmd += %W(-privileged) if params[:privileged] + run_cmd += %W(--privileged) if params[:privileged] run_cmd += %W(-h #{params[:hostname]}) if params[:hostname] run_cmd += [image, cmd] @@ -45,12 +45,12 @@ def state(cid) end def created?(cid) - result = execute('docker', 'ps', '-a', '-q', '-notrunc').to_s + result = execute('docker', 'ps', '-a', '-q', '--no-trunc').to_s result =~ /^#{Regexp.escape cid}$/ end def running?(cid) - result = execute('docker', 'ps', '-q', '-notrunc') + result = execute('docker', 'ps', '-q', '--no-trunc') result =~ /^#{Regexp.escape cid}$/m end @@ -87,7 +87,7 @@ def inspect_container(cid) end def all_containers - execute('docker', 'ps', '-a', '-q', '-notrunc').to_s.split + execute('docker', 'ps', '-a', '-q', '--no-trunc').to_s.split end def docker_bridge_ip diff --git a/test/unit/plugins/providers/docker/driver_spec.rb b/test/unit/plugins/providers/docker/driver_spec.rb index b057d0d0eae..c41bb392459 100644 --- a/test/unit/plugins/providers/docker/driver_spec.rb +++ b/test/unit/plugins/providers/docker/driver_spec.rb @@ -184,7 +184,7 @@ before { subject.stub(execute: containers) } it 'returns an array of all known containers' do - subject.should_receive(:execute).with('docker', 'ps', '-a', '-q', '-notrunc') + subject.should_receive(:execute).with('docker', 'ps', '-a', '-q', '--no-trunc') expect(subject.all_containers).to eq(['container1', 'container2']) end end From fa3553ad25128095c565d902a3f4aa03f8190961 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 27 Mar 2014 20:59:07 -0300 Subject: [PATCH 15/17] providers/docker: Handle forwarded port collisions --- plugins/providers/docker/action.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/providers/docker/action.rb b/plugins/providers/docker/action.rb index 70f46b86ac6..b9ee43c0dd7 100644 --- a/plugins/providers/docker/action.rb +++ b/plugins/providers/docker/action.rb @@ -13,9 +13,8 @@ def self.action_up # If the VM is NOT created yet, then do the setup steps if env[:result] b2.use HandleBox - # TODO: Find out where this fits into the process - # b2.use EnvSet, :port_collision_repair => true - # b2.use HandleForwardedPortCollisions + b2.use EnvSet, :port_collision_repair => true + b2.use HandleForwardedPortCollisions b2.use Provision b2.use PrepareNFSValidIds b2.use SyncedFolderCleanup From 6017b83758b1b5e3e2752edf7d89bede6a067bff Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 27 Mar 2014 21:10:48 -0300 Subject: [PATCH 16/17] providers/docker: Implement public_address capability for `vagrant share` --- plugins/providers/docker/cap/public_address.rb | 15 +++++++++++++++ plugins/providers/docker/plugin.rb | 5 +++++ 2 files changed, 20 insertions(+) create mode 100644 plugins/providers/docker/cap/public_address.rb diff --git a/plugins/providers/docker/cap/public_address.rb b/plugins/providers/docker/cap/public_address.rb new file mode 100644 index 00000000000..379b0452ba2 --- /dev/null +++ b/plugins/providers/docker/cap/public_address.rb @@ -0,0 +1,15 @@ +module VagrantPlugins + module DockerProvider + module Cap + module PublicAddress + def self.public_address(machine) + return nil if machine.state.id != :running + + ssh_info = machine.ssh_info + return nil if !ssh_info + ssh_info[:host] + end + end + end + end +end diff --git a/plugins/providers/docker/plugin.rb b/plugins/providers/docker/plugin.rb index 9e6c4f9c733..76abce9bb24 100644 --- a/plugins/providers/docker/plugin.rb +++ b/plugins/providers/docker/plugin.rb @@ -28,6 +28,11 @@ class Plugin < Vagrant.plugin("2") SyncedFolder end + provider_capability("docker", "public_address") do + require_relative "cap/public_address" + Cap::PublicAddress + end + protected def self.init! From c7884a786b5c5a4a85a3bc21e4475a124c6d1ef5 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 27 Mar 2014 21:11:19 -0300 Subject: [PATCH 17/17] providers/docker: Remove retryable around `docker run` as it seems that it is no longer needed --- plugins/providers/docker/driver.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/providers/docker/driver.rb b/plugins/providers/docker/driver.rb index 5aea34054ac..924a5340981 100644 --- a/plugins/providers/docker/driver.rb +++ b/plugins/providers/docker/driver.rb @@ -28,9 +28,7 @@ def create(params) run_cmd += %W(-h #{params[:hostname]}) if params[:hostname] run_cmd += [image, cmd] - retryable(tries: 10, sleep: 1) do - execute(*run_cmd.flatten).chomp - end + execute(*run_cmd.flatten).chomp end def state(cid)