continuum-stager-api 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +22 -0
- data/.travis.yml +15 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +37 -0
- data/Rakefile +7 -0
- data/apcera-stager-api-contrib.gemspec +25 -0
- data/lib/apcera/stager/error.rb +6 -0
- data/lib/apcera/stager/loader.rb +10 -0
- data/lib/apcera/stager/stager.rb +270 -0
- data/lib/continuum-stager-api.rb +1 -0
- data/spec/apcera/stager/stager_spec.rb +496 -0
- data/spec/fixtures/cassettes/complete.yml +55 -0
- data/spec/fixtures/cassettes/dependencies_add.yml +53 -0
- data/spec/fixtures/cassettes/dependencies_remove.yml +53 -0
- data/spec/fixtures/cassettes/done.yml +28 -0
- data/spec/fixtures/cassettes/download.yml +37400 -0
- data/spec/fixtures/cassettes/environment_add.yml +53 -0
- data/spec/fixtures/cassettes/environment_remove.yml +53 -0
- data/spec/fixtures/cassettes/fail.yml +28 -0
- data/spec/fixtures/cassettes/invalid/complete.yml +55 -0
- data/spec/fixtures/cassettes/invalid/dependencies_add.yml +53 -0
- data/spec/fixtures/cassettes/invalid/dependencies_remove.yml +53 -0
- data/spec/fixtures/cassettes/invalid/done.yml +55 -0
- data/spec/fixtures/cassettes/invalid/download.yml +54 -0
- data/spec/fixtures/cassettes/invalid/environment_add.yml +53 -0
- data/spec/fixtures/cassettes/invalid/environment_remove.yml +53 -0
- data/spec/fixtures/cassettes/invalid/fail.yml +28 -0
- data/spec/fixtures/cassettes/invalid/metadata.yml +28 -0
- data/spec/fixtures/cassettes/invalid/provides_add.yml +53 -0
- data/spec/fixtures/cassettes/invalid/provides_remove.yml +53 -0
- data/spec/fixtures/cassettes/invalid/relaunch.yml +53 -0
- data/spec/fixtures/cassettes/invalid/snapshot.yml +53 -0
- data/spec/fixtures/cassettes/invalid/templates_add.yml +53 -0
- data/spec/fixtures/cassettes/invalid/templates_remove.yml +53 -0
- data/spec/fixtures/cassettes/invalid/upload.yml +55 -0
- data/spec/fixtures/cassettes/metadata.yml +51 -0
- data/spec/fixtures/cassettes/provides_add.yml +53 -0
- data/spec/fixtures/cassettes/provides_remove.yml +116 -0
- data/spec/fixtures/cassettes/relaunch.yml +28 -0
- data/spec/fixtures/cassettes/snapshot.yml +28 -0
- data/spec/fixtures/cassettes/templates_add.yml +53 -0
- data/spec/fixtures/cassettes/templates_remove.yml +53 -0
- data/spec/fixtures/cassettes/upload.yml +30 -0
- data/spec/spec_helper.rb +31 -0
- metadata +189 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MWRiOTA4YWU1ZGNlZDA4YzI4MTMwMjRmYjA2ZjlmYTZiYjMxOTZlMg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZDE3NWEwODI5MGIyNjMyODcyYTNmNDU4NjZmNmI5ZmM4NWY2ODkzOA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MjUwY2Q0YzVkYzc4MTYxYTVmMTMwNGUxYzIxNGIzMzZiZjQ4MzVmM2JmMjAw
|
10
|
+
ODFhNTJmOTE2Yzc4YmMzNjMyMGRmOTUzZjlkYTY2NjIxYWVlZjJiOWIxZjRk
|
11
|
+
ZGRlODlmZDJmZDVmOTU0YjlhZmQ3ODU4YzQwZDlhMWQzYjUzNzM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MjQwMzdkODU0YzI3NGQxNTIwMzgxZmRmYWM5NzcyMDY2Mjk4ZTk1MDNkODgx
|
14
|
+
OGM0MjBlYzI5Y2NlYzdkZTA5ZTI5NmM0ODNkODczMTVmNjVkM2RmYWU2OGYy
|
15
|
+
ZWUwMjk0NTI2OTZjY2VhZjVkOTExMWQ2OTc5NGU2MjUwYzUwOGU=
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
.ruby-gemset
|
7
|
+
.ruby-version
|
8
|
+
.rvmrc
|
9
|
+
Gemfile.lock
|
10
|
+
InstalledFiles
|
11
|
+
_yardoc
|
12
|
+
coverage
|
13
|
+
doc/
|
14
|
+
lib/bundler/man
|
15
|
+
pkg
|
16
|
+
rdoc
|
17
|
+
spec/reports
|
18
|
+
test/tmp
|
19
|
+
test/version_tmp
|
20
|
+
tmp
|
21
|
+
.powenv
|
22
|
+
.idea/
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Apcera
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# continuum-stager-api
|
2
|
+
|
3
|
+
Simple gem to assist users writing custom Continuum Stagers.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add to your `Gemfile`:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem "continuum-stager-api"
|
11
|
+
```
|
12
|
+
|
13
|
+
Then `bundle install`.
|
14
|
+
|
15
|
+
## License
|
16
|
+
|
17
|
+
The MIT License (MIT)
|
18
|
+
|
19
|
+
Copyright (c) 2014 Apcera
|
20
|
+
|
21
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
22
|
+
of this software and associated documentation files (the "Software"), to deal
|
23
|
+
in the Software without restriction, including without limitation the rights
|
24
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
25
|
+
copies of the Software, and to permit persons to whom the Software is
|
26
|
+
furnished to do so, subject to the following conditions:
|
27
|
+
|
28
|
+
The above copyright notice and this permission notice shall be included in all
|
29
|
+
copies or substantial portions of the Software.
|
30
|
+
|
31
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
32
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
33
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
34
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
35
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
36
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
37
|
+
SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
Gem::Specification.new do |gem|
|
3
|
+
gem.add_dependency "rest-client"
|
4
|
+
gem.add_dependency 'json'
|
5
|
+
|
6
|
+
gem.authors = ["Josh Ellithorpe"]
|
7
|
+
gem.email = ["josh@apcera.com"]
|
8
|
+
gem.description = %q{Continuum Stager api library}
|
9
|
+
gem.summary = %q{Continuum Stager api library which makes it super easy to write stagers for Apcera's Continuum.}
|
10
|
+
gem.homepage = "http://apcera.com"
|
11
|
+
gem.license = "MIT"
|
12
|
+
|
13
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
|
+
gem.files = `git ls-files`.split("\n")
|
15
|
+
gem.test_files = `git ls-files -- {spec}/*`.split("\n")
|
16
|
+
gem.name = "continuum-stager-api"
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
gem.version = "0.1.0"
|
19
|
+
|
20
|
+
gem.add_development_dependency 'rspec', '~> 2.6.0'
|
21
|
+
gem.add_development_dependency 'rake'
|
22
|
+
gem.add_development_dependency 'webmock', '1.11'
|
23
|
+
gem.add_development_dependency 'simplecov'
|
24
|
+
gem.add_development_dependency 'vcr'
|
25
|
+
end
|
@@ -0,0 +1,270 @@
|
|
1
|
+
module Apcera
|
2
|
+
class Stager
|
3
|
+
attr_accessor :stager_url, :app_path, :root_path, :pkg_path, :updated_pkg_path, :system_options
|
4
|
+
|
5
|
+
PKG_NAME = "pkg.tar.gz"
|
6
|
+
UPDATED_PKG_NAME = "updated.tar.gz"
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
# Require stager url. Needed to talk to the Staging Coordinator.
|
10
|
+
@stager_url = options[:stager_url] || ENV["STAGER_URL"]
|
11
|
+
raise Apcera::Error::StagerURLRequired.new("stager_url required") unless @stager_url
|
12
|
+
|
13
|
+
# Setup the environment, some test items here.
|
14
|
+
setup_environment
|
15
|
+
end
|
16
|
+
|
17
|
+
# Download a package from the staging coordinator.
|
18
|
+
def download
|
19
|
+
response = RestClient.get(@stager_url + "/data")
|
20
|
+
File.open(@pkg_path, "wb") do |f|
|
21
|
+
f.write(response.to_str)
|
22
|
+
end
|
23
|
+
rescue => e
|
24
|
+
fail e
|
25
|
+
end
|
26
|
+
|
27
|
+
# Execute a command in the shell.
|
28
|
+
# We don't want real commands in tests.
|
29
|
+
def execute(cmd)
|
30
|
+
Bundler.with_clean_env do
|
31
|
+
result = system(cmd, @system_options)
|
32
|
+
if !result
|
33
|
+
raise Apcera::Error::ExecuteError.new("failed to execute: #{cmd}.\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
result
|
37
|
+
end
|
38
|
+
rescue => e
|
39
|
+
fail e
|
40
|
+
end
|
41
|
+
|
42
|
+
# Execute a command in the app dir. Useful helper.
|
43
|
+
def execute_app(cmd)
|
44
|
+
Bundler.with_clean_env do
|
45
|
+
Dir.chdir(@app_path) do |app_path|
|
46
|
+
result = system(cmd, @system_options)
|
47
|
+
if !result
|
48
|
+
raise Apcera::Error::ExecuteError.new("failed to execute: #{cmd}.\n")
|
49
|
+
end
|
50
|
+
|
51
|
+
result
|
52
|
+
end
|
53
|
+
end
|
54
|
+
rescue => e
|
55
|
+
fail e
|
56
|
+
end
|
57
|
+
|
58
|
+
# Extract the package to a given location.
|
59
|
+
def extract(location)
|
60
|
+
@app_path = File.join(@root_path, location)
|
61
|
+
Dir.mkdir(@app_path) unless Dir.exists?(@app_path)
|
62
|
+
|
63
|
+
execute_app("tar -zxf #{@pkg_path}")
|
64
|
+
rescue => e
|
65
|
+
fail e
|
66
|
+
end
|
67
|
+
|
68
|
+
# Upload the new package to the staging coordinator
|
69
|
+
def upload
|
70
|
+
execute_app("tar czf #{@updated_pkg_path} .")
|
71
|
+
|
72
|
+
sha1 = Digest::SHA1.file(@updated_pkg_path)
|
73
|
+
File.open(@updated_pkg_path, "rb") do |f|
|
74
|
+
response = RestClient.post(@stager_url+"/data?sha1=#{sha1.to_s}", f.read, { :content_type => "application/octet-stream" } )
|
75
|
+
end
|
76
|
+
rescue => e
|
77
|
+
fail e
|
78
|
+
end
|
79
|
+
|
80
|
+
# Snapshot the stager filesystem for app
|
81
|
+
def snapshot
|
82
|
+
response = RestClient.post(@stager_url+"/snapshot", {})
|
83
|
+
rescue => e
|
84
|
+
fail e
|
85
|
+
end
|
86
|
+
|
87
|
+
# Add environment variable to package.
|
88
|
+
def environment_add(key, value)
|
89
|
+
response = RestClient.post(@stager_url+"/meta", {
|
90
|
+
:resource => "environment",
|
91
|
+
:action => "add",
|
92
|
+
:key => key,
|
93
|
+
:value => value
|
94
|
+
})
|
95
|
+
rescue => e
|
96
|
+
fail e
|
97
|
+
end
|
98
|
+
|
99
|
+
# Delete environment variable from package.
|
100
|
+
def environment_remove(key, value)
|
101
|
+
response = RestClient.post(@stager_url+"/meta", {
|
102
|
+
:resource => "environment",
|
103
|
+
:action => "remove",
|
104
|
+
:key => key,
|
105
|
+
:value => value
|
106
|
+
})
|
107
|
+
rescue => e
|
108
|
+
fail e
|
109
|
+
end
|
110
|
+
|
111
|
+
# Add provides to package.
|
112
|
+
def provides_add(type, name)
|
113
|
+
response = RestClient.post(@stager_url+"/meta", {
|
114
|
+
:resource => "provides",
|
115
|
+
:action => "add",
|
116
|
+
:type => type,
|
117
|
+
:name => name
|
118
|
+
})
|
119
|
+
rescue => e
|
120
|
+
fail e
|
121
|
+
end
|
122
|
+
|
123
|
+
# Delete provides from package.
|
124
|
+
def provides_remove(key, value)
|
125
|
+
response = RestClient.post(@stager_url+"/meta", {
|
126
|
+
:resource => "provides",
|
127
|
+
:action => "remove",
|
128
|
+
:type => type,
|
129
|
+
:name => name
|
130
|
+
})
|
131
|
+
rescue => e
|
132
|
+
fail e
|
133
|
+
end
|
134
|
+
|
135
|
+
# Add dependencies to package.
|
136
|
+
def dependencies_add(type, name)
|
137
|
+
response = RestClient.post(@stager_url+"/meta", {
|
138
|
+
:resource => "dependencies",
|
139
|
+
:action => "add",
|
140
|
+
:type => type,
|
141
|
+
:name => name
|
142
|
+
})
|
143
|
+
rescue => e
|
144
|
+
fail e
|
145
|
+
end
|
146
|
+
|
147
|
+
# Delete dependencies from package.
|
148
|
+
def dependencies_remove(type, name)
|
149
|
+
response = RestClient.post(@stager_url+"/meta", {
|
150
|
+
:resource => "dependencies",
|
151
|
+
:action => "remove",
|
152
|
+
:type => type,
|
153
|
+
:name => name
|
154
|
+
})
|
155
|
+
rescue => e
|
156
|
+
fail e
|
157
|
+
end
|
158
|
+
|
159
|
+
# Add template to package.
|
160
|
+
def templates_add(path, left_delimiter = "{{", right_delimiter = "}}")
|
161
|
+
response = RestClient.post(@stager_url+"/meta", {
|
162
|
+
:resource => "templates",
|
163
|
+
:action => "add",
|
164
|
+
:path => path,
|
165
|
+
:left_delimiter => left_delimiter,
|
166
|
+
:right_delimiter => right_delimiter
|
167
|
+
})
|
168
|
+
rescue => e
|
169
|
+
fail e
|
170
|
+
end
|
171
|
+
|
172
|
+
# Delete template from package.
|
173
|
+
def templates_remove(path, left_delimiter = "{{", right_delimiter = "}}")
|
174
|
+
response = RestClient.post(@stager_url+"/meta", {
|
175
|
+
:resource => "templates",
|
176
|
+
:action => "remove",
|
177
|
+
:path => path,
|
178
|
+
:left_delimiter => left_delimiter,
|
179
|
+
:right_delimiter => right_delimiter
|
180
|
+
})
|
181
|
+
rescue => e
|
182
|
+
fail e
|
183
|
+
end
|
184
|
+
|
185
|
+
# Get metadata for the package being staged.
|
186
|
+
def meta
|
187
|
+
response = RestClient.get(@stager_url+"/meta")
|
188
|
+
return JSON.parse(response.to_s)
|
189
|
+
rescue => e
|
190
|
+
output_error "Error: #{e.message}.\n"
|
191
|
+
raise e
|
192
|
+
end
|
193
|
+
|
194
|
+
# Tell the staging coordinator you are done.
|
195
|
+
def done
|
196
|
+
response = RestClient.post(@stager_url+"/done", {})
|
197
|
+
exit0r 0
|
198
|
+
rescue => e
|
199
|
+
fail e
|
200
|
+
end
|
201
|
+
|
202
|
+
# Tell the staging coordinator you need to relaunch.
|
203
|
+
def relaunch
|
204
|
+
response = RestClient.post(@stager_url+"/relaunch", {})
|
205
|
+
exit0r 0
|
206
|
+
rescue => e
|
207
|
+
fail e
|
208
|
+
end
|
209
|
+
|
210
|
+
# Finish staging, compress your app dir and send to the staging coordinator.
|
211
|
+
# Then tell the staging coordinator we are done.
|
212
|
+
def complete
|
213
|
+
upload
|
214
|
+
done
|
215
|
+
end
|
216
|
+
|
217
|
+
# Returns the start command for the package.
|
218
|
+
def start_command
|
219
|
+
self.meta["environment"]["START_COMMAND"]
|
220
|
+
end
|
221
|
+
|
222
|
+
# Easily set the start command
|
223
|
+
def start_command=(val)
|
224
|
+
self.environment_add("START_COMMAND", val)
|
225
|
+
end
|
226
|
+
|
227
|
+
# Returns the start path for the package.
|
228
|
+
def start_path
|
229
|
+
self.meta["environment"]["START_PATH"]
|
230
|
+
end
|
231
|
+
|
232
|
+
# Easily set the start path
|
233
|
+
def start_path=(val)
|
234
|
+
self.environment_add("START_PATH", val)
|
235
|
+
end
|
236
|
+
|
237
|
+
# Fail the stager, something went wrong.
|
238
|
+
def fail(error = nil)
|
239
|
+
output_error "Error: #{error.message}.\n" if error
|
240
|
+
RestClient.post(@stager_url+"/failed", {})
|
241
|
+
rescue => e
|
242
|
+
output_error "Error: #{e.message}.\n"
|
243
|
+
ensure
|
244
|
+
exit0r 1
|
245
|
+
end
|
246
|
+
|
247
|
+
# Exit, needed for tests to not quit.
|
248
|
+
def exit0r(code)
|
249
|
+
exit code
|
250
|
+
end
|
251
|
+
|
252
|
+
private
|
253
|
+
|
254
|
+
def output_error(text)
|
255
|
+
$stderr.puts text
|
256
|
+
end
|
257
|
+
|
258
|
+
def output(text)
|
259
|
+
$stdout.puts text
|
260
|
+
end
|
261
|
+
|
262
|
+
def setup_environment
|
263
|
+
# When staging we use the root path. These are overridden in tests.
|
264
|
+
@root_path = "/"
|
265
|
+
@pkg_path = File.join(@root_path, PKG_NAME)
|
266
|
+
@updated_pkg_path = File.join(@root_path, UPDATED_PKG_NAME)
|
267
|
+
@system_options = {}
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|