shelly 0.4.38 → 0.4.39

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a378b3163f2759b50c3527162a36a2e448aaa0a2
4
- data.tar.gz: e51cc9e70dc529e7ebf7e1b638dd7972afc4a94c
3
+ metadata.gz: b5d9e5112799516f4300810c0c9d4bc63a755a18
4
+ data.tar.gz: ef02f4bd1ef58a34a5c72a566e22d99a685938dc
5
5
  SHA512:
6
- metadata.gz: 65b56e13341eb0e9ae7a8ed219c9537ab43d96c78b9c7e98ac9cb1f6c1d1d38752cc7f843b3105bbd30a5212aa95d236e97706be858c4af4ae0d23e577aeb0db
7
- data.tar.gz: 605a7ea1cd53db41017d14f98432c793ac332983911425b325fed46885ebe8029860523070f487c40f61c84b480f68ccca80f18d3d52a17ac165b73ce6a0c43a
6
+ metadata.gz: 3eaac18b74f4977637ff4d26d0d019ba4f3288a469caaa819fde9b90190c850198ec184ca0e4bf67c25d9bb7bc65ca105fd4e9c4e446bcd72cd5bc22c0f953de
7
+ data.tar.gz: 8fa35d39646836f2405484650bbba28b26b8f836349d7ff9e0e68e5c5b58b12a7cc4e3bab8e0c1cfe64554f6306f0e900f43efca319319ef6a2f803d63e43d6a
@@ -1,9 +1,9 @@
1
1
  rvm:
2
- - "2.1"
3
- - 2.0.0
4
- - 1.9.3
5
- - jruby-19mode
2
+ - '2.1'
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - jruby-19mode
6
6
  notifications:
7
7
  email: false
8
- campfire:
9
- secure: 'ZSIx+w/r0QrOtpWu8EfmlypA9+pCRYSNU01Hv0ZvxOBu1EEp1Z/sDif0dCyyLrhv7lUOESdlcfmwVXUx93zEk2f+YMakG0NBnvMUhlkUhBLEsxDdPIgihhTirUIcWLrtPhtUbFA68/eXAP55wlz4Vcou5CHz8kk0+qmUX7QnqlI='
8
+ slack:
9
+ secure: D5ohRHtjO58jbSOGxZIGFIBQ0GLGhpgojxgrNFxwebzyvfN4kQK9iDdurWapwuXPpsDukLz8gnnlaboJ0wjmqjp4MEtXoAO+3PdYHChPOiL/bSpOAtuE5o/Gh2LVu6RXI+//cuxjfREE2bSbdFJnFzlb3lccuoU4x1c3JB5YbS4=
@@ -1,3 +1,8 @@
1
+ ## 0.4.39 / 2014-11-17
2
+
3
+ * [improvement] API changed to support multiple certificates and IP addresses,
4
+ resource name changed from Cert to Endpoint
5
+
1
6
  ## 0.4.38 / 2014-10-20
2
7
 
3
8
  * [improvement] Deployment logs procesess moved after puma
@@ -215,16 +215,24 @@ module Shelly
215
215
  configs.any? { |config| config["path"] == path }
216
216
  end
217
217
 
218
- def cert
219
- shelly.cert(code_name)
218
+ def endpoints
219
+ shelly.endpoints(code_name)
220
220
  end
221
221
 
222
- def create_cert(content, key)
223
- shelly.create_cert(code_name, content, key)
222
+ def endpoint(uuid)
223
+ shelly.endpoint(code_name, uuid)
224
224
  end
225
225
 
226
- def update_cert(content, key)
227
- shelly.update_cert(code_name, content, key)
226
+ def create_endpoint(certificate, key, sni)
227
+ shelly.create_endpoint(code_name, certificate, key, sni)
228
+ end
229
+
230
+ def update_endpoint(uuid, certificate, key)
231
+ shelly.update_endpoint(code_name, uuid, certificate, key)
232
+ end
233
+
234
+ def delete_endpoint(uuid)
235
+ shelly.delete_endpoint(code_name, uuid)
228
236
  end
229
237
 
230
238
  def rake(task)
@@ -87,7 +87,7 @@ module Shelly
87
87
  def restore(filename)
88
88
  app = multiple_clouds(options[:cloud], "backup restore FILENAME")
89
89
  backup = app.database_backup(filename)
90
- say "You are about restore #{backup.kind} database for cloud #{backup.code_name} to state from #{backup.filename}"
90
+ say "You are about to restore #{backup.kind} database for cloud #{backup.code_name} to state from #{backup.filename}"
91
91
  say_new_line
92
92
  ask_to_restore_database
93
93
  app.restore_backup(filename)
