marathon-api 0.9.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +2 -2
  3. data/.travis.yml +1 -1
  4. data/README.md +40 -14
  5. data/bin/marathon +242 -0
  6. data/fixtures/marathon_docker_sample_2.json +2 -1
  7. data/fixtures/vcr/Marathon_App/_restart/restarts_an_app.yml +32 -0
  8. data/fixtures/vcr/Marathon_Group/_changes/changes_the_group.yml +61 -0
  9. data/fixtures/vcr/Marathon_Group/_delete/deletes_the_group.yml +32 -0
  10. data/fixtures/vcr/Marathon_Group/_delete/fails_deleting_not_existing_app.yml +32 -0
  11. data/fixtures/vcr/Marathon_Group/_get/fails_getting_not_existing_app.yml +32 -0
  12. data/fixtures/vcr/Marathon_Group/_get/gets_the_group.yml +32 -0
  13. data/fixtures/vcr/Marathon_Group/_list/lists_apps.yml +33 -0
  14. data/fixtures/vcr/Marathon_Group/_start/fails_getting_not_existing_group.yml +32 -0
  15. data/fixtures/vcr/Marathon_Group/_start/starts_the_group.yml +35 -0
  16. data/lib/marathon.rb +33 -5
  17. data/lib/marathon/app.rb +72 -22
  18. data/lib/marathon/base.rb +32 -0
  19. data/lib/marathon/connection.rb +32 -22
  20. data/lib/marathon/constraint.rb +39 -0
  21. data/lib/marathon/container.rb +41 -0
  22. data/lib/marathon/container_docker.rb +33 -0
  23. data/lib/marathon/container_docker_port_mapping.rb +32 -0
  24. data/lib/marathon/container_volume.rb +31 -0
  25. data/lib/marathon/deployment.rb +5 -15
  26. data/lib/marathon/deployment_info.rb +20 -0
  27. data/lib/marathon/error.rb +8 -2
  28. data/lib/marathon/group.rb +166 -0
  29. data/lib/marathon/health_check.rb +35 -0
  30. data/lib/marathon/queue.rb +4 -13
  31. data/lib/marathon/task.rb +15 -12
  32. data/lib/marathon/util.rb +47 -3
  33. data/lib/marathon/version.rb +1 -1
  34. data/marathon-api.gemspec +4 -3
  35. data/spec/marathon/app_spec.rb +108 -50
  36. data/spec/marathon/base_spec.rb +53 -0
  37. data/spec/marathon/connection_spec.rb +1 -1
  38. data/spec/marathon/constraint_spec.rb +27 -0
  39. data/spec/marathon/container_docker_port_mapping_spec.rb +55 -0
  40. data/spec/marathon/container_docker_spec.rb +42 -0
  41. data/spec/marathon/container_spec.rb +40 -0
  42. data/spec/marathon/container_volume_spec.rb +50 -0
  43. data/spec/marathon/deployment_info_spec.rb +43 -0
  44. data/spec/marathon/deployment_spec.rb +15 -16
  45. data/spec/marathon/error_spec.rb +17 -0
  46. data/spec/marathon/group_spec.rb +172 -0
  47. data/spec/marathon/health_check_spec.rb +50 -0
  48. data/spec/marathon/marathon_spec.rb +31 -0
  49. data/spec/marathon/queue_spec.rb +2 -2
  50. data/spec/marathon/task_spec.rb +24 -11
  51. data/spec/marathon/util_spec.rb +21 -1
  52. metadata +58 -6
