marathon-api 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 23bb47d2d3c76218c3aa461968660ac5551e3f76
4
- data.tar.gz: ce1149c5f48884ecd403b69e61fb9ab12f8e0b3b
3
+ metadata.gz: 37c0d0ae7d91ddeaa7861bffa40b81e72a434e19
4
+ data.tar.gz: c5d165cf0d590a78fea207dfc705fa409174a8a5
5
5
  SHA512:
6
- metadata.gz: 7fca9778495fc930fe67d956a7db8e749f08c56e2e0bcce4320bac3dfbf94ac6d1025909135c573e06938fa2c27705b1a2d7f774a8713830192d768c27990faa
7
- data.tar.gz: 6301fea04cd2a18a89aa6dd59a52c46b79d2ee8a6a580131783661c249021e75750aa758c19c7efad99dad13621e24243f64270654f29b6d3aa672c75f00684d
6
+ metadata.gz: 941597d6ae53616a9931735f9a016606933df061115ff21eb1202325388d785e8e824dedc64e00d3fd64725f2560aac1bfdec0758d3b22ad57245b485f94dcdd
7
+ data.tar.gz: 56afa004de719231016576cba81c13f2553d50e7378e9b79a05f68f5b8664e0ac52b0fa25f2df69f7f29710598f64b5809dfdaff39e1263efd43e4cccb0c828e
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014 Swipely, Inc.
3
+ Copyright (c) 2015 Otto (GmbH & Co KG)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -102,6 +102,12 @@ apps.last.delete!
102
102
 
103
103
  The other Marathon endpoints are available in the same way.
104
104
 
105
+ Contributing
106
+ ------------
107
+
108
+ Please fork and send pull request.
109
+ Make sure to have test cases for your changes.
110
+
105
111
  Credits
106
112
  -------
107
113
 
data/bin/marathon CHANGED
@@ -46,9 +46,9 @@ def subcmd_start(cmd_opts)
46
46
  if cmd_opts[:json]
47
47
  path = cmd_opts[:json]
48
48
  if path == '-'
49
- app_opts = Marathon::Util.keywordize_hash(JSON.parse($stdin.read))
49
+ app_opts = Marathon::Util.keywordize_hash!(JSON.parse($stdin.read))
50
50
  elsif File.exists?(path)
51
- app_opts = Marathon::Util.keywordize_hash(JSON.parse(File.read(cmd_opts[:json])))
51
+ app_opts = Marathon::Util.keywordize_hash!(JSON.parse(File.read(cmd_opts[:json])))
52
52
  else
53
53
  raise Marathon::Error::ArgumentError, "File '#{path}' does not exist"
54
54
  end
@@ -231,12 +231,10 @@ def run_subcmd(cmd, cmd_opts)
231
231
  end
232
232
  end
233
233
 
234
- if __FILE__ == $0
235
- global_opts = parse_global_opts
236
- set_global_opts(global_opts)
234
+ global_opts = parse_global_opts
235
+ set_global_opts(global_opts)
237
236
 
238
- cmd = parse_subcmd
239
- cmd_opts = parse_subcmd_opts(cmd)
237
+ cmd = parse_subcmd
238
+ cmd_opts = parse_subcmd_opts(cmd)
240
239
 
241
- run_subcmd(cmd, cmd_opts)
242
- end
240
+ run_subcmd(cmd, cmd_opts)
data/lib/marathon/app.rb CHANGED
@@ -6,13 +6,12 @@ class Marathon::App < Marathon::Base
6
6
  storeUris tasksRunning tasksStaged uris user version ]
7
7
 
8
8
  DEFAULTS = {
9
- :constraints => [],
10
9
  :env => {},
11
10
  :ports => [],
12
11
  :uris => []
13
12
  }
14
13
 
15
- attr_reader :read_only
14
+ attr_reader :healthChecks, :constraints, :container, :read_only, :tasks
16
15
 
17
16
  # Create a new application object.
18
17
  # ++hash++: Hash including all attributes.
@@ -22,6 +21,7 @@ class Marathon::App < Marathon::Base
22
21
  super(Marathon::Util.merge_keywordized_hash(DEFAULTS, hash), ACCESSORS)
23
22
  raise ArgumentError, 'App must have an id' unless id
24
23
  @read_only = read_only
24
+ refresh_attributes
25
25
  end
26
26
 
27
27
  # Prevent actions on read only instances.