@@ -0,0 +1,175 @@
1
+ # encoding: utf-8
2
+
3
+ require "shelly/cli/command"
4
+
5
+ module Shelly
6
+ module CLI
7
+ class Endpoint < Command
8
+ namespace :endpoint
9
+ include Helpers
10
+
11
+ before_hook :logged_in?, :only => [:index, :show, :create, :update]
12
+
13
+ class_option :cloud, :type => :string, :aliases => "-c", :desc => "Specify cloud"
14
+
15
+ desc "list", "List HTTP endpoints"
16
+ def list
17
+ app = multiple_clouds(options[:cloud], "endpoint list")
18
+
19
+ endpoints = app.endpoints
20
+
21
+ if endpoints.present?
22
+ say "Available HTTP endpoints", :green
23
+ say_new_line
24
+ to_display = [["UUID", "| IP address", "| Certificate", "| SNI"]]
25
+
26
+ endpoints.each do |endpoint|
27
+
28
+ to_display << [
29
+ endpoint['uuid'],
30
+ "| #{print_check(endpoint['ip_address'], :return_value => true)}",
31
+ "| #{print_check(endpoint['info']['domain'], :return_value => true)}",
32
+ "| #{print_check(endpoint['sni'])}"
33
+ ]
34
+ end
35
+
36
+ print_table(to_display, :ident => 2)
37
+
38
+ else
39
+ say "No HTTP endpoints available"
40
+ end
41
+ end
42
+
43
+ desc "show", "Show detail information about HTTP endpoint"
44
+ def show(uuid)
45
+ app = multiple_clouds(options[:cloud], "endpoint show UUID")
46
+
47
+ endpoint = app.endpoint(uuid)
48
+
49
+ say "UUID: #{endpoint['uuid']}"
50
+ say "IP address: #{endpoint['ip_address']}", nil, true
51
+ say "SNI: #{"✓" if endpoint['sni']}", nil, true
52
+
53
+ say_new_line
54
+ if endpoint['info']['subject'] && endpoint['info']['issuer']
55
+ say "Certificate details:", :green
56
+ say "Domain: #{endpoint['info']['domain']}", nil, true
57
+ say "Issuer: #{endpoint['info']['issuer']}"
58
+ say "Subject: #{endpoint['info']['subject']}"
59
+ say "Not valid before: #{Time.parse(endpoint['info']['since']).
60
+ getlocal.strftime("%Y-%m-%d %H:%M:%S")}"
61
+ say "Expires: #{Time.parse(endpoint['info']['to']).
62
+ getlocal.strftime("%Y-%m-%d %H:%M:%S")}"
63
+ else
64
+ say "No SSL certificate added"
65
+ end
66
+ rescue Client::NotFoundException => e
67
+ raise unless e.resource == :endpoint
68
+ say_error "Endpoint not found"
69
+ end
70
+
71
+ desc "create [CERT_PATH] [KEY_PATH] [BUNDLE_PATH]", "Add HTTP endpoint " \
72
+ "to your cloud"
73
+ long_desc %{
74
+ Add HTTP endpoint to your cloud. Adding SSL certificate is optional and not required\n
75
+ CERT_PATH - path to certificate.\n
76
+ KEY_PATH - path to private key.\n
77
+ BUNDLE_PATH - optional path to certificate bundle path.
78
+ }
79
+ method_option "sni", :type => :boolean,
80
+ :desc => "Create SNI endpoint"
81
+ def create(cert_path = nil, key_path = nil, bundle_path = nil)
82
+ app = multiple_clouds(options[:cloud],
83
+ "endpoint create [CERT_PATH] [KEY_PATH] [BUNDLE_PATH]")
84
+
85
+ certificate, key = read_certificate_components(cert_path, key_path,
86
+ bundle_path)
87
+
88
+ endpoint = app.create_endpoint(certificate, key, options["sni"])
89
+
90
+ say "Endpoint was created for #{app} cloud", :green
91
+ if endpoint['ip_address']
92
+ say "Deployed certificate on front end servers." if certificate && key
93
+ say "Point your domain to private IP address: #{endpoint['ip_address']}"
94
+ else
95
+ say "Private IP address was requested for your cloud."
96
+ say "Support has been notified and will contact you shortly."
97
+ end
98
+ rescue Client::ValidationException => e
99
+ e.each_error { |error| say_error error, :with_exit => false }
100
+ exit 1
101
+ end
102
+
103
+ desc "update UUID CERT_PATH KEY_PATH [BUNDLE_PATH]", "Update HTTP "\
104
+ "endpoint by adding SSL certificate"
105
+ long_desc %{
106
+ Update current HTTP endpoint with SSL certificate\n
107
+ CERT_PATH - path to certificate.\n
108
+ KEY_PATH - path to private key.\n
109
+ BUNDLE_PATH - optional path to certificate bundle path.
110
+ }
111
+ def update(uuid, cert_path, key_path, bundle_path = nil)
112
+ app = multiple_clouds(options[:cloud],
113
+ "endpoint update UUID CERT_PATH KEY_PATH [BUNDLE_PATH]")
114
+
115
+ certificate, key = read_certificate_components(cert_path, key_path,
116
+ bundle_path)
117
+
118
+ endpoint = app.update_endpoint(uuid, certificate, key)
119
+
120
+ say "Endpoint was updated", :green
121
+ if endpoint['ip_address']
122
+ say "Deployed certificate on front end servers."
123
+ say "Point your domain to private IP address: #{endpoint['ip_address']}"
124
+ else
125
+ say "Private IP address was requested for your cloud."
126
+ say "Support has been notified and will contact you shortly."
127
+ end
128
+ rescue Client::ValidationException => e
129
+ e.each_error { |error| say_error error, :with_exit => false }
130
+ exit 1
131
+ rescue Client::NotFoundException => e
132
+ raise unless e.resource == :certificate
133
+ say_error "Endpoint not found"
134
+ end
135
+
136
+ desc "delete UUID", "Delete HTTP endpoint"
137
+ def delete(uuid)
138
+ app = multiple_clouds(options[:cloud], "endpoint delete UUID")
139
+ endpoint = app.endpoint(uuid)
140
+
141
+ if endpoint['ip_address']
142
+ say_warning "Removing endpoint will release #{endpoint['ip_address']} IP address."
143
+ end
144
+ if yes?("Are you sure you want to delete endpoint (yes/no):")
145
+ app.delete_endpoint(uuid)
146
+ say "Endpoint was deleted"
147
+ end
148
+ rescue Client::NotFoundException => e
149
+ raise unless e.resource == :certificate
150
+ say_error "Endpoint not found"
151
+ end
152
+
153
+ no_tasks do
154
+ def print_check(check, options = {})
155
+ return check if options[:return_value] && check
156
+ check ? "✓" : "✗"
157
+ end
158
+
159
+ def read_certificate_components(cert_path, key_path, bundle_path)
160
+ if cert_path || key_path
161
+ say_error "Provide both certificate and key" unless (cert_path && key_path)
162
+
163
+ certificate = ::File.read(cert_path).strip
164
+ bundle = bundle_path ? ::File.read(bundle_path).strip : ""
165
+ key = ::File.read(key_path).strip
166
+
167
+ certificate = certificate + "\n" + bundle
168
+
169
+ [certificate, key]
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
@@ -7,7 +7,7 @@ require "shelly/cli/config"
7
7
  require "shelly/cli/file"