@@ -0,0 +1,32 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: delete
5
+ uri: http://localhost:8080/v2/groups//test-group?force=true
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Content-Type:
11
+ - application/json
12
+ Accept:
13
+ - application/json
14
+ User-Agent:
15
+ - ub0r/Marathon-API 0.9.0
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Content-Type:
22
+ - application/json
23
+ Transfer-Encoding:
24
+ - chunked
25
+ Server:
26
+ - Jetty(8.y.z-SNAPSHOT)
27
+ body:
28
+ encoding: UTF-8
29
+ string: '{"version":"2015-03-09T10:33:40.335Z","deploymentId":"c5ad3775-a422-48f0-99ee-e7e7f098a832"}'
30
+ http_version:
31
+ recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
32
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,32 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: delete
5
+ uri: http://localhost:8080/v2/groups/fooo%20group
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Content-Type:
11
+ - application/json
12
+ Accept:
13
+ - application/json
14
+ User-Agent:
15
+ - ub0r/Marathon-API 0.9.0
16
+ response:
17
+ status:
18
+ code: 404
19
+ message: Not Found
20
+ headers:
21
+ Content-Type:
22
+ - application/json
23
+ Transfer-Encoding:
24
+ - chunked
25
+ Server:
26
+ - Jetty(8.y.z-SNAPSHOT)
27
+ body:
28
+ encoding: UTF-8
29
+ string: '{"message":"Group ''/fooo group'' does not exist"}'
30
+ http_version:
31
+ recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
32
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,32 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://localhost:8080/v2/groups/fooo%20group
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Content-Type:
11
+ - application/json
12
+ Accept:
13
+ - application/json
14
+ User-Agent:
15
+ - ub0r/Marathon-API 0.9.0
16
+ response:
17
+ status:
18
+ code: 404
19
+ message: Not Found
20
+ headers:
21
+ Content-Type:
22
+ - application/json
23
+ Transfer-Encoding:
24
+ - chunked
25
+ Server:
26
+ - Jetty(8.y.z-SNAPSHOT)
27
+ body:
28
+ encoding: UTF-8
29
+ string: '{"message":"Group ''/fooo group'' does not exist"}'
30
+ http_version:
31
+ recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
32
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,32 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://localhost:8080/v2/groups//test-group
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Content-Type:
11
+ - application/json
12
+ Accept:
13
+ - application/json
14
+ User-Agent:
15
+ - ub0r/Marathon-API 0.9.0
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Content-Type:
22
+ - application/json
23
+ Transfer-Encoding:
24
+ - chunked
25
+ Server:
26
+ - Jetty(8.y.z-SNAPSHOT)
27
+ body:
28
+ encoding: UTF-8
29
+ string: '{"id":"/test-group","apps":[{"id":"/test-group/app","cmd":"sleep 30","args":null,"user":null,"env":{},"instances":1,"cpus":1.0,"mem":128.0,"disk":0.0,"executor":"","constraints":[],"uris":[],"storeUrls":[],"ports":[10000],"requirePorts":false,"backoffSeconds":1,"backoffFactor":1.15,"maxLaunchDelaySeconds":3600,"container":null,"healthChecks":[],"dependencies":[],"upgradeStrategy":{"minimumHealthCapacity":1.0,"maximumOverCapacity":0.0},"labels":{},"version":"2015-03-09T10:33:39.889Z"}],"groups":[],"dependencies":[],"version":"2015-03-09T10:33:39.889Z"}'
30
+ http_version:
31
+ recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
32
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,33 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://localhost:8080/v2/groups
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Content-Type:
11
+ - application/json
12
+ Accept:
13
+ - application/json
14
+ User-Agent:
15
+ - ub0r/Marathon-API 0.9.0
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Content-Type:
22
+ - application/json
23
+ Transfer-Encoding:
24
+ - chunked
25
+ Server:
26
+ - Jetty(8.y.z-SNAPSHOT)
27
+ body:
28
+ encoding: UTF-8
29
+ string: '{"id":"/","apps":[],"groups":[{"id":"/ubuntu2","apps":[],"groups":[],"dependencies":[],"version":"2015-03-09T10:33:39.889Z"},{"id":"/test-group","apps":[{"id":"/test-group/app","cmd":"sleep
30
+ 30","args":null,"user":null,"env":{},"instances":1,"cpus":1.0,"mem":128.0,"disk":0.0,"executor":"","constraints":[],"uris":[],"storeUrls":[],"ports":[10000],"requirePorts":false,"backoffSeconds":1,"backoffFactor":1.15,"maxLaunchDelaySeconds":3600,"container":null,"healthChecks":[],"dependencies":[],"upgradeStrategy":{"minimumHealthCapacity":1.0,"maximumOverCapacity":0.0},"labels":{},"version":"2015-03-09T10:33:39.889Z"}],"groups":[],"dependencies":[],"version":"2015-03-09T10:33:39.889Z"}],"dependencies":[],"version":"2015-03-09T10:33:39.889Z"}'
31
+ http_version:
32
+ recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
33
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,32 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://localhost:8080/v2/groups/fooo%20group
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Content-Type:
11
+ - application/json
12
+ Accept:
13
+ - application/json
14
+ User-Agent:
15
+ - ub0r/Marathon-API 0.9.0
16
+ response:
17
+ status:
18
+ code: 404
19
+ message: Not Found
20
+ headers:
21
+ Content-Type:
22
+ - application/json
23
+ Transfer-Encoding:
24
+ - chunked
25
+ Server:
26
+ - Jetty(8.y.z-SNAPSHOT)
27
+ body:
28
+ encoding: UTF-8
29
+ string: '{"message":"Group ''/fooo group'' does not exist"}'
30
+ http_version:
31
+ recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
32
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,35 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: http://localhost:8080/v2/groups
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"id":"/test-group","apps":[{"backoffFactor":1.15,"backoffSeconds":1,"maxLaunchDelaySeconds":3600,"cmd":"sleep
9
+ 30","constraints":[],"cpus":1.0,"dependencies":[],"disk":0.0,"env":{},"executor":"","id":"app","instances":1,"mem":128.0,"ports":[10000],"requirePorts":false,"storeUrls":[],"upgradeStrategy":{"minimumHealthCapacity":1.0},"tasks":[]}],"dependencies":[],"groups":[]}'
10
+ headers:
11
+ Content-Type:
12
+ - application/json
13
+ Accept:
14
+ - application/json
15
+ User-Agent:
16
+ - ub0r/Marathon-API 0.9.0
17
+ response:
18
+ status:
19
+ code: 201
20
+ message: Created
21
+ headers:
22
+ Location:
23
+ - http://localhost:8080/v2/groups/test-group
24
+ Content-Type:
25
+ - application/json
26
+ Transfer-Encoding:
27
+ - chunked
28
+ Server:
29
+ - Jetty(8.y.z-SNAPSHOT)
30
+ body:
31
+ encoding: UTF-8
32
+ string: '{"version":"2015-03-09T10:33:39.889Z","deploymentId":"ad618509-e8ee-4949-8267-ef35a619426f"}'
33
+ http_version:
34
+ recorded_at: Mon, 09 Mar 2015 10:33:40 GMT
35
+ recorded_with: VCR 2.9.3
@@ -9,16 +9,25 @@ module Marathon
9
9
 
10
10
  attr_accessor :logger
11
11
 
12
+ require 'marathon/version'
12
13
  require 'marathon/util'
13
14
  require 'marathon/error'
14
15
  require 'marathon/connection'
16
+ require 'marathon/base'
17
+ require 'marathon/constraint'
18
+ require 'marathon/container_docker_port_mapping'
19
+ require 'marathon/container_docker'
20
+ require 'marathon/container_volume'
21
+ require 'marathon/container'
22
+ require 'marathon/health_check'
23
+ require 'marathon/deployment_info'
24
+ require 'marathon/group'
15
25
  require 'marathon/app'
16
26
  require 'marathon/deployment'
17
27
  require 'marathon/event_subscriptions'
18
28
  require 'marathon/leader'
19
29
  require 'marathon/queue'
20
30
  require 'marathon/task'
21
- require 'marathon/version'
22
31
 
23
32
  DEFAULT_URL = 'http://localhost:8080'
24
33
 
@@ -27,21 +36,40 @@ module Marathon
27
36
  ENV['MARATHON_URL']
28
37
  end
29
38
 
30
- # Get the marathon url
39
+ # Get marathon options from environment
40
+ def env_options
41
+ opts = {}
42
+ opts[:username] = ENV['MARATHON_USER'] if ENV['MARATHON_USER']
43
+ opts[:password] = ENV['MARATHON_PASSWORD'] if ENV['MARATHON_PASSWORD']
44
+ opts
45
+ end
46
+
47
+ # Get the marathon API URL
31
48
  def url
32
49
  @url ||= env_url || DEFAULT_URL
33
50
  @url
34
51
  end
35
52
 
53
+ # Get options for connecting to marathon API
54
+ def options
55
+ @options ||= env_options
56
+ end
57
+
36
58
  # Set a new url
37
59
  def url=(new_url)
38
60
  @url = new_url
39
61
  reset_connection!
40
62
  end
41
63
 
64
+ # Set new options
65
+ def options=(new_options)
66
+ @options = env_options.merge(new_options || {})
67
+ reset_connection!
68
+ end
69
+
42
70
  # Set a new connection
43
71
  def connection
44
- @connection ||= Connection.new(url)
72
+ @connection ||= Connection.new(url, options)
45
73
  end
46
74
 
47
75
  # Reset the connection
@@ -59,7 +87,7 @@ module Marathon
59
87
  connection.get('/ping')
60
88
  end
61
89
 
62
- module_function :connection, :env_url, :info, :logger, :logger=,
63
- :ping, :url, :url= ,:reset_connection!
90
+ module_function :connection, :env_options, :env_url, :info, :logger, :logger=, :ping,
91
+ :options, :options=, :url, :url= ,:reset_connection!
64
92
 
65
93
  end
@@ -1,24 +1,29 @@
1
1
  # This class represents a Marathon App.
2
2
  # See https://mesosphere.github.io/marathon/docs/rest-api.html#apps for full list of API's methods.
3
- class Marathon::App
3
+ class Marathon::App < Marathon::Base
4
4
 
5
- attr_reader :info, :read_only
5
+ ACCESSORS = %w[ id args cmd cpus disk env executor instances mem ports requirePorts
6
+ storeUris tasksRunning tasksStaged uris user version ]
7
+
8
+ DEFAULTS = {
9
+ :constraints => [],
10
+ :env => {},
11
+ :ports => [],
12
+ :uris => []
13
+ }
14
+
15
+ attr_reader :read_only
6
16
 
7
17
  # Create a new application object.
8
18
  # ++hash++: Hash including all attributes.
9
19
  # See https://mesosphere.github.io/marathon/docs/rest-api.html#post-/v2/apps for full details.
10
20
  # ++read_only++: prevent actions on this application
11
- def initialize(hash = {}, read_only = false)
12
- @info = hash
21
+ def initialize(hash, read_only = false)
22
+ super(Marathon::Util.merge_keywordized_hash(DEFAULTS, hash), ACCESSORS)
23
+ raise ArgumentError, 'App must have an id' unless id
13
24
  @read_only = read_only
14
25
  end
15
26
 
16
- # Shortcuts for reaching attributes
17
- %w[ id args cmd cpus disk env executor instances mem ports requirePorts
18
- storeUris tasksRunning tasksStaged uris user version ].each do |method|
19
- define_method(method) { |*args, &block| info[method] }
20
- end
21
-
22
27
  # Prevent actions on read only instances.
23
28
  # Raises an ArgumentError when triying to change read_only instances.
24
29
  def check_read_only
@@ -27,17 +32,38 @@ class Marathon::App
27
32
  end
28
33
  end
29
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
+
30
57
  # List all running tasks for the application.
31
- # Returns an Array of Task objects.
58
+ # This is read only!
32
59
  def tasks
33
60
  check_read_only
34
- unless @info['tasks']
61
+ unless @info[:tasks]
35
62
  refresh
36
63
  end
37
64
 
38
- raise Marathon::Error::UnexpectedResponseError, "Expected to find tasks element in app's info" unless @info['tasks']
39
-
40
- @info['tasks'].map { |e| Marathon::Task.new(e) }
65
+ raise UnexpectedResponseError, "Expected to find tasks element in app's info" unless @info[:tasks]
66
+ @info[:tasks].map { |e| Marathon::Task.new(e) }
41
67
  end
42
68
 
43
69
  # List the versions of the application.
@@ -111,12 +137,36 @@ class Marathon::App
111
137
  end
112
138
 
113
139
  def to_s
114
- "Marathon::App { :id => #{self.id} }"
140
+ "Marathon::App { :id => #{id} }"
141
+ end
142
+
143
+ # Returns a string for listing the application.
144
+ def to_pretty_s
145
+ %Q[
146
+ App ID: #{id}
147
+ Instances: #{tasks.size}/#{instances}
148
+ Command: #{cmd}
149
+ CPUs: #{cpus}
150
+ Memory: #{mem} MB
151
+ #{pretty_uris()}
152
+ #{pretty_env()}
153
+ #{pretty_constraints()}
154
+ Version: #{version}
155
+ ].gsub(/\n\n+/, "\n").strip
156
+ end
157
+
158
+ private
159
+
160
+ def pretty_env
161
+ env.map { |k,v| "ENV: #{k}=#{v}" }.join("\n")
162
+ end
163
+
164
+ def pretty_uris
165
+ uris.map { |e| "URI: #{e}" }.join("\n")
115
166
  end
116
167
 
117
- # Return application as JSON formatted string.
118
- def to_json
119
- info.to_json
168
+ def pretty_constraints
169
+ constraints.map { |e| "Constraint: #{e.to_pretty_s}" }.join("\n")
120
170
  end
121
171
 
122
172
  class << self
@@ -166,7 +216,7 @@ class Marathon::App
166
216
  query = {}
167
217
  query[:force] = true if force
168
218
  json = Marathon.connection.post("/v2/apps/#{id}/restart", query)
169
- # TODO parse deploymentId + version
219
+ Marathon::DeploymentInfo.new(json)
170
220
  end
171
221
 
172
222
  # Change parameters of a running application. The new application parameters apply only to subsequently
@@ -179,7 +229,7 @@ class Marathon::App
179
229
  query = {}
180
230
  query[:force] = true if force
181
231
  json = Marathon.connection.put("/v2/apps/#{id}", query, :body => hash)
182
- # TODO parse deploymentId + version
232
+ Marathon::DeploymentInfo.new(json)
183
233
  end
184
234
 
185
235
  # List the versions of the application with id.
@@ -197,4 +247,4 @@ class Marathon::App
197
247
  new(json, true)
198
248
  end
199
249
  end
200
- end
250
+ end