@@ -32,40 +32,6 @@ class Marathon::App < Marathon::Base
32
32
  end
33
33
  end
34
34
 
35
- # Get container info.
36
- # This is read only!
37
- def container
38
- if @info[:container]
39
- Marathon::Container.new(@info[:container])
40
- else
41
- nil
42
- end
43
- end
44
-
45
- # Get constrains.
46
- # This is read only!
47
- def constraints
48
- @info[:constraints].map { |e| Marathon::Constraint.new(e) }
49
- end
50
-
51
- # Get health checks.
52
- # This is read only!
53
- def healthChecks
54
- @info[:healthChecks].map { |e| Marathon::HealthCheck.new(e) }
55
- end
56
-
57
- # List all running tasks for the application.
58
- # This is read only!
59
- def tasks
60
- check_read_only
61
- unless @info[:tasks]
62
- refresh
63
- end
64
-
65
- raise UnexpectedResponseError, "Expected to find tasks element in app's info" unless @info[:tasks]
66
- @info[:tasks].map { |e| Marathon::Task.new(e) }
67
- end
68
-
69
35
  # List the versions of the application.
70
36
  # ++version++: Get a specific versions
71
37
  # Returns Array of Strings if ++version = nil++,
@@ -83,13 +49,14 @@ class Marathon::App < Marathon::Base
83
49
  check_read_only
84
50
  new_app = self.class.get(id)
85
51
  @info = new_app.info
52
+ refresh_attributes
86
53
  end
87
54
 
88
55
  # Create and start the application.
89
- def start!
90
- check_read_only
91
- new_app = self.class.start(info)
92
- @info = new_app.info
56
+ # ++force++: If the app is affected by a running deployment, then the update operation will fail.
57
+ # The current deployment can be overridden by setting the `force` query parameter.
58
+ def start!(force = false)
59
+ change!(info, force)
93
60
  end
94
61
 
95
62
  # Initiates a rolling restart of all running tasks of the given app.
@@ -109,7 +76,14 @@ class Marathon::App < Marathon::Base
109
76
  # The current deployment can be overridden by setting the `force` query parameter.
110
77
  def change!(hash, force = false)
111
78
  check_read_only
112
- self.class.change(id, hash, force)
79
+ Marathon::Util.keywordize_hash!(hash)
80
+ if hash[:version] and hash.size > 1
81
+ # remove :version if it's not the only key
82
+ new_hash = Marathon::Util.remove_keys(hash, [:version])
83
+ else
84
+ new_hash = hash
85
+ end
86
+ self.class.change(id, new_hash, force)
113
87
  end
114
88
 
115
89
  # Create a new version with parameters of an old version.
@@ -118,7 +92,7 @@ class Marathon::App < Marathon::Base
118
92
  # ++force++: If the app is affected by a running deployment, then the update operation will fail.
119
93
  # The current deployment can be overridden by setting the `force` query parameter.
120
94
  def roll_back!(version, force = false)
121
- change!({'version' => version}, force)
95
+ change!({:version => version}, force)
122
96
  end
123
97
 
124
98
  # Change the number of desired instances.
@@ -126,7 +100,7 @@ class Marathon::App < Marathon::Base
126
100
  # ++force++: If the app is affected by a running deployment, then the update operation will fail.
127
101
  # The current deployment can be overridden by setting the `force` query parameter.
128
102
  def scale!(instances, force = false)
129
- change!({'instances' => instances}, force)
103
+ change!({:instances => instances}, force)
130
104
  end
131
105
 
132
106
  # Change the number of desired instances to 0.
@@ -169,6 +143,18 @@ Version: #{version}
169
143
  constraints.map { |e| "Constraint: #{e.to_pretty_s}" }.join("\n")
170
144
  end
171
145
 
146
+ # Rebuild attribute classes
147
+ def refresh_attributes
148
+ @healthChecks = (info[:healthChecks] || []).map { |e| Marathon::HealthCheck.new(e) }
149
+ @constraints = (info[:constraints] || []).map { |e| Marathon::Constraint.new(e) }
150
+ if info[:container]
151
+ @container = Marathon::Container.new(info[:container])
152
+ else
153
+ @container = nil
154
+ end
155
+ @tasks = (@info[:tasks] || []).map { |e| Marathon::Task.new(e) }
156
+ end
157
+
172
158
  class << self
173
159
 
174
160
  # List the application with id.