8
8
  require "shelly/cli/organization"
9
9
  require "shelly/cli/logs"
10
- require "shelly/cli/cert"
10
+ require "shelly/cli/endpoint"
11
11
  require "shelly/cli/maintenance"
12
12
 
13
13
  require "shelly/cli/main/add"
@@ -26,7 +26,7 @@ module Shelly
26
26
  register_subcommand(File, "file", "file <command>", "Upload and download files to and from persistent storage")
27
27
  register_subcommand(Organization, "organization", "organization <command>", "View organizations")
28
28
  register_subcommand(Logs, "log", "logs <command>", "View application logs")
29
- register_subcommand(Cert, "cert", "cert <command>", "Mange application certificates")
29
+ register_subcommand(Endpoint, "endpoint", "cert <command>", "Mange application HTTP(S) endpoints")
30
30
  register_subcommand(Maintenance, "maintenance", "maintenance <command>", "Mange application maintenance events")
31
31
 
32
32
  check_unknown_options!(:except => :rake)
@@ -118,7 +118,7 @@ module Shelly
118
118
  print_wrapped "Deployed by: #{app.git_info["deployed_push_author"]}", :ident => 2
119
119
  say_new_line
120
120
  print_wrapped "Repository URL: #{app.git_info["repository_url"]}", :ident => 2
121
- print_wrapped "Web server IP: #{app.web_server_ip}", :ident => 2
121
+ print_wrapped "Web server IP: #{app.web_server_ip.join(', ')}", :ident => 2
122
122
  say_new_line
123
123
 
124
124
  print_wrapped "Usage:", :ident => 2
@@ -18,7 +18,7 @@ module Shelly
18
18
  require 'shelly/client/ssh_keys'
19
19
  require 'shelly/client/organizations'
20
20
  require 'shelly/client/auth'
21
- require 'shelly/client/cert'
21
+ require 'shelly/client/endpoint'
22
22
  require 'shelly/client/maintenance'
23
23
 
24
24
  def api_url
@@ -0,0 +1,25 @@
1
+ class Shelly::Client
2
+ def endpoints(cloud)
3
+ get("/apps/#{cloud}/endpoints")
4
+ end
5
+
6
+ def endpoint(cloud, uuid)
7
+ get("/apps/#{cloud}/endpoints/#{uuid}")
8
+ end
9
+
10
+ def create_endpoint(cloud, certificate, key, sni)
11
+ endpoint = certificate && key ? {:certificate => certificate,
12
+ :key => key} : {}
13
+
14
+ post("/apps/#{cloud}/endpoints", :endpoint => endpoint.merge(:sni => sni))
15
+ end
16
+
17
+ def update_endpoint(cloud, uuid, certificate, key)
18
+ put("/apps/#{cloud}/endpoints/#{uuid}",
19
+ :endpoint => {:certificate => certificate, :key => key})
20
+ end
21
+
22
+ def delete_endpoint(cloud, uuid)
23
+ delete("/apps/#{cloud}/endpoints/#{uuid}")
24
+ end
25
+ end
@@ -1,3 +1,3 @@
1
1
  module Shelly
2
- VERSION = "0.4.38"
2
+ VERSION = "0.4.39"
3
3
  end
@@ -541,20 +541,39 @@ describe Shelly::App do
541
541
  end
542
542
  end
543
543
 
544
- context "certificate" do
545
- it "#show_cert should query api" do
546
- @client.should_receive(:cert).with(@app.code_name)
547
- @app.cert
544
+ describe "#endpoints" do
545
+ it "should use api" do
546
+ @client.should_receive(:endpoints).with(@app.code_name)
547
+ @app.endpoints
548
548
  end
549
+ end
550
+
551
+ describe "#show_endpoint" do
552
+ it "should use api" do
553
+ @client.should_receive(:endpoint).with(@app.code_name, 'uuid')
554
+ @app.endpoint('uuid')
555
+ end
556
+ end
549
557
 
550
- it "#create_cert should query api" do
551
- @client.should_receive(:create_cert).with(@app.code_name, 'crt', 'key')
552
- @app.create_cert("crt", "key")
558
+ describe "#create_cert" do
559
+ it "should use api" do
560
+ @client.should_receive(:create_endpoint).with(@app.code_name, 'crt', 'key', true)
561
+ @app.create_endpoint("crt", "key", true)
553
562
  end
563
+ end
564
+
565
+ describe "#update_cert" do
566
+ it "should use api" do
567
+ @client.should_receive(:update_endpoint).with(@app.code_name, 'uuid',
568
+ "crt", "key")
569
+ @app.update_endpoint("uuid", "crt", "key")
570
+ end
571
+ end
554
572
 
555
- it "#update_cert should query api" do
556
- @client.should_receive(:update_cert).with(@app.code_name, 'crt', 'key')
557
- @app.update_cert("crt", "key")
573
+ describe "#delete_endpoint" do
574
+ it "should use api" do
575
+ @client.should_receive(:delete_endpoint).with(@app.code_name, "uuid")
576
+ @app.delete_endpoint("uuid")
558
577
  end
