This includes updates for resolving all warnings provided by Ruby for deprecations and/or removed methods. It also enables support for Ruby 2.7 in the specification constraint as all 2.7 related warnings are resolved with this changeset.
332 lines
11 KiB
Ruby
332 lines
11 KiB
Ruby
require_relative "../../../base"
|
|
|
|
require Vagrant.source_root.join("lib/vagrant/util/deep_merge")
|
|
require Vagrant.source_root.join("plugins/providers/docker/driver")
|
|
|
|
describe VagrantPlugins::DockerProvider::Driver::Compose do
|
|
let(:cmd_executed) { @cmd }
|
|
let(:cid) { 'side-1-song-10' }
|
|
let(:docker_yml){ double("docker-yml", path: "/tmp-file") }
|
|
let(:machine){ double("machine", env: env, name: :docker_1, id: :docker_id, provider_config: provider_config) }
|
|
let(:compose_configuration){ {} }
|
|
let(:provider_config) do
|
|
double("provider-config",
|
|
compose: true,
|
|
compose_configuration: compose_configuration
|
|
)
|
|
end
|
|
let(:env) do
|
|
double("env",
|
|
cwd: Pathname.new("/compose/cwd"),
|
|
local_data_path: local_data_path
|
|
)
|
|
end
|
|
let(:composition_content){ "--- {}\n" }
|
|
let(:composition_path) do
|
|
double("composition-path",
|
|
to_s: "docker-compose.yml",
|
|
exist?: true,
|
|
read: composition_content,
|
|
delete: true
|
|
)
|
|
end
|
|
let(:data_directory){ double("data-directory", join: composition_path) }
|
|
let(:local_data_path){ double("local-data-path") }
|
|
let(:compose_execute_up){ ["docker-compose", "-f", "docker-compose.yml", "-p", "cwd", "up", "--remove-orphans", "-d", any_args] }
|
|
|
|
|
|
subject{ described_class.new(machine) }
|
|
|
|
before do
|
|
allow(Vagrant::Util::Which).to receive(:which).and_return("/dev/null/docker-compose")
|
|
allow(env).to receive(:lock).and_yield
|
|
allow(Pathname).to receive(:new).with(local_data_path).and_return(local_data_path)
|
|
allow(Pathname).to receive(:new).with('/host/path').and_call_original
|
|
allow(local_data_path).to receive(:join).and_return(data_directory)
|
|
allow(data_directory).to receive(:mkpath)
|
|
allow(FileUtils).to receive(:mv)
|
|
allow(Tempfile).to receive(:new).with("vagrant-docker-compose").and_return(docker_yml)
|
|
allow(docker_yml).to receive(:write)
|
|
allow(docker_yml).to receive(:close)
|
|
allow(subject).to receive(:execute) do |*args|
|
|
args.delete_if{|i| i.is_a?(Hash) }
|
|
@cmd = args.join(' ')
|
|
end
|
|
end
|
|
|
|
describe '#build' do
|
|
it 'creates a compose config with no extra options' do
|
|
expect(subject).to receive(:update_composition)
|
|
subject.build(composition_path)
|
|
end
|
|
|
|
it 'creates a compose config when given an array for build-arg' do
|
|
expect(subject).to receive(:update_composition)
|
|
subject.build(composition_path, extra_args: ["foo", "bar"])
|
|
end
|
|
|
|
it 'creates a compose config when given a hash for build-arg' do
|
|
expect(subject).to receive(:update_composition)
|
|
subject.build(composition_path, extra_args: {"foo"=>"bar"})
|
|
end
|
|
end
|
|
|
|
describe '#create' do
|
|
let(:params) { {
|
|
image: 'jimi/hendrix:electric-ladyland',
|
|
cmd: ['play', 'voodoo-chile'],
|
|
ports: '8080:80',
|
|
volumes: '/host/path:guest/path',
|
|
detach: true,
|
|
links: [[:janis, 'joplin'], [:janis, 'janis']],
|
|
env: {key: 'value'},
|
|
name: cid,
|
|
hostname: 'jimi-hendrix',
|
|
privileged: true
|
|
} }
|
|
|
|
before { expect(subject).to receive(:execute).with(*compose_execute_up) }
|
|
after { subject.create(params) }
|
|
|
|
it 'sets container name' do
|
|
expect(docker_yml).to receive(:write).with(/#{machine.name}/)
|
|
end
|
|
|
|
it 'forwards ports' do
|
|
expect(docker_yml).to receive(:write).with(/#{params[:ports]}/)
|
|
end
|
|
|
|
it 'shares folders' do
|
|
expect(docker_yml).to receive(:write).with(/#{params[:volumes]}/)
|
|
end
|
|
|
|
context 'when links are provided as strings' do
|
|
before{ params[:links] = ["linkl1:linkr1", "linkl2:linkr2"] }
|
|
|
|
it 'links containers' do
|
|
params[:links].flatten.map{|l| l.split(':')}.each do |link|
|
|
expect(docker_yml).to receive(:write).with(/#{link}/)
|
|
end
|
|
subject.create(params)
|
|
end
|
|
end
|
|
|
|
context 'with relative path in share folders' do
|
|
before do
|
|
params[:volumes] = './path:guest/path'
|
|
allow(Pathname).to receive(:new).with('./path').and_call_original
|
|
allow(Pathname).to receive(:new).with('/compose/cwd/path').and_call_original
|
|
end
|
|
|
|
it 'should expand the relative host directory' do
|
|
expect(docker_yml).to receive(:write).with(%r{/compose/cwd/path})
|
|
end
|
|
end
|
|
|
|
context 'with a volumes key in use for mounting' do
|
|
let(:compose_config) { {"volumes"=>{"my_volume_key"=>"data"}} }
|
|
|
|
before do
|
|
params[:volumes] = 'my_volume_key:my/guest/path'
|
|
allow(Pathname).to receive(:new).with('./path').and_call_original
|
|
allow(Pathname).to receive(:new).with('my_volume_key').and_call_original
|
|
allow(Pathname).to receive(:new).with('/compose/cwd/my_volume_key').and_call_original
|
|
allow(subject).to receive(:get_composition).and_return(compose_config)
|
|
end
|
|
|
|
it 'should not expand the relative host directory' do
|
|
expect(docker_yml).to receive(:write).with(%r{my_volume_key})
|
|
end
|
|
end
|
|
|
|
it 'links containers' do
|
|
params[:links].each do |link|
|
|
expect(docker_yml).to receive(:write).with(/#{link}/)
|
|
end
|
|
subject.create(params)
|
|
end
|
|
|
|
it 'sets environmental variables' do
|
|
expect(docker_yml).to receive(:write).with(/key.*value/)
|
|
end
|
|
|
|
it 'is able to run a privileged container' do
|
|
expect(docker_yml).to receive(:write).with(/privileged/)
|
|
end
|
|
|
|
it 'sets the hostname if specified' do
|
|
expect(docker_yml).to receive(:write).with(/#{params[:hostname]}/)
|
|
end
|
|
|
|
it 'executes the provided command' do
|
|
expect(docker_yml).to receive(:write).with(/#{params[:image]}/)
|
|
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 { allow(subject).to receive(:execute)
|
|
.and_return("foo\n#{cid}\nbar") }
|
|
it { expect(result).to be_truthy }
|
|
end
|
|
|
|
context 'when container does not exist' do
|
|
before { allow(subject).to receive(:execute)
|
|
.and_return("foo\n#{cid}extra\nbar") }
|
|
it { expect(result).to be_falsey }
|
|
end
|
|
end
|
|
|
|
describe '#pull' do
|
|
it 'should pull images' do
|
|
expect(subject).to receive(:execute).with('docker', 'pull', 'foo')
|
|
subject.pull('foo')
|
|
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 { allow(subject).to receive(:execute)
|
|
.and_return("foo\n#{cid}\nbar") }
|
|
it { expect(result).to be_truthy }
|
|
end
|
|
|
|
context 'when container does not exist' do
|
|
before { allow(subject).to receive(:execute)
|
|
.and_return("foo\n#{cid}extra\nbar") }
|
|
it { expect(result).to be_falsey }
|
|
end
|
|
end
|
|
|
|
describe '#privileged?' do
|
|
it 'identifies privileged containers' do
|
|
allow(subject).to receive(:inspect_container)
|
|
.and_return({'HostConfig' => {"Privileged" => true}})
|
|
expect(subject).to be_privileged(cid)
|
|
end
|
|
|
|
it 'identifies unprivileged containers' do
|
|
allow(subject).to receive(:inspect_container)
|
|
.and_return({'HostConfig' => {"Privileged" => false}})
|
|
expect(subject).to_not be_privileged(cid)
|
|
end
|
|
end
|
|
|
|
describe '#start' do
|
|
context 'when container is running' do
|
|
before { allow(subject).to receive(:running?).and_return(true) }
|
|
|
|
it 'does not start the container' do
|
|
expect(subject).not_to receive(:execute).with('docker', 'start', cid)
|
|
subject.start(cid)
|
|
end
|
|
end
|
|
|
|
context 'when container is not running' do
|
|
before { allow(subject).to receive(:running?).and_return(false) }
|
|
|
|
it 'starts the container' do
|
|
expect(subject).to receive(:execute).with('docker', 'start', cid)
|
|
subject.start(cid)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#stop' do
|
|
context 'when container is running' do
|
|
before { allow(subject).to receive(:running?).and_return(true) }
|
|
|
|
it 'stops the container' do
|
|
expect(subject).to receive(:execute).with('docker', 'stop', '-t', '1', cid)
|
|
subject.stop(cid, 1)
|
|
end
|
|
|
|
it "stops the container with the set timeout" do
|
|
expect(subject).to receive(:execute).with('docker', 'stop', '-t', '5', cid)
|
|
subject.stop(cid, 5)
|
|
end
|
|
end
|
|
|
|
context 'when container is not running' do
|
|
before { allow(subject).to receive(:running?).and_return(false) }
|
|
|
|
it 'does not stop container' do
|
|
expect(subject).not_to receive(:execute).with('docker', 'stop', '-t', '1', cid)
|
|
subject.stop(cid, 1)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#rm' do
|
|
context 'when container has been created' do
|
|
before { allow(subject).to receive(:created?).and_return(true) }
|
|
|
|
it 'removes the container' do
|
|
expect(subject).to receive(:execute).with("docker-compose", "-f", "docker-compose.yml", "-p", "cwd", "rm", "-f", "docker_1", any_args)
|
|
subject.rm(cid)
|
|
end
|
|
end
|
|
|
|
context 'when container has not been created' do
|
|
before { allow(subject).to receive(:created?).and_return(false) }
|
|
|
|
it 'does not attempt to remove the container' do
|
|
expect(subject).not_to receive(:execute).with("docker-compose", "-f", "docker-compose.yml", "-p", "cwd", "rm", "-f", "docker_1", {})
|
|
subject.rm(cid)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#inspect_container' do
|
|
let(:data) { '[{"json": "value"}]' }
|
|
|
|
before { allow(subject).to receive(:execute).and_return(data) }
|
|
|
|
it 'inspects the container' do
|
|
expect(subject).to 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 { allow(subject).to receive(:execute).and_return(containers) }
|
|
|
|
it 'returns an array of all known containers' do
|
|
expect(subject).to receive(:execute).with('docker', 'ps', '-a', '-q', '--no-trunc')
|
|
expect(subject.all_containers).to eq(['container1', 'container2'])
|
|
end
|
|
end
|
|
|
|
describe '#docker_bridge_ip' do
|
|
let(:containers) { " inet 123.456.789.012/16 " }
|
|
|
|
before { allow(subject).to receive(:execute).and_return(containers) }
|
|
|
|
it 'returns an array of all known containers' do
|
|
expect(subject).to 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
|