data/lib/marathon/base.rb CHANGED
@@ -7,13 +7,13 @@ class Marathon::Base
7
7
 
8
8
  # Create the object
9
9
  # ++hash++: object returned from API. May be Hash or Array.
10
- # ++attr_readers++: List of attribute readers.
11
- def initialize(hash, attr_readers = [])
12
- raise ArgumentError, 'hash must be a Hash' if attr_readers and attr_readers.size > 0 and not hash.is_a?(Hash)
10
+ # ++attr_accessors++: List of attribute accessors.
11
+ def initialize(hash, attr_accessors = [])
12
+ raise ArgumentError, 'hash must be a Hash' if attr_accessors and attr_accessors.size > 0 and not hash.is_a?(Hash)
13
13
  raise ArgumentError, 'hash must be Hash or Array' unless hash.is_a?(Hash) or hash.is_a?(Array)
14
- raise ArgumentError, 'attr_readers must be an Array' unless attr_readers.is_a?(Array)
15
- @info = Marathon::Util.keywordize_hash(hash)
16
- attr_readers.each { |e| add_attr_reader(e) }
14
+ raise ArgumentError, 'attr_accessors must be an Array' unless attr_accessors.is_a?(Array)
15
+ @info = Marathon::Util.keywordize_hash!(hash)
16
+ attr_accessors.each { |e| add_attr_accessor(e) }
17
17
  end
18
18
 
19
19
  # Return application as JSON formatted string.
@@ -23,10 +23,11 @@ class Marathon::Base
23
23
 
24
24
  private
25
25
 
26
- # Create attr_reader for @info[key].
26
+ # Create attr_accessor for @info[key].
27
27
  # ++key++: key in @info
28
- def add_attr_reader(key)
28
+ def add_attr_accessor(key)
29
29
  sym = key.to_sym
30
- self.class.send(:define_method, sym.id2name) { |*args, &block| info[sym] }
30
+ self.class.send(:define_method, sym.id2name) { info[sym] }
31
+ self.class.send(:define_method, "#{sym.id2name}=") { |v| info[sym] = v }
31
32
  end
32
- end
33
+ end
@@ -10,27 +10,15 @@ class Marathon::Container < Marathon::Base
10
10
  :volumes => []
11
11
  }
12
12
 
13
+ attr_reader :docker, :volumes
14
+
13
15
  # Create a new container object.
14
16
  # ++hash++: Hash returned by API.
15
17
  def initialize(hash)
16
18
  super(Marathon::Util.merge_keywordized_hash(DEFAULTS, hash), ACCESSORS)
17
19
  Marathon::Util.validate_choice('type', type, SUPPERTED_TYPES)
18
- end
19
-
20
- # Get container's docker information.
21
- # This is read only!
22
- def docker
23
- if @info[:docker]
24
- Marathon::ContainerDocker.new(@info[:docker])
25
- else
26
- nil
27
- end
28
- end
29
-
30
- # Get container's volumes.
31
- # This is read only!
32
- def volumes
33
- @info[:volumes].map { |e| Marathon::ContainerVolume.new(e) }
20
+ @docker = Marathon::ContainerDocker.new(info[:docker]) if info[:docker]
21
+ @volumes = info[:volumes].map { |e| Marathon::ContainerVolume.new(e) }
34
22
  end
35
23
 
36
24
  def to_s
@@ -38,4 +26,4 @@ class Marathon::Container < Marathon::Base
38
26
  + " :volumes => #{Marathon::Util.items_to_pretty_s(volumes)} }"
39
27
  end
40
28
 
41
- end
29
+ end
@@ -8,18 +8,15 @@ class Marathon::ContainerDocker < Marathon::Base
8
8
  :portMappings => []
9
9
  }
10
10
 
11
+ attr_reader :portMappings
12
+
11
13
  # Create a new container docker object.
12
14
  # ++hash++: Hash returned by API.
13
15
  def initialize(hash)
14
16
  super(Marathon::Util.merge_keywordized_hash(DEFAULTS, hash), ACCESSORS)
15
17
  Marathon::Util.validate_choice('network', network, %w[BRIDGE HOST])
16
18
  raise Marathon::Error::ArgumentError, 'image must not be nil' unless image
17
- end
18
-
19
- # Get container's port mappings.
20
- # This is read only!
21
- def portMappings
22
- @info[:portMappings].map { |e| Marathon::ContainerDockerPortMapping.new(e) }
19
+ @portMappings = (info[:portMappings] || []).map { |e| Marathon::ContainerDockerPortMapping.new(e) }
23
20
  end