559
578
  end
560
579
 
@@ -233,7 +233,7 @@ describe Shelly::CLI::Backup do
233
233
  end
234
234
 
235
235
  it "should restore database" do
236
- $stdout.should_receive(:puts).with("You are about restore postgresql database for cloud foo-staging to state from better.tar.gz")
236
+ $stdout.should_receive(:puts).with("You are about to restore postgresql database for cloud foo-staging to state from better.tar.gz")
237
237
  $stdout.should_receive(:print).with("I want to restore the database (yes/no): ")
238
238
  $stdout.should_receive(:puts).with("\n")
239
239
  @client.stub(:restore_backup).with("todo-list-test","better.tar.gz")
@@ -247,7 +247,7 @@ describe Shelly::CLI::Backup do
247
247
 
248
248
  context "when answering no" do
249
249
  it "should cancel restore database" do
250
- $stdout.should_receive(:puts).with("You are about restore postgresql database for cloud foo-staging to state from better.tar.gz")
250
+ $stdout.should_receive(:puts).with("You are about to restore postgresql database for cloud foo-staging to state from better.tar.gz")
251
251
  $stdout.should_receive(:print).with("I want to restore the database (yes/no): ")
252
252
  $stdout.should_receive(:puts).with("\n")
253
253
  $stdout.should_receive(:puts).with(red "Canceled")
