shelly 0.2.28 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ODQ3NzU0MWM0MWJhZTU5YzZhMjg5NmY3YzhiZjQ5N2Y1NDc4YmFiZQ==
4
+ OTBkYWQ5MTBjMzM5ODk3NzA2MjUxNmI1YmYxNjFkYjQ5ZDA3YmIzMA==
5
5
  data.tar.gz: !binary |-
6
- NmE3Y2Q0NWRlOWZjMzU4Y2Y0NzRjYWI2ODM4ZWMxZmE1OThlMzNlOA==
6
+ ZDEyM2ZiYzNhNjJjYWUwMmMxMjEzNWIzZDk3ZjI2NjEyMGUwN2RiMg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- MTAyN2EyNDFiZmExYmM1Mjg0ZWQwYTExY2IzNjQ5NGUwMzZlZTA2MDNmMTdk
10
- MWIyMzkyY2QyZWI1ZDIwNWZkMjgxNGJkNmZkNTAzMTg4YTZmNmMyNDQ5MDY4
11
- MWY4YzQ4Yjc2ZmM0ZTE3Zjc3YTgzMDAzYTg0YTU2MzU4NTc3N2I=
9
+ NDYyMGIzMDdhMDFkNTEzNjk0MzUyNjlkYTU5ZjViYjkzZTM4ZmVmN2E1OGNk
10
+ MmQwYjg5MDQ3MTVmMGRiZDFlMGFkNDhmNmMzMTdmZjc1ZWU0NTcyMTQ0NDE0
11
+ MDI1NWRlYjJiYTVkODcyODFkM2YxNWU1YzU5NmJlMzJjM2Q2ZjI=
12
12
  data.tar.gz: !binary |-
13
- Mzg4YTI5NjAyOTQwYWYzMTA1YTU0MTE4MWU1YTljMTA1Mzk0NWVmZTg3ZDRl
14
- YjZkYjEwMjhmNDM4ZDE4M2M3OGViMGJmMzEzNjAyMDQ2NTg1MzA1NmZkZmU4
15
- MjAwY2E2MThkY2NkMGI1NWVmM2E2Y2MwODYxNzFjNjU2YjI2M2E=
13
+ ODk0MDZkZjRiOWIwYWM5YzNmNGU3YjU5MDZmYzE2OWJiYjc4ZTg4OWE2NjFk
14
+ MDQ3MWI3M2VhOGIwYmE4ODc1ODJlODk1M2ExZmQ1YzgxM2ZmZjNkNDliYzJh
15
+ MGFjYTg4NDkxMjcwZjgxMmM2NTdkMWJmM2I1ZmQ2ZDNiNzY3ZDA=
data/.travis.yml CHANGED
@@ -6,3 +6,6 @@ rvm:
6
6
  - ree
7
7
  - jruby-18mode
8
8
  - jruby-19mode
9
+ notifications:
10
+ email:
11
+ - devs@shellycloud.com
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.3.0 / 2013-06-23
2
+
3
+ * [improvement] API key is now stored in .netrc
4
+
1
5
  ## 0.2.28 / 2013-06-18
2
6
 
3
7
  * [improvement] user can answer 'y' to 'yes/no' questions
@@ -33,13 +33,13 @@ module Shelly
33
33
 
34
34
  desc "register [EMAIL]", "Register new account"
35
35
  def register(email = nil)
36
- user = Shelly::User.new
37
36
  say "Your public SSH key will be uploaded to Shelly Cloud after registration."
38
37
  say "Registering with email: #{email}" if email
39
- user.email = (email || ask_for_email)
40
- user.password = ask_for_password
38
+ user = Shelly::User.new
39
+ email ||= ask_for_email
40
+ password = ask_for_password
41
41
  ask_for_acceptance_of_terms
42
- user.register
42
+ user.register(email, password)
43
43
  if user.ssh_key_exists?
44
44
  say "Uploading your public SSH key from #{user.ssh_key_path}"
45
45
  else
@@ -58,9 +58,9 @@ module Shelly
58
58
  user = Shelly::User.new
59
59
  say "Your public SSH key will be uploaded to Shelly Cloud after login."
60
60
  raise Errno::ENOENT, user.ssh_key_path unless user.ssh_key_exists?
