marathon-api 0.9.0 → 1.0.0
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.
- checksums.yaml +4 -4
- data/.simplecov +2 -2
- data/.travis.yml +1 -1
- data/README.md +40 -14
- data/bin/marathon +242 -0
- data/fixtures/marathon_docker_sample_2.json +2 -1
- data/fixtures/vcr/Marathon_App/_restart/restarts_an_app.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_changes/changes_the_group.yml +61 -0
- data/fixtures/vcr/Marathon_Group/_delete/deletes_the_group.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_delete/fails_deleting_not_existing_app.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_get/fails_getting_not_existing_app.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_get/gets_the_group.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_list/lists_apps.yml +33 -0
- data/fixtures/vcr/Marathon_Group/_start/fails_getting_not_existing_group.yml +32 -0
- data/fixtures/vcr/Marathon_Group/_start/starts_the_group.yml +35 -0
- data/lib/marathon.rb +33 -5
- data/lib/marathon/app.rb +72 -22
- data/lib/marathon/base.rb +32 -0
- data/lib/marathon/connection.rb +32 -22
- data/lib/marathon/constraint.rb +39 -0
- data/lib/marathon/container.rb +41 -0
- data/lib/marathon/container_docker.rb +33 -0
- data/lib/marathon/container_docker_port_mapping.rb +32 -0
- data/lib/marathon/container_volume.rb +31 -0
- data/lib/marathon/deployment.rb +5 -15
- data/lib/marathon/deployment_info.rb +20 -0
- data/lib/marathon/error.rb +8 -2
- data/lib/marathon/group.rb +166 -0
- data/lib/marathon/health_check.rb +35 -0
- data/lib/marathon/queue.rb +4 -13
- data/lib/marathon/task.rb +15 -12
- data/lib/marathon/util.rb +47 -3
- data/lib/marathon/version.rb +1 -1
- data/marathon-api.gemspec +4 -3
- data/spec/marathon/app_spec.rb +108 -50
- data/spec/marathon/base_spec.rb +53 -0
- data/spec/marathon/connection_spec.rb +1 -1
- data/spec/marathon/constraint_spec.rb +27 -0
- data/spec/marathon/container_docker_port_mapping_spec.rb +55 -0
- data/spec/marathon/container_docker_spec.rb +42 -0
- data/spec/marathon/container_spec.rb +40 -0
- data/spec/marathon/container_volume_spec.rb +50 -0
- data/spec/marathon/deployment_info_spec.rb +43 -0
- data/spec/marathon/deployment_spec.rb +15 -16
- data/spec/marathon/error_spec.rb +17 -0
- data/spec/marathon/group_spec.rb +172 -0
- data/spec/marathon/health_check_spec.rb +50 -0
- data/spec/marathon/marathon_spec.rb +31 -0
- data/spec/marathon/queue_spec.rb +2 -2
- data/spec/marathon/task_spec.rb +24 -11
- data/spec/marathon/util_spec.rb +21 -1
- metadata +58 -6
@@ -0,0 +1,32 @@
|
|
1
|
+
# Base class for all the API specific classes.
|
2
|
+
class Marathon::Base
|
3
|
+
|
4
|
+
include Marathon::Error
|
5
|
+
|
6
|
+
attr_reader :info
|
7
|
+
|
8
|
+
# Create the object
|
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)
|
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) }
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return application as JSON formatted string.
|
20
|
+
def to_json
|
21
|
+
info.to_json
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# Create attr_reader for @info[key].
|
27
|
+
# ++key++: key in @info
|
28
|
+
def add_attr_reader(key)
|
29
|
+
sym = key.to_sym
|
30
|
+
self.class.send(:define_method, sym.id2name) { |*args, &block| info[sym] }
|
31
|
+
end
|
32
|
+
end
|
data/lib/marathon/connection.rb
CHANGED
@@ -13,12 +13,22 @@ class Marathon::Connection
|
|
13
13
|
default_timeout 5
|
14
14
|
maintain_method_across_redirects
|
15
15
|
|
16
|
-
attr_reader :url
|
16
|
+
attr_reader :url, :options
|
17
17
|
|
18
18
|
# Create a new API connection.
|
19
19
|
# ++url++: URL of the marathon API.
|
20
|
-
|
20
|
+
# ++options++: Hash with options for marathon API.
|
21
|
+
def initialize(url, options = {})
|
21
22
|
@url = url
|
23
|
+
@options = options
|
24
|
+
if @options[:username] and @options[:password]
|
25
|
+
@options[:basic_auth] = {
|
26
|
+
:username => @options[:username],
|
27
|
+
:password => @options[:password]
|
28
|
+
}
|
29
|
+
@options.delete(:username)
|
30
|
+
@options.delete(:password)
|
31
|
+
end
|
22
32
|
end
|
23
33
|
|
24
34
|
# Delegate all HTTP methods to the #request.
|
@@ -27,7 +37,7 @@ class Marathon::Connection
|
|
27
37
|
end
|
28
38
|
|
29
39
|
def to_s
|
30
|
-
"Marathon::Connection { :url => #{url} }"
|
40
|
+
"Marathon::Connection { :url => #{url} :options => #{options} }"
|
31
41
|
end
|
32
42
|
|
33
43
|
private
|
@@ -58,16 +68,25 @@ private
|
|
58
68
|
end
|
59
69
|
|
60
70
|
# Create full URL with query parameters.
|
61
|
-
# ++
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
url += '?' + query_params(query)
|
71
|
+
# ++request++: hash containing :url and optional :query
|
72
|
+
def build_url(request)
|
73
|
+
url = URI.escape(request[:url])
|
74
|
+
if request[:query].size > 0
|
75
|
+
url += '?' + query_params(request[:query])
|
67
76
|
end
|
68
77
|
url
|
69
78
|
end
|
70
79
|
|
80
|
+
# Parse response or raise error.
|
81
|
+
# ++response++: response from HTTParty call.
|
82
|
+
def parse_response(response)
|
83
|
+
if response.success?
|
84
|
+
response.parsed_response
|
85
|
+
else
|
86
|
+
raise Marathon::Error.from_response(response)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
71
90
|
# Send a request to the server and parse response.
|
72
91
|
# ++http_method++: GET/POST/PUT/DELETE.
|
73
92
|
# ++path++: Relative path to connection's URL.
|
@@ -75,19 +94,10 @@ private
|
|
75
94
|
# ++opts++: Optional options. Ex. opts[:body] is used for PUT/POST request.
|
76
95
|
def request(*args)
|
77
96
|
request = compile_request_params(*args)
|
78
|
-
url = build_url(request
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
else
|
83
|
-
raise Marathon::Error.from_response(response)
|
84
|
-
end
|
85
|
-
rescue MarathonError => e
|
86
|
-
raise e
|
87
|
-
rescue SocketError => e
|
88
|
-
raise IOError, "HTTP call failed: #{e.message}"
|
89
|
-
rescue SystemCallError => e
|
90
|
-
if e.class.name.start_with?('Errno::')
|
97
|
+
url = build_url(request)
|
98
|
+
parse_response(self.class.send(request[:method], url, request))
|
99
|
+
rescue => e
|
100
|
+
if e.class == SocketError or e.class.name.start_with?('Errno::')
|
91
101
|
raise IOError, "HTTP call failed: #{e.message}"
|
92
102
|
else
|
93
103
|
raise e
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# This class represents a Marathon Constraint.
|
2
|
+
# See https://mesosphere.github.io/marathon/docs/constraints.html for full details.
|
3
|
+
class Marathon::Constraint < Marathon::Base
|
4
|
+
|
5
|
+
# Create a new constraint object.
|
6
|
+
# ++array++: Array returned by API, holds attribute, operator and parameter.
|
7
|
+
def initialize(array)
|
8
|
+
raise Marathon::Error::ArgumentError, 'array must be an Array' unless array.is_a?(Array)
|
9
|
+
raise Marathon::Error::ArgumentError,
|
10
|
+
'array must be [attribute, operator, parameter] where only parameter is optional' \
|
11
|
+
unless array.size != 2 or array.size != 3
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def attribute
|
16
|
+
info[0]
|
17
|
+
end
|
18
|
+
|
19
|
+
def operator
|
20
|
+
info[1]
|
21
|
+
end
|
22
|
+
|
23
|
+
def parameter
|
24
|
+
info[2]
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
if parameter
|
29
|
+
"Marathon::Constraint { :attribute => #{attribute} :operator => #{operator} :parameter => #{parameter} }"
|
30
|
+
else
|
31
|
+
"Marathon::Constraint { :attribute => #{attribute} :operator => #{operator} }"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns a string for listing the constraint.
|
36
|
+
def to_pretty_s
|
37
|
+
info.join(':')
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# This class represents a Marathon Container information.
|
2
|
+
# It is included in App's definition.
|
3
|
+
# See https://mesosphere.github.io/marathon/docs/native-docker.html for full details.
|
4
|
+
class Marathon::Container < Marathon::Base
|
5
|
+
|
6
|
+
SUPPERTED_TYPES = %w[ DOCKER ]
|
7
|
+
ACCESSORS = %w[ type ]
|
8
|
+
DEFAULTS = {
|
9
|
+
:type => 'DOCKER',
|
10
|
+
:volumes => []
|
11
|
+
}
|
12
|
+
|
13
|
+
# Create a new container object.
|
14
|
+
# ++hash++: Hash returned by API.
|
15
|
+
def initialize(hash)
|
16
|
+
super(Marathon::Util.merge_keywordized_hash(DEFAULTS, hash), ACCESSORS)
|
17
|
+
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) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
"Marathon::Container { :type => #{type} :docker => #{Marathon::Util.items_to_pretty_s(docker)}"\
|
38
|
+
+ " :volumes => #{Marathon::Util.items_to_pretty_s(volumes)} }"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# This class represents a Marathon Container docker information.
|
2
|
+
# See https://mesosphere.github.io/marathon/docs/native-docker.html for full details.
|
3
|
+
class Marathon::ContainerDocker < Marathon::Base
|
4
|
+
|
5
|
+
ACCESSORS = %w[ image network ]
|
6
|
+
DEFAULTS = {
|
7
|
+
:network => 'BRIDGE',
|
8
|
+
:portMappings => []
|
9
|
+
}
|
10
|
+
|
11
|
+
# Create a new container docker object.
|
12
|
+
# ++hash++: Hash returned by API.
|
13
|
+
def initialize(hash)
|
14
|
+
super(Marathon::Util.merge_keywordized_hash(DEFAULTS, hash), ACCESSORS)
|
15
|
+
Marathon::Util.validate_choice('network', network, %w[BRIDGE HOST])
|
16
|
+
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) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_pretty_s
|
26
|
+
"#{image}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
"Marathon::ContainerDocker { :image => #{image} }"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# This class represents a Marathon Container docker information.
|
2
|
+
# See https://mesosphere.github.io/marathon/docs/native-docker.html for full details.
|
3
|
+
class Marathon::ContainerDockerPortMapping < Marathon::Base
|
4
|
+
|
5
|
+
ACCESSORS = %w[ containerPort hostPort servicePort protocol ]
|
6
|
+
DEFAULTS = {
|
7
|
+
:protocol => 'tcp',
|
8
|
+
:hostPort => 0
|
9
|
+
}
|
10
|
+
|
11
|
+
# Create a new container docker port mappint object.
|
12
|
+
# ++hash++: Hash returned by API.
|
13
|
+
def initialize(hash)
|
14
|
+
super(Marathon::Util.merge_keywordized_hash(DEFAULTS, hash), ACCESSORS)
|
15
|
+
Marathon::Util.validate_choice('protocol', protocol, %w[tcp udp])
|
16
|
+
raise Marathon::Error::ArgumentError, 'containerPort must not be nil' unless containerPort
|
17
|
+
raise Marathon::Error::ArgumentError, 'containerPort must be a positive number' \
|
18
|
+
unless containerPort.is_a?(Integer) and containerPort > 0
|
19
|
+
raise Marathon::Error::ArgumentError, 'hostPort must be a non negative number' \
|
20
|
+
unless hostPort.is_a?(Integer) and hostPort >= 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_pretty_s
|
24
|
+
"#{protocol}/#{containerPort}:#{hostPort}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"Marathon::ContainerDockerPortMapping { :protocol => #{protocol} " \
|
29
|
+
+ ":containerPort => #{containerPort} :hostPort => #{hostPort} }"
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# This class represents a Marathon Container Volume information.
|
2
|
+
# See https://mesosphere.github.io/marathon/docs/native-docker.html for full details.
|
3
|
+
class Marathon::ContainerVolume < Marathon::Base
|
4
|
+
|
5
|
+
ACCESSORS = %w[ containerPath hostPath mode ]
|
6
|
+
DEFAULTS = {
|
7
|
+
:mode => 'RW'
|
8
|
+
}
|
9
|
+
|
10
|
+
# Create a new container volume object.
|
11
|
+
# ++hash++: Hash returned by API.
|
12
|
+
def initialize(hash)
|
13
|
+
super(Marathon::Util.merge_keywordized_hash(DEFAULTS, hash), ACCESSORS)
|
14
|
+
Marathon::Util.validate_choice('mode', mode, %w[RW RO])
|
15
|
+
raise Marathon::Error::ArgumentError, 'containerPath must not be nil' unless containerPath
|
16
|
+
raise Marathon::Error::ArgumentError, 'containerPath must be an absolute path' \
|
17
|
+
unless Pathname.new(containerPath).absolute?
|
18
|
+
raise Marathon::Error::ArgumentError, 'hostPath must not be nil' unless hostPath
|
19
|
+
raise Marathon::Error::ArgumentError, 'hostPath must be an absolute path' \
|
20
|
+
unless Pathname.new(hostPath).absolute?
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_pretty_s
|
24
|
+
"#{containerPath}:#{hostPath}:#{mode}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"Marathon::ContainerVolume { :containerPath => #{containerPath} :hostPath => #{hostPath} :mode => #{mode} }"
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/lib/marathon/deployment.rb
CHANGED
@@ -1,19 +1,14 @@
|
|
1
1
|
# This class represents a Marathon Deployment.
|
2
2
|
# See https://mesosphere.github.io/marathon/docs/rest-api.html#deployments for full list of API's methods.
|
3
|
-
class Marathon::Deployment
|
3
|
+
class Marathon::Deployment < Marathon::Base
|
4
4
|
|
5
|
-
|
5
|
+
ACCESSORS = %w[ id affectedApps steps currentActions version currentStep totalSteps ]
|
6
6
|
|
7
7
|
# Create a new deployment object.
|
8
8
|
# ++hash++: Hash including all attributes.
|
9
9
|
# See https://mesosphere.github.io/marathon/docs/rest-api.html#get-/v2/deployments for full details.
|
10
|
-
def initialize(hash
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
# Shortcuts for reaching attributes
|
15
|
-
%w[ id affectedApps steps currentActions version currentStep totalSteps ].each do |method|
|
16
|
-
define_method(method) { |*args, &block| info[method] }
|
10
|
+
def initialize(hash)
|
11
|
+
super(hash, ACCESSORS)
|
17
12
|
end
|
18
13
|
|
19
14
|
# Cancel the deployment.
|
@@ -30,11 +25,6 @@ class Marathon::Deployment
|
|
30
25
|
+ ":id => #{id} :affectedApps => #{affectedApps} :currentStep => #{currentStep} :totalSteps => #{totalSteps} }"
|
31
26
|
end
|
32
27
|
|
33
|
-
# Return deployment as JSON formatted string.
|
34
|
-
def to_json
|
35
|
-
info.to_json
|
36
|
-
end
|
37
|
-
|
38
28
|
class << self
|
39
29
|
|
40
30
|
# List running deployments.
|
@@ -52,7 +42,7 @@ class Marathon::Deployment
|
|
52
42
|
query = {}
|
53
43
|
query[:force] = true if force
|
54
44
|
json = Marathon.connection.delete("/v2/deployments/#{id}")
|
55
|
-
|
45
|
+
Marathon::DeploymentInfo.new(json)
|
56
46
|
end
|
57
47
|
alias :cancel :delete
|
58
48
|
alias :remove :delete
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This class represents a Marathon Deployment information.
|
2
|
+
# It is returned by asynchronious deployment calls.
|
3
|
+
class Marathon::DeploymentInfo < Marathon::Base
|
4
|
+
|
5
|
+
# Create a new deployment info object.
|
6
|
+
# ++hash++: Hash returned by API, including 'deploymentId' and 'version'
|
7
|
+
def initialize(hash)
|
8
|
+
super(hash, %w[deploymentId version])
|
9
|
+
raise Marathon::Error::ArgumentError, 'version must not be nil' unless version
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
if deploymentId
|
14
|
+
"Marathon::DeploymentInfo { :version => #{version} :deploymentId => #{deploymentId} }"
|
15
|
+
else
|
16
|
+
"Marathon::DeploymentInfo { :version => #{version} }"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/lib/marathon/error.rb
CHANGED
@@ -7,7 +7,7 @@ module Marathon::Error
|
|
7
7
|
# Raised when invalid arguments are passed to a method.
|
8
8
|
class ArgumentError < MarathonError; end
|
9
9
|
|
10
|
-
# Raised when a request returns a 400.
|
10
|
+
# Raised when a request returns a 400 or 422.
|
11
11
|
class ClientError < MarathonError; end
|
12
12
|
|
13
13
|
# Raised when a request returns a 404.
|
@@ -39,6 +39,8 @@ module Marathon::Error
|
|
39
39
|
case response.code
|
40
40
|
when 400
|
41
41
|
ClientError
|
42
|
+
when 422
|
43
|
+
ClientError
|
42
44
|
when 404
|
43
45
|
NotFoundError
|
44
46
|
else
|
@@ -50,8 +52,12 @@ module Marathon::Error
|
|
50
52
|
# ++response++: HTTParty response object.
|
51
53
|
def error_message(response)
|
52
54
|
body = response.parsed_response
|
53
|
-
if body.is_a?(Hash)
|
55
|
+
if not body.is_a?(Hash)
|
56
|
+
body
|
57
|
+
elsif body['message']
|
54
58
|
body['message']
|
59
|
+
elsif body['errors']
|
60
|
+
body['errors']
|
55
61
|
else
|
56
62
|
body
|
57
63
|
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# This class represents a Marathon Group.
|
2
|
+
# See https://mesosphere.github.io/marathon/docs/rest-api.html#groups for full list of API's methods.
|
3
|
+
class Marathon::Group < Marathon::Base
|
4
|
+
|
5
|
+
ACCESSORS = %w[ id dependencies version ]
|
6
|
+
|
7
|
+
DEFAULTS = {
|
8
|
+
:apps => [],
|
9
|
+
:dependencies => [],
|
10
|
+
:groups => []
|
11
|
+
}
|
12
|
+
|
13
|
+
# Create a new group object.
|
14
|
+
# ++hash++: Hash including all attributes.
|
15
|
+
# See https://mesosphere.github.io/marathon/docs/rest-api.html#post-/v2/groups for full details.
|
16
|
+
def initialize(hash)
|
17
|
+
super(Marathon::Util.merge_keywordized_hash(DEFAULTS, hash), ACCESSORS)
|
18
|
+
raise ArgumentError, 'Group must have an id' unless id
|
19
|
+
raise ArgumentError, 'Group can have either groups or apps, not both' if apps.size > 0 and groups.size > 0
|
20
|
+
end
|
21
|
+
|
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
|
+
# Reload attributes from marathon API.
|
35
|
+
def refresh
|
36
|
+
new_app = self.class.get(id)
|
37
|
+
@info = new_app.info
|
38
|
+
end
|
39
|
+
|
40
|
+
# Create and start a the application group. Application groups can contain other application groups.
|
41
|
+
# An application group can either hold other groups or applications, but can not be mixed in one.
|
42
|
+
# Since the deployment of the group can take a considerable amount of time,
|
43
|
+
# this endpoint returns immediatly with a version. The failure or success of the action is signalled via event.
|
44
|
+
# There is a group_change_success and group_change_failed event with the given version.
|
45
|
+
def start!
|
46
|
+
self.class.start(info)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Change parameters of a deployed application group.
|
50
|
+
# Changes to application parameters will result in a restart of this application.
|
51
|
+
# A new application added to the group is started.
|
52
|
+
# An existing application removed from the group gets stopped.
|
53
|
+
# If there are no changes to the application definition, no restart is triggered.
|
54
|
+
# During restart marathon keeps track, that the configured amount of minimal running instances are always available.
|
55
|
+
# A deployment can run forever. This is the case, when the new application has a problem and does not become healthy.
|
56
|
+
# In this case, human interaction is needed with 2 possible choices:
|
57
|
+
# Rollback to an existing older version (send an existing version in the body)
|
58
|
+
# Update with a newer version of the group which does not have the problems of the old one.
|
59
|
+
# If there is an upgrade process already in progress, a new update will be rejected unless the force flag is set.
|
60
|
+
# With the force flag given, a running upgrade is terminated and a new one is started.
|
61
|
+
# Since the deployment of the group can take a considerable amount of time,
|
62
|
+
# this endpoint returns immediatly with a version. The failure or success of the action is signalled via event.
|
63
|
+
# There is a group_change_success and group_change_failed event with the given version.
|
64
|
+
# ++hash++: Hash of attributes to change.
|
65
|
+
# ++force++: If the group is affected by a running deployment, then the update operation will fail.
|
66
|
+
# The current deployment can be overridden by setting the `force` query parameter.
|
67
|
+
def change!(hash, force = false)
|
68
|
+
self.class.change(id, hash, force)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Create a new version with parameters of an old version.
|
72
|
+
# Currently running tasks are restarted, while maintaining the minimumHealthCapacity.
|
73
|
+
# ++version++: Version name of the old version.
|
74
|
+
# ++force++: If the group is affected by a running deployment, then the update operation will fail.
|
75
|
+
# The current deployment can be overridden by setting the `force` query parameter.
|
76
|
+
def roll_back!(version, force = false)
|
77
|
+
change!({'version' => version}, force)
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_s
|
81
|
+
"Marathon::Group { :id => #{id} }"
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns a string for listing the group.
|
85
|
+
def to_pretty_s
|
86
|
+
%Q[
|
87
|
+
Group ID: #{id}
|
88
|
+
#{pretty_array(apps)}
|
89
|
+
#{pretty_array(groups)}
|
90
|
+
Version: #{version}
|
91
|
+
].gsub(/\n\n+/, "\n").strip
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def pretty_array(array)
|
97
|
+
array.map { |e| e.to_pretty_s.split("\n").map { |e| " #{e}" }}.join("\n")
|
98
|
+
end
|
99
|
+
|
100
|
+
class << self
|
101
|
+
|
102
|
+
# List the group with the specified ID.
|
103
|
+
# ++id++: Group's id.
|
104
|
+
def get(id)
|
105
|
+
json = Marathon.connection.get("/v2/groups/#{id}")
|
106
|
+
new(json)
|
107
|
+
end
|
108
|
+
|
109
|
+
# List all groups.
|
110
|
+
def list
|
111
|
+
json = Marathon.connection.get('/v2/groups')
|
112
|
+
new(json)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Delete the application group with id.
|
116
|
+
# ++id++: Group's id.
|
117
|
+
# ++force++: If the group is affected by a running deployment, then the update operation will fail.
|
118
|
+
# The current deployment can be overridden by setting the `force` query parameter.
|
119
|
+
def delete(id, force = false)
|
120
|
+
query = {}
|
121
|
+
query[:force] = true if force
|
122
|
+
Marathon.connection.delete("/v2/groups/#{id}", query)
|
123
|
+
end
|
124
|
+
alias :remove :delete
|
125
|
+
|
126
|
+
# Create and start a new application group. Application groups can contain other application groups.
|
127
|
+
# An application group can either hold other groups or applications, but can not be mixed in one.
|
128
|
+
# Since the deployment of the group can take a considerable amount of time,
|
129
|
+
# this endpoint returns immediatly with a version. The failure or success of the action is signalled via event.
|
130
|
+
# There is a group_change_success and group_change_failed event with the given version.
|
131
|
+
# ++hash++: Hash including all attributes
|
132
|
+
# see https://mesosphere.github.io/marathon/docs/rest-api.html#post-/v2/groups for full details
|
133
|
+
def start(hash)
|
134
|
+
json = Marathon.connection.post('/v2/groups', nil, :body => hash)
|
135
|
+
Marathon::DeploymentInfo.new(json)
|
136
|
+
end
|
137
|
+
alias :create :start
|
138
|
+
|
139
|
+
# Change parameters of a deployed application group.
|
140
|
+
# Changes to application parameters will result in a restart of this application.
|
141
|
+
# A new application added to the group is started.
|
142
|
+
# An existing application removed from the group gets stopped.
|
143
|
+
# If there are no changes to the application definition, no restart is triggered.
|
144
|
+
# During restart marathon keeps track, that the configured amount of minimal running instances are always available.
|
145
|
+
# A deployment can run forever. This is the case,
|
146
|
+
# when the new application has a problem and does not become healthy.
|
147
|
+
# In this case, human interaction is needed with 2 possible choices:
|
148
|
+
# Rollback to an existing older version (send an existing version in the body)
|
149
|
+
# Update with a newer version of the group which does not have the problems of the old one.
|
150
|
+
# If there is an upgrade process already in progress, a new update will be rejected unless the force flag is set.
|
151
|
+
# With the force flag given, a running upgrade is terminated and a new one is started.
|
152
|
+
# Since the deployment of the group can take a considerable amount of time,
|
153
|
+
# this endpoint returns immediatly with a version. The failure or success of the action is signalled via event.
|
154
|
+
# There is a group_change_success and group_change_failed event with the given version.
|
155
|
+
# ++id++: Group's id.
|
156
|
+
# ++hash++: Hash of attributes to change.
|
157
|
+
# ++force++: If the group is affected by a running deployment, then the update operation will fail.
|
158
|
+
# The current deployment can be overridden by setting the `force` query parameter.
|
159
|
+
def change(id, hash, force = false)
|
160
|
+
query = {}
|
161
|
+
query[:force] = true if force
|
162
|
+
json = Marathon.connection.put("/v2/groups/#{id}", query, :body => hash)
|
163
|
+
Marathon::DeploymentInfo.new(json)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|