docker-compose-api 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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