61
- user.email = email || ask_for_email
62
- user.password = ask_for_password(:with_confirmation => false)
63
- user.login
61
+ email ||= ask_for_email
62
+ password = ask_for_password(:with_confirmation => false)
63
+ user.login(email, password)
64
64
  say "Login successful", :green
65
65
  user.upload_ssh_key
66
66
  say "Uploading your public SSH key"
@@ -320,7 +320,7 @@ Wait until cloud is in 'turned off' state and try again.}
320
320
  def logout
321
321
  user = Shelly::User.new
322
322
  say "Your public SSH key has been removed from Shelly Cloud" if user.delete_ssh_key
323
- say "You have been successfully logged out" if user.delete_credentials
323
+ say "You have been successfully logged out" if user.logout
324
324
  end
325
325
 
326
326
  desc "rake TASK", "Run rake task"
data/lib/shelly/client.rb CHANGED
@@ -1,219 +1,29 @@
1
1
  require "rest_client"
2
2
  require "json"
3
3
  require "cgi"
4
+ require "netrc"
4
5
 
5
6
  module Shelly
6
7
  class Client
7
- class APIException < Exception
8
- attr_reader :status_code, :body, :request_id
9
-
10
- def initialize(body = {}, status_code = nil, request_id = nil)
11
- @status_code = status_code
12
- @body = body
13
- @request_id = request_id
14
- end
15
-
16
- def [](key)
17
- body[key.to_s]
18
- end
19
- end
20
-
21
- class UnauthorizedException < APIException; end
22
- class ForbiddenException < APIException; end
23
- class ConflictException < APIException; end
24
- class GemVersionException < APIException; end
25
- class GatewayTimeoutException < APIException; end
26
- class LockedException < APIException; end
27
- class ValidationException < APIException
28
- def errors
29
- self[:errors]
30
- end
31
-
32
- def each_error
33
- errors.each do |field, message|
34
- yield [field.gsub('_',' ').capitalize, message].join(" ")
35
- end
36
- end
37
- end
38
- class NotFoundException < APIException
39
- def resource
40
- self[:resource].to_sym
41
- end
42
-
43
- def id
44
- self[:id]
45
- end
46
- end
47
-
48
- attr_reader :email, :password
49
-
50
- def initialize(email = nil, password = nil)
51
- @email = email
52
- @password = password
53
- end
8
+ require 'shelly/client/errors'
9
+ require 'shelly/client/shellyapp'
10
+ require 'shelly/client/users'
11
+ require 'shelly/client/apps'
12
+ require 'shelly/client/configs'
13
+ require 'shelly/client/deployment_logs'
14
+ require 'shelly/client/application_logs'
15
+ require 'shelly/client/database_backups'
16
+ require 'shelly/client/deploys'
17
+ require 'shelly/client/ssh_keys'
18
+ require 'shelly/client/organizations'
19
+ require 'shelly/client/auth'
54
20
 
55
21
  def api_url
56
22
  ENV["SHELLY_URL"] || "https://api.shellycloud.com/apiv2"
57
23
  end
58
24
 
