kitchen-marathon 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rubocop.yml +17 -0
- data/.ruby-version +1 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.md +31 -0
- data/Gemfile +3 -0
- data/LICENSE +15 -0
- data/README.md +196 -0
- data/Rakefile +21 -0
- data/kitchen-marathon.gemspec +30 -0
- data/lib/kitchen/driver/marathon.rb +250 -0
- data/lib/kitchen/driver/marathon_version.rb +41 -0
- metadata +169 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2aa0bbba85109d90f504e58435d2cd4684ad8524
|
4
|
+
data.tar.gz: 739815dcb6b7f1be5c5d2a131ea7f84f325584d9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e139a9ac30170290a4da0632805caae833d42bfd6ad6ff265595fc56b2058bb616a99dd6d202568680e1925c50ca287bd7d6f8f6ebae48feea29336cd486663a
|
7
|
+
data.tar.gz: fe948ef53cea04aa7ccdc852cc1fed57a1cae3fc3a4377bfbd70ea5973c6e08edce5ad26b445945c35b1a11842053b25a9f1058dc300a93a782534f0f92761d4
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.1.3
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Change Log
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
This project adheres to [Semantic Versioning](http://semver.org/).
|
4
|
+
|
5
|
+
## [Unreleased]
|
6
|
+
- Nothing at this time.
|
7
|
+
|
8
|
+
## [0.1.0]
|
9
|
+
### Notes
|
10
|
+
- Initial public release
|
11
|
+
|
12
|
+
## [0.0.3]
|
13
|
+
### Changes
|
14
|
+
- Make the assumption that if a single port mapping is available that it is the SSH port.
|
15
|
+
|
16
|
+
## [0.0.2]
|
17
|
+
### Changes
|
18
|
+
- Remove unnecessary ssh configuration params -- this is handled by the transport.
|
19
|
+
- Renamed the proxy configuration pieces to be reflecting of being tied to marathon host.
|
20
|
+
- Fixed an issue with the merging of the 3 configuration pieces with regards to symbols and deep merging sanity.
|
21
|
+
- Changed the default prefix to include the forward slash -- making it optional.
|
22
|
+
- Fixed an issue with how app_id was managed in state that allows for apps to not be cleaned up properly.
|
23
|
+
|
24
|
+
# 0.0.1
|
25
|
+
### Added
|
26
|
+
- Initial internal release
|
27
|
+
|
28
|
+
[Unreleased]: https://github.com/yieldbot/kitchen-marathon/compare/kitchen-marathon-0.1.0...HEAD
|
29
|
+
[0.1.0]: https://github.com/yieldbot/kitchen-master/compare/kitchen-marathon-0.0.3...kitchen-marathon-0.1.0
|
30
|
+
[0.0.3]: https://github.com/yieldbot/kitchen-master/compare/kitchen-marathon-0.0.2...kitchen-marathon-0.0.3
|
31
|
+
[0.0.2]: https://github.com/yieldbot/kitchen-master/compare/kitchen-marathon-0.0.1...kitchen-marathon-0.0.2
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Author:: Anthony Spring (<aspring@yieldbot.com>)
|
2
|
+
|
3
|
+
Copyright (C) 2016, Anthony Spring
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
# <a name="title"></a> Kitchen::Marathon
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/kitchen-marathon.svg)](http://badge.fury.io/rb/kitchen-marathon)
|
4
|
+
[![Build Status](https://travis-ci.org/yieldbot/kitchen-marathon.svg?branch=master)](https://travis-ci.org/yieldbot/kitchen-marathon)
|
5
|
+
|
6
|
+
A Test Kitchen Driver for Mesos Marathon.
|
7
|
+
|
8
|
+
This driver uses the [Marathon REST API][marathon_api] to create and destroy Marathon applications which act as Kitchen suites, allowing you to leverage the resources of a Mesos cluster to help reduce testing time.
|
9
|
+
|
10
|
+
## <a name="requirements"></a> Requirements
|
11
|
+
|
12
|
+
### Mesos/Marathon
|
13
|
+
|
14
|
+
To use this driver you will need access to a Mesos Marathon cluster. You will need to know the hostname and access credentials of the cluster for the plugin to access the REST API.
|
15
|
+
|
16
|
+
This cluster must be configured to run [Docker containers][marathon_docker].
|
17
|
+
|
18
|
+
### Marathon Job Configuration
|
19
|
+
|
20
|
+
This driver requires the following be true of the Marathon job configuration:
|
21
|
+
|
22
|
+
* You are running a Marathon container job of type "DOCKER".
|
23
|
+
* You can SSH into the container with a user specified username and private key.
|
24
|
+
|
25
|
+
This driver requires a slightly opinionated approach to Marathon Application configuration to assist in identifying what host port to use to acccess SSH running inside of a container.
|
26
|
+
|
27
|
+
If there is a single port mapping defined, the plugin will assume that this is where SSH is listening, if there is more than one port mapping defined, the plugin looks for a mapping label with the key of "SERVICE" and a value of "SSH".
|
28
|
+
|
29
|
+
The following is a slice of json showing the label:
|
30
|
+
|
31
|
+
```json
|
32
|
+
{
|
33
|
+
"container": {
|
34
|
+
"docker": {
|
35
|
+
"forcePullImage": true,
|
36
|
+
"image": "someimagenamehere:latest",
|
37
|
+
"network": "BRIDGE",
|
38
|
+
"portMappings": [
|
39
|
+
{
|
40
|
+
"containerPort": 22,
|
41
|
+
"hostPort": 0,
|
42
|
+
"labels": {
|
43
|
+
"SERVICE" : "ssh"
|
44
|
+
},
|
45
|
+
"protocol": "tcp"
|
46
|
+
},
|
47
|
+
],
|
48
|
+
},
|
49
|
+
"type": "DOCKER",
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
```
|
54
|
+
|
55
|
+
## Installation and Setup
|
56
|
+
|
57
|
+
Please read the Test Kitchen [docs][test_kitchen_docs] for more details.
|
58
|
+
|
59
|
+
Example `.kitchen.local.yml`:
|
60
|
+
|
61
|
+
```yaml
|
62
|
+
---
|
63
|
+
driver:
|
64
|
+
name: marathon
|
65
|
+
|
66
|
+
# Username and key used to access the container
|
67
|
+
transport:
|
68
|
+
ssh_key: '~/.ssh/vagrant'
|
69
|
+
username: kitchen
|
70
|
+
|
71
|
+
driver_config:
|
72
|
+
app_launch_timeout: 30
|
73
|
+
app_template: '.kitchen-marathon.json'
|
74
|
+
marathon_host: 'http://core-apps.mesos-marathon.service.consul:8080'
|
75
|
+
|
76
|
+
platforms:
|
77
|
+
- name: centos-7
|
78
|
+
driver_config:
|
79
|
+
app_config:
|
80
|
+
container:
|
81
|
+
docker:
|
82
|
+
image: jdeathe/centos-ssh:centos-7
|
83
|
+
run_list:
|
84
|
+
- recipe[yum]
|
85
|
+
```
|
86
|
+
|
87
|
+
## <a name="config"></a> Configuration
|
88
|
+
|
89
|
+
### <a name="config-app-prefix"></a> app\_prefix
|
90
|
+
|
91
|
+
This is the prefix applied to Marathon App names.
|
92
|
+
|
93
|
+
The default value is `kitchen/`.
|
94
|
+
|
95
|
+
### <a name="config-app-template"></a> app\_template
|
96
|
+
|
97
|
+
This allows for a Marathon Job template that will be used as the base template when the job template is created. If this value is not provided all configuration parameters need to be set via `app_config`.
|
98
|
+
|
99
|
+
The default value is `nil`.
|
100
|
+
|
101
|
+
### <a name="config-app-config"></a> app\_config
|
102
|
+
|
103
|
+
This allows for Marathon Job configuration to be configured at the platform/suite/etc level as necessary.
|
104
|
+
|
105
|
+
This configuration is merged on top of any configuration provided by `app_template`.
|
106
|
+
|
107
|
+
The default value is `{}`.
|
108
|
+
|
109
|
+
### <a name="config-app-launch-timeout"></a> app\_launch\_timeout
|
110
|
+
|
111
|
+
Determines the timeout, in seconds, that the driver will wait for a Marathon App to deploy. If the timeout is reached, the driver will assume that the deployment will not succeed and will attempt to stop the deployment and delete the Marathon App. (This cleanup is best effort.)
|
112
|
+
|
113
|
+
The default value is `30` seconds.
|
114
|
+
|
115
|
+
### <a name="config-marathon-host"></a> marathon\_host
|
116
|
+
|
117
|
+
The web address to the Marathon host.
|
118
|
+
|
119
|
+
The default value is `http://localhost:8080`.
|
120
|
+
|
121
|
+
### <a name="config-marathon-password"></a> marathon\_password
|
122
|
+
|
123
|
+
The password to use for an HTTP AUTH protected Marathon Host
|
124
|
+
|
125
|
+
The default value is `nil`.
|
126
|
+
|
127
|
+
### <a name="config-marathon-username"></a> marathon\_username
|
128
|
+
|
129
|
+
The username to use for an HTTP AUTH protected Marathon Host
|
130
|
+
|
131
|
+
The default value is `nil`.
|
132
|
+
|
133
|
+
### <a name="config-marathon-verify-ssl"></a> marathon\_verify\_ssl
|
134
|
+
|
135
|
+
Whether or not a certificate presented by the Marathon Host is verified.
|
136
|
+
|
137
|
+
The default value is `true`.
|
138
|
+
|
139
|
+
## Marathon Proxy Configuration
|
140
|
+
|
141
|
+
### <a name="config-marathon-proxy-address"></a> marathon\_proxy\_address
|
142
|
+
|
143
|
+
Provides the option to specify a proxy address if necessary when connecting to the Marathon host.
|
144
|
+
|
145
|
+
The default value is `nil`.
|
146
|
+
|
147
|
+
### <a name="config-marathon-proxy-password"></a> marathon\_proxy\_password
|
148
|
+
|
149
|
+
Provides the option to specify a proxy passowrd if necessary when connecting to the Marathon host.
|
150
|
+
|
151
|
+
The default value is `nil`.
|
152
|
+
|
153
|
+
### <a name="config-marathon-proxy-port"></a> marathon\_proxy\_port
|
154
|
+
|
155
|
+
Provides the option to specify a proxy port if necessary when connecting to the Marathon host.
|
156
|
+
|
157
|
+
The default value is `nil`.
|
158
|
+
|
159
|
+
### <a name="config-marathon-proxy-username"></a> marathon\_proxy\_username
|
160
|
+
|
161
|
+
Provides the option to specify a proxy username if necessary when connecting to the Marathon host.
|
162
|
+
|
163
|
+
The default value is `nil`.
|
164
|
+
|
165
|
+
## Development
|
166
|
+
|
167
|
+
* Source hosted at [GitHub][repo]
|
168
|
+
* Report issues/questions/feature requests on [GitHub Issues][issues]
|
169
|
+
|
170
|
+
Pull requests are very welcome! Make sure your patches are well tested.
|
171
|
+
Ideally create a topic branch for every separate change you make. For
|
172
|
+
example:
|
173
|
+
|
174
|
+
1. Fork the repo
|
175
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
176
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
177
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
178
|
+
5. Create new Pull Request
|
179
|
+
|
180
|
+
## Authors
|
181
|
+
|
182
|
+
Created and maintained by [Anthony Spring][author] (<aspring@yieldbot.com>)
|
183
|
+
|
184
|
+
## License
|
185
|
+
|
186
|
+
Apache 2.0 (see [LICENSE][license])
|
187
|
+
|
188
|
+
[author]: https://github.com/yieldbot
|
189
|
+
[issues]: https://github.com/yieldbot/kitchen-marathon/issues
|
190
|
+
[license]: https://github.com/yieldbot/kitchen-marathon/blob/master/LICENSE
|
191
|
+
[marathon]: https://mesosphere.github.io/marathon/
|
192
|
+
[marathon_api]: https://github.com/otto-de/marathon-api
|
193
|
+
[marathon_docker]: https://mesosphere.github.io/marathon/docs/native-docker.html
|
194
|
+
[repo]: https://github.com/yieldbot/kitchen-marathon
|
195
|
+
[test_kitchen_docs]: http://kitchen.ci/docs/getting-started/
|
196
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rake'
|
4
|
+
require 'rspec/core'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
require 'rubocop/rake_task'
|
7
|
+
|
8
|
+
RuboCop::RakeTask.new(:rubocop) do |t|
|
9
|
+
# Specify the files we will look at
|
10
|
+
t.patterns = [File.join('{lib}', '**', '*.rb'), 'Rakefile', '*.gemspec']
|
11
|
+
|
12
|
+
# Do not fail on error
|
13
|
+
t.fail_on_error = false
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Run RSpec code examples'
|
17
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
18
|
+
t.pattern = FileList['spec/**/*_spec.rb']
|
19
|
+
end
|
20
|
+
|
21
|
+
task default: [:spec]
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'kitchen/driver/marathon_version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'kitchen-marathon'
|
8
|
+
spec.version = Kitchen::Driver::Version::STRING.dup
|
9
|
+
spec.authors = ['Anthony Spring']
|
10
|
+
spec.email = ['aspring@yieldbot.com']
|
11
|
+
spec.description = %q{A Test Kitchen Driver for Marathon}
|
12
|
+
spec.summary = spec.description
|
13
|
+
spec.homepage = 'http://github.com/yieldbot/kitchen-marathon'
|
14
|
+
spec.license = 'Apache 2.0'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.executables = []
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'deep_merge', '= 1.0.1'
|
22
|
+
spec.add_dependency 'marathon-api', '~> 1.3.2'
|
23
|
+
spec.add_dependency 'retryable', '>= 1.3.3'
|
24
|
+
spec.add_dependency 'test-kitchen', '~> 1.6'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler'
|
27
|
+
spec.add_development_dependency 'rake'
|
28
|
+
spec.add_development_dependency 'rspec'
|
29
|
+
spec.add_development_dependency 'rubocop'
|
30
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Anthony Spring (<aspring@yieldbot.com>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2016, Anthony Spring
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require 'deep_merge'
|
20
|
+
require 'json'
|
21
|
+
require 'kitchen'
|
22
|
+
require 'marathon'
|
23
|
+
require 'net/ssh'
|
24
|
+
require 'retryable'
|
25
|
+
|
26
|
+
module Kitchen
|
27
|
+
module Driver
|
28
|
+
# Marathon driver for Kitchen.
|
29
|
+
#
|
30
|
+
# @author Anthony Spring <aspring@yieldbot.com>
|
31
|
+
class Marathon < Kitchen::Driver::SSHBase # rubocop:disable Metrics/ClassLength
|
32
|
+
# Marathon Application Configuration
|
33
|
+
|
34
|
+
default_config :app_prefix, 'kitchen/'
|
35
|
+
default_config :app_template, nil
|
36
|
+
expand_path_for :app_template
|
37
|
+
|
38
|
+
default_config :app_config, {}
|
39
|
+
|
40
|
+
default_config :app_launch_timeout, 30
|
41
|
+
|
42
|
+
# Marathon HTTP Configuration
|
43
|
+
|
44
|
+
default_config :marathon_host, 'http://localhost:8080'
|
45
|
+
default_config :marathon_password, nil
|
46
|
+
default_config :marathon_username, nil
|
47
|
+
default_config :marathon_verify_ssl, true
|
48
|
+
|
49
|
+
# Marathon Proxy Configuration
|
50
|
+
|
51
|
+
default_config :marathon_proxy_address, nil
|
52
|
+
default_config :marathon_proxy_port, nil
|
53
|
+
default_config :marathon_proxy_password, nil
|
54
|
+
default_config :marathon_proxy_username, nil
|
55
|
+
|
56
|
+
default_config(:instance_name) do |driver|
|
57
|
+
driver.windows_os? ? nil : driver.instance.name
|
58
|
+
end
|
59
|
+
|
60
|
+
# Creates a new Driver object using the provided configuration data
|
61
|
+
# which will be merged with any default configuration.
|
62
|
+
#
|
63
|
+
# @param config [Hash] provided driver configuration
|
64
|
+
def initialize(config = {})
|
65
|
+
# Let our parent do its work
|
66
|
+
super(config)
|
67
|
+
|
68
|
+
# Initialize marathon
|
69
|
+
initialize_marathon
|
70
|
+
end
|
71
|
+
|
72
|
+
def create(state)
|
73
|
+
return if state[:app_id]
|
74
|
+
|
75
|
+
# Generate the application configuration
|
76
|
+
app_config = generate_app_config
|
77
|
+
|
78
|
+
# Create the app
|
79
|
+
state[:app_id] = create_app(app_config)
|
80
|
+
|
81
|
+
# Wait for the apps deployment to finish
|
82
|
+
wait_for_app_deployment(app_config)
|
83
|
+
|
84
|
+
# Update state
|
85
|
+
update_app_state(state)
|
86
|
+
end
|
87
|
+
|
88
|
+
def converge(state)
|
89
|
+
# Update the app state
|
90
|
+
update_app_state(state)
|
91
|
+
|
92
|
+
super(state)
|
93
|
+
end
|
94
|
+
|
95
|
+
def destroy(state)
|
96
|
+
return if state[:app_id].nil?
|
97
|
+
|
98
|
+
destroy_app(state[:app_id])
|
99
|
+
|
100
|
+
state.delete(:app_id)
|
101
|
+
end
|
102
|
+
|
103
|
+
def setup(state)
|
104
|
+
# Update the app state
|
105
|
+
update_app_state(state)
|
106
|
+
|
107
|
+
super(state)
|
108
|
+
end
|
109
|
+
|
110
|
+
def verify(state)
|
111
|
+
# Update the app state
|
112
|
+
update_app_state(state)
|
113
|
+
|
114
|
+
super(state)
|
115
|
+
end
|
116
|
+
|
117
|
+
protected
|
118
|
+
|
119
|
+
def create_app(app_config)
|
120
|
+
Retryable.retryable(
|
121
|
+
tries: 10,
|
122
|
+
sleep: ->(n) { [2**n, 30].min },
|
123
|
+
on: [::Marathon::Error::TimeoutError]
|
124
|
+
) do |_r, _|
|
125
|
+
info("Creating the application: #{app_config['id']}")
|
126
|
+
|
127
|
+
# Create the application
|
128
|
+
::Marathon::App.create(app_config)
|
129
|
+
end
|
130
|
+
|
131
|
+
app_config['id']
|
132
|
+
end
|
133
|
+
|
134
|
+
def create_app_id # rubocop:disable Metrics/LineLength
|
135
|
+
# Need to remove any underscores from the app name
|
136
|
+
"#{config[:app_prefix]}#{config[:instance_name]}-#{SecureRandom.hex}".tr('_', '-')
|
137
|
+
end
|
138
|
+
|
139
|
+
def destroy_app(app_id)
|
140
|
+
::Marathon::App.delete(app_id)
|
141
|
+
rescue ::Marathon::Error::NotFoundError
|
142
|
+
info("App (#{app_id}) not found.")
|
143
|
+
end
|
144
|
+
|
145
|
+
def generate_app_config # rubocop:disable Metrics/MethodLength
|
146
|
+
# Generate the necessary config
|
147
|
+
necessary_config = {}
|
148
|
+
necessary_config['id'] = create_app_id
|
149
|
+
necessary_config['instances'] = 1
|
150
|
+
|
151
|
+
# Bring in the user defined JSON template
|
152
|
+
user_config = if File.file?(config[:app_template])
|
153
|
+
JSON.parse(IO.read(config[:app_template]))
|
154
|
+
else
|
155
|
+
{}
|
156
|
+
end
|
157
|
+
|
158
|
+
# Convert the app config into non-symbolized names
|
159
|
+
app_config = JSON.parse(config[:app_config].to_json, symbolize_names: false)
|
160
|
+
|
161
|
+
# Overlay the app config
|
162
|
+
user_config.deep_merge!(app_config)
|
163
|
+
|
164
|
+
# Overlay the necessary config
|
165
|
+
user_config.deep_merge!(necessary_config)
|
166
|
+
|
167
|
+
# Return the derived configuration
|
168
|
+
user_config
|
169
|
+
end
|
170
|
+
|
171
|
+
def initialize_marathon
|
172
|
+
# Initialize Marathon based off of configuration data
|
173
|
+
marathon = {}
|
174
|
+
|
175
|
+
# Basic HTTP Information
|
176
|
+
marathon[:username] = config[:marathon_username]
|
177
|
+
marathon[:password] = config[:marathon_password]
|
178
|
+
|
179
|
+
# Basic SSL information
|
180
|
+
marathon[:verify] = config[:marathon_verify_ssl]
|
181
|
+
|
182
|
+
# Basic Proxy information
|
183
|
+
marathon[:http_proxyaddr] = config[:marathon_proxy_address]
|
184
|
+
marathon[:http_proxyport] = config[:marathon_proxy_port]
|
185
|
+
marathon[:http_proxyuser] = config[:marathon_proxy_username]
|
186
|
+
marathon[:http_proxypass] = config[:marathon_proxy_password]
|
187
|
+
|
188
|
+
# Set the Marathon credentials if given
|
189
|
+
::Marathon.options = marathon
|
190
|
+
|
191
|
+
# Set the Marathon URL
|
192
|
+
::Marathon.url = config[:marathon_host]
|
193
|
+
end
|
194
|
+
|
195
|
+
def update_app_state(state) # rubocop:disable Metrics/MethodLength, Metrics/LineLength
|
196
|
+
info('Refreshing host and port from Marathon...')
|
197
|
+
|
198
|
+
app = nil
|
199
|
+
|
200
|
+
# Get the host and port to SSH on
|
201
|
+
Retryable.retryable(
|
202
|
+
tries: 10,
|
203
|
+
sleep: ->(n) { [2**n, 30].min },
|
204
|
+
on: [::Marathon::Error::TimeoutError]
|
205
|
+
) do |_r, _|
|
206
|
+
# Get the app
|
207
|
+
app = ::Marathon::App.get(state[:app_id])
|
208
|
+
end
|
209
|
+
|
210
|
+
# Get the host
|
211
|
+
state[:hostname] = app.info[:tasks][0][:host]
|
212
|
+
|
213
|
+
# Get the mappings
|
214
|
+
mappings = app.info[:container][:docker][:portMappings]
|
215
|
+
|
216
|
+
# Get the index
|
217
|
+
ssh_index = case mappings.length
|
218
|
+
when 1
|
219
|
+
info("Single port mapping found! Defaulting to that port.")
|
220
|
+
|
221
|
+
# If there is a single mapping assume it is the SSH service port
|
222
|
+
0
|
223
|
+
else
|
224
|
+
info("Multiple port mappings found! Looking for label 'SERVICE' => 'ssh'...")
|
225
|
+
|
226
|
+
# Attempt to find the index via labels
|
227
|
+
mappings.find_index(mappings.find { |mapping| mapping[:labels][:SERVICE] == 'ssh' })
|
228
|
+
end
|
229
|
+
|
230
|
+
info("Unable to determine SSH port index from mappings!") if ssh_index.nil?
|
231
|
+
|
232
|
+
state[:port] = ssh_index.nil? ? 0 : app.info[:tasks][0][:ports][ssh_index]
|
233
|
+
end
|
234
|
+
|
235
|
+
def wait_for_app_deployment(app_config) # rubocop:disable Metrics/LineLength
|
236
|
+
Retryable.retryable(
|
237
|
+
tries: 10,
|
238
|
+
sleep: ->(n) { [2**n, config[:app_launch_timeout]].min },
|
239
|
+
on: [::Marathon::Error::TimeoutError, ::Timeout::Error]
|
240
|
+
) do |_r, _|
|
241
|
+
info("Waiting for application to deploy: #{app_config['id']}")
|
242
|
+
|
243
|
+
raise(::Timeout::Error.new, 'App is not running.') if ::Marathon::App.get(app_config['id']).info[:tasksRunning] == 0
|
244
|
+
|
245
|
+
info("Application #{app_config['id']} is running.")
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Anthony Spring (<aspring@yieldbot.com>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2016, Anthony Spring
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require 'json'
|
20
|
+
|
21
|
+
module Kitchen
|
22
|
+
module Driver
|
23
|
+
# This defines the version of the gem
|
24
|
+
module Version
|
25
|
+
MAJOR = 0
|
26
|
+
MINOR = 1
|
27
|
+
PATCH = 0
|
28
|
+
BUILD = ''.freeze
|
29
|
+
|
30
|
+
STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.').chomp('.')
|
31
|
+
|
32
|
+
module_function
|
33
|
+
|
34
|
+
def json_version
|
35
|
+
{
|
36
|
+
'version' => STRING
|
37
|
+
}.to_json
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kitchen-marathon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anthony Spring
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: deep_merge
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: marathon-api
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.3.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.3.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: retryable
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.3.3
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.3.3
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: test-kitchen
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.6'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.6'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: A Test Kitchen Driver for Marathon
|
126
|
+
email:
|
127
|
+
- aspring@yieldbot.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".gitignore"
|
133
|
+
- ".rubocop.yml"
|
134
|
+
- ".ruby-version"
|
135
|
+
- ".travis.yml"
|
136
|
+
- CHANGELOG.md
|
137
|
+
- Gemfile
|
138
|
+
- LICENSE
|
139
|
+
- README.md
|
140
|
+
- Rakefile
|
141
|
+
- kitchen-marathon.gemspec
|
142
|
+
- lib/kitchen/driver/marathon.rb
|
143
|
+
- lib/kitchen/driver/marathon_version.rb
|
144
|
+
homepage: http://github.com/yieldbot/kitchen-marathon
|
145
|
+
licenses:
|
146
|
+
- Apache 2.0
|
147
|
+
metadata: {}
|
148
|
+
post_install_message:
|
149
|
+
rdoc_options: []
|
150
|
+
require_paths:
|
151
|
+
- lib
|
152
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
requirements: []
|
163
|
+
rubyforge_project:
|
164
|
+
rubygems_version: 2.2.2
|
165
|
+
signing_key:
|
166
|
+
specification_version: 4
|
167
|
+
summary: A Test Kitchen Driver for Marathon
|
168
|
+
test_files: []
|
169
|
+
has_rdoc:
|