ubalo 0.1 → 0.2
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.
- data/bin/ubalo +131 -215
- data/lib/ubalo/account.rb +93 -0
- data/lib/ubalo/pod.rb +99 -0
- data/lib/ubalo/pod_archive.rb +54 -0
- data/lib/ubalo/pod_dir.rb +81 -0
- data/lib/ubalo/task.rb +87 -0
- data/lib/ubalo/util.rb +189 -0
- data/lib/ubalo/version.rb +2 -2
- data/lib/ubalo.rb +9 -321
- metadata +24 -13
data/lib/ubalo.rb
CHANGED
@@ -4,326 +4,14 @@ require 'rest-client'
|
|
4
4
|
require 'json'
|
5
5
|
require 'pp'
|
6
6
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
else
|
17
|
-
""
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class UbaloOKExit < StandardError
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
class UbaloMessage < StandardError
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
class Ubalo
|
30
|
-
class UbaloJSON
|
31
|
-
def self.content_type
|
32
|
-
"application/json; schema=ubalo-data"
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.dump(obj)
|
36
|
-
JSON.dump('data' => obj)
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.load(data)
|
40
|
-
JSON.load(data)['data']
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class PodError < StandardError
|
45
|
-
end
|
46
|
-
|
47
|
-
class << self
|
48
|
-
def make_tgz file_list, tgz_name
|
49
|
-
tgz = Zlib::GzipWriter.new(File.open(tgz_name, 'wb'))
|
50
|
-
Minitar.pack(file_list, tgz)
|
51
|
-
tgz_name
|
52
|
-
end
|
53
|
-
|
54
|
-
def extract_tgz destination_dir, tgz_name
|
55
|
-
Dir.chdir(destination_dir) do
|
56
|
-
tgz = Zlib::GzipReader.new(File.open(tgz_name, 'rb'))
|
57
|
-
Minitar.unpack(tgz, '.')
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def print_content name, content
|
62
|
-
data = content.fetch('data')
|
63
|
-
content_type = content.fetch('content_type')
|
64
|
-
if content_type == UbaloJSON.content_type
|
65
|
-
s = UbaloJSON.load(data).pretty_inspect.strip
|
66
|
-
if s.include?("\n")
|
67
|
-
puts "#{name}:"
|
68
|
-
puts s
|
69
|
-
else
|
70
|
-
puts "#{name}: #{s}"
|
71
|
-
end
|
72
|
-
else
|
73
|
-
puts "#{name}: (#{content_type})"
|
74
|
-
puts indent(data)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def format_task task
|
79
|
-
"#{task['label']} (#{task['state']}) - #{task['pod_name']} (#{time_ago_in_words task['submitted_at']})"
|
80
|
-
end
|
81
|
-
|
82
|
-
def format_pod pod
|
83
|
-
"#{pod.fetch('fullname')} (updated #{time_ago_in_words pod.fetch('updated_at')})"
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
def pluralize count, word
|
88
|
-
if count == 1
|
89
|
-
"#{count} #{word}"
|
90
|
-
else
|
91
|
-
"#{count} #{word}s"
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def time_ago_in_words time
|
96
|
-
seconds = Time.now - Time.parse(time)
|
97
|
-
case
|
98
|
-
when seconds < 60
|
99
|
-
"#{pluralize(seconds.floor, "second")} ago"
|
100
|
-
when seconds/60 < 60
|
101
|
-
"#{pluralize((seconds/60).floor, "minute")} ago"
|
102
|
-
when seconds/60/60 < 24
|
103
|
-
"#{pluralize((seconds/60/60).floor, "hour")} ago"
|
104
|
-
else
|
105
|
-
"#{pluralize((seconds/60/60/24).floor, "day")} ago"
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
attr_reader :base_url
|
111
|
-
attr_accessor :authorization
|
112
|
-
|
113
|
-
def self.login authorization, base_url
|
114
|
-
new(authorization, base_url)
|
115
|
-
end
|
116
|
-
|
117
|
-
def initialize authorization, base_url
|
118
|
-
@authorization = authorization
|
119
|
-
@base_url = base_url
|
120
|
-
end
|
121
|
-
|
122
|
-
def raw_request(method, url, params)
|
123
|
-
resource = RestClient::Resource.new url, timeout: 60
|
124
|
-
if method == :get
|
125
|
-
resource.get add_headers(:params => params, :accept => :json)
|
126
|
-
elsif method == :post
|
127
|
-
resource.post params, add_headers(:accept => :json)
|
128
|
-
elsif method == :put
|
129
|
-
resource.put params, add_headers(:accept => :json)
|
130
|
-
elsif method == :delete
|
131
|
-
resource.delete add_headers(:accept => :json)
|
132
|
-
else
|
133
|
-
raise "don't understand request method #{method.inspect}"
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def request(method, url, params)
|
138
|
-
parse(raw_request(method, url, params))
|
139
|
-
end
|
140
|
-
|
141
|
-
def post(url, params={})
|
142
|
-
request(:post, url, params)
|
143
|
-
end
|
144
|
-
|
145
|
-
def get(url, params={})
|
146
|
-
request(:get, url, params)
|
147
|
-
end
|
148
|
-
|
149
|
-
def put(url, params={})
|
150
|
-
raw_request(:put, url, params)
|
151
|
-
end
|
152
|
-
|
153
|
-
def delete(url)
|
154
|
-
raw_request(:delete, url, {})
|
155
|
-
end
|
156
|
-
|
157
|
-
def whoami
|
158
|
-
response = get("#{base_url}/user")
|
159
|
-
"You are logged in as #{response['username'].inspect}."
|
160
|
-
end
|
161
|
-
|
162
|
-
def tasks count
|
163
|
-
get("#{base_url}/tasks", :count => count)
|
164
|
-
end
|
165
|
-
|
166
|
-
def submit_task pod_name, arg
|
167
|
-
params = {
|
168
|
-
:arg_content_type => UbaloJSON.content_type,
|
169
|
-
:arg => UbaloJSON.dump(arg)
|
170
|
-
}
|
171
|
-
post("#{base_url}/pods/#{pod_name}/tasks", params)
|
172
|
-
end
|
173
|
-
|
174
|
-
def poll_on(message)
|
175
|
-
600.times do
|
176
|
-
if result = yield
|
177
|
-
$stderr.puts " done."
|
178
|
-
return result
|
179
|
-
end
|
180
|
-
$stderr.print '.'
|
181
|
-
$stderr.flush
|
182
|
-
sleep 0.5
|
183
|
-
end
|
184
|
-
|
185
|
-
$stderr.puts
|
186
|
-
raise "timed-out polling on #{message}"
|
187
|
-
end
|
188
|
-
|
189
|
-
def wait_task(label)
|
190
|
-
poll_on("task #{label}") do
|
191
|
-
task = check_task(label)
|
192
|
-
task if task['state'] == 'exited'
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def clone(pod_name)
|
197
|
-
get("#{base_url}/pods/#{pod_name}")
|
198
|
-
rescue RestClient::ResourceNotFound
|
199
|
-
raise UbaloMessage, "could not find #{pod_name}"
|
200
|
-
end
|
201
|
-
|
202
|
-
def pods
|
203
|
-
get("#{base_url}/pods")
|
204
|
-
end
|
205
|
-
|
206
|
-
def show_result(result)
|
207
|
-
puts " label: #{result['label']}"
|
208
|
-
puts " pod: #{result['pod_name']}"
|
209
|
-
if arg = result['arg']
|
210
|
-
Ubalo.print_content(' arg', arg)
|
211
|
-
end
|
212
|
-
|
213
|
-
puts " state: #{result['state']}"
|
214
|
-
|
215
|
-
if container_process = result['container_process']
|
216
|
-
puts "status: #{container_process['exit_result']}"
|
217
|
-
|
218
|
-
if stdout = container_process['stdout'] and stdout.length > 0
|
219
|
-
puts "stdout:"
|
220
|
-
puts indent(stdout)
|
221
|
-
end
|
222
|
-
|
223
|
-
if stderr = container_process['stderr'] and stderr.length > 0
|
224
|
-
puts "stderr:"
|
225
|
-
puts indent(stderr)
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
if outputs = result['outputs']
|
230
|
-
Ubalo.print_content('output', outputs)
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def get_authorization login, password
|
235
|
-
post("#{base_url}/user/authorization", :user => {:login => login, :password => password})
|
236
|
-
end
|
237
|
-
|
238
|
-
def create_or_update pod_url, params={}
|
239
|
-
put(pod_url, :pod => params)
|
240
|
-
end
|
241
|
-
|
242
|
-
def check_task label
|
243
|
-
get("#{base_url}/tasks/#{label}")
|
244
|
-
end
|
245
|
-
|
246
|
-
def upload_tgz pod_url, tgz_name
|
247
|
-
# Create the new archive in rails.
|
248
|
-
response = post("#{pod_url}/archives")
|
249
|
-
label = response.fetch('label')
|
250
|
-
put_url = response.fetch('put_url')
|
251
|
-
archive_location = response.fetch('url')
|
252
|
-
|
253
|
-
print "Uploading files... "
|
254
|
-
RestClient.put put_url, File.open(tgz_name, 'rb'), content_type: 'application/x-tar', content_encoding: 'x-gzip'
|
255
|
-
put("#{archive_location}/activate")
|
256
|
-
|
257
|
-
puts "done."
|
258
|
-
end
|
259
|
-
|
260
|
-
def push_files(pod_url)
|
261
|
-
ignore_filename = ".ubaloignore"
|
262
|
-
if File.exist?(ignore_filename)
|
263
|
-
ignore_patterns = File.read(ignore_filename).each_line.map(&:strip)
|
264
|
-
else
|
265
|
-
ignore_patterns = []
|
266
|
-
end
|
267
|
-
|
268
|
-
ignore_patterns += %w{. .. .ubalo}
|
269
|
-
|
270
|
-
filenames = []
|
271
|
-
Dir.glob('{.**,**}').each do |path|
|
272
|
-
next if ignore_patterns.any?{|pattern| File.fnmatch?(pattern, path, File::FNM_DOTMATCH)}
|
273
|
-
|
274
|
-
filenames << path
|
275
|
-
end
|
276
|
-
|
277
|
-
if filenames.empty?
|
278
|
-
raise UbaloMessage, "You do not have files to push. Cancelling!"
|
279
|
-
end
|
280
|
-
|
281
|
-
Dir.mktmpdir do |dir|
|
282
|
-
tar_path = File.join(dir, "files.tar.gz")
|
283
|
-
Ubalo.make_tgz(filenames, tar_path)
|
284
|
-
upload_tgz(pod_url, tar_path)
|
285
|
-
end
|
286
|
-
|
287
|
-
print "Waiting on pod compilation.."
|
288
|
-
poll_on("compilation of pod at #{pod_url}") do
|
289
|
-
pod = get(pod_url)
|
290
|
-
pod if pod['state'] == 'compiled'
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
def retrieve_files(destination_path, files_url)
|
295
|
-
Dir.mktmpdir do |dir|
|
296
|
-
tar_path = File.join(dir, "files.tar.gz")
|
297
|
-
RestClient.get(files_url) do |response|
|
298
|
-
if response.code == 200
|
299
|
-
File.open(tar_path, "wb") do |f|
|
300
|
-
f.write response
|
301
|
-
end
|
302
|
-
Ubalo.extract_tgz(destination_path, tar_path)
|
303
|
-
else
|
304
|
-
raise UbaloMessage, "failed to download pod files"
|
305
|
-
end
|
306
|
-
end
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
def delete_pod pod_name
|
311
|
-
delete("#{base_url}/pods/#{pod_name}")
|
312
|
-
end
|
313
|
-
|
314
|
-
private
|
315
|
-
|
316
|
-
def add_headers headers
|
317
|
-
# Add authorization headers.
|
318
|
-
if authorization
|
319
|
-
headers.merge!(:authorization => authorization)
|
320
|
-
end
|
321
|
-
|
322
|
-
# Add version header.
|
323
|
-
headers.merge!('X-Ubalo-Version' => Ubalo::VERSION)
|
324
|
-
end
|
325
|
-
|
326
|
-
def parse(result)
|
327
|
-
JSON.load(result)
|
7
|
+
require "ubalo/util"
|
8
|
+
require "ubalo/account"
|
9
|
+
require "ubalo/pod"
|
10
|
+
require "ubalo/pod_archive"
|
11
|
+
require "ubalo/task"
|
12
|
+
require "ubalo/pod_dir"
|
13
|
+
|
14
|
+
module Ubalo
|
15
|
+
class Error < StandardError
|
328
16
|
end
|
329
17
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ubalo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.2'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-03
|
12
|
+
date: 2012-04-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gli
|
16
|
-
requirement: &
|
16
|
+
requirement: &70111153539360 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70111153539360
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: highline
|
27
|
-
requirement: &
|
27
|
+
requirement: &70111153538720 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70111153538720
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: json
|
38
|
-
requirement: &
|
38
|
+
requirement: &70111153538200 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70111153538200
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rest-client
|
49
|
-
requirement: &
|
49
|
+
requirement: &70111153537640 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.6.3
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70111153537640
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: archive-tar-minitar
|
60
|
-
requirement: &
|
60
|
+
requirement: &70111153536860 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70111153536860
|
69
69
|
description: CLI and API client for Ubalo
|
70
70
|
email: dev@ubalo.com
|
71
71
|
executables:
|
@@ -73,6 +73,12 @@ executables:
|
|
73
73
|
extensions: []
|
74
74
|
extra_rdoc_files: []
|
75
75
|
files:
|
76
|
+
- lib/ubalo/account.rb
|
77
|
+
- lib/ubalo/pod.rb
|
78
|
+
- lib/ubalo/pod_archive.rb
|
79
|
+
- lib/ubalo/pod_dir.rb
|
80
|
+
- lib/ubalo/task.rb
|
81
|
+
- lib/ubalo/util.rb
|
76
82
|
- lib/ubalo/version.rb
|
77
83
|
- lib/ubalo.rb
|
78
84
|
- bin/ubalo
|
@@ -88,12 +94,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
88
94
|
- - ! '>='
|
89
95
|
- !ruby/object:Gem::Version
|
90
96
|
version: '0'
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
hash: -3363828113033122894
|
91
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
101
|
none: false
|
93
102
|
requirements:
|
94
103
|
- - ! '>='
|
95
104
|
- !ruby/object:Gem::Version
|
96
105
|
version: '0'
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
hash: -3363828113033122894
|
97
109
|
requirements: []
|
98
110
|
rubyforge_project:
|
99
111
|
rubygems_version: 1.8.11
|
@@ -101,4 +113,3 @@ signing_key:
|
|
101
113
|
specification_version: 3
|
102
114
|
summary: CLI and API client for Ubalo
|
103
115
|
test_files: []
|
104
|
-
has_rdoc:
|