59
- def shellyapp_url
60
- get("/shellyapp")["url"]
61
- end
62
-
63
- def register_user(email, password, ssh_key)
64
- post("/users", :user => {:email => email, :password => password, :ssh_key => ssh_key})
65
- end
66
-
67
- def token
68
- get("/token")
69
- end
70
-
71
- def app_configs(cloud)
72
- get("/apps/#{cloud}/configs")
73
- end
74
-
75
- def app_config(cloud, path)
76
- get("/apps/#{cloud}/configs/#{CGI.escape(path)}")
77
- end
78
-
79
- def app_create_config(cloud, path, content)
80
- post("/apps/#{cloud}/configs", :config => {:path => path, :content => content})
81
- end
82
-
83
- def app_update_config(cloud, path, content)
84
- put("/apps/#{cloud}/configs/#{CGI.escape(path)}", :config => {:content => content})
85
- end
86
-
87
- def app_delete_config(cloud, path)
88
- delete("/apps/#{cloud}/configs/#{CGI.escape(path)}")
89
- end
90
-
91
- def send_invitation(name, email, owner = false)
92
- post("/organizations/#{name}/memberships", :email => email, :owner => owner)
93
- end
94
-
95
- def delete_member(name, email)
96
- delete("/organizations/#{name}/memberships/#{email}")
97
- end
98
-
99
- def create_app(attributes)
100
- organization = attributes.delete(:organization_name)
101
- zone = attributes.delete(:zone_name)
102
- post("/apps", :app => attributes, :organization_name => organization,
103
- :zone_name => zone)
104
- end
105
-
106
- def delete_app(code_name)
107
- delete("/apps/#{code_name}")
108
- end
109
-
110
- def add_ssh_key(ssh_key)
111
- post("/ssh_keys", :ssh_key => ssh_key)
112
- end
113
-
114
- def logout(ssh_key)
115
- delete("/ssh_keys", :ssh_key => ssh_key)
116
- end
117
-
118
- def start_cloud(cloud)
119
- put("/apps/#{cloud}/start")
120
- end
121
-
122
- def stop_cloud(cloud)
123
- put("/apps/#{cloud}/stop")
124
- end
125
-
126
- def apps
127
- get("/apps")
128
- end
129
-
130
- def app(code_name)
131
- get("/apps/#{code_name}")
132
- end
133
-
134
- def organizations
135
- get("/organizations")
136
- end
137
-
138
- def organization(name)
139
- get("/organizations/#{name}")
140
- end
141
-
142
- def statistics(code_name)
143
- get("/apps/#{code_name}/statistics")
144
- end
145
-
146
- def command(cloud, body, type)
147
- post("/apps/#{cloud}/command", {:body => body, :type => type})
148
- end
149
-
150
- def console(code_name, server = nil)
151
- get("/apps/#{code_name}/console", {:server => server})
152
- end
153
-
154
- def deploy_logs(cloud)
155
- get("/apps/#{cloud}/deployment_logs")
156
- end
157
-
158
- def deploy_log(cloud, log)
159
- get("/apps/#{cloud}/deployment_logs/#{log}")
160
- end
161
-
162
- def application_logs(cloud, options = {})
163
- get("/apps/#{cloud}/application_logs#{query(options)}")
164
- end
165
-
166
- def application_logs_tail(cloud)
167
- url = get("/apps/#{cloud}/application_logs/tail")["url"]
168
- options = {
169
- :url => url,
170
- :method => :get,
171
- :timeout => 60 * 60 * 24,
172
- :block_response => Proc.new { |r| r.read_body { |c| yield(c) } }
173
- }.merge(http_basic_auth_options)
174
- RestClient::Request.execute(options)
175
- end
176
-
177
- def download_application_logs_attributes(code_name, options)
178
- attributes = get("/apps/#{code_name}/application_logs/download#{query(options)}")
179
- headers = RestClient::Request.execute({
180
- :method => :get,
181
- :url => "#{attributes["url"]}/headers"
182
- }.merge(http_basic_auth_options)).headers
183
-
184
- attributes.merge("size" => headers[:content_lenght].to_i)
185
- end
186
-
187
- def database_backups(code_name)
188
- get("/apps/#{code_name}/database_backups")
189
- end
190
-
191
- def database_backup(code_name, handler)
192
- get("/apps/#{code_name}/database_backups/#{handler}")
193
- end
194
-
195
- def restore_backup(code_name, filename)
196
- put("/apps/#{code_name}/database_backups/#{filename}/restore")
197
- end
198
-
199
- def request_backup(code_name, kind = nil)
200
- post("/apps/#{code_name}/database_backups", :kind => kind)
201
- end
202
-
203
- def download_backup_url(code_name, filename)
204
- get("/apps/#{code_name}/database_backups/#{filename}/download_url")["url"]
205
- end
206
-
207
- def members(name)
208
- get("/organizations/#{name}/memberships")
209
- end
210
-
211
- def redeploy(cloud)
212
- post("/apps/#{cloud}/deploys")
213
- end
214
-
215
- def deployment(cloud, deployment_id)
216
- get("/apps/#{cloud}/deploys/#{deployment_id}")
25
+ def api_host
26
+ URI.parse(api_url).host
217
27
  end
218
28
 
219
29
  def query(options = {})
@@ -271,7 +81,11 @@ module Shelly
271
81
  end
272
82
 
273
83
  def http_basic_auth_options
274
- @email ? {:user => @email, :password => @password} : {}
84
+ if @email && @password
85
+ {:user => @email, :password => @password}
86
+ else
87
+ basic_auth_from_netrc
88
+ end
275
89
  end
276
90
 
