stormmq-client 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README +1 -0
- data/Rakefile +19 -0
- data/TODO +11 -0
- data/bin/stormmq-amqp-echo-test +204 -0
- data/bin/stormmq-create-system +211 -0
- data/bin/stormmq-delete-system +117 -0
- data/bin/stormmq-describe-company +106 -0
- data/bin/stormmq-describe-system +135 -0
- data/bin/stormmq-get-amqpuser-password +148 -0
- data/bin/stormmq-list-amqpusers +142 -0
- data/bin/stormmq-list-apis +86 -0
- data/bin/stormmq-list-bindings +130 -0
- data/bin/stormmq-list-clusters +101 -0
- data/bin/stormmq-list-companies +89 -0
- data/bin/stormmq-list-exchanges +131 -0
- data/bin/stormmq-list-queues +131 -0
- data/bin/stormmq-list-systems +111 -0
- data/bin/stormmq-url-signer +111 -0
- data/lib/stormmq/amqp.rb +92 -0
- data/lib/stormmq/application.rb +36 -0
- data/lib/stormmq/base64_extensions.rb +19 -0
- data/lib/stormmq/errors.rb +33 -0
- data/lib/stormmq/rest.rb +160 -0
- data/lib/stormmq/secret_keys.rb +70 -0
- data/lib/stormmq/url.rb +125 -0
- data/lib/stormmq/utils.rb +27 -0
- data/spec/stormmq/amqp_spec.rb +21 -0
- data/spec/stormmq/secret_keys_spec.rb +25 -0
- data/spec/stormmq/url_spec.rb +129 -0
- data/spec/stormmq/utils_spec.rb +13 -0
- metadata +254 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
#--
|
4
|
+
# Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
|
5
|
+
# All rights reserved.
|
6
|
+
#
|
7
|
+
# Please refer to the LICENSE file that accompanies this source
|
8
|
+
# for terms of use and redistribution.
|
9
|
+
#++
|
10
|
+
|
11
|
+
$:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
|
12
|
+
|
13
|
+
require 'stormmq/secret_keys'
|
14
|
+
require 'stormmq/application'
|
15
|
+
|
16
|
+
class StormMQ::Application::URLSigner < StormMQ::Application
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
synopsis "--help | --user <userName> --method <HttpMethod> --url <URL>"
|
20
|
+
options :help
|
21
|
+
|
22
|
+
option :names => %w(--user -u),
|
23
|
+
:opt_description => "a valid user name, i.e. the user name that you log into the site with",
|
24
|
+
:arity => [1,1],
|
25
|
+
:opt_found => get_args
|
26
|
+
|
27
|
+
option :names => %w(--method -m),
|
28
|
+
:opt_description => "the HTTP method to use - defaults to 'GET'",
|
29
|
+
:arity => [1,1],
|
30
|
+
:opt_found => get_args,
|
31
|
+
:opt_not_found => 'GET'
|
32
|
+
|
33
|
+
option :names => %w(--url -a),
|
34
|
+
:opt_description => "the URL to be signed",
|
35
|
+
:arity => [1,1],
|
36
|
+
:opt_found => get_args,
|
37
|
+
:opt_not_found => CommandLine::OptionParser::OPT_NOT_FOUND_BUT_REQUIRED
|
38
|
+
end
|
39
|
+
|
40
|
+
def main
|
41
|
+
puts self.url.canonicalise_and_sign(opt.user, self.secret_key(opt.user), opt['--method'])
|
42
|
+
end
|
43
|
+
|
44
|
+
def man
|
45
|
+
<<-EOM
|
46
|
+
NAME
|
47
|
+
|
48
|
+
#{File.basename(__FILE__)}
|
49
|
+
|
50
|
+
PURPOSE
|
51
|
+
|
52
|
+
Use this to experiment with the how signing URLs works if you need
|
53
|
+
a reference implementation.
|
54
|
+
|
55
|
+
USAGE
|
56
|
+
|
57
|
+
#{File.basename(__FILE__)} --help
|
58
|
+
#{File.basename(__FILE__)} --user <userName> --method <HttpMethod> --url <URL>
|
59
|
+
|
60
|
+
PARAMETERS
|
61
|
+
|
62
|
+
--user
|
63
|
+
|
64
|
+
The user name you log in to this site with.
|
65
|
+
|
66
|
+
--method
|
67
|
+
|
68
|
+
One of:
|
69
|
+
|
70
|
+
* GET
|
71
|
+
* HEAD
|
72
|
+
* OPTIONS
|
73
|
+
* PUT
|
74
|
+
* DELETE
|
75
|
+
|
76
|
+
POST is not yet supported.
|
77
|
+
|
78
|
+
--url
|
79
|
+
|
80
|
+
The unsigned URL to be signed.
|
81
|
+
|
82
|
+
--help, -h
|
83
|
+
|
84
|
+
Displays this help page then quits.
|
85
|
+
|
86
|
+
RESULT
|
87
|
+
|
88
|
+
Outputs a signed URL to STDOUT.
|
89
|
+
|
90
|
+
NOTES
|
91
|
+
|
92
|
+
Advanced use only - commandline subject to change.
|
93
|
+
|
94
|
+
COPYRIGHT
|
95
|
+
|
96
|
+
Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
|
97
|
+
All rights reserved.
|
98
|
+
|
99
|
+
EOM
|
100
|
+
end
|
101
|
+
|
102
|
+
def url
|
103
|
+
StormMQ::URL.new(opt.url)
|
104
|
+
end
|
105
|
+
|
106
|
+
def secret_key(user) # :nodoc:
|
107
|
+
StormMQ::SecretKeys.key_for(user)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
StormMQ::Application::URLSigner.run
|
data/lib/stormmq/amqp.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Please refer to the LICENSE file that accompanies this source
|
6
|
+
# for terms of use and redistribution.
|
7
|
+
#++
|
8
|
+
|
9
|
+
require 'mq'
|
10
|
+
require 'pp'
|
11
|
+
|
12
|
+
module StormMQ
|
13
|
+
|
14
|
+
module AMQPClientImplementation
|
15
|
+
|
16
|
+
VERSION = '0.0.4'
|
17
|
+
|
18
|
+
def process_frame frame
|
19
|
+
if mq = channels[frame.channel]
|
20
|
+
mq.process_frame(frame)
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
case frame
|
25
|
+
when Frame::Method
|
26
|
+
case method = frame.payload
|
27
|
+
when Protocol::Connection::Start
|
28
|
+
send Protocol::Connection::StartOk.new(
|
29
|
+
{
|
30
|
+
:platform => 'Ruby/EventMachine',
|
31
|
+
:product => 'StormMQ AMQP',
|
32
|
+
:information => 'http://github.com/tonybyrne/StormMQ-Ruby-Client/',
|
33
|
+
:version => VERSION
|
34
|
+
},
|
35
|
+
'AMQPLAIN',
|
36
|
+
{
|
37
|
+
:LOGIN => @settings[:user],
|
38
|
+
:PASSWORD => @settings[:password]
|
39
|
+
},
|
40
|
+
'en_US'
|
41
|
+
)
|
42
|
+
|
43
|
+
when Protocol::Connection::Tune
|
44
|
+
send Protocol::Connection::TuneOk.new(
|
45
|
+
:channel_max => 0,
|
46
|
+
:frame_max => 131072,
|
47
|
+
:heartbeat => 0
|
48
|
+
)
|
49
|
+
|
50
|
+
send Protocol::Connection::Open.new(
|
51
|
+
:virtual_host => @settings[:vhost],
|
52
|
+
:capabilities => '',
|
53
|
+
:insist => @settings[:insist]
|
54
|
+
)
|
55
|
+
|
56
|
+
when Protocol::Connection::OpenOk
|
57
|
+
succeed(self)
|
58
|
+
|
59
|
+
when Protocol::Connection::Close
|
60
|
+
STDERR.puts "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]}"
|
61
|
+
|
62
|
+
when Protocol::Connection::CloseOk
|
63
|
+
@on_disconnect.call if @on_disconnect
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module AMQPClient
|
70
|
+
|
71
|
+
def self.connect(options={})
|
72
|
+
AMQP.client = AMQPClientImplementation
|
73
|
+
AMQP.connect(
|
74
|
+
{
|
75
|
+
:vhost => self.vhost_from_options(options),
|
76
|
+
:host => 'amqp.stormmq.com',
|
77
|
+
:port => 443,
|
78
|
+
:ssl => true
|
79
|
+
}.merge(options)
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.vhost_from_options(options)
|
84
|
+
vhost = "/#{options[:company]}/#{options[:system]}/#{options[:environment]}"
|
85
|
+
[:company, :system, :environment].each {|option| options.delete(option)}
|
86
|
+
vhost
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Please refer to the LICENSE file that accompanies this source
|
6
|
+
# for terms of use and redistribution.
|
7
|
+
#++
|
8
|
+
|
9
|
+
require 'stormmq/errors'
|
10
|
+
require 'stormmq/rest'
|
11
|
+
require 'commandline'
|
12
|
+
require 'commandline/optionparser'
|
13
|
+
|
14
|
+
module StormMQ
|
15
|
+
class Application < CommandLine::Application_wo_AutoRun
|
16
|
+
|
17
|
+
def initialize(*args)
|
18
|
+
author "Tony Byrne"
|
19
|
+
copyright "2010, Tony Byrne & StormMQ. All rights reserved."
|
20
|
+
super(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def rest_client(user)
|
24
|
+
begin
|
25
|
+
Rest.new(:user => user)
|
26
|
+
rescue Error::SecretKeyNotProvidedError
|
27
|
+
raise "Could not find the secret key for user '#{user}' - please ensure it is present in the secret key file"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self_test
|
32
|
+
'Self test ouput goes here'
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Please refer to the LICENSE file that accompanies this source
|
6
|
+
# for terms of use and redistribution.
|
7
|
+
#++
|
8
|
+
|
9
|
+
module Base64
|
10
|
+
|
11
|
+
def urlsafe_decode64(str)
|
12
|
+
decode64(str.tr("-_", "+/"))
|
13
|
+
end
|
14
|
+
|
15
|
+
def urlsafe_encode64(bin)
|
16
|
+
encode64(bin).tr("+/", "-_")
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Please refer to the LICENSE file that accompanies this source
|
6
|
+
# for terms of use and redistribution.
|
7
|
+
#++
|
8
|
+
|
9
|
+
module StormMQ
|
10
|
+
|
11
|
+
module Error
|
12
|
+
|
13
|
+
class Base < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
class LoadSecretKeysError < StormMQ::Error::Base
|
17
|
+
end
|
18
|
+
|
19
|
+
class SecretKeyNotFoundError < StormMQ::Error::Base
|
20
|
+
end
|
21
|
+
|
22
|
+
class SecretKeyNotProvidedError < StormMQ::Error::Base
|
23
|
+
end
|
24
|
+
|
25
|
+
class UserNotProvidedError < StormMQ::Error::Base
|
26
|
+
end
|
27
|
+
|
28
|
+
class InvalidURLError < StormMQ::Error::Base
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/stormmq/rest.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Please refer to the LICENSE file that accompanies this source
|
6
|
+
# for terms of use and redistribution.
|
7
|
+
#++
|
8
|
+
|
9
|
+
require 'stormmq/url'
|
10
|
+
require 'stormmq/errors'
|
11
|
+
require 'stormmq/secret_keys'
|
12
|
+
require 'json'
|
13
|
+
require 'rest_client'
|
14
|
+
|
15
|
+
module StormMQ
|
16
|
+
|
17
|
+
API_HOST = ENV['STORMMQ_HOST'] || "api.stormmq.com"
|
18
|
+
API = ENV['STORMMQ_API'] || "api"
|
19
|
+
API_VERSION = ENV['STORMMQ_API_VERSION'] || "2009-01-01"
|
20
|
+
|
21
|
+
COMPANIES_PATH = '/companies/'
|
22
|
+
CLUSTERS_PATH = '/clusters'
|
23
|
+
APIS_PATH = '/'
|
24
|
+
|
25
|
+
# The Rest class implements the client for StormMQ's RESTful API. The API allows clients to access
|
26
|
+
# company, system and environment information.
|
27
|
+
|
28
|
+
class Rest
|
29
|
+
|
30
|
+
RestClient.proxy = ENV['http_proxy'] unless ENV['http_proxy'].nil?
|
31
|
+
|
32
|
+
def initialize(options={})
|
33
|
+
unless @user = options.delete(:user)
|
34
|
+
raise Error::UserNotProvidedError,
|
35
|
+
"could not determine the user name - either provide it via the :user param",
|
36
|
+
caller
|
37
|
+
end
|
38
|
+
|
39
|
+
unless @secret_key = options.delete(:secret_key) || self.class.secret_key_from_key_store(@user)
|
40
|
+
raise Error::SecretKeyNotProvidedError, "could not determine the secret key for user '#{@user}' - either provide it via the :secret_key param or ensure it is available in the secret key file",
|
41
|
+
caller
|
42
|
+
end
|
43
|
+
|
44
|
+
@host = options.delete(:host) || API_HOST
|
45
|
+
@api = options.delete(:api) || API
|
46
|
+
@version = options.delete(:version) || API_VERSION
|
47
|
+
|
48
|
+
@url_options = options
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns an Array of company indentifiers associated with the user.
|
52
|
+
def companies
|
53
|
+
signed_get(COMPANIES_PATH)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Takes a String containing a valid company identifier and returns a
|
57
|
+
# Hash representation of the detailed information stored on the StormMQ
|
58
|
+
# system about the company.
|
59
|
+
def describe_company(company)
|
60
|
+
signed_get(COMPANIES_PATH, escape(company))
|
61
|
+
end
|
62
|
+
|
63
|
+
def systems(company)
|
64
|
+
signed_get(COMPANIES_PATH, escape(company), '/')
|
65
|
+
end
|
66
|
+
|
67
|
+
def create_system(company, system, json)
|
68
|
+
signed_put(json, COMPANIES_PATH, escape(company), escape(system))
|
69
|
+
end
|
70
|
+
|
71
|
+
def describe_system(company, system)
|
72
|
+
signed_get(COMPANIES_PATH, escape(company), escape(system))
|
73
|
+
end
|
74
|
+
|
75
|
+
def delete_system(company, system)
|
76
|
+
signed_delete(COMPANIES_PATH, escape(company), escape(system))
|
77
|
+
end
|
78
|
+
|
79
|
+
def clusters(company)
|
80
|
+
signed_get(CLUSTERS_PATH, escape(company))
|
81
|
+
end
|
82
|
+
|
83
|
+
def queues(company, system, environment)
|
84
|
+
signed_get(COMPANIES_PATH, escape(company), escape(system), escape(environment), 'queues/')
|
85
|
+
end
|
86
|
+
|
87
|
+
def bindings(company, system, environment)
|
88
|
+
signed_get(COMPANIES_PATH, escape(company), escape(system), escape(environment), 'bindings/')
|
89
|
+
end
|
90
|
+
|
91
|
+
def exchanges(company, system, environment)
|
92
|
+
signed_get(COMPANIES_PATH, escape(company), escape(system), escape(environment), 'exchanges/')
|
93
|
+
end
|
94
|
+
|
95
|
+
def apis
|
96
|
+
signed_get(APIS_PATH)
|
97
|
+
end
|
98
|
+
|
99
|
+
def amqp_password(company, system, environment, amqp_user)
|
100
|
+
signed_get(COMPANIES_PATH, escape(company), escape(system), escape(environment), 'users', escape(amqp_user))
|
101
|
+
end
|
102
|
+
|
103
|
+
def amqp_users(company, system, environment)
|
104
|
+
signed_get(COMPANIES_PATH, escape(company), escape(system), escape(environment), 'users/')
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def signed_get(*path_args)
|
110
|
+
get(build_signed_resource_url(make_normalised_path(*path_args)))
|
111
|
+
end
|
112
|
+
|
113
|
+
def signed_delete(*path_args)
|
114
|
+
delete(build_signed_resource_url(make_normalised_path(*path_args), 'DELETE'))
|
115
|
+
end
|
116
|
+
|
117
|
+
def signed_put(payload, *path_args)
|
118
|
+
put(build_signed_resource_url(make_normalised_path(*path_args), 'PUT'), payload)
|
119
|
+
end
|
120
|
+
|
121
|
+
def escape(string) # :nodoc:
|
122
|
+
StormMQ::URL.escape(string)
|
123
|
+
end
|
124
|
+
|
125
|
+
def get(signed_url) # :nodoc:
|
126
|
+
JSON.parse(RestClient.get(signed_url.to_s, {:accept => '*/*'}).to_s)
|
127
|
+
end
|
128
|
+
|
129
|
+
def delete(signed_url) # :nodoc:
|
130
|
+
JSON.parse(RestClient.delete(signed_url.to_s).to_s)
|
131
|
+
end
|
132
|
+
|
133
|
+
def put(signed_url, payload) # :nodoc:
|
134
|
+
JSON.parse(RestClient.put(signed_url.to_s, payload, {:accept => '*/*', :content_type => 'application/json'}).to_s)
|
135
|
+
end
|
136
|
+
|
137
|
+
def build_signed_resource_url(resource_path='/', method='GET') # :nodoc:
|
138
|
+
StormMQ::URL.new(
|
139
|
+
{
|
140
|
+
:host => @host,
|
141
|
+
:scheme => 'https',
|
142
|
+
:path => make_normalised_path(@api, @version, resource_path)
|
143
|
+
}.merge(@url_options)
|
144
|
+
).canonicalise_and_sign(@user, @secret_key, method)
|
145
|
+
end
|
146
|
+
|
147
|
+
def make_normalised_path(*args) # :nodoc:
|
148
|
+
('/' + args.join('/')).gsub(/\/+/,'/')
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.secret_key_from_key_store(user) # :nodoc:
|
152
|
+
begin
|
153
|
+
SecretKeys.key_for(user)
|
154
|
+
rescue
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|