24
21
 
25
22
  def to_pretty_s
@@ -30,4 +27,4 @@ class Marathon::ContainerDocker < Marathon::Base
30
27
  "Marathon::ContainerDocker { :image => #{image} }"
31
28
  end
32
29
 
33
- end
30
+ end
@@ -5,36 +5,26 @@ class Marathon::Group < Marathon::Base
5
5
  ACCESSORS = %w[ id dependencies version ]
6
6
 
7
7
  DEFAULTS = {
8
- :apps => [],
9
- :dependencies => [],
10
- :groups => []
8
+ :dependencies => []
11
9
  }
12
10
 
11
+ attr_reader :apps, :groups
12
+
13
13
  # Create a new group object.
14
14
  # ++hash++: Hash including all attributes.
15
15
  # See https://mesosphere.github.io/marathon/docs/rest-api.html#post-/v2/groups for full details.
16
16
  def initialize(hash)
17
17
  super(Marathon::Util.merge_keywordized_hash(DEFAULTS, hash), ACCESSORS)
18
18
  raise ArgumentError, 'Group must have an id' unless id
19
+ refresh_attributes
19
20
  raise ArgumentError, 'Group can have either groups or apps, not both' if apps.size > 0 and groups.size > 0
20
21
  end
21
22
 
22
- # Get apps.
23
- # This is read only!
24
- def apps
25
- @info[:apps].map { |e| Marathon::App.new(e) }
26
- end
27
-
28
- # Get groups.
29
- # This is read only!
30
- def groups
31
- @info[:groups].map { |e| Marathon::Group.new(e) }
32
- end
33
-
34
23
  # Reload attributes from marathon API.
35
24
  def refresh
36
25
  new_app = self.class.get(id)
37
26
  @info = new_app.info
27
+ refresh_attributes
38
28
  end
39
29
 
40
30
  # Create and start a the application group. Application groups can contain other application groups.
@@ -65,7 +55,14 @@ class Marathon::Group < Marathon::Base
65
55
  # ++force++: If the group is affected by a running deployment, then the update operation will fail.
66
56
  # The current deployment can be overridden by setting the `force` query parameter.
67
57
  def change!(hash, force = false)
68
- self.class.change(id, hash, force)
58
+ Marathon::Util.keywordize_hash!(hash)
59
+ if hash[:version] and hash.size > 1
60
+ # remove :version if it's not the only key
61
+ new_hash = Marathon::Util.remove_keys(hash, [:version])
62
+ else
63
+ new_hash = hash
64
+ end
65
+ self.class.change(id, new_hash, force)
69
66
  end
70
67
 
71
68
  # Create a new version with parameters of an old version.
@@ -97,6 +94,12 @@ Version: #{version}
97
94
  array.map { |e| e.to_pretty_s.split("\n").map { |e| " #{e}" }}.join("\n")
98
95
  end
99
96
 
97
+ # Rebuild attribute classes
98
+ def refresh_attributes
99
+ @apps = (info[:apps] || []).map { |e| Marathon::App.new(e) }
100
+ @groups = (info[:groups] || []).map { |e| Marathon::Group.new(e) }
101
+ end
102
+
100
103
  class << self
101
104
 
102
105
  # List the group with the specified ID.
data/lib/marathon/util.rb CHANGED
@@ -40,21 +40,33 @@ class Marathon::Util
40
40
 
41
41
  # Swap keys of the hash against their symbols.
42
42
  # ++hash++: the hash
43
- def keywordize_hash(hash)
43
+ # ++ignore_keys++: don't keywordize hashes under theses keys
44
+ def keywordize_hash!(hash, ignore_keys = [:env])
44
45
  if hash.is_a?(Hash)
45
- new_hash = {}
46
- hash.each do |k,v|
46
+ hmap!(hash) do |k,v|
47
47
  key = k.to_sym
48
- if key == :env and v.is_a?(Hash)
49
- # ignore :env => {} to prevent renameing environment variables
50
- new_hash[key] = hash[k]
48
+ if ignore_keys.include?(key) and v.is_a?(Hash)
49
+ { key => v }
51
50
  else
52
- new_hash[key] = keywordize_hash(hash[k])
51
+ { key => keywordize_hash!(v) }
53
52
  end
54
53
  end