@@ -0,0 +1,197 @@
1
+ require "spec_helper"
2
+ require "shelly/cli/endpoint"
3
+
4
+ describe Shelly::CLI::Endpoint do
5
+ before do
6
+ FileUtils.stub(:chmod)
7
+ @cli = Shelly::CLI::Endpoint.new
8
+ Shelly::CLI::Endpoint.stub(:new).and_return(@cli)
9
+ @client = mock
10
+ Shelly::Client.stub(:new).and_return(@client)
11
+ @client.stub(:authorize!)
12
+ FileUtils.mkdir_p("/projects/foo")
13
+ Dir.chdir("/projects/foo")
14
+ @app = Shelly::App.new("foo-production")
15
+ Shelly::App.stub(:new).and_return(@app)
16
+ File.open("Cloudfile", 'w') { |f| f.write("foo-production:\n") }
17
+ end
18
+
19
+ describe "#index" do
20
+ it "should show all endpoints" do
21
+ @app.should_receive(:endpoints).and_return(endpoints_response)
22
+
23
+ $stdout.should_receive(:puts).with(green "Available HTTP endpoints")
24
+ $stdout.should_receive(:puts).with("\n")
25
+ $stdout.should_receive(:puts).with(" UUID | IP address | Certificate | SNI")
26
+ $stdout.should_receive(:puts).with(" uuid1 | 10.0.0.1 | example.com | \u2713")
27
+ $stdout.should_receive(:puts).with(" uuid2 | 10.0.0.2 | \u2717 | \u2717")
28
+
29
+ invoke(@cli, :list)
30
+ end
31
+
32
+ def endpoints_response
33
+ [
34
+ {'ip_address' => '10.0.0.1',
35
+ 'sni' => true,
36
+ 'uuid' => 'uuid1', 'info' => {
37
+ 'domain' => 'example.com',
38
+ 'issuer' => 'CA',
39
+ 'subjcet' => 'organization info',
40
+ 'since' => '2012-06-11 23:00:00 UTC',
41
+ 'to' => '2015-06-11 23:00:00 UTC'
42
+ }
43
+ },
44
+ {'ip_address' => '10.0.0.2',
45
+ 'sni' => false,
46
+ 'uuid' => 'uuid2', 'info' => {
47
+ 'domain' => nil,
48
+ 'issuer' => nil,
49
+ 'subjcet' => nil,
50
+ 'since' => nil,
51
+ 'to' => nil
52
+ }
53
+ }
54
+ ]
55
+ end
56
+
57
+ context "no endpoints" do
58
+ it "should display information" do
59
+ @app.should_receive(:endpoints).and_return([])
60
+ $stdout.should_receive(:puts).with("No HTTP endpoints available")
61
+ invoke(@cli, :list)
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "#show" do
67
+ it "should description" do
68
+ @app.should_receive(:endpoint).with('uuid1').and_return(endpoint_response)
69
+ $stdout.should_receive(:puts).with("UUID: uuid1")
70
+ $stdout.should_receive(:puts).with("IP address: 10.0.0.1")
71
+ $stdout.should_receive(:puts).with("SNI: \u2713")
72
+ $stdout.should_receive(:puts).with("\n")
73
+ $stdout.should_receive(:puts).with(green "Certificate details:")
74
+ $stdout.should_receive(:puts).with("Domain: example.com")
75
+ $stdout.should_receive(:puts).with("Issuer: CA")
76
+ $stdout.should_receive(:puts).with("Subject: organization info")
77
+ $stdout.should_receive(:puts).with("Not valid before:"\
78
+ " #{Time.parse(endpoint_response['info']['since']).getlocal.strftime("%Y-%m-%d %H:%M:%S")}")
79
+ $stdout.should_receive(:puts).with("Expires:"\
80
+ " #{Time.parse(endpoint_response['info']['to']).getlocal.strftime("%Y-%m-%d %H:%M:%S")}")
81
+ invoke(@cli, :show, 'uuid1')
82
+ end
83
+
84
+ context "endpoint not found" do
85
+ it "should exit" do
86
+ exception = Shelly::Client::NotFoundException.new("resource" => "endpoint")
87
+ @app.should_receive(:endpoint).with('uuid').and_raise(exception)
88
+ $stdout.should_receive(:puts).with(red "Endpoint not found")
89
+ lambda {
90
+ invoke(@cli, :show, 'uuid')
91
+ }.should raise_error(SystemExit)
92
+ end
93
+ end
94
+ end
95
+
96
+ describe "#create" do
97
+ before do
98
+ File.stub(:read).with('crt_path').and_return('crt')
99
+ File.stub(:read).with('key_path').and_return('key')
100
+ File.stub(:read).with('bundle_path').and_return('bundle')
101
+ end
102
+
103
+ it "should create endpoint" do
104
+ @app.should_receive(:create_endpoint).with("crt\n", "key", true).
105
+ and_return(endpoint_response('ip_address' => '10.0.0.1'))
106
+
107
+ $stdout.should_receive(:puts).with(green "Endpoint was created for #{@app.to_s} cloud")
108
+ $stdout.should_receive(:puts).with("Deployed certificate on front end servers.")
109
+ $stdout.should_receive(:puts).with("Point your domain to private IP address: 10.0.0.1")
110
+
111
+ @cli.options = {"sni" => true}
112
+ invoke(@cli, :create, "crt_path", "key_path")
113
+ end
114
+
115
+ context "validation errors" do
116
+ it "should show errors and exit" do
117
+ exception = Shelly::Client::ValidationException.new({"errors" => [["key", "is invalid"]]})
118
+ @app.should_receive(:create_endpoint).and_raise(exception)
119
+ $stdout.should_receive(:puts).with(red "Key is invalid")
120
+
121
+ lambda {
122
+ invoke(@cli, :create, "crt_path", "key_path", "bundle_path")
123
+ }.should raise_error(SystemExit)
124
+ end
125
+ end
126
+
127
+ context "providing one only part of certificate" do
128
+ it "should show error and exit" do
129
+ @app.should_not_receive(:create_endpoint)
130
+ $stdout.should_receive(:puts).with(red "Provide both certificate and key")
131
+
132
+ lambda {
133
+ invoke(@cli, :create, "crt_path")
134
+ }.should raise_error(SystemExit)
135
+ end
136
+ end
137
+ end
138
+
139
+ describe "#update" do
140
+ before do
141
+ File.stub(:read).with('crt_path').and_return('crt')
142
+ File.stub(:read).with('key_path').and_return('key')
143
+ File.stub(:read).with('bundle_path').and_return('bundle')
144
+ end
145
+
146
+ it "should create endpoint" do
147
+ @app.should_receive(:update_endpoint).with('uuid', "crt\nbundle", "key").
148
+ and_return(endpoint_response)
149
+ $stdout.should_receive(:puts).with(green "Endpoint was updated")
150
+ $stdout.should_receive(:puts).with("Deployed certificate on front end servers.")
151
+ $stdout.should_receive(:puts).with("Point your domain to private IP address: 10.0.0.1")
152
+
153
+ invoke(@cli, :update, 'uuid', "crt_path", "key_path", "bundle_path")
154
+ end
155
+
156
+ context "validation errors" do
157
+ it "should show errors and exit" do
158
+ exception = Shelly::Client::ValidationException.new({"errors" => [["key", "is invalid"]]})
159
+ @app.should_receive(:update_endpoint).and_raise(exception)
160
+ $stdout.should_receive(:puts).with(red "Key is invalid")
161
+
162
+ lambda {
163
+ invoke(@cli, :update, 'uuid', "crt_path", "key_path", "bundle_path")
164
+ }.should raise_error(SystemExit)
165
+ end
166
+ end
167
+ end
168
+
169
+ describe "#delete" do
170
+ it "should ask to delete endpoint" do
171
+ @app.should_receive(:endpoint).with('uuid').
172
+ and_return(endpoint_response)
173
+ @app.should_receive(:delete_endpoint).with('uuid')
174
+
175
+ $stdout.should_receive(:puts).with(yellow "Removing endpoint will release 10.0.0.1 IP address.")
176
+ $stdout.should_receive(:print).with("Are you sure you want to delete endpoint (yes/no): ")
177
+ $stdout.should_receive(:puts).with("Endpoint was deleted")
178
+
179
+ fake_stdin(["yes"]) do
180
+ invoke(@cli, :delete, 'uuid')
181
+ end
182
+
183
+ end
184
+ end
185
+
186
+ def endpoint_response(options = {})
187
+ {'ip_address' => '10.0.0.1', 'sni' => true,
188
+ 'uuid' => 'uuid1', 'info' => {
189
+ 'domain' => 'example.com',
190
+ 'issuer' => 'CA',
191
+ 'subject' => 'organization info',
192
+ 'since' => '2012-06-11 23:00:00 UTC',
193
+ 'to' => '2015-06-11 23:00:00 UTC'
194
+ }
195
+ }.merge(options)
196
+ end
197
+ end
@@ -1176,7 +1176,7 @@ Wait until cloud is in 'turned off' state and try again.")
1176
1176
  }
1177
1177
  }
1178
1178
  },
1179
- "web_server_ip" => "22.22.22.22"}.merge(options)
1179
+ "web_server_ip" => ["22.22.22.22"]}.merge(options)
1180
1180
  end
1181
1181
  end
1182
1182
 
@@ -432,22 +432,32 @@ describe Shelly::Client do
432
432
  end
433
433
  end
434
434
 
435
- context "certificate" do
436
- it "#cert should perform a get request" do
437
- @client.should_receive(:get).with("/apps/staging-foo/cert")
438
- @client.cert("staging-foo")
435
+ context "endpoints" do
436
+ it "#endpoints should perform a get request" do
437
+ @client.should_receive(:get).with("/apps/staging-foo/endpoints")
438
+ @client.endpoints("staging-foo")
439
439
  end
