docker-compose-api 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -19,8 +19,7 @@ module DockerCompose
19
19
  #
20
20
  def self.load(filepath)
21
21
  unless File.exist?(filepath)
22
- puts("Compose file doesn't exists")
23
- raise ENOENT
22
+ raise ArgumentError, 'Compose file doesn\'t exists'
24
23
  end
25
24
 
26
25
  compose = Compose.new
@@ -28,8 +28,8 @@ class Compose
28
28
 
29
29
  next if links.nil?
30
30
 
31
- links.each do |link|
32
- dependency_container = @containers[link]
31
+ links.each do |service, label|
32
+ dependency_container = @containers[service]
33
33
  container.add_dependency(dependency_container)
34
34
  end
35
35
  end
@@ -1,16 +1,17 @@
1
1
  require 'docker'
2
+ require 'securerandom'
2
3
  require_relative 'compose_port'
3
4
  require_relative '../utils/compose_utils'
4
5
 
5
6
  class ComposeContainer
6
- attr_reader :attributes
7
+ attr_reader :attributes, :container, :dependencies
7
8
 
8
9
  def initialize(hash_attributes)
9
10
  @attributes = {
10
11
  label: hash_attributes[:label],
11
12
  image: ComposeUtils.format_image(hash_attributes[:image]),
12
13
  build: hash_attributes[:build],
13
- links: hash_attributes[:links],
14
+ links: ComposeUtils.format_links(hash_attributes[:links]),
14
15
  ports: prepare_ports(hash_attributes[:ports]),
15
16
  volumes: hash_attributes[:volumes],
16
17
  command: ComposeUtils.format_command(hash_attributes[:command]),
@@ -57,4 +57,28 @@ module ComposeUtils
57
57
 
58
58
  compose_port
59
59
  end
60
+
61
+ #
62
+ # Generate a pair key:hash with
63
+ # format {service:label}
64
+ #
65
+ def self.format_links(links_array)
66
+ links = {}
67
+
68
+ return if links_array.nil?
69
+
70
+ links_array.each do |link|
71
+ parts = link.split(':')
72
+
73
+ case parts.length
74
+ when 1
75
+ links[parts[0]] = SecureRandom.hex
76
+
77
+ when 2
78
+ links[parts[0]] = parts[1]
79
+ end
80
+ end
81
+
82
+ links
83
+ end
60
84
  end
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module DockerCompose
2
2
  def self.version
3
- "1.0.1"
3
+ "1.0.2"
4
4
  end
5
5
  end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe DockerCompose do
4
4
  before(:all) do
5
- @compose = DockerCompose.load(File.expand_path('spec/docker-compose/fixtures/sample1.yaml'))
5
+ @compose = DockerCompose.load(File.expand_path('spec/docker-compose/fixtures/compose_1.yaml'))
6
6
  end
7
7
 
8
8
  it 'should be able to access gem version' do
@@ -17,6 +17,10 @@ describe DockerCompose do
17
17
  expect(@compose.containers.length).to eq(2)
18
18
  end
19
19
 
20
+ it 'should raise error when reading an invalid YAML file' do
21
+ expect{DockerCompose.load('')}.to raise_error(ArgumentError)
22
+ end
23
+
20
24
  context 'All containers' do
21
25
  it 'should start/stop all containers' do
22
26
  # Start containers to test Stop
@@ -50,85 +54,99 @@ describe DockerCompose do
50
54
  context 'Single container' do
51
55
  context 'Without dependencies' do
52
56
  it 'should start/stop a single container' do
53
- ubuntu = @compose.containers.values.first.attributes[:label]
54
- redis = @compose.containers.values.last.attributes[:label]
57
+ container1 = @compose.containers.values.first.attributes[:label]
58
+ container2 = @compose.containers.values.last.attributes[:label]
55
59
 
56
60
  # Should start Redis only, since it hasn't dependencies
57
- @compose.start([redis])
58
- expect(@compose.containers[ubuntu].running?).to be false
59
- expect(@compose.containers[redis].running?).to be true
61
+ @compose.start([container2])
62
+ expect(@compose.containers[container1].running?).to be false
63
+ expect(@compose.containers[container2].running?).to be true
60
64
 
61
65
  # Stop Redis
62
- @compose.stop([redis])
63
- expect(@compose.containers[ubuntu].running?).to be false
64
- expect(@compose.containers[redis].running?).to be false
66
+ @compose.stop([container2])
67
+ expect(@compose.containers[container1].running?).to be false
68
+ expect(@compose.containers[container2].running?).to be false
65
69
  end
66
70
 
67
71
  it 'should start/kill a single container' do
68
- ubuntu = @compose.containers.values.first.attributes[:label]
69
- redis = @compose.containers.values.last.attributes[:label]
72
+ container1 = @compose.containers.values.first.attributes[:label]
73
+ container2 = @compose.containers.values.last.attributes[:label]
70
74
 
71
75
  # Should start Redis only, since it hasn't dependencies
72
- @compose.start([redis])
73
- expect(@compose.containers[ubuntu].running?).to be false
74
- expect(@compose.containers[redis].running?).to be true
76
+ @compose.start([container2])
77
+ expect(@compose.containers[container1].running?).to be false
78
+ expect(@compose.containers[container2].running?).to be true
75
79
 
76
80
  # Stop Redis
77
- @compose.kill([redis])
78
- expect(@compose.containers[ubuntu].running?).to be false
79
- expect(@compose.containers[redis].running?).to be false
81
+ @compose.kill([container2])
82
+ expect(@compose.containers[container1].running?).to be false
83
+ expect(@compose.containers[container2].running?).to be false
80
84
  end
81
85
  end # context 'Without dependencies'
82
86
 
83
87
  context 'With dependencies' do
84
88
  it 'should start/stop a single container' do
85
- ubuntu = @compose.containers.values.first.attributes[:label]
86
- redis = @compose.containers.values.last.attributes[:label]
89
+ container1 = @compose.containers.values.first.attributes[:label]
90
+ container2 = @compose.containers.values.last.attributes[:label]
87
91
 
88
92
  # Should start Ubuntu and Redis, since Ubuntu depends on Redis
89
- @compose.start([ubuntu])
90
- expect(@compose.containers[ubuntu].running?).to be true
91
- expect(@compose.containers[redis].running?).to be true
93
+ @compose.start([container1])
94
+ expect(@compose.containers[container1].running?).to be true
95
+ expect(@compose.containers[container2].running?).to be true
92
96
 
93
97
  # Stop Ubuntu (Redis keeps running)
94
- @compose.stop([ubuntu])
95
- expect(@compose.containers[ubuntu].running?).to be false
96
- expect(@compose.containers[redis].running?).to be true
98
+ @compose.stop([container1])
99
+ expect(@compose.containers[container1].running?).to be false
100
+ expect(@compose.containers[container2].running?).to be true
97
101
 
98
102
  # Stop Redis
99
- @compose.stop([redis])
100
- expect(@compose.containers[redis].running?).to be false
103
+ @compose.stop([container2])
104
+ expect(@compose.containers[container2].running?).to be false
101
105
  end
102
106
 
103
107
  it 'should start/kill a single container' do
104
- ubuntu = @compose.containers.values.first.attributes[:label]
105
- redis = @compose.containers.values.last.attributes[:label]
108
+ container1 = @compose.containers.values.first.attributes[:label]
109
+ container2 = @compose.containers.values.last.attributes[:label]
106
110
 
107
111
  # Should start Ubuntu and Redis, since Ubuntu depends on Redis
108
- @compose.start([ubuntu])
109
- expect(@compose.containers[ubuntu].running?).to be true
110
- expect(@compose.containers[redis].running?).to be true
112
+ @compose.start([container1])
113
+ expect(@compose.containers[container1].running?).to be true
114
+ expect(@compose.containers[container2].running?).to be true
111
115
 
112
116
  # Kill Ubuntu (Redis keeps running)
113
- @compose.kill([ubuntu])
114
- expect(@compose.containers[ubuntu].running?).to be false
115
- expect(@compose.containers[redis].running?).to be true
117
+ @compose.kill([container1])
118
+ expect(@compose.containers[container1].running?).to be false
119
+ expect(@compose.containers[container2].running?).to be true
116
120
 
117
121
  # Kill Redis
118
- @compose.kill([redis])
119
- expect(@compose.containers[redis].running?).to be false
122
+ @compose.kill([container2])
123
+ expect(@compose.containers[container2].running?).to be false
124
+ end
125
+
126
+ it 'should be able to ping a dependent container' do
127
+ container1 = @compose.containers.values.first.attributes[:label]
128
+ container2 = @compose.containers.values.last.attributes[:label]
129
+
130
+ # Start all containers
131
+ @compose.start
132
+ expect(@compose.containers[container1].running?).to be true
133
+ expect(@compose.containers[container2].running?).to be true
134
+
135
+ # Ping container2 from container1
136
+ ping_response = @compose.containers[container1].container.exec(['ping', '-c', '3', 'busybox2'])
137
+ expect(ping_response[2]).to eq(0) # Status 0 = OK
120
138
  end
121
139
  end # context 'with dependencies'
122
140
  end # context 'Single container'
123
141
 
124
142
  it 'should assign ports' do
125
- ubuntu = @compose.containers.values.first
143
+ container1 = @compose.containers.values.first
126
144
 
127
145
  # Start container
128
- ubuntu.start
146
+ container1.start
129
147
 
130
- port_bindings = ubuntu.stats['HostConfig']['PortBindings']
131
- exposed_ports = ubuntu.stats['Config']['ExposedPorts']
148
+ port_bindings = container1.stats['HostConfig']['PortBindings']
149
+ exposed_ports = container1.stats['Config']['ExposedPorts']
132
150
 
133
151
  # Check port bindings
134
152
  expect(port_bindings.length).to eq(3)
@@ -142,21 +160,21 @@ describe DockerCompose do
142
160
  expect(exposed_ports.key?('8001/tcp')).to be true
143
161
 
144
162
  # Stop container
145
- ubuntu.stop
163
+ container1.stop
146
164
  end
147
165
 
148
166
  it 'should link containers' do
149
- ubuntu = @compose.containers.values.first
167
+ container1 = @compose.containers.values.first
150
168
 
151
169
  # Start container
152
- ubuntu.start
170
+ container1.start
153
171
 
154
172
  # Ubuntu should be linked to Redis
155
- links = ubuntu.stats['HostConfig']['Links']
173
+ links = container1.stats['HostConfig']['Links']
156
174
  expect(links.length).to eq(1)
157
175
 
158
176
  # Stop container
159
- ubuntu.stop
177
+ container1.stop
160
178
  end
161
179
 
162
180
  after(:all) do
@@ -1,2 +1,2 @@
1
- FROM ubuntu
2
- CMD ["sleep", "1000"]
1
+ FROM busybox
2
+ CMD ["ping", "localhost"]
@@ -1,5 +1,5 @@
1
- ubuntu:
2
- image: ubuntu
1
+ busybox1:
2
+ image: busybox
3
3
  ports:
4
4
  - "3000"
5
5
  - "8000:8000"
@@ -7,10 +7,11 @@ ubuntu:
7
7
  expose:
8
8
  - "5000"
9
9
  links:
10
- - redis
11
- command: /bin/sleep 60
10
+ - busybox2
11
+ command: ping busybox2
12
12
 
13
- redis:
14
- image: redis
13
+ busybox2:
14
+ image: busybox
15
15
  expose:
16
16
  - "6000"
17
+ command: ping localhost
@@ -2,87 +2,123 @@ require 'spec_helper'
2
2
 
3
3
  describe ComposeContainer do
4
4
  context 'Object creation' do
5
- it 'should prepare the attributes correctly' do
6
- attributes = {
7
- image: 'ubuntu:latest',
8
- links: ['links:links'],
5
+ before(:all) do
6
+ @attributes = {
7
+ image: 'busybox:latest',
8
+ links: ['service:label'],
9
9
  ports: ['3000', '8000:8000', '127.0.0.1:8001:8001'],
10
10
  volumes: {'/tmp' => {}},
11
- command: 'ps aux',
11
+ command: 'ping -c 3 localhost',
12
12
  environment: ['ENVIRONMENT']
13
13
  }
14
14
 
15
- entry = ComposeContainer.new(attributes)
15
+ @entry = ComposeContainer.new(@attributes)
16
+ end
16
17
 
17
- expect(entry.attributes[:image]).to eq(attributes[:image])
18
- expect(entry.attributes[:links]).to eq(attributes[:links])
19
- expect(entry.attributes[:volumes]).to eq(attributes[:volumes])
20
- expect(entry.attributes[:command]).to eq(attributes[:command].split(' '))
21
- expect(entry.attributes[:environment]).to eq(attributes[:environment])
18
+ it 'should prepare attributes correctly' do
19
+ expect(@entry.attributes[:image]).to eq(@attributes[:image])
20
+ expect(@entry.attributes[:links]).to eq({'service' => 'label'})
21
+ expect(@entry.attributes[:volumes]).to eq(@attributes[:volumes])
22
+ expect(@entry.attributes[:command]).to eq(@attributes[:command].split(' '))
23
+ expect(@entry.attributes[:environment]).to eq(@attributes[:environment])
24
+ end
22
25
 
26
+ it 'should map ports' do
23
27
  # Check ports structure
24
- expect(entry.attributes[:ports].length).to eq(attributes[:ports].length)
28
+ expect(@entry.attributes[:ports].length).to eq(@attributes[:ports].length)
25
29
 
26
30
  # Port 1: '3000'
27
- port_entry = entry.attributes[:ports][0]
31
+ port_entry = @entry.attributes[:ports][0]
28
32
  expect(port_entry.container_port).to eq('3000')
29
33
  expect(port_entry.host_ip).to eq(nil)
30
34
  expect(port_entry.host_port).to eq(nil)
31
35
 
32
36
  # Port 2: '8000:8000'
33
- port_entry = entry.attributes[:ports][1]
37
+ port_entry = @entry.attributes[:ports][1]
34
38
  expect(port_entry.container_port).to eq('8000')
35
39
  expect(port_entry.host_ip).to eq(nil)
36
40
  expect(port_entry.host_port).to eq('8000')
37
41
 
38
42
  # Port 3: '127.0.0.1:8001:8001'
39
- port_entry = entry.attributes[:ports][2]
43
+ port_entry = @entry.attributes[:ports][2]
40
44
  expect(port_entry.container_port).to eq('8001')
41
45
  expect(port_entry.host_ip).to eq('127.0.0.1')
42
46
  expect(port_entry.host_port).to eq('8001')
43
47
  end
44
48
  end
45
49
 
46
- context 'Start container' do
47
- it 'should start/stop a container from image' do
50
+ context 'From image' do
51
+ before(:all) do
48
52
  attributes = {
49
- image: 'ubuntu:latest',
53
+ image: 'busybox:latest',
50
54
  links: ['links:links'],
51
55
  volumes: {'/tmp' => {}},
52
- command: 'ps aux',
56
+ command: 'ping -c 3 localhost',
53
57
  environment: ['ENVIRONMENT']
54
58
  }
55
59
 
56
- entry = ComposeContainer.new(attributes)
60
+ @entry = ComposeContainer.new(attributes)
61
+ end
62
+
63
+ it 'should start/stop a container' do
64
+ #Start container
65
+ @entry.start
66
+ expect(@entry.running?).to be true
67
+
68
+ # Stop container
69
+ @entry.stop
70
+ expect(@entry.running?).to be false
71
+ end
57
72
 
73
+ it 'should provide container stats' do
58
74
  #Start container
59
- entry.start
60
- expect(entry.running?).to be true
75
+ @entry.start
76
+ expect(@entry.running?).to be true
77
+
78
+ expect(@entry.stats).to_not be_nil
61
79
 
62
80
  # Stop container
63
- entry.stop
64
- expect(entry.running?).to be false
81
+ @entry.stop
82
+ expect(@entry.running?).to be false
65
83
  end
84
+ end
66
85
 
67
- it 'should start/stop a container from build' do
86
+ context 'From Dockerfile' do
87
+ before(:all) do
68
88
  attributes = {
69
89
  build: File.expand_path('spec/docker-compose/fixtures/'),
70
90
  links: ['links:links'],
71
91
  volumes: {'/tmp' => {}}
72
92
  }
73
93
 
74
- entry = ComposeContainer.new(attributes)
94
+ @entry = ComposeContainer.new(attributes)
95
+ end
96
+
97
+ it 'should start/stop a container' do
98
+ #Start container
99
+ @entry.start
100
+ expect(@entry.running?).to be true
101
+
102
+ # Stop container
103
+ @entry.stop
104
+ expect(@entry.running?).to be false
105
+ end
75
106
 
107
+ it 'should provide container stats' do
76
108
  #Start container
77
- entry.start
78
- expect(entry.running?).to be true
109
+ @entry.start
110
+ expect(@entry.running?).to be true
111
+
112
+ expect(@entry.stats).to_not be_nil
79
113
 
80
114
  # Stop container
81
- entry.stop
82
- expect(entry.running?).to be false
115
+ @entry.stop
116
+ expect(@entry.running?).to be false
83
117
  end
118
+ end
84
119
 
85
- it 'should not start a container without either image and build commands' do
120
+ context 'Without image or Dockerfile' do
121
+ before(:all) do
86
122
  attributes = {
87
123
  links: ['links:links'],
88
124
  volumes: {'/tmp' => {}},
@@ -90,8 +126,11 @@ describe ComposeContainer do
90
126
  environment: ['ENVIRONMENT']
91
127
  }
92
128
 
93
- entry = ComposeContainer.new(attributes)
94
- expect{entry.start}.to raise_error(ArgumentError)
129
+ @entry = ComposeContainer.new(attributes)
130
+ end
131
+
132
+ it 'should not start a container' do
133
+ expect{@entry.start}.to raise_error(ArgumentError)
95
134
  end
96
135
  end
97
136
  end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe Compose do
4
+ context 'Initialize' do
5
+ before(:all) do
6
+ @compose = Compose.new
7
+ end
8
+
9
+ it 'should start with no containers' do
10
+ expect(@compose.containers.empty?).to be true
11
+ end
12
+ end
13
+
14
+ context 'Add containers' do
15
+ before(:all) do
16
+ @attributes_container1 = {
17
+ label: 'container1',
18
+ image: 'busybox:latest',
19
+ command: 'ping -c 3 localhost'
20
+ }
21
+
22
+ @attributes_container2 = {
23
+ label: 'container2',
24
+ image: 'busybox:latest',
25
+ links: ['container3'],
26
+ command: 'ping -c 3 localhost'
27
+ }
28
+
29
+ @attributes_container3 = {
30
+ label: 'container3',
31
+ image: 'busybox:latest',
32
+ command: 'ping -c 3 localhost'
33
+ }
34
+ end
35
+
36
+ context 'Without dependencies' do
37
+ before(:all) do
38
+ @compose = Compose.new
39
+ @compose.add_container(ComposeContainer.new(@attributes_container1))
40
+ @compose.add_container(ComposeContainer.new(@attributes_container3))
41
+ @compose.link_containers
42
+ end
43
+
44
+ it 'should have 2 containers' do
45
+ expect(@compose.containers.length).to eq(2)
46
+ end
47
+
48
+ it 'should not have dependencies between containers' do
49
+ @compose.containers.values.each do |container|
50
+ expect(container.dependencies.empty?).to be true
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'With dependencies' do
56
+ before(:all) do
57
+ @compose = Compose.new
58
+ @compose.add_container(ComposeContainer.new(@attributes_container2))
59
+ @compose.add_container(ComposeContainer.new(@attributes_container3))
60
+ @compose.link_containers
61
+ end
62
+
63
+ it 'should have 2 containers' do
64
+ expect(@compose.containers.length).to eq(2)
65
+ end
66
+
67
+ it 'container2 should depend on container3' do
68
+ container2 = @compose.containers[@attributes_container2[:label]]
69
+ container3 = @compose.containers[@attributes_container3[:label]]
70
+
71
+ expect(container2.dependencies.include?(container3)).to be true
72
+ expect(container3.dependencies.empty?).to be true
73
+ end
74
+ end
75
+ end
76
+ end
@@ -51,4 +51,18 @@ describe ComposeUtils do
51
51
  expect(compose_port.host_ip).to eq('127.0.0.1')
52
52
  end
53
53
  end
54
+
55
+ context 'Format links' do
56
+ it 'should recognize pattern "[service]"' do
57
+ links = ComposeUtils.format_links(['service'])
58
+ expect(links.key?('service')).to be true
59
+ expect(links['service']).to_not be_nil
60
+ end
61
+
62
+ it 'should recognize pattern "[service:label]"' do
63
+ links = ComposeUtils.format_links(['service:label'])
64
+ expect(links.key?('service')).to be true
65
+ expect(links['service']).to eq('label')
66
+ end
67
+ end
54
68
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docker-compose-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-10-23 00:00:00.000000000 Z
12
+ date: 2015-10-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: docker-api
@@ -97,8 +97,9 @@ files:
97
97
  - lib/version.rb
98
98
  - spec/docker-compose/docker_compose_spec.rb
99
99
  - spec/docker-compose/fixtures/Dockerfile
100
- - spec/docker-compose/fixtures/sample1.yaml
100
+ - spec/docker-compose/fixtures/compose_1.yaml
101
101
  - spec/docker-compose/models/compose_container_spec.rb
102
+ - spec/docker-compose/models/compose_spec.rb
102
103
  - spec/docker-compose/utils/compose_utils_spec.rb
103
104
  - spec/spec_helper.rb
104
105
  homepage: https://github.com/mauricioklein/docker-compose-api
@@ -129,7 +130,8 @@ summary: A simple ruby client for docker-compose api
129
130
  test_files:
130
131
  - spec/docker-compose/docker_compose_spec.rb
131
132
  - spec/docker-compose/fixtures/Dockerfile
132
- - spec/docker-compose/fixtures/sample1.yaml
133
+ - spec/docker-compose/fixtures/compose_1.yaml
133
134
  - spec/docker-compose/models/compose_container_spec.rb
135
+ - spec/docker-compose/models/compose_spec.rb
134
136
  - spec/docker-compose/utils/compose_utils_spec.rb
135
137
  - spec/spec_helper.rb