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.
- 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
|