rhc 0.92.11 → 0.93.18
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -9
- data/Rakefile +1 -55
- data/bin/rhc +31 -1
- data/bin/rhc-app +62 -127
- data/bin/rhc-chk +6 -7
- data/bin/rhc-create-app +8 -8
- data/bin/rhc-create-domain +6 -86
- data/bin/rhc-ctl-app +3 -3
- data/bin/rhc-ctl-domain +4 -4
- data/bin/rhc-domain +16 -18
- data/bin/rhc-domain-info +3 -3
- data/bin/rhc-port-forward +127 -24
- data/bin/rhc-snapshot +7 -46
- data/bin/rhc-sshkey +13 -79
- data/bin/rhc-tail-files +16 -8
- data/lib/rhc-common.rb +406 -230
- data/lib/rhc-rest.rb +3 -3
- data/lib/rhc-rest/client.rb +1 -1
- data/lib/rhc-rest/domain.rb +1 -1
- data/lib/rhc.rb +20 -0
- data/lib/rhc/cli.rb +38 -0
- data/lib/rhc/client.rb +15 -0
- data/lib/rhc/commands.rb +32 -0
- data/lib/rhc/commands/base.rb +67 -0
- data/lib/rhc/commands/server.rb +24 -0
- data/lib/rhc/config.rb +141 -0
- data/lib/rhc/core_ext.rb +15 -0
- data/lib/rhc/helpers.rb +142 -0
- data/lib/rhc/json.rb +52 -0
- data/lib/rhc/targz.rb +46 -0
- data/lib/rhc/vendor/okjson.rb +600 -0
- data/lib/rhc/vendor/zliby.rb +628 -0
- data/lib/rhc/wizard.rb +579 -0
- data/spec/rhc/assets/foo.txt +1 -0
- data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
- data/spec/rhc/assets/targz_sample.tar.gz +0 -0
- data/spec/rhc/cli_spec.rb +24 -0
- data/spec/rhc/command_spec.rb +88 -0
- data/spec/rhc/commands/server_spec.rb +39 -0
- data/spec/rhc/helpers_spec.rb +171 -0
- data/spec/rhc/json_spec.rb +30 -0
- data/spec/rhc/targz_spec.rb +42 -0
- data/spec/rhc/wizard_spec.rb +426 -0
- data/spec/spec_helper.rb +192 -0
- data/test/functional/application_test.rb +71 -0
- data/test/functional/domain_test.rb +123 -0
- data/test/functional/test_credentials.rb +5 -0
- data/test/sample-usage.rb +122 -0
- data/test/support/server.rb +14 -0
- data/test/support/testcase.rb +3 -0
- data/test/test_helper.rb +4 -0
- data/test/unit/command_test.rb +19 -0
- metadata +181 -29
- data/ext/mkrf_conf.rb +0 -58
- data/lib/rhc +0 -115
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
#require 'rubygems'
|
2
|
+
#require 'spec'
|
3
|
+
require 'webmock/rspec'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'simplecov'
|
7
|
+
SimpleCov.start do
|
8
|
+
add_filter 'lib/rhc-rest.rb'
|
9
|
+
add_filter 'lib/rhc-common.rb'
|
10
|
+
add_filter 'lib/helpers.rb'
|
11
|
+
add_filter 'lib/rhc/vendor/'
|
12
|
+
add_filter 'lib/rhc-rest/' #temporary
|
13
|
+
add_filter 'lib/rhc/wizard.rb' #temporary
|
14
|
+
add_filter 'lib/rhc/config.rb' #temporary
|
15
|
+
end
|
16
|
+
|
17
|
+
original_stderr = $stderr
|
18
|
+
at_exit do
|
19
|
+
begin
|
20
|
+
SimpleCov.result.format!
|
21
|
+
if SimpleCov.result.covered_percent < 100
|
22
|
+
original_stderr.puts "Coverage not 100%, build failed."
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
rescue
|
26
|
+
puts "No coverage check, older Ruby"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
rescue
|
30
|
+
end
|
31
|
+
|
32
|
+
#include 'mocha'
|
33
|
+
require 'rhc/cli'
|
34
|
+
|
35
|
+
include WebMock::API
|
36
|
+
|
37
|
+
module Commander::UI
|
38
|
+
alias :enable_paging_old :enable_paging
|
39
|
+
def enable_paging
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
module ClassSpecHelpers
|
45
|
+
|
46
|
+
include Commander::Delegates
|
47
|
+
|
48
|
+
def const_for(obj=nil)
|
49
|
+
if obj
|
50
|
+
Object.const_set(const_for, obj)
|
51
|
+
else
|
52
|
+
"#{description}".split(" ").map{|word| word.capitalize}.join.gsub(/[^\w]/, '')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
def new_command_runner *args, &block
|
56
|
+
Commander::Runner.instance_variable_set :"@singleton", Commander::Runner.new(args)
|
57
|
+
program :name, 'test'
|
58
|
+
program :version, '1.2.3'
|
59
|
+
program :description, 'something'
|
60
|
+
#create_test_command
|
61
|
+
yield if block
|
62
|
+
Commander::Runner.instance
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
#
|
67
|
+
#
|
68
|
+
def expects_running *args
|
69
|
+
mock_terminal
|
70
|
+
r = new_command_runner args do
|
71
|
+
instance #ensure instance is created before subject :new is mocked
|
72
|
+
subject.should_receive(:new).any_number_of_times.and_return(instance)
|
73
|
+
RHC::Commands.to_commander
|
74
|
+
end
|
75
|
+
lambda { r.run!; @output }
|
76
|
+
end
|
77
|
+
|
78
|
+
class MockHighLineTerminal < HighLine
|
79
|
+
def initialize(input, output)
|
80
|
+
super
|
81
|
+
@last_read_pos = 0
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# read
|
86
|
+
#
|
87
|
+
# seeks to the last read in the IO stream and reads
|
88
|
+
# the data from that position so we don't repeat
|
89
|
+
# reads or get empty data due to writes moving
|
90
|
+
# the caret to the end of the stream
|
91
|
+
def read
|
92
|
+
@output.seek(@last_read_pos)
|
93
|
+
result = @output.read
|
94
|
+
@last_read_pos = @output.pos
|
95
|
+
result
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# write_line
|
100
|
+
#
|
101
|
+
# writes a line of data to the end of the
|
102
|
+
# input stream appending a newline so
|
103
|
+
# highline knows to stop processing and then
|
104
|
+
# resets the caret position to the last read
|
105
|
+
def write_line(str)
|
106
|
+
reset_pos = @input.pos
|
107
|
+
# seek end so we don't overwrite anything
|
108
|
+
@input.seek(0, IO::SEEK_END)
|
109
|
+
result = @input.write "#{str}\n"
|
110
|
+
@input.seek(reset_pos)
|
111
|
+
result
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def mock_terminal
|
116
|
+
@input = StringIO.new
|
117
|
+
@output = StringIO.new
|
118
|
+
$stderr = (@error = StringIO.new)
|
119
|
+
$terminal = MockHighLineTerminal.new @input, @output
|
120
|
+
end
|
121
|
+
|
122
|
+
def run
|
123
|
+
#Commander::Runner.instance_variable_set :"@singleton", nil
|
124
|
+
mock_terminal
|
125
|
+
RHC::CLI.start(arguments)
|
126
|
+
"#{@output.string}\n#{$stderr.string}"
|
127
|
+
end
|
128
|
+
def run_output
|
129
|
+
run
|
130
|
+
rescue SystemExit => e
|
131
|
+
"#{@output.string}\n#{$stderr.string}#{e}"
|
132
|
+
else
|
133
|
+
"#{@output.string}\n#{$stderr.string}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
module ExitCodeMatchers
|
138
|
+
Spec::Matchers.define :exit_with_code do |code|
|
139
|
+
actual = nil
|
140
|
+
match do |block|
|
141
|
+
begin
|
142
|
+
block.call
|
143
|
+
rescue SystemExit => e
|
144
|
+
actual = e.status
|
145
|
+
else
|
146
|
+
actual = 0
|
147
|
+
end
|
148
|
+
actual and actual == code
|
149
|
+
end
|
150
|
+
failure_message_for_should do |block|
|
151
|
+
"expected block to call exit(#{code}) but exit" +
|
152
|
+
(actual.nil? ? " not called" : "(#{actual}) was called")
|
153
|
+
end
|
154
|
+
failure_message_for_should_not do |block|
|
155
|
+
"expected block not to call exit(#{code})"
|
156
|
+
end
|
157
|
+
description do
|
158
|
+
"expect block to call exit(#{code})"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
module CommanderInvocationMatchers
|
164
|
+
Spec::Matchers.define :call do |method|
|
165
|
+
chain :on do |object|
|
166
|
+
@object = object
|
167
|
+
end
|
168
|
+
chain :with do |args|
|
169
|
+
@args = args
|
170
|
+
end
|
171
|
+
|
172
|
+
match do |block|
|
173
|
+
e = @object.should_receive(method)
|
174
|
+
e.with(@args) if @args
|
175
|
+
begin
|
176
|
+
block.call
|
177
|
+
true
|
178
|
+
rescue SystemExit => e
|
179
|
+
false
|
180
|
+
end
|
181
|
+
end
|
182
|
+
description do
|
183
|
+
"expect block to invoke '#{method}' on #{@object} with #{@args}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
Spec::Runner.configure do |config|
|
189
|
+
config.include(ExitCodeMatchers)
|
190
|
+
config.include(CommanderInvocationMatchers)
|
191
|
+
config.include(ClassSpecHelpers)
|
192
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.expand_path('../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class ApplicationTest < Test::Unit::TestCase
|
4
|
+
setup :with_devenv
|
5
|
+
|
6
|
+
def teardown
|
7
|
+
if @client && @client.domains
|
8
|
+
@client.domains.each do |domain|
|
9
|
+
domain.delete(true)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_create_app
|
15
|
+
domain_name = "rhcrest#{@random}"
|
16
|
+
domain = @client.add_domain(domain_name)
|
17
|
+
assert domain.namespace == domain_name
|
18
|
+
app = domain.add_application("app", {:cartridge => "php-5.3"})
|
19
|
+
puts app
|
20
|
+
assert app.name == "app", "application name is not equal "
|
21
|
+
puts app.framework
|
22
|
+
assert app.framework == "php-5.3"
|
23
|
+
apps = @client.find_application("app")
|
24
|
+
assert apps.length == 1
|
25
|
+
assert apps.first.name == "app"
|
26
|
+
end
|
27
|
+
|
28
|
+
=begin
|
29
|
+
def test_create_scalable_app
|
30
|
+
domain_name = "rhcrest#{@random}"
|
31
|
+
domain = @client.add_domain(domain_name)
|
32
|
+
assert domain.namespace == domain_name
|
33
|
+
app = domain.add_application("app", {:cartridge => "php-5.3", :scale => true})
|
34
|
+
assert app.name == "app"
|
35
|
+
assert app.framework == "php-5.3"
|
36
|
+
assert app.scalable == true
|
37
|
+
apps = @client.find_application("app")
|
38
|
+
assert apps.length == 1
|
39
|
+
assert apps.first.name == "app"
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_create_app_with_small_node
|
43
|
+
domain_name = "rhcrest#{@random}"
|
44
|
+
domain = @client.add_domain(domain_name)
|
45
|
+
assert domain.namespace == domain_name
|
46
|
+
app = domain.add_application("app", {:cartridge => "php-5.3", :node_profile => "small"})
|
47
|
+
assert app.name == "app"
|
48
|
+
assert app.framework == "php-5.3"
|
49
|
+
assert app.node_profile = "small"
|
50
|
+
apps = @client.find_application("app")
|
51
|
+
assert apps.length == 1
|
52
|
+
assert apps.first.name == "app"
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_create_scalable_app_with_small_node
|
57
|
+
domain_name = "rhcrest#{@random}"
|
58
|
+
domain = @client.add_domain(domain_name)
|
59
|
+
assert domain.namespace == domain_name
|
60
|
+
app = domain.add_application("app", {:cartridge => "php-5.3", :scale => true, :node_profile => "small"})
|
61
|
+
assert app.name == "app"
|
62
|
+
assert app.framework == "php-5.3"
|
63
|
+
assert app.node_profile = "small"
|
64
|
+
assert app.scalable == true
|
65
|
+
apps = @client.find_application("app")
|
66
|
+
assert apps.length == 1
|
67
|
+
assert apps.first.name == "app"
|
68
|
+
end
|
69
|
+
=end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require File.expand_path('../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class DomainTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
setup :with_devenv
|
6
|
+
|
7
|
+
def teardown
|
8
|
+
if @client && @client.domains
|
9
|
+
@client.domains.each do |domain|
|
10
|
+
domain.delete(true)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_create_domain
|
16
|
+
|
17
|
+
domain_name = "rhcrest#{@random}"
|
18
|
+
|
19
|
+
domain = @client.add_domain(domain_name)
|
20
|
+
assert domain.namespace == domain_name
|
21
|
+
|
22
|
+
domains = @client.domains
|
23
|
+
assert domains.length == 1
|
24
|
+
domain = domains.first
|
25
|
+
assert domain.namespace == domain_name
|
26
|
+
|
27
|
+
domains = @client.find_domain(domain_name)
|
28
|
+
assert domains.length == 1
|
29
|
+
domain = domains.first
|
30
|
+
assert domain.namespace == domain_name
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_create_multiple_domains
|
35
|
+
|
36
|
+
domain_name = "rhcrest#{@random}"
|
37
|
+
domain = @client.add_domain(domain_name)
|
38
|
+
assert domain.namespace == domain_name
|
39
|
+
|
40
|
+
domains = @client.domains
|
41
|
+
assert domains.length == 1
|
42
|
+
domain = domains.first
|
43
|
+
assert domain.namespace == domain_name
|
44
|
+
|
45
|
+
domains = @client.find_domain(domain_name)
|
46
|
+
assert domains.length == 1
|
47
|
+
domain = domains.first
|
48
|
+
assert domain.namespace == domain_name
|
49
|
+
|
50
|
+
domain_name = "rhcrest#{@random}X"
|
51
|
+
domain = @client.add_domain(domain_name)
|
52
|
+
assert domain.namespace == domain_name
|
53
|
+
|
54
|
+
domains = @client.domains
|
55
|
+
assert domains.length == 2
|
56
|
+
|
57
|
+
domains = @client.find_domain(domain_name)
|
58
|
+
assert domains.length == 1
|
59
|
+
domain = domains.first
|
60
|
+
assert domain.namespace == domain_name
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_update_domain
|
64
|
+
|
65
|
+
domain_name = "rhcrest#{@random}"
|
66
|
+
domain = @client.add_domain(domain_name)
|
67
|
+
assert domain.namespace == domain_name
|
68
|
+
new_domain_name = "rhcrest#{@random}X"
|
69
|
+
domain = domain.update(new_domain_name)
|
70
|
+
|
71
|
+
domains = @client.domains
|
72
|
+
assert domains.length == 1
|
73
|
+
domain = domains.first
|
74
|
+
assert domain.namespace == new_domain_name
|
75
|
+
|
76
|
+
domains = @client.find_domain(new_domain_name)
|
77
|
+
assert domains.length == 1
|
78
|
+
domain = domains.first
|
79
|
+
assert domain.namespace == new_domain_name
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_update_domain_with_app
|
84
|
+
|
85
|
+
domain_name = "rhcrest#{@random}"
|
86
|
+
domain = @client.add_domain(domain_name)
|
87
|
+
assert domain.namespace == domain_name
|
88
|
+
app = domain.add_application("app", {:cartridge => "php-5.3"})
|
89
|
+
new_domain_name = "rhcrest#{@random}X"
|
90
|
+
domain = domain.update(new_domain_name)
|
91
|
+
|
92
|
+
domains = @client.domains
|
93
|
+
assert domains.length == 1
|
94
|
+
domain = domains.first
|
95
|
+
assert domain.namespace == new_domain_name
|
96
|
+
|
97
|
+
domains = @client.find_domain(new_domain_name)
|
98
|
+
assert domains.length == 1
|
99
|
+
domain = domains.first
|
100
|
+
assert domain.namespace == new_domain_name
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_delete_domain_with_app
|
105
|
+
|
106
|
+
domain_name = "rhcrest#{@random}"
|
107
|
+
domain = @client.add_domain(domain_name)
|
108
|
+
assert domain.namespace == domain_name
|
109
|
+
app = domain.add_application("app", {:cartridge => "php-5.3"})
|
110
|
+
assert_raise Rhc::Rest::ClientErrorException do
|
111
|
+
domain.delete
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_force_delete_domain_with_app
|
116
|
+
domain_name = "rhcrest#{@random}"
|
117
|
+
domain = @client.add_domain(domain_name)
|
118
|
+
assert domain.namespace == domain_name
|
119
|
+
app = domain.add_application("app", {:cartridge => "php-5.3"})
|
120
|
+
domain.delete(true)
|
121
|
+
assert @client.domains.length == 0
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright 2011 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require 'rhc-rest'
|
17
|
+
|
18
|
+
|
19
|
+
if __FILE__ == $0
|
20
|
+
|
21
|
+
end_point = ARGV[0]
|
22
|
+
username = ARGV[1]
|
23
|
+
password = ARGV[2]
|
24
|
+
domain_id = ARGV[3]
|
25
|
+
|
26
|
+
if end_point.nil? or username.nil? or password.nil? or domain_id.nil?
|
27
|
+
puts "Usage: https://<hostname>/broker/rest <username> <password> <domain_id>"
|
28
|
+
exit 1
|
29
|
+
end
|
30
|
+
@mydebug =true
|
31
|
+
client = Rhc::Rest::Client.new(end_point, username, password)
|
32
|
+
|
33
|
+
client.domains.each do |domain|
|
34
|
+
domain.applications.each do |app|
|
35
|
+
app.delete
|
36
|
+
end
|
37
|
+
domain.delete
|
38
|
+
end
|
39
|
+
puts "Creating a domain"
|
40
|
+
domain = client.add_domain(domain_id)
|
41
|
+
puts "Domain created: #{domain.id}"
|
42
|
+
|
43
|
+
puts "Getting all cartridges..."
|
44
|
+
client.cartridges.each do |cart|
|
45
|
+
puts " #{cart.name} (type: #{cart.type})"
|
46
|
+
end
|
47
|
+
|
48
|
+
puts "Creating application appone"
|
49
|
+
carts = client.find_cartridge("php-5.3")
|
50
|
+
domain.add_application("appone", {:cartridge => carts.first.name})
|
51
|
+
|
52
|
+
puts "Try deleting domain with an application"
|
53
|
+
begin
|
54
|
+
domain.delete
|
55
|
+
rescue Exception => e
|
56
|
+
puts e.message
|
57
|
+
end
|
58
|
+
|
59
|
+
puts "Getting all domains and applications..."
|
60
|
+
client.domains.each do |domain|
|
61
|
+
puts " Domain: #{domain.id}"
|
62
|
+
domain.applications.each do |app|
|
63
|
+
puts " Application: #{app.name}"
|
64
|
+
app.cartridges.each do |cart|
|
65
|
+
puts " Cartridge #{cart.name} (#{cart.type})"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
puts "Find application=appone and restart it..."
|
71
|
+
apps = client.find_application("appone")
|
72
|
+
apps.first.restart
|
73
|
+
|
74
|
+
apps = client.find_application("appthree")
|
75
|
+
if not apps.nil? and not apps.first.nil?
|
76
|
+
apps.first.delete
|
77
|
+
end
|
78
|
+
|
79
|
+
puts "Create new application named appthree..."
|
80
|
+
app = client.domains.first.add_application("appthree", {:cartridge =>"php-5.3"})
|
81
|
+
puts "Adding MySQL cartridge to appthree"
|
82
|
+
cartridge = app.add_cartridge("mysql-5.1")
|
83
|
+
puts "Check to see if it was added"
|
84
|
+
app.cartridges.each do |cart|
|
85
|
+
puts "Cartridge #{cart.name} (#{cart.type})"
|
86
|
+
end
|
87
|
+
|
88
|
+
puts "Restart MySQL cartridge"
|
89
|
+
cartridge.restart
|
90
|
+
puts "Deleting MySQL cartridge"
|
91
|
+
cartridge.delete
|
92
|
+
puts "Check to see if it was deleted"
|
93
|
+
if app.cartridges.size == 0
|
94
|
+
puts "MySQL cartridge is deleted"
|
95
|
+
end
|
96
|
+
puts "Deleting appthree"
|
97
|
+
app.delete
|
98
|
+
end
|
99
|
+
|
100
|
+
puts "Adding, updating and deleting keys"
|
101
|
+
key = client.user.add_key("newkey", "NEWKEYCONTENT", "ssh-rsa")
|
102
|
+
|
103
|
+
puts "Added key: #{key.name} updating key content"
|
104
|
+
key.update(key.type, "NEWKEYCONTENT123")
|
105
|
+
|
106
|
+
puts "Getting all keys..."
|
107
|
+
client.user.keys.each do |key|
|
108
|
+
puts " Key: #{key.name} (type: #{key.type}) #{key.content}"
|
109
|
+
end
|
110
|
+
|
111
|
+
puts "Deleting key"
|
112
|
+
begin
|
113
|
+
key.delete
|
114
|
+
rescue Exception => e
|
115
|
+
puts e.message
|
116
|
+
end
|
117
|
+
|
118
|
+
puts 'Clean up domains and apps by force deleting domain'
|
119
|
+
client.domains.each do |domain|
|
120
|
+
domain.delete(true)
|
121
|
+
end
|
122
|
+
|