shelly 0.4.42 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|