54
+ elsif hash.is_a?(Array)
55
+ hash.map! { |e| keywordize_hash!(e) }
56
+ end
57
+ hash
58
+ end
59
+
60
+ # Remove keys from hash and all it's sub hashes.
61
+ # ++hash++: the hash
62
+ # ++keys++: list of keys to remove
63
+ def remove_keys(hash, keys)
64
+ if hash.is_a?(Hash)
65
+ new_hash = {}
66
+ hash.each { |k,v| new_hash[k] = remove_keys(v, keys) unless keys.include?(k) }
55
67
  new_hash
56
68
  elsif hash.is_a?(Array)
57
- hash.map { |e| keywordize_hash(e) }
69
+ hash.map { |e| remove_keys(e, keys) }
58
70
  else
59
71
  hash
60
72
  end
@@ -62,7 +74,7 @@ class Marathon::Util
62
74
 
63
75
  # Merge two hashes but keywordize both.
64
76
  def merge_keywordized_hash(h1, h2)
65
- keywordize_hash(h1).merge(keywordize_hash(h2))
77
+ keywordize_hash!(h1).merge(keywordize_hash!(h2))
66
78
  end
67
79
 
68
80
  # Stringify an item or an array of items.
@@ -75,5 +87,16 @@ class Marathon::Util
75
87
  item.to_pretty_s
76
88
  end
77
89
  end
90
+
91
+ # Implement map! on a hash
92
+ def hmap!(hash, &block)
93
+ hash.keys.each do |key|
94
+ new_hash = block.call(key, hash[key])
95
+ new_key = new_hash.keys.first
96
+ hash[new_key] = new_hash[new_key]
97
+ hash.delete(key) unless key == new_key
98
+ end
99
+ hash
100
+ end
78
101
  end
79
102
  end
@@ -1,3 +1,3 @@
1
1
  module Marathon
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -38,7 +38,7 @@ describe Marathon::App do
38
38
  subject { described_class.new({ 'id' => '/app/foo' }) }
39
39
 
40
40
  let(:expected_string) do
41
- '{"constraints":[],"env":{},"ports":[],"uris":[],"id":"/app/foo"}'
41
+ '{"env":{},"ports":[],"uris":[],"id":"/app/foo"}'
42
42
  end
43
43
 
44
44
  its(:to_json) { should == expected_string }
@@ -84,26 +84,6 @@ describe Marathon::App do
84
84
  describe '#tasks' do
85
85
  subject { described_class.new({ 'id' => '/ubuntu2' }) }
86
86
 
87
- it 'checks for read only' do
88
- expect(subject).to receive(:check_read_only)
89
- subject.info[:tasks] = []
90
- subject.tasks
91
- end
92
-
93
- it 'has tasks', :vcr do
94
- tasks = subject.tasks
95
- expect(tasks).to be_instance_of(Array)
96
- expect(tasks.size).to eq(1)
97
- expect(tasks.first).to be_instance_of(Marathon::Task)
98
- expect(tasks.first.appId).to eq(subject.id)
99
- end
100
-
101
- it 'loads tasks from API when not loaded already' do
102
- subject.info[:tasks] = nil
103
- expect(subject).to receive(:refresh) { subject.info[:tasks] = [] }
104
- expect(subject.tasks).to eq([])
105
- end
106
-
107
87
  it 'shows already loaded tasks w/o API call' do
108
88
  subject.info[:tasks] = []
109
89
  expect(subject).not_to receive(:refresh)
@@ -132,17 +112,22 @@ describe Marathon::App do
132
112
 
133
113
  it 'checks for read only' do
134
114
  expect(subject).to receive(:check_read_only)
135
- expect(described_class).to receive(:start) { described_class.new('id' => subject.id) }
115
+ expect(described_class).to receive(:change).with(
116
+ '/app/foo',
117
+ {:env=>{}, :ports=>[], :uris=>[], :id=>"/app/foo"},
118
+ false
119
+ )
136
120
  subject.start!
137
121
  end
138
122
 
139
123
  it 'starts the app' do
140
- expect(described_class).to receive(:start)
141
- .with({:constraints=>[], :env=>{}, :ports=>[], :uris=>[], :id=>"/app/foo"}) do
142
- described_class.new({ 'id' => '/app/foo', 'started' => true })
143
- end
124
+ expect(described_class).to receive(:change)
125
+ .with(
126
+ '/app/foo',
127
+ {:env=>{}, :ports=>[], :uris=>[], :id=>"/app/foo"},
128
+ false
129
+ )
144
130
  subject.start!