277
91
  def request_parameters(path, method, params = {})
@@ -0,0 +1,26 @@
1
+ class Shelly::Client
2
+ def application_logs(cloud, options = {})
3
+ get("/apps/#{cloud}/application_logs#{query(options)}")
4
+ end
5
+
6
+ def application_logs_tail(cloud)
7
+ url = get("/apps/#{cloud}/application_logs/tail")["url"]
8
+ options = {
9
+ :url => url,
10
+ :method => :get,
11
+ :timeout => 60 * 60 * 24,
12
+ :block_response => Proc.new { |r| r.read_body { |c| yield(c) } }
13
+ }.merge(http_basic_auth_options)
14
+ RestClient::Request.execute(options)
15
+ end
16
+
17
+ def download_application_logs_attributes(code_name, options)
18
+ attributes = get("/apps/#{code_name}/application_logs/download#{query(options)}")
19
+ headers = RestClient::Request.execute({
20
+ :method => :get,
21
+ :url => "#{attributes["url"]}/headers"
22
+ }.merge(http_basic_auth_options)).headers
23
+
24
+ attributes.merge("size" => headers[:content_lenght].to_i)
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ class Shelly::Client
2
+ def create_app(attributes)
3
+ organization = attributes.delete(:organization_name)
4
+ zone = attributes.delete(:zone_name)
5
+ post("/apps", :app => attributes, :organization_name => organization,
6
+ :zone_name => zone)
7
+ end
8
+
9
+ def delete_app(code_name)
10
+ delete("/apps/#{code_name}")
11
+ end
12
+
13
+ def start_cloud(cloud)
14
+ put("/apps/#{cloud}/start")
15
+ end
16
+
17
+ def stop_cloud(cloud)
18
+ put("/apps/#{cloud}/stop")
19
+ end
20
+
21
+ def apps
22
+ get("/apps")
23
+ end
24
+
25
+ def app(code_name)
26
+ get("/apps/#{code_name}")
27
+ end
28
+
29
+ def statistics(code_name)
30
+ get("/apps/#{code_name}/statistics")
31
+ end
32
+
33
+ def command(cloud, body, type)
34
+ post("/apps/#{cloud}/command", {:body => body, :type => type})
35
+ end
36
+
37
+ def console(code_name, server = nil)
38
+ get("/apps/#{code_name}/console", {:server => server})
39
+ end
40
+ end
@@ -0,0 +1,69 @@
1
+ class Shelly::Client
2
+ def authorize_with_email_and_password(email, password)
3
+ forget_authorization
4
+ @email = email; @password = password
5
+ api_key = get_token
6
+ store_api_key_in_netrc(email, api_key)
7
+ end
8
+
9
+ def user_email
10
+ @email || email_from_netrc
11
+ end
12
+
13
+ def authorize!
14
+ get_token
15
+ true
16
+ end
17
+
18
+ def forget_authorization
19
+ remove_api_key_from_netrc
20
+ end
21
+
22
+ def get_token
23
+ get("/token")["token"]
24
+ end
25
+
26
+ def basic_auth_from_netrc
27
+ if netrc
28
+ user, password = netrc[api_host]
29
+ {:user => user, :password => password}
30
+ else
31
+ {}
32
+ end
33
+ end
34
+
35
+ def store_api_key_in_netrc(email, api_key)
36
+ FileUtils.mkdir_p(File.dirname(netrc_path))
37
+ FileUtils.touch(netrc_path)
38
+ FileUtils.chmod(0600, netrc_path)
39
+
40
+ netrc[api_host] = [email, api_key]
41
+ netrc.save
42
+ end
43
+
44
+ def remove_api_key_from_netrc
45
+ if netrc
46
+ netrc.delete(api_host)
47
+ netrc.save
48
+ true # must return a truthy value to print logout confirmation
49
+ end
50
+ end
51
+
52
+ def email_from_netrc
53
+ netrc[api_host].first if netrc
54
+ end
55
+
56
+ def netrc
57
+ @netrc ||= File.exists?(netrc_path) && Netrc.read(netrc_path)
58
+ end
59
+
60
+ def netrc_path
61
+ default = Netrc.default_path
62
+ encrypted = default + ".gpg"
63
+ if File.exists?(encrypted)
64
+ encrypted
65
+ else
66
+ default
67
+ end
68
+ end
69
+ end