440
440
 
441
- it "#create_cert should perform a post request" do
442
- @client.should_receive(:post).with("/apps/staging-foo/cert",
443
- :cert => {:content => 'crt', :key => 'key'})
444
- @client.create_cert("staging-foo", "crt", "key")
441
+ it "#endpoint should perform a get request" do
442
+ @client.should_receive(:get).with("/apps/staging-foo/endpoints/uuid")
443
+ @client.endpoint("staging-foo", 'uuid')
445
444
  end
446
445
 
447
- it "#update_cert should perform a put request" do
448
- @client.should_receive(:put).with("/apps/staging-foo/cert",
449
- :cert => {:content => 'crt', :key => 'key'})
450
- @client.update_cert("staging-foo", "crt", "key")
446
+ it "#create_endpoint should perform a post request" do
447
+ @client.should_receive(:post).with("/apps/staging-foo/endpoints",
448
+ :endpoint => {:certificate => 'crt', :key => 'key', :sni => true})
449
+ @client.create_endpoint("staging-foo", 'crt', 'key', true)
450
+ end
451
+
452
+ it "#update_endpoint should perform a put request" do
453
+ @client.should_receive(:put).with("/apps/staging-foo/endpoints/uuid",
454
+ :endpoint => {:certificate => 'crt', :key => 'key'})
455
+ @client.update_endpoint("staging-foo", 'uuid', 'crt', 'key')
456
+ end
457
+
458
+ it "#delete_endpoint should perform a delete request" do
459
+ @client.should_receive(:delete).with("/apps/staging-foo/endpoints/uuid")
460
+ @client.delete_endpoint('staging-foo', 'uuid')
451
461
  end
452
462
  end
453
463
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shelly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.38
4
+ version: 0.4.39
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shelly Cloud team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-20 00:00:00.000000000 Z
11
+ date: 2014-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -257,11 +257,11 @@ files:
257
257
  - lib/shelly/app.rb
258
258
  - lib/shelly/backup.rb
259
259
  - lib/shelly/cli/backup.rb
260
- - lib/shelly/cli/cert.rb
261
260
  - lib/shelly/cli/command.rb
262
261
  - lib/shelly/cli/config.rb
263
262
  - lib/shelly/cli/database.rb
264
263
  - lib/shelly/cli/deploy.rb
264
+ - lib/shelly/cli/endpoint.rb
265
265
  - lib/shelly/cli/errors.rb
266
266
  - lib/shelly/cli/file.rb
267
267
  - lib/shelly/cli/logs.rb
@@ -276,11 +276,11 @@ files:
276
276
  - lib/shelly/client/application_logs.rb
277
277
  - lib/shelly/client/apps.rb
278
278
  - lib/shelly/client/auth.rb
279
- - lib/shelly/client/cert.rb
280
279
  - lib/shelly/client/configs.rb
281
280
  - lib/shelly/client/database_backups.rb
282
281
  - lib/shelly/client/deployment_logs.rb
283
282
  - lib/shelly/client/deploys.rb
283
+ - lib/shelly/client/endpoint.rb
284
284
  - lib/shelly/client/errors.rb
285
285
  - lib/shelly/client/maintenance.rb
286
286
  - lib/shelly/client/organizations.rb
@@ -310,11 +310,11 @@ files:
310
310
  - spec/shelly/app_spec.rb
311
311
  - spec/shelly/backup_spec.rb
312
312
  - spec/shelly/cli/backup_spec.rb
313
- - spec/shelly/cli/cert_spec.rb
314
313
  - spec/shelly/cli/command_spec.rb
315
314
  - spec/shelly/cli/config_spec.rb
316
315
  - spec/shelly/cli/database_spec.rb
317
316
  - spec/shelly/cli/deploy_spec.rb
317
+ - spec/shelly/cli/endpoint_spec.rb
318
318
  - spec/shelly/cli/file_spec.rb
319
319
  - spec/shelly/cli/logs_spec.rb
320
320
  - spec/shelly/cli/main_spec.rb
@@ -353,7 +353,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
353
353
  version: '0'
354
354
  requirements: []
355
355
  rubyforge_project: shelly
356
- rubygems_version: 2.4.2
356
+ rubygems_version: 2.2.2
357
357
  signing_key:
358
358
  specification_version: 4
359
359
  summary: Shelly Cloud command line tool
@@ -363,11 +363,11 @@ test_files:
363
363
  - spec/shelly/app_spec.rb
364
364
  - spec/shelly/backup_spec.rb
365
365
  - spec/shelly/cli/backup_spec.rb
366
- - spec/shelly/cli/cert_spec.rb
367
366
  - spec/shelly/cli/command_spec.rb
368
367
  - spec/shelly/cli/config_spec.rb
369
368
  - spec/shelly/cli/database_spec.rb
370
369
  - spec/shelly/cli/deploy_spec.rb
370
+ - spec/shelly/cli/endpoint_spec.rb
371
371
  - spec/shelly/cli/file_spec.rb
372
372
  - spec/shelly/cli/logs_spec.rb
373
373
  - spec/shelly/cli/main_spec.rb