145
- expect(subject.info[:started]).to be(true)
146
131
  end
147
132
  end
148
133
 
@@ -196,13 +181,13 @@ describe Marathon::App do
196
181
  end
197
182
 
198
183
  it 'changes the app' do
199
- expect(described_class).to receive(:change).with('/app/foo', {'instances' => 9000 }, false)
200
- subject.change!('instances' => 9000)
184
+ expect(described_class).to receive(:change).with('/app/foo', {:instances => 9000 }, false)
185
+ subject.change!('instances' => 9000, 'version' => 'old-version')
201
186
  end
202
187
  end
203
188
 
204
189
  describe '#roll_back!' do
205
- subject { described_class.new({ 'id' => '/app/foo', 'instances' => 10 }) }
190
+ subject { described_class.new({:id => '/app/foo', :instances => 10}) }
206
191
 
207
192
  it 'checks for read only' do
208
193
  expect(subject).to receive(:check_read_only)
@@ -211,18 +196,18 @@ describe Marathon::App do
211
196
  end
212
197
 
213
198
  it 'changes the app' do
214
- expect(subject).to receive(:change!).with({'version' => 'old_version' }, false)
199
+ expect(subject).to receive(:change!).with({:version => 'old_version' }, false)
215
200
  subject.roll_back!('old_version')
216
201
  end
217
202
 
218
203
  it 'changes the app with force' do
219
- expect(subject).to receive(:change!).with({'version' => 'old_version' }, true)
204
+ expect(subject).to receive(:change!).with({:version => 'old_version' }, true)
220
205
  subject.roll_back!('old_version', true)
221
206
  end
222
207
  end
223
208
 
224
209
  describe '#scale!' do
225
- subject { described_class.new({ 'id' => '/app/foo', 'instances' => 10 }) }
210
+ subject { described_class.new({:id => '/app/foo', :instances => 10}) }
226
211
 
227
212
  it 'checks for read only' do
228
213
  expect(subject).to receive(:check_read_only)
@@ -231,18 +216,18 @@ describe Marathon::App do
231
216
  end
232
217
 
233
218
  it 'changes the app' do
234
- expect(subject).to receive(:change!).with({'instances' => 9000 }, false)
219
+ expect(subject).to receive(:change!).with({:instances => 9000}, false)
235
220
  subject.scale!(9000)
236
221
  end
237
222
 
238
223
  it 'changes the app with force' do
239
- expect(subject).to receive(:change!).with({'instances' => 9000 }, true)
224
+ expect(subject).to receive(:change!).with({:instances => 9000}, true)
240
225
  subject.scale!(9000, true)
241
226
  end
242
227
  end
243
228
 
244
229
  describe '#suspend!' do
245
- subject { described_class.new({ 'id' => '/app/foo', 'instances' => 10 }) }
230
+ subject { described_class.new({'id' => '/app/foo', :instances => 10}) }
246
231
 
247
232
  it 'checks for read only' do
248
233
  expect(subject).to receive(:check_read_only)
@@ -290,7 +275,14 @@ describe Marathon::App do
290
275
  subject { described_class }
291
276
 
292
277
  it 'starts the app', :vcr do
293
- app = subject.start({ :id => '/test', :cmd => 'sleep 10', :instances => 1, :cpus => 0.1, :mem => 32})
278
+ app = subject.start({
279
+ :id => '/test',
280
+ :cmd => 'sleep 10',
281
+ :instances => 1,
282
+ :cpus => 0.1,
283
+ :mem => 32,
284
+ :version => 'foo-version'
285
+ })
294
286
  expect(app).to be_instance_of(described_class)
295
287
  expect(app.id).to eq('/test')
296
288
  expect(app.instances).to eq(1)
@@ -22,7 +22,7 @@ describe Marathon::Base do
22
22
  }) }
23
23
 
24
24
  let(:expected_string) do
25
- '{"app":{"id":"/app/foo"},"foo":"blubb","bar":1}'
25
+ '{"foo":"blubb","bar":1,"app":{"id":"/app/foo"}}'
26
26
  end
27
27
 
28
28
  its(:to_json) { should == expected_string }
@@ -50,4 +50,4 @@ describe Marathon::Base do
50
50
  its(:bar) { should == 1 }
51
51
  end
