nimbu 0.4 → 0.5.1
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/lib/nimbu.rb +3 -19
- data/lib/nimbu/auth.rb +106 -95
- data/lib/nimbu/cli.rb +20 -3
- data/lib/nimbu/command.rb +138 -68
- data/lib/nimbu/command/auth.rb +21 -3
- data/lib/nimbu/command/base.rb +38 -75
- data/lib/nimbu/command/browse.rb +63 -0
- data/lib/nimbu/command/help.rb +1 -1
- data/lib/nimbu/command/helpers.rb +6 -4
- data/lib/nimbu/command/init.rb +5 -6
- data/lib/nimbu/command/server.rb +119 -55
- data/lib/nimbu/command/sites.rb +32 -0
- data/lib/nimbu/command/themes.rb +29 -52
- data/lib/nimbu/helpers.rb +268 -89
- data/lib/nimbu/server/base.rb +56 -41
- data/lib/nimbu/ssh.rb +54 -0
- data/lib/nimbu/version.rb +1 -1
- metadata +128 -42
- data/lib/nimbu/client.rb +0 -289
- data/lib/nimbu/client/rendezvous.rb +0 -76
- data/lib/nimbu/server/views/index.haml +0 -1
data/lib/nimbu/client.rb
DELETED
@@ -1,289 +0,0 @@
|
|
1
|
-
require 'rexml/document'
|
2
|
-
require 'rest_client'
|
3
|
-
require 'uri'
|
4
|
-
require 'time'
|
5
|
-
require 'nimbu/auth'
|
6
|
-
require 'nimbu/helpers'
|
7
|
-
require 'nimbu/version'
|
8
|
-
|
9
|
-
# A Ruby class to call the Nimbu REST API. You might use this if you want to
|
10
|
-
# manage your Nimbu apps from within a Ruby program, such as Capistrano.
|
11
|
-
#
|
12
|
-
# Example:
|
13
|
-
#
|
14
|
-
# require 'nimbu'
|
15
|
-
# nimbu = Nimbu::Client.new('me@example.com', 'mypass')
|
16
|
-
# nimbu.create('myapp')
|
17
|
-
#
|
18
|
-
class Nimbu::Client
|
19
|
-
|
20
|
-
include Nimbu::Helpers
|
21
|
-
extend Nimbu::Helpers
|
22
|
-
|
23
|
-
def self.version
|
24
|
-
Nimbu::VERSION
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.gem_version_string
|
28
|
-
"nimbu-gem/#{version}"
|
29
|
-
end
|
30
|
-
|
31
|
-
attr_accessor :host, :user, :password
|
32
|
-
|
33
|
-
def self.auth(user, password, host=Nimbu::Auth.host)
|
34
|
-
client = new(user, password, host)
|
35
|
-
json_decode client.post('/login', { :user => {:email => user, :password => password }}, :accept => 'json').to_s
|
36
|
-
end
|
37
|
-
|
38
|
-
def initialize(user, password, host=Nimbu::Auth.host)
|
39
|
-
@user = user
|
40
|
-
@password = password
|
41
|
-
@host = host
|
42
|
-
end
|
43
|
-
|
44
|
-
# Show a list of sites
|
45
|
-
def list
|
46
|
-
doc = xml(get('/sites').to_s)
|
47
|
-
doc.elements.to_a("//sites/site").map do |a|
|
48
|
-
name = a.elements.to_a("name").first
|
49
|
-
owner = a.elements.to_a("domain").first
|
50
|
-
[name.text, owner.text]
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# Show info such as mode, custom domain, and collaborators on an app.
|
55
|
-
def info(name_or_domain)
|
56
|
-
raise ArgumentError.new("name_or_domain is required for info") unless name_or_domain
|
57
|
-
name_or_domain = name_or_domain.gsub(/^(http:\/\/)?(www\.)?/, '')
|
58
|
-
doc = xml(get("/apps/#{name_or_domain}").to_s)
|
59
|
-
attrs = hash_from_xml_doc(doc)[:app]
|
60
|
-
attrs.merge!(:collaborators => list_collaborators(attrs[:name]))
|
61
|
-
attrs.merge!(:addons => installed_addons(attrs[:name]))
|
62
|
-
end
|
63
|
-
|
64
|
-
def on_warning(&blk)
|
65
|
-
@warning_callback = blk
|
66
|
-
end
|
67
|
-
|
68
|
-
def get_template(params)
|
69
|
-
post("/engine/template",params)
|
70
|
-
end
|
71
|
-
|
72
|
-
def get_request(params)
|
73
|
-
post("/engine/render",params)
|
74
|
-
end
|
75
|
-
|
76
|
-
def post_request(params)
|
77
|
-
post("/engine/process",params)
|
78
|
-
end
|
79
|
-
|
80
|
-
def list_themes
|
81
|
-
get("/themes")
|
82
|
-
end
|
83
|
-
|
84
|
-
def show_theme_contents(theme)
|
85
|
-
get("/themes/#{theme}/list")
|
86
|
-
end
|
87
|
-
|
88
|
-
def fetch_theme_layout(theme,id)
|
89
|
-
get("/themes/#{theme}/layouts/#{id}")
|
90
|
-
end
|
91
|
-
|
92
|
-
def fetch_theme_template(theme,id)
|
93
|
-
get("/themes/#{theme}/templates/#{id}")
|
94
|
-
end
|
95
|
-
|
96
|
-
def fetch_theme_assets(theme,id)
|
97
|
-
get("/themes/#{theme}/assets/#{id}")
|
98
|
-
end
|
99
|
-
|
100
|
-
def upload_layout(theme,name,content)
|
101
|
-
post("/themes/#{theme}/layouts", {:name => name, :content => content})
|
102
|
-
end
|
103
|
-
|
104
|
-
def upload_template(theme,name,content)
|
105
|
-
post("/themes/#{theme}/templates", {:name => name, :content => content})
|
106
|
-
end
|
107
|
-
|
108
|
-
def upload_snippet(theme,name,content)
|
109
|
-
post("/themes/#{theme}/snippets", {:name => name, :content => content})
|
110
|
-
end
|
111
|
-
|
112
|
-
def upload_asset(theme,name,file)
|
113
|
-
post("/themes/#{theme}/assets", {:name => name, :file => file})
|
114
|
-
end
|
115
|
-
|
116
|
-
##################
|
117
|
-
|
118
|
-
def resource(uri, options={})
|
119
|
-
if http_proxy
|
120
|
-
RestClient.proxy = http_proxy
|
121
|
-
end
|
122
|
-
resource = RestClient::Resource.new(realize_full_uri(uri), options)
|
123
|
-
resource
|
124
|
-
end
|
125
|
-
|
126
|
-
def get(uri, extra_headers={}) # :nodoc:
|
127
|
-
process(:get, uri, extra_headers)
|
128
|
-
end
|
129
|
-
|
130
|
-
def post(uri, payload="", extra_headers={}) # :nodoc:
|
131
|
-
process(:post, uri, extra_headers, payload)
|
132
|
-
end
|
133
|
-
|
134
|
-
def put(uri, payload, extra_headers={}) # :nodoc:
|
135
|
-
process(:put, uri, extra_headers, payload)
|
136
|
-
end
|
137
|
-
|
138
|
-
def delete(uri, extra_headers={}) # :nodoc:
|
139
|
-
process(:delete, uri, extra_headers)
|
140
|
-
end
|
141
|
-
|
142
|
-
def process(method, uri, extra_headers={}, payload=nil)
|
143
|
-
headers = nimbu_headers.merge(extra_headers)
|
144
|
-
args = [method, payload, headers].compact
|
145
|
-
|
146
|
-
resource_options = default_resource_options_for_uri(uri)
|
147
|
-
|
148
|
-
begin
|
149
|
-
response = resource(uri, resource_options).send(*args)
|
150
|
-
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, SocketError
|
151
|
-
host = URI.parse(realize_full_uri(uri)).host
|
152
|
-
error "Unable to connect to #{host}"
|
153
|
-
rescue RestClient::SSLCertificateNotVerified => ex
|
154
|
-
host = URI.parse(realize_full_uri(uri)).host
|
155
|
-
error "WARNING: Unable to verify SSL certificate for #{host}\nTo disable SSL verification, run with HEROKU_SSL_VERIFY=disable"
|
156
|
-
end
|
157
|
-
|
158
|
-
extract_warning(response)
|
159
|
-
response
|
160
|
-
end
|
161
|
-
|
162
|
-
def extract_warning(response)
|
163
|
-
return unless response
|
164
|
-
if response.headers[:x_nimbu_warning] && @warning_callback
|
165
|
-
warning = response.headers[:x_nimbu_warning]
|
166
|
-
@displayed_warnings ||= {}
|
167
|
-
unless @displayed_warnings[warning]
|
168
|
-
@warning_callback.call(warning)
|
169
|
-
@displayed_warnings[warning] = true
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
def nimbu_headers # :nodoc:
|
175
|
-
{
|
176
|
-
'X-Nimbu-API-Version' => '1',
|
177
|
-
'X-Nimbu-Token' => password,
|
178
|
-
'User-Agent' => self.class.gem_version_string,
|
179
|
-
'X-Ruby-Version' => RUBY_VERSION,
|
180
|
-
'X-Ruby-Platform' => RUBY_PLATFORM
|
181
|
-
}
|
182
|
-
end
|
183
|
-
|
184
|
-
def xml(raw) # :nodoc:
|
185
|
-
REXML::Document.new(raw)
|
186
|
-
end
|
187
|
-
|
188
|
-
def escape(value) # :nodoc:
|
189
|
-
escaped = URI.escape(value.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
190
|
-
escaped.gsub('.', '%2E') # not covered by the previous URI.escape
|
191
|
-
end
|
192
|
-
|
193
|
-
module JSON
|
194
|
-
def self.parse(json)
|
195
|
-
json_decode(json)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
private
|
200
|
-
|
201
|
-
def configure_addon(action, app_name, addon, config = {})
|
202
|
-
response = update_addon action,
|
203
|
-
addon_path(app_name, addon),
|
204
|
-
config
|
205
|
-
|
206
|
-
json_decode(response.to_s) unless response.to_s.empty?
|
207
|
-
end
|
208
|
-
|
209
|
-
def addon_path(app_name, addon)
|
210
|
-
"/apps/#{app_name}/addons/#{escape(addon)}"
|
211
|
-
end
|
212
|
-
|
213
|
-
def update_addon(action, path, config)
|
214
|
-
params = { :config => config }
|
215
|
-
app = params[:config].delete(:confirm)
|
216
|
-
headers = { :accept => 'application/json' }
|
217
|
-
params.merge!(:confirm => app) if app
|
218
|
-
|
219
|
-
case action
|
220
|
-
when :install
|
221
|
-
post path, params, headers
|
222
|
-
when :upgrade
|
223
|
-
put path, params, headers
|
224
|
-
when :uninstall
|
225
|
-
confirm = app ? "confirm=#{app}" : ''
|
226
|
-
delete "#{path}?#{confirm}", headers
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
def realize_full_uri(given)
|
231
|
-
full_host = (host =~ /^http/) ? host : "http://#{host}"
|
232
|
-
host = URI.parse(full_host)
|
233
|
-
uri = URI.parse(given)
|
234
|
-
uri.host ||= host.host
|
235
|
-
uri.scheme ||= host.scheme || "http"
|
236
|
-
uri.path = "/api/v2" + ((uri.path[0..0] == "/") ? uri.path : "/#{uri.path}")
|
237
|
-
uri.port = host.port if full_host =~ /\:\d+/
|
238
|
-
uri.to_s
|
239
|
-
end
|
240
|
-
|
241
|
-
def default_resource_options_for_uri(uri)
|
242
|
-
if ENV["HEROKU_SSL_VERIFY"] == "disable"
|
243
|
-
{}
|
244
|
-
elsif realize_full_uri(uri) =~ %r|^https://api.getnimbu.com|
|
245
|
-
{ :verify_ssl => OpenSSL::SSL::VERIFY_PEER, :ssl_ca_file => local_ca_file }
|
246
|
-
else
|
247
|
-
{}
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
def local_ca_file
|
252
|
-
File.expand_path("../../../data/cacert.pem", __FILE__)
|
253
|
-
end
|
254
|
-
|
255
|
-
def hash_from_xml_doc(elements)
|
256
|
-
elements.inject({}) do |hash, e|
|
257
|
-
next(hash) unless e.respond_to?(:children)
|
258
|
-
hash.update(e.name.gsub("-","_").to_sym => case e.children.length
|
259
|
-
when 0 then nil
|
260
|
-
when 1 then e.text
|
261
|
-
else hash_from_xml_doc(e.children)
|
262
|
-
end)
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
def http_proxy
|
267
|
-
proxy = ENV['HTTP_PROXY'] || ENV['http_proxy']
|
268
|
-
if proxy && !proxy.empty?
|
269
|
-
unless /^[^:]+:\/\// =~ proxy
|
270
|
-
proxy = "http://" + proxy
|
271
|
-
end
|
272
|
-
proxy
|
273
|
-
else
|
274
|
-
nil
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
def https_proxy
|
279
|
-
proxy = ENV['HTTPS_PROXY'] || ENV['https_proxy']
|
280
|
-
if proxy && !proxy.empty?
|
281
|
-
unless /^[^:]+:\/\// =~ proxy
|
282
|
-
proxy = "https://" + proxy
|
283
|
-
end
|
284
|
-
proxy
|
285
|
-
else
|
286
|
-
nil
|
287
|
-
end
|
288
|
-
end
|
289
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
require "timeout"
|
2
|
-
require "socket"
|
3
|
-
require "uri"
|
4
|
-
require "nimbu/client"
|
5
|
-
require "nimbu/helpers"
|
6
|
-
|
7
|
-
class Nimbu::Client::Rendezvous
|
8
|
-
attr_reader :rendezvous_url, :connect_timeout, :activity_timeout, :input, :output, :on_connect
|
9
|
-
|
10
|
-
def initialize(opts)
|
11
|
-
@rendezvous_url = opts[:rendezvous_url]
|
12
|
-
@connect_timeout = opts[:connect_timeout]
|
13
|
-
@activity_timeout = opts[:activity_timeout]
|
14
|
-
@input = opts[:input]
|
15
|
-
@output = opts[:output]
|
16
|
-
end
|
17
|
-
|
18
|
-
def on_connect(&blk)
|
19
|
-
@on_connect = blk if block_given?
|
20
|
-
@on_connect
|
21
|
-
end
|
22
|
-
|
23
|
-
def start
|
24
|
-
uri = URI.parse(rendezvous_url)
|
25
|
-
host, port, secret = uri.host, uri.port, uri.path[1..-1]
|
26
|
-
|
27
|
-
ssl_socket = Timeout.timeout(connect_timeout) do
|
28
|
-
ssl_context = OpenSSL::SSL::SSLContext.new
|
29
|
-
if ((host =~ /nimbu\.com$/) && !(ENV["HEROKU_SSL_VERIFY"] == "disable"))
|
30
|
-
ssl_context.ca_file = File.expand_path("../../../../data/cacert.pem", __FILE__)
|
31
|
-
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
32
|
-
end
|
33
|
-
tcp_socket = TCPSocket.open(host, port)
|
34
|
-
ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, ssl_context)
|
35
|
-
ssl_socket.connect
|
36
|
-
ssl_socket.puts(secret)
|
37
|
-
ssl_socket.readline
|
38
|
-
ssl_socket
|
39
|
-
end
|
40
|
-
|
41
|
-
on_connect.call if on_connect
|
42
|
-
|
43
|
-
readables = [input, ssl_socket].compact
|
44
|
-
|
45
|
-
begin
|
46
|
-
loop do
|
47
|
-
if o = IO.select(readables, nil, nil, activity_timeout)
|
48
|
-
if (input && (o.first.first == input))
|
49
|
-
begin
|
50
|
-
data = input.readpartial(10000)
|
51
|
-
rescue EOFError
|
52
|
-
readables.delete(input)
|
53
|
-
next
|
54
|
-
end
|
55
|
-
ssl_socket.write(data)
|
56
|
-
ssl_socket.flush
|
57
|
-
elsif (o.first.first == ssl_socket)
|
58
|
-
begin
|
59
|
-
data = ssl_socket.readpartial(10000)
|
60
|
-
rescue EOFError
|
61
|
-
break
|
62
|
-
end
|
63
|
-
output.write(data)
|
64
|
-
end
|
65
|
-
else
|
66
|
-
raise(Timeout::Error.new)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
rescue Interrupt
|
70
|
-
ssl_socket.write("\003")
|
71
|
-
ssl_socket.flush
|
72
|
-
retry
|
73
|
-
rescue Errno::EIO
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1 +0,0 @@
|
|
1
|
-
Hello world!
|