shelly 0.4.42 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +9 -0
- data/lib/shelly/app.rb +8 -2
- data/lib/shelly/cli/config.rb +1 -1
- data/lib/shelly/cli/endpoint.rb +26 -1
- data/lib/shelly/cli/main.rb +1 -0
- data/lib/shelly/cli/main/add.rb +48 -19
- data/lib/shelly/cli/maintenance.rb +2 -2
- data/lib/shelly/client/apps.rb +2 -1
- data/lib/shelly/version.rb +1 -1
- data/spec/shelly/app_spec.rb +9 -1
- data/spec/shelly/cli/config_spec.rb +1 -1
- data/spec/shelly/cli/endpoint_spec.rb +125 -29
- data/spec/shelly/cli/main_spec.rb +121 -35
- data/spec/shelly/client_spec.rb +3 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b85bcd0e7111d1a7bdaf59a47384141a49fb347
|
4
|
+
data.tar.gz: c0279a7748d978b1cb427240b4b0c9a49dbbd039
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72a140d37c0f1027109b1a066e9ac6b9c4e8c785be895e46c3225b8b9c92f166b15ba72fc85439137bb3f0de2c18cfd0489d76b8a82085fe8d9bafd05a12409d
|
7
|
+
data.tar.gz: a9c4dc381a59cd781993d8a319767552ea013eea3aace1fead433a14a369cbe58f636baadc2db18cc5d3ce32ad156e2dce5868a62f49011ab5bed84e6165f6f5
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 0.5.0 / 2015-01-02
|
2
|
+
|
3
|
+
* [bugfix] Catch Conflict 409 when creating or updating endpoints
|
4
|
+
* [improvement] shelly info should print cloud region
|
5
|
+
* [improvement] shelly add should ask about organization name instead of number
|
6
|
+
from the list
|
7
|
+
* [improvement] Replaced zone with region
|
8
|
+
* [improvement] Allow user to choose region for the new cloud
|
9
|
+
|
1
10
|
## 0.4.42 / 2014-12-14
|
2
11
|
|
3
12
|
* [improvement] Added --server / -s option for shelly rake command, so user
|
data/lib/shelly/app.rb
CHANGED
@@ -11,10 +11,11 @@ module Shelly
|
|
11
11
|
DATABASE_KINDS = %w(postgresql mysql mongodb redis)
|
12
12
|
DATABASE_CHOICES = DATABASE_KINDS + %w(none)
|
13
13
|
SERVER_SIZES = %w(small large)
|
14
|
+
REGIONS = %w(EU NA)
|
14
15
|
|
15
16
|
attr_accessor :code_name, :databases, :ruby_version, :environment,
|
16
17
|
:git_url, :domains, :web_server_ip, :size, :thin,
|
17
|
-
:organization_name, :zone, :usage, :traffic
|
18
|
+
:organization_name, :zone, :region, :usage, :traffic
|
18
19
|
|
19
20
|
def initialize(code_name = nil)
|
20
21
|
self.code_name = code_name
|
@@ -71,7 +72,8 @@ module Shelly
|
|
71
72
|
def create
|
72
73
|
attributes = {:code_name => code_name,
|
73
74
|
:organization_name => organization_name,
|
74
|
-
:zone => zone
|
75
|
+
:zone => zone,
|
76
|
+
:region => @region}
|
75
77
|
response = shelly.create_app(attributes)
|
76
78
|
assign_attributes(response)
|
77
79
|
end
|
@@ -279,6 +281,10 @@ module Shelly
|
|
279
281
|
attributes["git_info"]
|
280
282
|
end
|
281
283
|
|
284
|
+
def region
|
285
|
+
attributes['region'] || @region
|
286
|
+
end
|
287
|
+
|
282
288
|
def state
|
283
289
|
attributes["state"]
|
284
290
|
end
|
data/lib/shelly/cli/config.rb
CHANGED
@@ -52,7 +52,7 @@ module Shelly
|
|
52
52
|
def create(path)
|
53
53
|
app = multiple_clouds(options[:cloud], "create #{path}")
|
54
54
|
if app.config_exists?(path)
|
55
|
-
say "File '#{path}' already exists. Use `shelly config edit #{path} --cloud #{
|
55
|
+
say "File '#{path}' already exists. Use `shelly config edit #{path} --cloud #{app}` to update it.", :red
|
56
56
|
else
|
57
57
|
output = open_editor(path)
|
58
58
|
app.create_config(path, output)
|
data/lib/shelly/cli/endpoint.rb
CHANGED
@@ -34,7 +34,6 @@ module Shelly
|
|
34
34
|
end
|
35
35
|
|
36
36
|
print_table(to_display, :ident => 2)
|
37
|
-
|
38
37
|
else
|
39
38
|
say "No HTTP endpoints available"
|
40
39
|
end
|
@@ -81,6 +80,18 @@ module Shelly
|
|
81
80
|
app = multiple_clouds(options[:cloud],
|
82
81
|
"endpoint create [CERT_PATH] [KEY_PATH] [BUNDLE_PATH]")
|
83
82
|
|
83
|
+
say "Every unique IP address assigned to endpoint costs 10€/month"
|
84
|
+
say "It's required for SSL/TLS"
|
85
|
+
if cert_path == nil && key_path == nil
|
86
|
+
say "You didn't provide certificate but it can be added later"
|
87
|
+
say "Assigned IP address can be used to catch all domains pointing to that address, without SSL/TLS enabled"
|
88
|
+
exit(0) unless yes?("Are you sure you want to create endpoint without certificate (yes/no):")
|
89
|
+
elsif app.endpoints.count > 0
|
90
|
+
ask_if_endpoints_were_already_created(app)
|
91
|
+
else
|
92
|
+
exit(0) unless yes?("Are you sure you want to create endpoint? (yes/no):")
|
93
|
+
end
|
94
|
+
|
84
95
|
certificate, key = read_certificate_components(cert_path, key_path,
|
85
96
|
bundle_path)
|
86
97
|
|
@@ -94,6 +105,8 @@ module Shelly
|
|
94
105
|
say "Private IP address was requested for your cloud."
|
95
106
|
say "Support has been notified and will contact you shortly."
|
96
107
|
end
|
108
|
+
rescue Client::ConflictException => e
|
109
|
+
say_error e['message']
|
97
110
|
rescue Client::ValidationException => e
|
98
111
|
e.each_error { |error| say_error error, :with_exit => false }
|
99
112
|
exit 1
|
@@ -127,6 +140,8 @@ module Shelly
|
|
127
140
|
rescue Client::ValidationException => e
|
128
141
|
e.each_error { |error| say_error error, :with_exit => false }
|
129
142
|
exit 1
|
143
|
+
rescue Client::ConflictException => e
|
144
|
+
say_error e['message']
|
130
145
|
rescue Client::NotFoundException => e
|
131
146
|
raise unless e.resource == :certificate
|
132
147
|
say_error "Endpoint not found"
|
@@ -168,6 +183,16 @@ module Shelly
|
|
168
183
|
[certificate, key]
|
169
184
|
end
|
170
185
|
end
|
186
|
+
|
187
|
+
def ask_if_endpoints_were_already_created(app)
|
188
|
+
cli = Shelly::CLI::Endpoint.new
|
189
|
+
cli.options = {:cloud => app}
|
190
|
+
cli.list
|
191
|
+
say_new_line
|
192
|
+
exit(0) unless yes?("You already have assigned endpoint(s). Are " \
|
193
|
+
"you sure you want to create another one with a new IP address? " \
|
194
|
+
"(yes/no):")
|
195
|
+
end
|
171
196
|
end
|
172
197
|
end
|
173
198
|
end
|
data/lib/shelly/cli/main.rb
CHANGED
@@ -111,6 +111,7 @@ module Shelly
|
|
111
111
|
app = multiple_clouds(options[:cloud], "info")
|
112
112
|
msg = info_show_last_deploy_logs(app)
|
113
113
|
say "Cloud #{app}:", app.in_deploy_failed_state? ? :red : :green
|
114
|
+
print_wrapped "Region: #{app.region}", :ident => 2
|
114
115
|
print_wrapped "State: #{app.state_description}#{msg}", :ident => 2
|
115
116
|
say_new_line
|
116
117
|
print_wrapped "Deployed commit sha: #{app.git_info["deployed_commit_sha"]}", :ident => 2
|
data/lib/shelly/cli/main/add.rb
CHANGED
@@ -17,6 +17,8 @@ module Shelly
|
|
17
17
|
:desc => "Skip Shelly Cloud requirements check"
|
18
18
|
method_option "zone", :type => :string, :hide => true,
|
19
19
|
:desc => "Create cloud in given zone"
|
20
|
+
method_option "region", :type => :string,
|
21
|
+
:desc => "Create cloud in given region"
|
20
22
|
desc "add", "Add a new cloud"
|
21
23
|
def add
|
22
24
|
check_options(options)
|
@@ -27,8 +29,13 @@ module Shelly
|
|
27
29
|
app.code_name = options["code-name"] || ask_for_code_name
|
28
30
|
app.databases = options["databases"] || ask_for_databases
|
29
31
|
app.size = options["size"] || "small"
|
30
|
-
app.organization_name = options["organization"] ||
|
31
|
-
|
32
|
+
app.organization_name = options["organization"] ||
|
33
|
+
ask_for_organization(options)
|
34
|
+
if options["zone"].present?
|
35
|
+
app.zone = options["zone"]
|
36
|
+
else
|
37
|
+
app.region = options["region"] || ask_for_region
|
38
|
+
end
|
32
39
|
|
33
40
|
app.create
|
34
41
|
say "Cloud '#{app}' created in '#{app.organization_name}' organization", :green
|
@@ -60,7 +67,7 @@ module Shelly
|
|
60
67
|
e.each_error { |error| say_error error, :with_exit => false }
|
61
68
|
say_new_line
|
62
69
|
say_error "Fix erros in the below command and type it again to create your cloud" , :with_exit => false
|
63
|
-
say_error "shelly add --code-name=#{app.code_name.downcase.dasherize} --databases=#{app.databases.join(',')} --organization=#{app.organization_name} --size=#{app.size}"
|
70
|
+
say_error "shelly add --code-name=#{app.code_name.downcase.dasherize} --databases=#{app.databases.join(',')} --organization=#{app.organization_name} --size=#{app.size} --region=#{app.region}"
|
64
71
|
rescue Client::ForbiddenException
|
65
72
|
say_error "You have to be the owner of '#{app.organization_name}' organization to add clouds"
|
66
73
|
rescue Client::NotFoundException => e
|
@@ -72,33 +79,33 @@ module Shelly
|
|
72
79
|
no_tasks do
|
73
80
|
def ask_for_organization(options)
|
74
81
|
organizations = Shelly::User.new.organizations
|
82
|
+
|
75
83
|
if organizations.blank?
|
76
84
|
ask_for_new_organization(options)
|
77
85
|
else
|
78
|
-
|
79
|
-
|
86
|
+
say "Select organization for this cloud:"
|
87
|
+
say_new_line
|
88
|
+
|
80
89
|
loop do
|
81
|
-
say "Select organization for this cloud:"
|
82
|
-
say_new_line
|
83
90
|
say "existing organizations:"
|
84
91
|
|
85
92
|
organizations.each_with_index do |organization, i|
|
86
93
|
print_wrapped "#{i + 1}) #{organization.name}", :ident => 2
|
87
94
|
end
|
88
|
-
say_new_line
|
89
|
-
|
90
|
-
print_wrapped "#{count + 1}) provide name for new organization", :ident => 2
|
91
95
|
|
92
|
-
|
93
|
-
|
94
|
-
end
|
95
|
-
|
96
|
-
if option_selected.to_i == count + 1
|
97
|
-
return ask_for_new_organization(options)
|
98
|
-
end
|
96
|
+
say green "Or leave empty to create a new organization"
|
97
|
+
say_new_line
|
99
98
|
|
100
|
-
|
101
|
-
|
99
|
+
selected = ask("Organization:")
|
100
|
+
if organizations.select { |o| o.name == selected }.present?
|
101
|
+
return selected
|
102
|
+
elsif selected.empty?
|
103
|
+
say_new_line
|
104
|
+
return ask_for_new_organization(options)
|
105
|
+
else
|
106
|
+
say_new_line
|
107
|
+
say_warning "#{selected} organization does not exist"
|
108
|
+
end
|
102
109
|
end
|
103
110
|
end
|
104
111
|
end
|
@@ -113,6 +120,28 @@ module Shelly
|
|
113
120
|
end
|
114
121
|
end
|
115
122
|
|
123
|
+
def ask_for_region
|
124
|
+
regions = Shelly::App::REGIONS
|
125
|
+
say "Select region for this cloud:"
|
126
|
+
say_new_line
|
127
|
+
|
128
|
+
loop do
|
129
|
+
say "available regions:"
|
130
|
+
|
131
|
+
regions.each_with_index do |region, i|
|
132
|
+
print_wrapped "#{i + 1}) #{region}", :ident => 2
|
133
|
+
end
|
134
|
+
say_new_line
|
135
|
+
|
136
|
+
selected = ask("Region:").upcase
|
137
|
+
if regions.include?(selected)
|
138
|
+
return selected
|
139
|
+
else
|
140
|
+
say_new_line
|
141
|
+
say_warning "#{selected} region is not available"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
116
145
|
end
|
117
146
|
end
|
118
147
|
end
|
@@ -21,10 +21,10 @@ module Shelly
|
|
21
21
|
say_new_line
|
22
22
|
|
23
23
|
maintenances.each do |maintenance|
|
24
|
-
started_at = Time.parse(maintenance['created_at']).
|
24
|
+
started_at = Time.parse(maintenance['created_at']).getlocal.
|
25
25
|
strftime('%Y-%m-%d %H:%M:%S')
|
26
26
|
finished_at = if maintenance['finished']
|
27
|
-
Time.parse(maintenance['updated_at']).
|
27
|
+
Time.parse(maintenance['updated_at']).getlocal.
|
28
28
|
strftime('%Y-%m-%d %H:%M:%S')
|
29
29
|
else
|
30
30
|
'in progress'
|
data/lib/shelly/client/apps.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
class Shelly::Client
|
2
2
|
def create_app(attributes)
|
3
3
|
organization = attributes.delete(:organization_name)
|
4
|
+
region = attributes.delete(:region)
|
4
5
|
zone = attributes.delete(:zone)
|
5
6
|
post("/apps", :app => attributes, :organization_name => organization,
|
6
|
-
:zone => zone)
|
7
|
+
:region => region, :zone => zone)
|
7
8
|
end
|
8
9
|
|
9
10
|
def delete_app(code_name)
|
data/lib/shelly/version.rb
CHANGED
data/spec/shelly/app_spec.rb
CHANGED
@@ -153,6 +153,7 @@ describe Shelly::App do
|
|
153
153
|
describe "#attributes" do
|
154
154
|
before do
|
155
155
|
@response = {"web_server_ip" => "192.0.2.1",
|
156
|
+
"region" => "EU",
|
156
157
|
"state" => "running",
|
157
158
|
"maintenance" => false,
|
158
159
|
"organization" => {
|
@@ -190,6 +191,12 @@ describe Shelly::App do
|
|
190
191
|
end
|
191
192
|
end
|
192
193
|
|
194
|
+
describe "#region" do
|
195
|
+
it "should return cloud region" do
|
196
|
+
@app.region.should == "EU"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
193
200
|
describe "#state" do
|
194
201
|
it "should return state of cloud" do
|
195
202
|
@app.state.should == "running"
|
@@ -356,7 +363,8 @@ describe Shelly::App do
|
|
356
363
|
attributes = {
|
357
364
|
:code_name => "fooo",
|
358
365
|
:organization_name => nil,
|
359
|
-
:zone => nil
|
366
|
+
:zone => nil,
|
367
|
+
:region => nil
|
360
368
|
}
|
361
369
|
@client.should_receive(:create_app).with(attributes).and_return("git_url" => "git@git.shellycloud.com:fooo.git",
|
362
370
|
"domains" => %w(fooo.shellyapp.com))
|
@@ -122,7 +122,7 @@ describe Shelly::CLI::Config do
|
|
122
122
|
it "should warn that config file already exists in specified path" do
|
123
123
|
Shelly::App.stub(:new).and_return(@app)
|
124
124
|
@app.stub(:config_exists? => true)
|
125
|
-
$stdout.should_receive(:puts).with(red "File 'new_config' already exists. Use `shelly config edit new_config --cloud ` to update it.")
|
125
|
+
$stdout.should_receive(:puts).with(red "File 'new_config' already exists. Use `shelly config edit new_config --cloud foo-production` to update it.")
|
126
126
|
invoke(@config, :create, "new_config")
|
127
127
|
end
|
128
128
|
|
@@ -29,31 +29,6 @@ describe Shelly::CLI::Endpoint do
|
|
29
29
|
invoke(@cli, :list)
|
30
30
|
end
|
31
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
32
|
context "no endpoints" do
|
58
33
|
it "should display information" do
|
59
34
|
@app.should_receive(:endpoints).and_return([])
|
@@ -98,28 +73,86 @@ describe Shelly::CLI::Endpoint do
|
|
98
73
|
File.stub(:read).with('crt_path').and_return('crt')
|
99
74
|
File.stub(:read).with('key_path').and_return('key')
|
100
75
|
File.stub(:read).with('bundle_path').and_return('bundle')
|
76
|
+
@app.stub(:endpoints).and_return([])
|
101
77
|
end
|
102
78
|
|
103
|
-
it "should create endpoint" do
|
79
|
+
it "should create endpoint with provided certificate" do
|
104
80
|
@app.should_receive(:create_endpoint).with("crt\n", "key", true).
|
105
81
|
and_return(endpoint_response('ip_address' => '10.0.0.1'))
|
106
82
|
|
83
|
+
$stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
|
84
|
+
$stdout.should_receive(:puts).with("It's required for SSL/TLS")
|
85
|
+
$stdout.should_receive(:print).with("Are you sure you want to create endpoint? (yes/no): ")
|
86
|
+
|
107
87
|
$stdout.should_receive(:puts).with(green "Endpoint was created for #{@app.to_s} cloud")
|
108
88
|
$stdout.should_receive(:puts).with("Deployed certificate on front end servers.")
|
109
89
|
$stdout.should_receive(:puts).with("Point your domain to private IP address: 10.0.0.1")
|
110
90
|
|
111
91
|
@cli.options = {"sni" => true}
|
112
|
-
|
92
|
+
fake_stdin(["yes"]) do
|
93
|
+
invoke(@cli, :create, "crt_path", "key_path")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "without certificate" do
|
98
|
+
it "should create endpoint" do
|
99
|
+
@app.should_receive(:create_endpoint).with(nil, nil, true).
|
100
|
+
and_return(endpoint_response('ip_address' => '10.0.0.1'))
|
101
|
+
|
102
|
+
$stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
|
103
|
+
$stdout.should_receive(:puts).with("It's required for SSL/TLS")
|
104
|
+
$stdout.should_receive(:puts).with("You didn't provide certificate but it can be added later")
|
105
|
+
$stdout.should_receive(:puts).with("Assigned IP address can be used to catch all domains pointing to that address, without SSL/TLS enabled")
|
106
|
+
$stdout.should_receive(:print).with("Are you sure you want to create endpoint without certificate (yes/no): ")
|
107
|
+
$stdout.should_receive(:puts).with(green "Endpoint was created for #{@app.to_s} cloud")
|
108
|
+
$stdout.should_receive(:puts).with("Point your domain to private IP address: 10.0.0.1")
|
109
|
+
|
110
|
+
@cli.options = {"sni" => true}
|
111
|
+
fake_stdin(["yes"]) do
|
112
|
+
invoke(@cli, :create)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "multiple endpoints" do
|
118
|
+
it "should create endpoint with provided certificate" do
|
119
|
+
@app.should_receive(:create_endpoint).with("crt\n", "key", nil).
|
120
|
+
and_return(endpoint_response('ip_address' => '10.0.0.1'))
|
121
|
+
@app.stub(:endpoints).and_return(endpoints_response)
|
122
|
+
|
123
|
+
$stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
|
124
|
+
$stdout.should_receive(:puts).with("It's required for SSL/TLS")
|
125
|
+
$stdout.should_receive(:puts).with(green "Available HTTP endpoints")
|
126
|
+
$stdout.should_receive(:puts).with("\n")
|
127
|
+
$stdout.should_receive(:puts).with(" UUID | IP address | Certificate | SNI")
|
128
|
+
$stdout.should_receive(:puts).with(" uuid1 | 10.0.0.1 | example.com | \u2713")
|
129
|
+
$stdout.should_receive(:puts).with(" uuid2 | 10.0.0.2 | \u2717 | \u2717")
|
130
|
+
$stdout.should_receive(:puts).with("\n")
|
131
|
+
$stdout.should_receive(:print).with("You already have assigned endpoint(s). Are you sure you want to create another one with a new IP address? (yes/no): ")
|
132
|
+
$stdout.should_receive(:puts).with(green "Endpoint was created for #{@app.to_s} cloud")
|
133
|
+
$stdout.should_receive(:puts).with("Deployed certificate on front end servers.")
|
134
|
+
$stdout.should_receive(:puts).with("Point your domain to private IP address: 10.0.0.1")
|
135
|
+
|
136
|
+
fake_stdin(["yes"]) do
|
137
|
+
invoke(@cli, :create, "crt_path", "key_path")
|
138
|
+
end
|
139
|
+
end
|
113
140
|
end
|
114
141
|
|
115
142
|
context "validation errors" do
|
116
143
|
it "should show errors and exit" do
|
117
144
|
exception = Shelly::Client::ValidationException.new({"errors" => [["key", "is invalid"]]})
|
118
145
|
@app.should_receive(:create_endpoint).and_raise(exception)
|
146
|
+
|
147
|
+
$stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
|
148
|
+
$stdout.should_receive(:puts).with("It's required for SSL/TLS")
|
149
|
+
$stdout.should_receive(:print).with("Are you sure you want to create endpoint? (yes/no): ")
|
119
150
|
$stdout.should_receive(:puts).with(red "Key is invalid")
|
120
151
|
|
121
152
|
lambda {
|
122
|
-
|
153
|
+
fake_stdin(["yes"]) do
|
154
|
+
invoke(@cli, :create, "crt_path", "key_path", "bundle_path")
|
155
|
+
end
|
123
156
|
}.should raise_error(SystemExit)
|
124
157
|
end
|
125
158
|
end
|
@@ -127,10 +160,35 @@ describe Shelly::CLI::Endpoint do
|
|
127
160
|
context "providing one only part of certificate" do
|
128
161
|
it "should show error and exit" do
|
129
162
|
@app.should_not_receive(:create_endpoint)
|
163
|
+
|
164
|
+
$stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
|
165
|
+
$stdout.should_receive(:puts).with("It's required for SSL/TLS")
|
166
|
+
$stdout.should_receive(:print).with("Are you sure you want to create endpoint? (yes/no): ")
|
130
167
|
$stdout.should_receive(:puts).with(red "Provide both certificate and key")
|
131
168
|
|
132
169
|
lambda {
|
133
|
-
|
170
|
+
fake_stdin(["yes"]) do
|
171
|
+
invoke(@cli, :create, "crt_path")
|
172
|
+
end
|
173
|
+
}.should raise_error(SystemExit)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context "conflict error" do
|
178
|
+
it "should show errors and exit" do
|
179
|
+
exception = Shelly::Client::ConflictException.new("message" =>
|
180
|
+
"That's an error")
|
181
|
+
@app.should_receive(:create_endpoint).and_raise(exception)
|
182
|
+
|
183
|
+
$stdout.should_receive(:puts).with("Every unique IP address assigned to endpoint costs 10\u20AC/month")
|
184
|
+
$stdout.should_receive(:puts).with("It's required for SSL/TLS")
|
185
|
+
$stdout.should_receive(:print).with("Are you sure you want to create endpoint? (yes/no): ")
|
186
|
+
$stdout.should_receive(:puts).with(red "That's an error")
|
187
|
+
|
188
|
+
lambda {
|
189
|
+
fake_stdin(["yes"]) do
|
190
|
+
invoke(@cli, :create, "crt_path", "key_path", "bundle_path")
|
191
|
+
end
|
134
192
|
}.should raise_error(SystemExit)
|
135
193
|
end
|
136
194
|
end
|
@@ -164,6 +222,19 @@ describe Shelly::CLI::Endpoint do
|
|
164
222
|
}.should raise_error(SystemExit)
|
165
223
|
end
|
166
224
|
end
|
225
|
+
|
226
|
+
context "conflict error" do
|
227
|
+
it "should show errors and exit" do
|
228
|
+
exception = Shelly::Client::ConflictException.new("message" =>
|
229
|
+
"That's an error")
|
230
|
+
@app.should_receive(:update_endpoint).and_raise(exception)
|
231
|
+
$stdout.should_receive(:puts).with(red "That's an error")
|
232
|
+
|
233
|
+
lambda {
|
234
|
+
invoke(@cli, :update, "crt_path", "key_path", "bundle_path")
|
235
|
+
}.should raise_error(SystemExit)
|
236
|
+
end
|
237
|
+
end
|
167
238
|
end
|
168
239
|
|
169
240
|
describe "#delete" do
|
@@ -183,6 +254,31 @@ describe Shelly::CLI::Endpoint do
|
|
183
254
|
end
|
184
255
|
end
|
185
256
|
|
257
|
+
def endpoints_response
|
258
|
+
[
|
259
|
+
{ 'ip_address' => '10.0.0.1',
|
260
|
+
'sni' => true,
|
261
|
+
'uuid' => 'uuid1', 'info' => {
|
262
|
+
'domain' => 'example.com',
|
263
|
+
'issuer' => 'CA',
|
264
|
+
'subjcet' => 'organization info',
|
265
|
+
'since' => '2012-06-11 23:00:00 UTC',
|
266
|
+
'to' => '2015-06-11 23:00:00 UTC'
|
267
|
+
}
|
268
|
+
},
|
269
|
+
{ 'ip_address' => '10.0.0.2',
|
270
|
+
'sni' => false,
|
271
|
+
'uuid' => 'uuid2', 'info' => {
|
272
|
+
'domain' => nil,
|
273
|
+
'issuer' => nil,
|
274
|
+
'subjcet' => nil,
|
275
|
+
'since' => nil,
|
276
|
+
'to' => nil
|
277
|
+
}
|
278
|
+
}
|
279
|
+
]
|
280
|
+
end
|
281
|
+
|
186
282
|
def endpoint_response(options = {})
|
187
283
|
{'ip_address' => '10.0.0.1', 'sni' => true,
|
188
284
|
'uuid' => 'uuid1', 'info' => {
|
@@ -317,6 +317,7 @@ describe Shelly::CLI::Main do
|
|
317
317
|
@app.stub(:git_remote_exist?).and_return(false)
|
318
318
|
@main.stub(:check => true)
|
319
319
|
@main.stub(:ask_for_organization)
|
320
|
+
@main.stub(:ask_for_region).and_return('EU')
|
320
321
|
end
|
321
322
|
|
322
323
|
# This spec tests inside_git_repository? hook
|
@@ -370,9 +371,29 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
|
|
370
371
|
invoke(@main, :add)
|
371
372
|
end
|
372
373
|
|
373
|
-
|
374
|
-
|
375
|
-
|
374
|
+
context "for zone param" do
|
375
|
+
it "should use zone from option" do
|
376
|
+
@app.should_receive(:zone=).with('zone')
|
377
|
+
@main.options = {"zone" => "zone"}
|
378
|
+
fake_stdin(["mycodename", ""]) do
|
379
|
+
invoke(@main, :add)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
it "should not ask about the region" do
|
384
|
+
@app.should_not_receive(:region=)
|
385
|
+
$stdout.should_not_receive(:puts).
|
386
|
+
with("Select region for this cloud:")
|
387
|
+
@main.options = {"zone" => "zone"}
|
388
|
+
fake_stdin(["mycodename", ""]) do
|
389
|
+
invoke(@main, :add)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
it "should use region from option" do
|
395
|
+
@app.should_receive(:region=).with('eu1')
|
396
|
+
@main.options = {"region" => "eu1"}
|
376
397
|
fake_stdin(["mycodename", ""]) do
|
377
398
|
invoke(@main, :add)
|
378
399
|
end
|
@@ -476,7 +497,7 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
|
|
476
497
|
@app.should_receive(:create).and_raise(exception)
|
477
498
|
$stdout.should_receive(:puts).with(red "Code name has been already taken")
|
478
499
|
$stdout.should_receive(:puts).with(red "Fix erros in the below command and type it again to create your cloud")
|
479
|
-
$stdout.should_receive(:puts).with(red "shelly add --code-name=big-letters --databases=postgresql --organization=org-name --size=small")
|
500
|
+
$stdout.should_receive(:puts).with(red "shelly add --code-name=big-letters --databases=postgresql --organization=org-name --size=small --region=EU")
|
480
501
|
lambda {
|
481
502
|
fake_stdin(["BiG_LETTERS", ""]) do
|
482
503
|
invoke(@main, :add)
|
@@ -608,7 +629,7 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
|
|
608
629
|
it "should use --organization option" do
|
609
630
|
@main.options = {"organization" => "foo"}
|
610
631
|
@app.should_receive(:organization_name=).with("foo")
|
611
|
-
fake_stdin(["
|
632
|
+
fake_stdin(["foo", "none"]) do
|
612
633
|
invoke(@main, :add)
|
613
634
|
end
|
614
635
|
end
|
@@ -618,46 +639,51 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
|
|
618
639
|
@client.stub(:organizations).and_return([{"name" => "aaa"}])
|
619
640
|
end
|
620
641
|
|
621
|
-
it "should ask user to choose organization
|
622
|
-
|
623
|
-
|
642
|
+
it "should ask user to choose organization" do
|
643
|
+
$stdout.should_receive(:puts).
|
644
|
+
with("Select organization for this cloud:")
|
624
645
|
$stdout.should_receive(:puts).with("existing organizations:")
|
625
646
|
$stdout.should_receive(:puts).with(" 1) aaa")
|
626
|
-
$stdout.should_receive(:puts).
|
627
|
-
|
628
|
-
|
647
|
+
$stdout.should_receive(:puts).
|
648
|
+
with(green "Or leave empty to create a new organization")
|
649
|
+
$stdout.should_receive(:print).with("Organization: ")
|
650
|
+
fake_stdin(["foo", "none", "aaa"]) do
|
629
651
|
invoke(@main, :add)
|
630
652
|
end
|
631
653
|
end
|
632
654
|
|
633
|
-
it "should
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
$stdout.should_receive(:print).with("Organization name (foo - default): ")
|
644
|
-
$stdout.should_receive(:puts).with(green "Organization 'org-name' created")
|
645
|
-
fake_stdin(["foooo", "none", "2", "org-name"]) do
|
655
|
+
it "should keep asking until user will provide a valid option" do
|
656
|
+
$stdout.should_receive(:print).with("Organization: ").twice
|
657
|
+
fake_stdin(["foo", "none", "bbb", "aaa"]) do
|
658
|
+
invoke(@main, :add)
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
it "should use choosen organization" do
|
663
|
+
@app.should_receive(:organization_name=).with("aaa")
|
664
|
+
fake_stdin(["foo", "none", "aaa"]) do
|
646
665
|
invoke(@main, :add)
|
647
666
|
end
|
648
667
|
end
|
649
668
|
|
650
|
-
it "should
|
669
|
+
it "should ask user to create a new organization" do
|
670
|
+
@app.should_receive(:organization_name=).with('org-name')
|
651
671
|
@client.should_receive(:create_organization).
|
652
672
|
with({:name => "org-name", :redeem_code => nil})
|
653
|
-
$stdout.should_receive(:
|
654
|
-
|
655
|
-
$stdout.should_receive(:puts).
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
673
|
+
$stdout.should_receive(:print).
|
674
|
+
with("Organization name (foo - default): ")
|
675
|
+
$stdout.should_receive(:puts).
|
676
|
+
with(green "Organization 'org-name' created")
|
677
|
+
fake_stdin(["foo", "none", "", "org-name"]) do
|
678
|
+
invoke(@main, :add)
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
682
|
+
it "should use --redeem-code option" do
|
683
|
+
@main.options = {'redeem-code' => 'discount'}
|
684
|
+
@client.should_receive(:create_organization).
|
685
|
+
with({:name => "org-name", :redeem_code => 'discount'})
|
686
|
+
fake_stdin(["foo", "none", "", "org-name"]) do
|
661
687
|
invoke(@main, :add)
|
662
688
|
end
|
663
689
|
end
|
@@ -668,8 +694,11 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
|
|
668
694
|
response = {"resource" => "organization"}
|
669
695
|
exception = Shelly::Client::NotFoundException.new(response)
|
670
696
|
@app.should_receive(:create).and_raise(exception)
|
671
|
-
$stdout.should_receive(:puts).
|
672
|
-
|
697
|
+
$stdout.should_receive(:puts).
|
698
|
+
with(red "Organization 'foo' not found")
|
699
|
+
$stdout.should_receive(:puts).
|
700
|
+
with(red "You can list organizations you have access to with" \
|
701
|
+
" `shelly organization list`")
|
673
702
|
|
674
703
|
expect do
|
675
704
|
fake_stdin(["foooo", "none"]) do
|
@@ -678,6 +707,59 @@ More info at http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository\e[0m
|
|
678
707
|
end.to raise_error(SystemExit)
|
679
708
|
end
|
680
709
|
end
|
710
|
+
|
711
|
+
context "for region" do
|
712
|
+
before do
|
713
|
+
@main.unstub(:ask_for_region)
|
714
|
+
end
|
715
|
+
|
716
|
+
it "should use the value from the --region option" do
|
717
|
+
@main.options = {"region" => "EU"}
|
718
|
+
@app.should_receive(:region=).with("EU")
|
719
|
+
fake_stdin(["foo", "none"]) do
|
720
|
+
invoke(@main, :add)
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
724
|
+
it "should ask user to choose the region" do
|
725
|
+
@app.should_receive(:region=).with("NA")
|
726
|
+
$stdout.should_receive(:puts).with("Select region for this cloud:")
|
727
|
+
$stdout.should_receive(:puts).with("available regions:")
|
728
|
+
$stdout.should_receive(:puts).with(" 1) EU")
|
729
|
+
$stdout.should_receive(:puts).with(" 2) NA")
|
730
|
+
$stdout.should_receive(:print).with("Region: ")
|
731
|
+
fake_stdin(["foo", "none", "NA"]) do
|
732
|
+
invoke(@main, :add)
|
733
|
+
end
|
734
|
+
end
|
735
|
+
|
736
|
+
context "when given region is not available" do
|
737
|
+
it "should print a warning message and ask again" do
|
738
|
+
$stdout.should_receive(:puts).
|
739
|
+
with(yellow "ASIA region is not available")
|
740
|
+
$stdout.should_receive(:puts).with("available regions:").twice
|
741
|
+
fake_stdin(["foo", "none", "ASIA", "NA"]) do
|
742
|
+
invoke(@main, :add)
|
743
|
+
end
|
744
|
+
end
|
745
|
+
end
|
746
|
+
|
747
|
+
context "when given region does not accepts new apps" do
|
748
|
+
it "should show that it is not available" do
|
749
|
+
@main.options = {"region" => "NA"}
|
750
|
+
response = {"error" => "Given region is unavailable"}
|
751
|
+
exception = Shelly::Client::ConflictException.new(response)
|
752
|
+
@app.should_receive(:create).and_raise(exception)
|
753
|
+
$stdout.should_receive(:puts).with(red "Given region is unavailable")
|
754
|
+
|
755
|
+
expect do
|
756
|
+
fake_stdin(["foo", "none", "NA"]) do
|
757
|
+
invoke(@main, :add)
|
758
|
+
end
|
759
|
+
end.to raise_error(SystemExit)
|
760
|
+
end
|
761
|
+
end
|
762
|
+
end
|
681
763
|
end
|
682
764
|
|
683
765
|
describe "#list" do
|
@@ -1006,6 +1088,7 @@ Wait until cloud is in 'turned off' state and try again.")
|
|
1006
1088
|
it "should display basic information about cloud" do
|
1007
1089
|
@main.should_receive(:multiple_clouds).and_return(@app)
|
1008
1090
|
$stdout.should_receive(:puts).with(green "Cloud foo-production:")
|
1091
|
+
$stdout.should_receive(:puts).with(" Region: EU")
|
1009
1092
|
$stdout.should_receive(:puts).with(" State: running")
|
1010
1093
|
$stdout.should_receive(:puts).with(" Deployed commit sha: 52e65ed2d085eaae560cdb81b2b56a7d76")
|
1011
1094
|
$stdout.should_receive(:puts).with(" Deployed commit message: Commit message")
|
@@ -1068,6 +1151,7 @@ Wait until cloud is in 'turned off' state and try again.")
|
|
1068
1151
|
"maintenance" => true}))
|
1069
1152
|
@main.should_receive(:multiple_clouds).and_return(@app)
|
1070
1153
|
$stdout.should_receive(:puts).with(red "Cloud foo-production:")
|
1154
|
+
$stdout.should_receive(:puts).with(" Region: EU")
|
1071
1155
|
$stdout.should_receive(:puts).with(" State: admin maintenance in progress")
|
1072
1156
|
$stdout.should_receive(:puts).with(" Deployed commit sha: 52e65ed2d085eaae560cdb81b2b56a7d76")
|
1073
1157
|
$stdout.should_receive(:puts).with(" Deployed commit message: Commit message")
|
@@ -1101,6 +1185,7 @@ Wait until cloud is in 'turned off' state and try again.")
|
|
1101
1185
|
"maintenance" => false}))
|
1102
1186
|
@main.should_receive(:multiple_clouds).and_return(@app)
|
1103
1187
|
$stdout.should_receive(:puts).with(red "Cloud foo-production:")
|
1188
|
+
$stdout.should_receive(:puts).with(" Region: EU")
|
1104
1189
|
$stdout.should_receive(:puts).with(" State: running (last deployment failed) (deployment log: `shelly deploys show last -c foo-production`)")
|
1105
1190
|
$stdout.should_receive(:puts).with(" Deployed commit sha: 52e65ed2d085eaae560cdb81b2b56a7d76")
|
1106
1191
|
$stdout.should_receive(:puts).with(" Deployed commit message: Commit message")
|
@@ -1148,6 +1233,7 @@ Wait until cloud is in 'turned off' state and try again.")
|
|
1148
1233
|
|
1149
1234
|
def response(options = {})
|
1150
1235
|
{ "code_name" => "foo-production",
|
1236
|
+
"region" => "EU",
|
1151
1237
|
"state" => "running",
|
1152
1238
|
"state_description" => "running",
|
1153
1239
|
"git_info" => {
|
data/spec/shelly/client_spec.rb
CHANGED
@@ -171,9 +171,10 @@ describe Shelly::Client do
|
|
171
171
|
describe "#create_app" do
|
172
172
|
it "should send post with app's attributes" do
|
173
173
|
@client.should_receive(:post).with("/apps", :app => {:code_name => "foo",
|
174
|
-
:ruby_version => "1.9.2"}, :organization_name => "foo", :
|
174
|
+
:ruby_version => "1.9.2"}, :organization_name => "foo", :region => 'EU',
|
175
|
+
:zone => nil)
|
175
176
|
@client.create_app(:code_name => "foo", :ruby_version => "1.9.2",
|
176
|
-
:organization_name => "foo", :
|
177
|
+
:organization_name => "foo", :region => "EU", :zone => nil)
|
177
178
|
end
|
178
179
|
end
|
179
180
|
|
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
|
+
version: 0.5.0
|
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:
|
11
|
+
date: 2015-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|