52
52
 
53
- end
53
+ end
@@ -1,25 +1,25 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  DEPLOYMENT_EXAMPLE = {
4
- "affectedApps" => ["/test"],
5
- "id" => "867ed450-f6a8-4d33-9b0e-e11c5513990b",
6
- "steps" => [
4
+ :affectedApps => ["/test"],
5
+ :id => "867ed450-f6a8-4d33-9b0e-e11c5513990b",
6
+ :steps => [
7
7
  [
8
8
  {
9
- "action" => "ScaleApplication",
10
- "app" => "/test"
9
+ :action => "ScaleApplication",
10
+ :app => "/test"
11
11
  }
12
12
  ]
13
13
  ],
14
- "currentActions" => [
14
+ :currentActions => [
15
15
  {
16
- "action" => "ScaleApplication",
17
- "app" => "/test"
16
+ :action => "ScaleApplication",
17
+ :app => "/test"
18
18
  }
19
19
  ],
20
- "version" => "2014-08-26T08:18:03.595Z",
21
- "currentStep" => 1,
22
- "totalSteps" => 1
20
+ :version => "2014-08-26T08:18:03.595Z",
21
+ :currentStep => 1,
22
+ :totalSteps => 1
23
23
  }
24
24
 
25
25
  describe Marathon::Deployment do
@@ -44,23 +44,23 @@ describe Marathon::Deployment do
44
44
  describe 'attributes' do
45
45
  subject { described_class.new(DEPLOYMENT_EXAMPLE) }
46
46
 
47
- its(:id) { should == DEPLOYMENT_EXAMPLE['id'] }
48
- its(:affectedApps) { should == DEPLOYMENT_EXAMPLE['affectedApps'] }
49
- its(:version) { should == DEPLOYMENT_EXAMPLE['version'] }
50
- its(:currentStep) { should == DEPLOYMENT_EXAMPLE['currentStep'] }
51
- its(:totalSteps) { should == DEPLOYMENT_EXAMPLE['totalSteps'] }
47
+ its(:id) { should == DEPLOYMENT_EXAMPLE[:id] }
48
+ its(:affectedApps) { should == DEPLOYMENT_EXAMPLE[:affectedApps] }
49
+ its(:version) { should == DEPLOYMENT_EXAMPLE[:version] }
50
+ its(:currentStep) { should == DEPLOYMENT_EXAMPLE[:currentStep] }
51
+ its(:totalSteps) { should == DEPLOYMENT_EXAMPLE[:totalSteps] }
52
52
  end
53
53
 
54
54
  describe '#delete' do
55
55
  subject { described_class.new(DEPLOYMENT_EXAMPLE) }
56
56
 
57
57
  it 'deletes the deployment' do
58
- expect(described_class).to receive(:delete).with(DEPLOYMENT_EXAMPLE['id'], false)
58
+ expect(described_class).to receive(:delete).with(DEPLOYMENT_EXAMPLE[:id], false)
59
59
  subject.delete
60
60
  end
61
61
 
62
62
  it 'force deletes the deployment' do
63
- expect(described_class).to receive(:delete).with(DEPLOYMENT_EXAMPLE['id'], true)
63
+ expect(described_class).to receive(:delete).with(DEPLOYMENT_EXAMPLE[:id], true)
64
64
  subject.delete(true)
65
65
  end
66
66
  end
@@ -70,9 +70,9 @@ describe Marathon::Deployment do
70
70
 
71
71
  it 'lists deployments', :vcr do
72
72
  # start a deployment
73
- Marathon::App.change('/test', {'instances' => 0})
73
+ Marathon::App.change('/test', {:instances => 0})
74
74
  sleep 1
75
- Marathon::App.change('/test', {'instances' => 2})
75
+ Marathon::App.change('/test', {:instances => 2})
76
76
  sleep 1
77
77
 
78
78
  deployments = subject.list
@@ -86,9 +86,9 @@ describe Marathon::Deployment do
86
86
 
87
87
  it 'deletes deployments', :vcr do
88
88
  # start a deployment
89
- info = Marathon::App.change('/test', {'instances' => 1})
89
+ info = Marathon::App.change('/test', {:instances => 1})
90
90
  expect(subject.delete(info.deploymentId)).to be_instance_of(Marathon::DeploymentInfo)
91
91
  end
92
92
  end
93
93
 
94
- end
94
+ end
@@ -23,11 +23,13 @@ EXAMPLE_GROUP = {
23
23
  "upgradeStrategy" => {
24
24
  "minimumHealthCapacity" => 1.0
25
25
  },
26
- "tasks" => []
26
+ "tasks" => [],
27
+ "version" => 'foo-version'
27
28
  }
28
29
  ],
29
30
  "dependencies" => [],
30
- "groups" => []
31
+ "groups" => [],
32
+ "version" => 'foo-version'
31
33
  }