@@ -1,99 +0,0 @@
1
- require "shelly/cli/command"
2
-
3
- module Shelly
4
- module CLI
5
- class Cert < Command
6
- namespace :cert
7
- include Helpers
8
-
9
- before_hook :logged_in?, :only => [:show, :create, :update]
10
-
11
- class_option :cloud, :type => :string, :aliases => "-c", :desc => "Specify cloud"
12
-
13
- desc "show", "Show current certificate information"
14
- def show
15
- app = multiple_clouds(options[:cloud], "backup list")
16
-
17
- cert = app.cert
18
- say "Issuer: #{cert['info']['issuer']}"
19
- say "Subject: #{cert['info']['subject']}"
20
- say "Not valid before: #{Time.parse(cert['info']['since']).
21
- getlocal.strftime("%Y-%m-%d %H:%M:%S")}"
22
- say "Expires: #{Time.parse(cert['info']['to']).
23
- getlocal.strftime("%Y-%m-%d %H:%M:%S")}"
24
- rescue Client::NotFoundException => e
25
- raise unless e.resource == :certificate
26
- say_error "Certificate not found"
27
- end
28
-
29
- desc "create CERT_PATH KEY_PATH [BUNDLE_PATH]", "Add certificate to your cloud"
30
- long_desc %{
31
- Add certificate to your cloud.\n
32
- CERT_PATH - path to certificate.\n
33
- KEY_PATH - path to private key.\n
34
- BUNDLE_PATH - optional path to certificate bundle path.
35
- }
36
- def create(cert_path, key_path, bundle_path = nil)
37
- app = multiple_clouds(options[:cloud], "cert create CERT_PATH [BUNDLE_PATH] KEY_PATH")
38
-
39
- content = ::File.read(cert_path).strip
40
- bundle = bundle_path ? ::File.read(bundle_path).strip : ""
41
- key = ::File.read(key_path).strip
42
-
43
- content = content + "\n" + bundle
44
- cert = app.create_cert(content, key)
45
-
46
- say "Certificate was added to your cloud", :green
47
- if cert['ip_address']
48
- say "Deploying certificate on front end."
49
- say "Point your domain to private IP address: #{cert['ip_address']}"
50
- else
51
- say "SSL requires certificate and private IP address."
52
- say "Private IP address was requested for your cloud."
53
- say "Support has been notified and will contact you shortly."
54
- end
55
- rescue Client::ValidationException => e
56
- e.each_error { |error| say_error error, :with_exit => false }
57
- exit 1
58
- rescue Client::ConflictException => e
59
- say_error e[:message]
60
- end
61
-
62
- desc "update CERT_PATH KEY_PATH [BUNDLE_PATH]", "Update current certificate"
63
- long_desc %{
64
- Update current certificate.\n
65
- CERT_PATH - path to certificate.\n
66
- KEY_PATH - path to private key.\n
67
- BUNDLE_PATH - optional path to certificate bundle path.
68
- }
69
- def update(cert_path, key_path, bundle_path = nil)
70
- app = multiple_clouds(options[:cloud], "cert update CERT_PATH [BUNDLE_PATH] KEY_PATH")
71
-
72
- content = ::File.read(cert_path).strip
73
- bundle = bundle_path ? ::File.read(bundle_path).strip : ""
74
- key = ::File.read(key_path).strip
75
-
76
- content = content + "\n" + bundle
77
- cert = app.update_cert(content, key)
78
-
79
- say "Certificate was updated", :green
80
- if cert['ip_address']
81
- say "Deploying certificate on front end."
82
- say "Point your domain to private IP address: #{cert['ip_address']}"
83
- else
84
- say "SSL requires certificate and private IP address."
85
- say "Private IP address was requested for your cloud."
86
- say "Support has been notified and will contact you shortly."
87
- end
88
- rescue Client::ValidationException => e
89
- e.each_error { |error| say_error error, :with_exit => false }
90
- exit 1
91
- rescue Client::NotFoundException => e
92
- raise unless e.resource == :certificate
93
- say_error "Certificate not found"
94
- rescue Client::ConflictException => e
95
- say_error e[:message]
96
- end
97
- end
98
- end
99
- end
@@ -1,13 +0,0 @@
1
- class Shelly::Client
2
- def cert(cloud)
3
- get("/apps/#{cloud}/cert")
4
- end
5
-
6
- def create_cert(cloud, content, key)
7
- post("/apps/#{cloud}/cert", :cert => {:content => content, :key => key})
8
- end
9
-
10
- def update_cert(cloud, content, key)
11
- put("/apps/#{cloud}/cert", :cert => {:content => content, :key => key})
12
- end
13
- end
@@ -1,161 +0,0 @@
1
- require "spec_helper"
2
- require "shelly/cli/cert"
3
-
4
- describe Shelly::CLI::Cert do
5
- before do
6
- FileUtils.stub(:chmod)
7
- @cli = Shelly::CLI::Cert.new
8
- Shelly::CLI::Cert.stub(:new).and_return(@cli)
9
- @client = mock
10
- Shelly::Client.stub(:new).and_return(@client)
11
- @client.stub(:authorize!)
12
- FileUtils.mkdir_p("/projects/foo")
13
- Dir.chdir("/projects/foo")
14
- @app = Shelly::App.new("foo-production")
15
- Shelly::App.stub(:new).and_return(@app)
16
- File.open("Cloudfile", 'w') { |f| f.write("foo-production:\n") }
17
- end
18
-
19
- describe "#show" do
20
- it "should description" do
21
- @app.should_receive(:cert).and_return(cert_response)
22
- $stdout.should_receive(:puts).with("Issuer: Some issuer")
23
- $stdout.should_receive(:puts).with("Subject: Some subject")
24
- $stdout.should_receive(:puts).with("Not valid before:"\
25
- " #{Time.parse(cert_response['info']['since']).getlocal.strftime("%Y-%m-%d %H:%M:%S")}")
26
- $stdout.should_receive(:puts).with("Expires:"\
27
- " #{Time.parse(cert_response['info']['to']).getlocal.strftime("%Y-%m-%d %H:%M:%S")}")
28
- invoke(@cli, :show)
29
- end
30
-
31
- context "certificate not found" do
32
- it "should exit" do
33
- exception = Shelly::Client::NotFoundException.new("resource" => "certificate")
34
- @app.should_receive(:cert).and_raise(exception)
35
- $stdout.should_receive(:puts).with(red "Certificate not found")
36
- lambda {
37
- invoke(@cli, :show)
38
- }.should raise_error(SystemExit)
39
- end
40
- end
41
- end
42
-
43
- describe "#create" do
44
- before do
45
- File.stub(:read).with('crt_path').and_return('crt')
46
- File.stub(:read).with('key_path').and_return('key')
47
- File.stub(:read).with('bundle_path').and_return('bundle')
48
- end
49
-
50
- it "should create certificate" do
51
- @app.should_receive(:create_cert).with("crt\nbundle", "key").
52
- and_return(cert_response)
53
- $stdout.should_receive(:puts).with(green "Certificate was added to your cloud")
54
- $stdout.should_receive(:puts).with("Deploying certificate on front end.")
55
- $stdout.should_receive(:puts).with("Point your domain to private IP address: 10.0.0.1")
56
-
57
- invoke(@cli, :create, "crt_path", "key_path", "bundle_path")
58
- end
59
-
60
- it "should create certificate without bundle" do
61
- @app.should_receive(:create_cert).with("crt\n", "key").
62
- and_return(cert_response('ip_address' => nil))
63
-
64
- $stdout.should_receive(:puts).with(green "Certificate was added to your cloud")
65
- $stdout.should_receive(:puts).with("SSL requires certificate and private IP address.")
66
- $stdout.should_receive(:puts).with("Private IP address was requested for your cloud.")
67
- $stdout.should_receive(:puts).with("Support has been notified and will contact you shortly.")
68
-
69
- invoke(@cli, :create, "crt_path", "key_path")
70
- end
71
-
72
- context "validation errors" do
73
- it "should show errors and exit" do
74
- exception = Shelly::Client::ValidationException.new({"errors" => [["key", "is invalid"]]})
75
- @app.should_receive(:create_cert).and_raise(exception)
76
- $stdout.should_receive(:puts).with(red "Key is invalid")
77
-
78
- lambda {
79
- invoke(@cli, :create, "crt_path", "key_path", "bundle_path")
80
- }.should raise_error(SystemExit)
81
- end
82
- end
83
-
84
- context "deployment conflict" do
85
- it "should show errors and exit" do
86
- exception = Shelly::Client::ConflictException.new({"message" => "Deployment is in progress"})
87
- @app.should_receive(:create_cert).and_raise(exception)
88
- $stdout.should_receive(:puts).with(red "Deployment is in progress")
89
-
90
- lambda {
91
- invoke(@cli, :create, "crt_path", "key_path", "bundle_path")
92
- }.should raise_error(SystemExit)
93
- end
94
- end
95
- end
96
-
97
- describe "#update" do
98
- before do
99
- File.stub(:read).with('crt_path').and_return('crt')
100
- File.stub(:read).with('key_path').and_return('key')
101
- File.stub(:read).with('bundle_path').and_return('bundle')
102
- end
103
-
104
- it "should create certificate" do
105
- @app.should_receive(:update_cert).with("crt\nbundle", "key").
106
- and_return(cert_response)
107
- $stdout.should_receive(:puts).with(green "Certificate was updated")
108
- $stdout.should_receive(:puts).with("Deploying certificate on front end.")
109
- $stdout.should_receive(:puts).with("Point your domain to private IP address: 10.0.0.1")
110
-
111
- invoke(@cli, :update, "crt_path", "key_path", "bundle_path")
112
- end
113
-
114
- it "should create certificate without bundle" do
115
- @app.should_receive(:update_cert).with("crt\n", "key").
116
- and_return(cert_response('ip_address' => nil))
117
-
118
- $stdout.should_receive(:puts).with(green "Certificate was updated")
119
- $stdout.should_receive(:puts).with("SSL requires certificate and private IP address.")
120
- $stdout.should_receive(:puts).with("Private IP address was requested for your cloud.")
121
- $stdout.should_receive(:puts).with("Support has been notified and will contact you shortly.")
122
-
123
- invoke(@cli, :update, "crt_path", "key_path")
124
- end
125
-
126
- context "validation errors" do
127
- it "should show errors and exit" do
128
- exception = Shelly::Client::ValidationException.new({"errors" => [["key", "is invalid"]]})
129
- @app.should_receive(:update_cert).and_raise(exception)
130
- $stdout.should_receive(:puts).with(red "Key is invalid")
131
-
132
- lambda {
133
- invoke(@cli, :update, "crt_path", "key_path", "bundle_path")
134
- }.should raise_error(SystemExit)
135
- end
136
- end
137
-
138
- context "deployment conflict" do
139
- it "should show errors and exit" do
140
- exception = Shelly::Client::ConflictException.new({"message" => "Deployment is in progress"})
141
- @app.should_receive(:update_cert).and_raise(exception)
142
- $stdout.should_receive(:puts).with(red "Deployment is in progress")
143
-
144
- lambda {
145
- invoke(@cli, :update, "crt_path", "key_path", "bundle_path")
146
- }.should raise_error(SystemExit)
147
- end
148
- end
149
- end
150
-
151
- def cert_response(options = {})
152
- {
153
- 'info' => {
154
- 'issuer' => 'Some issuer',
155
- 'subject' => 'Some subject',
156
- 'since' => '2012-06-11 23:00:00 UTC',
157
- 'to' => '2013-06-11 11:00:00 UTC'},
158
- 'ip_address' => '10.0.0.1'
159
- }.merge(options)
160
- end
161
- end