32
34
 
33
35
  describe Marathon::Group do
@@ -46,8 +48,8 @@ describe Marathon::Group do
46
48
  " Command: sleep 30\n" + \
47
49
  " CPUs: 1.0\n" + \
48
50
  " Memory: 128.0 MB\n" + \
49
- " Version:\n" + \
50
- "Version:"
51
+ " Version: foo-version\n" + \
52
+ "Version: foo-version"
51
53
 
52
54
  end
53
55
 
@@ -60,7 +62,7 @@ describe Marathon::Group do
60
62
 
61
63
  it 'starts the group' do
62
64
  expect(described_class).to receive(:start)
63
- .with({:apps=>[], :dependencies=>[], :groups=>[], :id=>'/group/foo'}) do
65
+ .with({:dependencies=>[], :id=>'/group/foo'}) do
64
66
  Marathon::DeploymentInfo.new({ 'version' => 'new-version' })
65
67
  end
66
68
  expect(subject.start!.version).to eq('new-version')
@@ -83,9 +85,14 @@ describe Marathon::Group do
83
85
  subject { described_class.new({ 'id' => '/app/foo' }) }
84
86
 
85
87
  it 'changes the group' do
86
- expect(described_class).to receive(:change).with('/app/foo', {'instances' => 9000 }, false)
88
+ expect(described_class).to receive(:change).with('/app/foo', {:instances => 9000 }, false)
87
89
  subject.change!('instances' => 9000)
88
90
  end
91
+
92
+ it 'changes the group and strips :version' do
93
+ expect(described_class).to receive(:change).with('/app/foo', {:instances => 9000 }, false)
94
+ subject.change!('instances' => 9000, :version => 'old-version')
95
+ end
89
96
  end
90
97
 
91
98
  describe '#roll_back!' do
@@ -41,23 +41,46 @@ describe Marathon::Util do
41
41
  end
42
42
  end
43
43
 
44
- describe '.keywordize_hash' do
44
+ describe '.keywordize_hash!' do
45
45
  subject { described_class }
46
46
 
47
47
  it 'keywordizes the hash' do
48
- expect(subject.keywordize_hash({
49
- 'foo' => 'bar',
50
- 'f00' => {'w00h00' => 'yeah'},
51
- 'bang' => [{'tricky' => 'one'}],
52
- 'env' => {'foo' => 'bar'},
53
- 'null' => nil
54
- })).to eq({
48
+ hash = {
49
+ 'foo' => 'bar',
50
+ 'f00' => {'w00h00' => 'yeah'},
51
+ 'bang' => [{'tricky' => 'one'}],
52
+ 'env' => {'foo' => 'bar'},
53
+ 'null' => nil
54
+ }
55
+
56
+ expect(subject.keywordize_hash!(hash)).to eq({
55
57
  :foo => 'bar',
56
58
  :f00 => {:w00h00 => 'yeah'},
57
59
  :bang => [{:tricky => 'one'}],
58
60
  :env => {'foo' => 'bar'},
59
61
  :null => nil
60
62
  })
63
+ # make sure, it changes the hash w/o creating a new one
64
+ expect(hash[:foo]).to eq('bar')
65
+ end
66
+ end
67
+
68
+ describe '.remove_keys' do
69
+ subject { described_class }
70
+
71
+ it 'removes keys from hash' do
72
+ hash = {
73
+ :foo => 'bar',
74
+ :deleteme => {'w00h00' => 'yeah'},
75
+ :blah => [{:deleteme => :foo}, 1]
76
+ }
77
+
78
+ expect(subject.remove_keys(hash, [:deleteme])).to eq({
79
+ :foo => 'bar',
80
+ :blah => [{}, 1]
81
+ })
82
+ # make sure, it does not changes the original hash
83
+ expect(hash.size).to eq(3)
61
84
  end
62
85
  end
63
86
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: marathon-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix Bechstein
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-09 00:00:00.000000000 Z
11
+ date: 2015-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json