appscale-tools 1.6.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.
- data/LICENSE +37 -0
- data/README +17 -0
- data/bin/appscale-add-keypair +15 -0
- data/bin/appscale-describe-instances +16 -0
- data/bin/appscale-remove-app +13 -0
- data/bin/appscale-reset-pwd +13 -0
- data/bin/appscale-run-instances +15 -0
- data/bin/appscale-terminate-instances +14 -0
- data/bin/appscale-upload-app +13 -0
- data/doc/AdvancedNode.html +163 -0
- data/doc/AppControllerClient.html +831 -0
- data/doc/AppEngineConfigException.html +165 -0
- data/doc/AppScaleException.html +165 -0
- data/doc/AppScaleTools.html +768 -0
- data/doc/BadCommandLineArgException.html +166 -0
- data/doc/BadConfigurationException.html +166 -0
- data/doc/CommonFunctions.html +2559 -0
- data/doc/EncryptionHelper.html +332 -0
- data/doc/GodInterface.html +443 -0
- data/doc/InfrastructureException.html +166 -0
- data/doc/Node.html +470 -0
- data/doc/NodeLayout.html +1297 -0
- data/doc/Object.html +539 -0
- data/doc/ParseArgs.html +268 -0
- data/doc/RemoteLogging.html +268 -0
- data/doc/SimpleNode.html +163 -0
- data/doc/UsageText.html +1204 -0
- data/doc/UserAppClient.html +993 -0
- data/doc/VMTools.html +1365 -0
- data/doc/bin/appscale-add-keypair.html +56 -0
- data/doc/bin/appscale-describe-instances.html +56 -0
- data/doc/bin/appscale-remove-app.html +56 -0
- data/doc/bin/appscale-reset-pwd.html +56 -0
- data/doc/bin/appscale-run-instances.html +56 -0
- data/doc/bin/appscale-terminate-instances.html +56 -0
- data/doc/bin/appscale-upload-app.html +56 -0
- data/doc/created.rid +21 -0
- data/doc/images/add.png +0 -0
- data/doc/images/brick.png +0 -0
- data/doc/images/brick_link.png +0 -0
- data/doc/images/bug.png +0 -0
- data/doc/images/bullet_black.png +0 -0
- data/doc/images/bullet_toggle_minus.png +0 -0
- data/doc/images/bullet_toggle_plus.png +0 -0
- data/doc/images/date.png +0 -0
- data/doc/images/delete.png +0 -0
- data/doc/images/find.png +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/doc/images/macFFBgHack.png +0 -0
- data/doc/images/package.png +0 -0
- data/doc/images/page_green.png +0 -0
- data/doc/images/page_white_text.png +0 -0
- data/doc/images/page_white_width.png +0 -0
- data/doc/images/plugin.png +0 -0
- data/doc/images/ruby.png +0 -0
- data/doc/images/tag_blue.png +0 -0
- data/doc/images/tag_green.png +0 -0
- data/doc/images/transparent.png +0 -0
- data/doc/images/wrench.png +0 -0
- data/doc/images/wrench_orange.png +0 -0
- data/doc/images/zoom.png +0 -0
- data/doc/index.html +116 -0
- data/doc/js/darkfish.js +153 -0
- data/doc/js/jquery.js +18 -0
- data/doc/js/navigation.js +142 -0
- data/doc/js/quicksearch.js +114 -0
- data/doc/js/search.js +94 -0
- data/doc/js/search_index.js +1 -0
- data/doc/js/searcher.js +228 -0
- data/doc/js/thickbox-compressed.js +10 -0
- data/doc/lib/app_controller_client_rb.html +60 -0
- data/doc/lib/appscale_tools_rb.html +88 -0
- data/doc/lib/common_functions_rb.html +78 -0
- data/doc/lib/custom_exceptions_rb.html +54 -0
- data/doc/lib/encryption_helper_rb.html +60 -0
- data/doc/lib/godinterface_rb.html +52 -0
- data/doc/lib/node_layout_rb.html +55 -0
- data/doc/lib/parse_args_rb.html +58 -0
- data/doc/lib/remote_log_rb.html +58 -0
- data/doc/lib/sshcopyid.html +174 -0
- data/doc/lib/usage_text_rb.html +58 -0
- data/doc/lib/user_app_client_rb.html +62 -0
- data/doc/lib/vm_tools_rb.html +62 -0
- data/doc/table_of_contents.html +496 -0
- data/lib/app_controller_client.rb +181 -0
- data/lib/appscale_tools.rb +403 -0
- data/lib/common_functions.rb +1467 -0
- data/lib/custom_exceptions.rb +25 -0
- data/lib/encryption_helper.rb +86 -0
- data/lib/godinterface.rb +152 -0
- data/lib/node_layout.rb +665 -0
- data/lib/parse_args.rb +415 -0
- data/lib/remote_log.rb +46 -0
- data/lib/sshcopyid +65 -0
- data/lib/usage_text.rb +144 -0
- data/lib/user_app_client.rb +245 -0
- data/lib/vm_tools.rb +549 -0
- data/test/tc_app_controller_client.rb +10 -0
- data/test/tc_appscale_add_keypair.rb +44 -0
- data/test/tc_appscale_describe_instances.rb +69 -0
- data/test/tc_appscale_remove_app.rb +128 -0
- data/test/tc_appscale_reset_pwd.rb +156 -0
- data/test/tc_appscale_run_instances.rb +48 -0
- data/test/tc_appscale_terminate_instances.rb +104 -0
- data/test/tc_appscale_upload_app.rb +166 -0
- data/test/tc_common_functions.rb +56 -0
- data/test/tc_encryption_helper.rb +10 -0
- data/test/tc_god_interface.rb +10 -0
- data/test/tc_node_layout.rb +93 -0
- data/test/tc_parse_args.rb +160 -0
- data/test/tc_user_app_client.rb +10 -0
- data/test/tc_vm_tools.rb +10 -0
- data/test/ts_all.rb +20 -0
- metadata +211 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
|
2
|
+
require 'appscale_tools'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
require 'rubygems'
|
|
6
|
+
require 'flexmock/test_unit'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestAppScaleTerminateInstances < Test::Unit::TestCase
|
|
10
|
+
def setup
|
|
11
|
+
kernel = flexmock(Kernel)
|
|
12
|
+
kernel.should_receive(:print).and_return()
|
|
13
|
+
kernel.should_receive(:puts).and_return()
|
|
14
|
+
kernel.should_receive(:sleep).and_return()
|
|
15
|
+
|
|
16
|
+
stdout = flexmock(STDOUT)
|
|
17
|
+
stdout.should_receive(:flush).and_return()
|
|
18
|
+
|
|
19
|
+
fileutils = flexmock(FileUtils)
|
|
20
|
+
fileutils.should_receive(:rm_f).and_return()
|
|
21
|
+
|
|
22
|
+
# taken from the standard two node deployment
|
|
23
|
+
node1 = {
|
|
24
|
+
'public_ip' => 'public_ip1',
|
|
25
|
+
'private_ip' => 'private_ip1',
|
|
26
|
+
'jobs' => ['load_balancer', 'shadow', 'db_master', 'zookeeper', 'login', 'memcache', 'rabbitmq_master'],
|
|
27
|
+
'instance_id' => 'instance_id1',
|
|
28
|
+
'cloud' => 'cloud1',
|
|
29
|
+
'creation_time' => nil,
|
|
30
|
+
'destruction_time' => nil
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
node2 = {
|
|
34
|
+
'public_ip' => 'public_ip2',
|
|
35
|
+
'private_ip' => 'private_ip2',
|
|
36
|
+
'jobs' => ['load_balancer', 'db_slave', 'memcache', 'rabbitmq_slave', 'appengine'],
|
|
37
|
+
'instance_id' => 'instance_id2',
|
|
38
|
+
'cloud' => 'cloud2',
|
|
39
|
+
'creation_time' => nil,
|
|
40
|
+
'destruction_time' => nil
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@role_info = [node1, node2]
|
|
44
|
+
@key = "appscale"
|
|
45
|
+
|
|
46
|
+
commonfunctions = flexmock(CommonFunctions)
|
|
47
|
+
commonfunctions.should_receive(:read_file).
|
|
48
|
+
with(File.expand_path("~/.appscale/locations-#{@key}.json")).
|
|
49
|
+
and_return(JSON.dump(@role_info))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_no_locations_yaml
|
|
53
|
+
file = flexmock(File)
|
|
54
|
+
file.should_receive(:exists?).and_return(false)
|
|
55
|
+
|
|
56
|
+
options = {"keyname" => @key}
|
|
57
|
+
assert_raises(AppScaleException) {
|
|
58
|
+
AppScaleTools.terminate_instances(options)
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_terminate_xen_boxes
|
|
63
|
+
file = flexmock(File)
|
|
64
|
+
file.should_receive(:exists?).and_return(true)
|
|
65
|
+
|
|
66
|
+
@secret = "booooo"
|
|
67
|
+
@fake_yaml = {
|
|
68
|
+
:shadow => "public_ip",
|
|
69
|
+
:secret => @secret,
|
|
70
|
+
#:table => "cassandra",
|
|
71
|
+
:infrastructure => "xen",
|
|
72
|
+
:ips => "public_ip"
|
|
73
|
+
}
|
|
74
|
+
yaml = flexmock(YAML)
|
|
75
|
+
yaml.should_receive(:load_file).and_return(@fake_yaml)
|
|
76
|
+
|
|
77
|
+
commonfunctions = flexmock(CommonFunctions)
|
|
78
|
+
commonfunctions.should_receive(:run_remote_command).and_return()
|
|
79
|
+
commonfunctions.should_receive(:shell).and_return("service appscale-controller stop", "")
|
|
80
|
+
|
|
81
|
+
# mocks for get_role_info, which will return the node's state
|
|
82
|
+
appcontroller = flexmock('appcontroller')
|
|
83
|
+
appcontroller.should_receive(:get_role_info).and_return(@role_info)
|
|
84
|
+
flexmock(AppControllerClient).should_receive(:new).
|
|
85
|
+
and_return(appcontroller)
|
|
86
|
+
|
|
87
|
+
commonfunctions.should_receive(:write_file).with(
|
|
88
|
+
File.expand_path("~/.appscale/locations-appscale.json"),
|
|
89
|
+
JSON.dump(@role_info)).and_return()
|
|
90
|
+
|
|
91
|
+
options = {"keyname" => "appscale"}
|
|
92
|
+
assert_nothing_raised(Exception) {
|
|
93
|
+
AppScaleTools.terminate_instances(options)
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_usage_is_up_to_date
|
|
98
|
+
AppScaleTools::TERMINATE_INSTANCES_FLAGS.each { |flag|
|
|
99
|
+
assert_equal(true,
|
|
100
|
+
AppScaleTools::TERMINATE_INSTANCES_USAGE.include?("-#{flag}"),
|
|
101
|
+
"No usage text for #{flag}.")
|
|
102
|
+
}
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
|
2
|
+
require 'appscale_tools'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
require 'rubygems'
|
|
6
|
+
require 'flexmock/test_unit'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestAppScaleUploadApp < Test::Unit::TestCase
|
|
10
|
+
def setup
|
|
11
|
+
@app_name = "boo"
|
|
12
|
+
@file_location = "/tmp/boo.tar.gz"
|
|
13
|
+
@language = "python"
|
|
14
|
+
@user = "a@a.a"
|
|
15
|
+
|
|
16
|
+
@key = "booscale"
|
|
17
|
+
@options = { "file_location" => @file_location, "keyname" => @key,
|
|
18
|
+
"test" => true}
|
|
19
|
+
|
|
20
|
+
# common mocks, mostly involving reading files
|
|
21
|
+
file = flexmock(File)
|
|
22
|
+
file.should_receive(:exists?).and_return(true)
|
|
23
|
+
|
|
24
|
+
@secret = "booooo"
|
|
25
|
+
@fake_yaml = {:load_balancer => "public_ip1",
|
|
26
|
+
:shadow => "public_ip1",
|
|
27
|
+
:secret => @secret,
|
|
28
|
+
:db_master => "public_ip1",
|
|
29
|
+
:table => "cassandra",
|
|
30
|
+
:instance_id => "i-FOOBARZ"}
|
|
31
|
+
yaml = flexmock(YAML)
|
|
32
|
+
yaml.should_receive(:load_file).and_return(@fake_yaml)
|
|
33
|
+
|
|
34
|
+
# taken from the standard two node deployment
|
|
35
|
+
node1 = {
|
|
36
|
+
'public_ip' => 'public_ip1',
|
|
37
|
+
'private_ip' => 'private_ip1',
|
|
38
|
+
'jobs' => ['load_balancer', 'shadow', 'db_master', 'zookeeper', 'login', 'memcache', 'rabbitmq_master'],
|
|
39
|
+
'instance_id' => 'instance_id1',
|
|
40
|
+
'cloud' => 'cloud1',
|
|
41
|
+
'creation_time' => nil,
|
|
42
|
+
'destruction_time' => nil
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
node2 = {
|
|
46
|
+
'public_ip' => 'public_ip2',
|
|
47
|
+
'private_ip' => 'private_ip2',
|
|
48
|
+
'jobs' => ['load_balancer', 'db_slave', 'memcache', 'rabbitmq_slave', 'appengine'],
|
|
49
|
+
'instance_id' => 'instance_id2',
|
|
50
|
+
'cloud' => 'cloud2',
|
|
51
|
+
'creation_time' => nil,
|
|
52
|
+
'destruction_time' => nil
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@role_info = [node1, node2]
|
|
56
|
+
|
|
57
|
+
commonfunctions = flexmock(CommonFunctions)
|
|
58
|
+
commonfunctions.should_receive(:read_file).
|
|
59
|
+
with(File.expand_path("~/.appscale/locations-#{@key}.json")).
|
|
60
|
+
and_return(JSON.dump(@role_info))
|
|
61
|
+
|
|
62
|
+
# mocks for get_role_info, which will return the node's state
|
|
63
|
+
appcontroller = flexmock('appcontroller')
|
|
64
|
+
appcontroller.should_receive(:get_role_info).and_return(@role_info)
|
|
65
|
+
appcontroller.should_receive(:get_userappserver_ip).and_return("127.0.0.1")
|
|
66
|
+
flexmock(AppControllerClient).should_receive(:new).and_return(appcontroller)
|
|
67
|
+
|
|
68
|
+
commonfunctions.should_receive(:write_file).with(
|
|
69
|
+
File.expand_path("~/.appscale/locations-#{@key}.json"),
|
|
70
|
+
JSON.dump(@role_info)).and_return()
|
|
71
|
+
|
|
72
|
+
fileutils = flexmock(FileUtils)
|
|
73
|
+
fileutils.should_receive(:rm_rf).and_return()
|
|
74
|
+
|
|
75
|
+
kernel = flexmock(Kernel)
|
|
76
|
+
kernel.should_receive(:print).and_return()
|
|
77
|
+
kernel.should_receive(:puts).and_return()
|
|
78
|
+
|
|
79
|
+
@app_info = {
|
|
80
|
+
:app_name => @app_name,
|
|
81
|
+
:file => @file_location,
|
|
82
|
+
:language => @language
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
commonfunctions = flexmock(CommonFunctions)
|
|
86
|
+
commonfunctions.should_receive(:get_app_name_from_tar).and_return(@app_info)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def test_no_app_provided
|
|
90
|
+
options = {"keyname" => @key}
|
|
91
|
+
assert_raises(AppScaleException) {
|
|
92
|
+
AppScaleTools.upload_app(options)
|
|
93
|
+
}
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def test_app_already_exists_and_user_does_not
|
|
97
|
+
commonfunctions = flexmock(CommonFunctions)
|
|
98
|
+
commonfunctions.should_receive(:create_user).and_return()
|
|
99
|
+
|
|
100
|
+
appcontrollerclient = flexmock(AppControllerClient)
|
|
101
|
+
appcontrollerclient.new_instances { |instance|
|
|
102
|
+
instance.should_receive(:get_userappserver_ip).and_return("127.0.0.1")
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
userappclient = flexmock(UserAppClient)
|
|
106
|
+
userappclient.new_instances { |instance|
|
|
107
|
+
instance.should_receive(:does_user_exist?).and_return(false)
|
|
108
|
+
instance.should_receive(:does_app_exist?).and_return(true)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
assert_raises(AppScaleException) {
|
|
112
|
+
AppScaleTools.upload_app(@options)
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_upload_user_not_app_administrator
|
|
117
|
+
commonfunctions = flexmock(CommonFunctions)
|
|
118
|
+
commonfunctions.should_receive(:create_user).and_return()
|
|
119
|
+
|
|
120
|
+
appcontrollerclient = flexmock(AppControllerClient)
|
|
121
|
+
appcontrollerclient.new_instances { |instance|
|
|
122
|
+
instance.should_receive(:get_userappserver_ip).and_return("127.0.0.1")
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
userappclient = flexmock(UserAppClient)
|
|
126
|
+
userappclient.new_instances { |instance|
|
|
127
|
+
instance.should_receive(:does_user_exist?).and_return(true)
|
|
128
|
+
instance.should_receive(:does_app_exist?).and_return(false)
|
|
129
|
+
instance.should_receive(:get_app_admin).and_return(@user + "boo")
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
assert_raises(AppScaleException) {
|
|
133
|
+
AppScaleTools.upload_app(@options)
|
|
134
|
+
}
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def test_app_uploads_successfully
|
|
138
|
+
commonfunctions = flexmock(CommonFunctions)
|
|
139
|
+
commonfunctions.should_receive(:scp_app_to_ip).and_return(@file_location)
|
|
140
|
+
commonfunctions.should_receive(:update_appcontroller).and_return()
|
|
141
|
+
commonfunctions.should_receive(:wait_for_app_to_start).and_return()
|
|
142
|
+
|
|
143
|
+
appcontrollerclient = flexmock(AppControllerClient)
|
|
144
|
+
appcontrollerclient.new_instances { |instance|
|
|
145
|
+
instance.should_receive(:get_userappserver_ip).and_return("127.0.0.1")
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
userappclient = flexmock(UserAppClient)
|
|
149
|
+
userappclient.new_instances { |instance|
|
|
150
|
+
instance.should_receive(:does_user_exist?).and_return(true)
|
|
151
|
+
instance.should_receive(:does_app_exist?).and_return(false)
|
|
152
|
+
instance.should_receive(:get_app_admin).and_return(@user)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
assert_nothing_raised(Exception) {
|
|
156
|
+
AppScaleTools.upload_app(@options)
|
|
157
|
+
}
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def test_usage_is_up_to_date
|
|
161
|
+
AppScaleTools::UPLOAD_APP_FLAGS.each { |flag|
|
|
162
|
+
assert_equal(true, AppScaleTools::UPLOAD_APP_USAGE.include?("-#{flag}"),
|
|
163
|
+
"No usage text for #{flag}.")
|
|
164
|
+
}
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
|
2
|
+
require 'common_functions'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
require 'flexmock/test_unit'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestCommonFunctions < Test::Unit::TestCase
|
|
9
|
+
def setup
|
|
10
|
+
@secret = "baz"
|
|
11
|
+
@fake_yaml = {
|
|
12
|
+
:load_balancer => "public_ip1",
|
|
13
|
+
:shadow => "public_ip1",
|
|
14
|
+
:secret => @secret,
|
|
15
|
+
:table => "cassandra",
|
|
16
|
+
:infrastructure => "xen",
|
|
17
|
+
:ips => ["public_ip1", "public_ip2"]
|
|
18
|
+
}
|
|
19
|
+
yaml = flexmock(YAML)
|
|
20
|
+
yaml.should_receive(:load_file).and_return(@fake_yaml)
|
|
21
|
+
|
|
22
|
+
# taken from the standard two node deployment
|
|
23
|
+
node1 = {
|
|
24
|
+
'public_ip' => 'public_ip1',
|
|
25
|
+
'private_ip' => 'private_ip1',
|
|
26
|
+
'jobs' => ['load_balancer', 'shadow', 'db_master', 'zookeeper', 'login', 'memcache', 'rabbitmq_master'],
|
|
27
|
+
'instance_id' => 'instance_id1',
|
|
28
|
+
'cloud' => 'cloud1',
|
|
29
|
+
'creation_time' => nil,
|
|
30
|
+
'destruction_time' => nil
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
node2 = {
|
|
34
|
+
'public_ip' => 'public_ip2',
|
|
35
|
+
'private_ip' => 'private_ip2',
|
|
36
|
+
'jobs' => ['load_balancer', 'db_slave', 'memcache', 'rabbitmq_slave', 'appengine'],
|
|
37
|
+
'instance_id' => 'instance_id2',
|
|
38
|
+
'cloud' => 'cloud2',
|
|
39
|
+
'creation_time' => nil,
|
|
40
|
+
'destruction_time' => nil
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@role_info = [node1, node2]
|
|
44
|
+
@key = "appscale"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_get_ips_for_roles
|
|
49
|
+
commonfunctions = flexmock(CommonFunctions)
|
|
50
|
+
commonfunctions.should_receive(:read_file).
|
|
51
|
+
with(File.expand_path("~/.appscale/locations-#{@key}.json")).
|
|
52
|
+
and_return(JSON.dump(@role_info))
|
|
53
|
+
|
|
54
|
+
assert_equal("public_ip1", CommonFunctions.get_load_balancer_ip(@key))
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
|
2
|
+
require 'node_layout'
|
|
3
|
+
|
|
4
|
+
require 'test/unit'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestNodeLayout < Test::Unit::TestCase
|
|
8
|
+
def setup
|
|
9
|
+
@blank_input_yaml = nil
|
|
10
|
+
@blank_options = {}
|
|
11
|
+
|
|
12
|
+
@ip_1 = '192.168.1.1'
|
|
13
|
+
@ip_2 = '192.168.1.2'
|
|
14
|
+
@ip_3 = '192.168.1.3'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_simple_layout_yaml_only
|
|
18
|
+
# Specifying one controller and one server should be ok
|
|
19
|
+
input_yaml_1 = {:controller => @ip_1, :servers => [@ip_2]}
|
|
20
|
+
layout_1 = NodeLayout.new(input_yaml_1, @blank_options)
|
|
21
|
+
assert_equal(true, layout_1.valid?)
|
|
22
|
+
|
|
23
|
+
# Specifying one controller should be ok
|
|
24
|
+
input_yaml_2 = {:controller => @ip_1}
|
|
25
|
+
layout_2 = NodeLayout.new(input_yaml_2, @blank_options)
|
|
26
|
+
assert_equal(true, layout_2.valid?)
|
|
27
|
+
|
|
28
|
+
# Specifying the same IP more than once is not ok
|
|
29
|
+
input_yaml_3 = {:controller => @ip_1, :servers => [@ip_1]}
|
|
30
|
+
layout_3 = NodeLayout.new(input_yaml_3, @blank_options)
|
|
31
|
+
assert_equal(false, layout_3.valid?)
|
|
32
|
+
assert_equal(DUPLICATE_IPS, layout_3.errors)
|
|
33
|
+
|
|
34
|
+
# Failing to specify a controller is not ok
|
|
35
|
+
input_yaml_4 = {:servers => [@ip_1, @ip_2]}
|
|
36
|
+
layout_4 = NodeLayout.new(input_yaml_4, @blank_options)
|
|
37
|
+
assert_equal(false, layout_4.valid?)
|
|
38
|
+
assert_equal(NO_CONTROLLER, layout_4.errors)
|
|
39
|
+
|
|
40
|
+
# Specifying more than one controller is not ok
|
|
41
|
+
input_yaml_5 = {:controller => [@ip_1, @ip_2], :servers => [@ip_3]}
|
|
42
|
+
layout_5 = NodeLayout.new(input_yaml_5, @blank_options)
|
|
43
|
+
assert_equal(false, layout_5.valid?)
|
|
44
|
+
assert_equal(ONLY_ONE_CONTROLLER, layout_5.errors)
|
|
45
|
+
|
|
46
|
+
# Specifying something other than controller and servers in simple
|
|
47
|
+
# deployments is not ok
|
|
48
|
+
input_yaml_6 = {:controller => @ip_1, :servers => [@ip_2], :boo => @ip_3}
|
|
49
|
+
layout_6 = NodeLayout.new(input_yaml_6, @blank_options)
|
|
50
|
+
assert_equal(false, layout_6.valid?)
|
|
51
|
+
assert_equal(["The flag boo is not a supported flag"], layout_6.errors)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_simple_layout_options
|
|
55
|
+
# Using Euca with no input yaml, and no max or min images is not ok
|
|
56
|
+
options_1 = {:infrastructure => "euca"}
|
|
57
|
+
layout_1 = NodeLayout.new(@blank_input_yaml, options_1)
|
|
58
|
+
assert_equal(false, layout_1.valid?)
|
|
59
|
+
assert_equal(NO_INPUT_YAML_REQUIRES_MIN_IMAGES, layout_1.errors)
|
|
60
|
+
|
|
61
|
+
options_2 = {:infrastructure => "euca", :max_images => 2}
|
|
62
|
+
layout_2 = NodeLayout.new(@blank_input_yaml, options_2)
|
|
63
|
+
assert_equal(false, layout_2.valid?)
|
|
64
|
+
assert_equal(NO_INPUT_YAML_REQUIRES_MIN_IMAGES, layout_2.errors)
|
|
65
|
+
|
|
66
|
+
options_3 = {:infrastructure => "euca", :min_images => 2}
|
|
67
|
+
layout_3 = NodeLayout.new(@blank_input_yaml, options_3)
|
|
68
|
+
assert_equal(false, layout_3.valid?)
|
|
69
|
+
assert_equal(NO_INPUT_YAML_REQUIRES_MAX_IMAGES, layout_3.errors)
|
|
70
|
+
|
|
71
|
+
# Using Euca with no input yaml, with max and min images set is ok
|
|
72
|
+
options_4 = {:infrastructure => "euca", :min_images => 2, :max_images => 2}
|
|
73
|
+
layout_4 = NodeLayout.new(@blank_input_yaml, options_4)
|
|
74
|
+
assert_equal(true, layout_4.valid?)
|
|
75
|
+
|
|
76
|
+
# Using Xen or hybrid cloud deployments with no input yaml is not ok
|
|
77
|
+
options_5 = {:infrastructure => "xen"}
|
|
78
|
+
layout_5 = NodeLayout.new(@blank_input_yaml, options_5)
|
|
79
|
+
assert_equal(false, layout_5.valid?)
|
|
80
|
+
assert_equal([INPUT_YAML_REQUIRED], layout_5.errors)
|
|
81
|
+
|
|
82
|
+
options_6 = {:infrastructure => "hybrid"}
|
|
83
|
+
layout_6 = NodeLayout.new(@blank_input_yaml, options_6)
|
|
84
|
+
assert_equal(false, layout_6.valid?)
|
|
85
|
+
assert_equal([INPUT_YAML_REQUIRED], layout_6.errors)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def test_advanced_format_yaml_only
|
|
89
|
+
input_yaml_1 = {:master => @ip_1, :database => @ip_1, :appengine => @ip_1, :open => @ip_2}
|
|
90
|
+
layout_1 = NodeLayout.new(input_yaml_1, @blank_options)
|
|
91
|
+
assert_equal(true, layout_1.valid?)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
|
2
|
+
require 'parse_args'
|
|
3
|
+
|
|
4
|
+
require 'test/unit'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestParseArgs < Test::Unit::TestCase
|
|
8
|
+
def setup
|
|
9
|
+
@args = {}
|
|
10
|
+
@usage = "boo"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def get_exception_msg
|
|
14
|
+
if !block_given?
|
|
15
|
+
abort('need to give me a block!')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
begin
|
|
19
|
+
yield
|
|
20
|
+
rescue SystemExit => e
|
|
21
|
+
return e.message
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_flags_that_cause_program_abort
|
|
26
|
+
# Using a flag that isn't acceptable should cause ParseArgs to abort
|
|
27
|
+
args_1 = ['--boo!']
|
|
28
|
+
all_flags_1 = []
|
|
29
|
+
assert_raises(BadCommandLineArgException) {
|
|
30
|
+
ParseArgs.get_vals_from_args(args_1, all_flags_1, @usage)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# The --usage flag should cause ParseArgs to abort and print the usage
|
|
34
|
+
args_2 = ['--usage']
|
|
35
|
+
all_flags_2 = ['usage']
|
|
36
|
+
assert_raises(BadCommandLineArgException) {
|
|
37
|
+
ParseArgs.get_vals_from_args(args_2, all_flags_2, @usage)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# The --version flag should cause ParseArgs to abort and print the version
|
|
41
|
+
args_3 = ['--version']
|
|
42
|
+
all_flags_3 = ['version']
|
|
43
|
+
assert_raises(BadCommandLineArgException) {
|
|
44
|
+
ParseArgs.get_vals_from_args(args_3, all_flags_3, @usage)
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_get_min_and_max
|
|
49
|
+
# Setting min or max below 1 is not acceptable
|
|
50
|
+
args_1 = ['--min', '0']
|
|
51
|
+
all_flags_1 = ['min']
|
|
52
|
+
assert_raises(BadCommandLineArgException) {
|
|
53
|
+
ParseArgs.get_vals_from_args(args_1, all_flags_1, @usage)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
args_2 = ['--max', '0']
|
|
57
|
+
all_flags_2 = ['max']
|
|
58
|
+
assert_raises(BadCommandLineArgException) {
|
|
59
|
+
ParseArgs.get_vals_from_args(args_2, all_flags_2, @usage)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# If max is specified but not min, min should be equal to max
|
|
63
|
+
args_3 = ['--max', '1']
|
|
64
|
+
all_flags_3 = ['max']
|
|
65
|
+
actual_3 = ParseArgs.get_vals_from_args(args_3, all_flags_3, @usage)
|
|
66
|
+
assert_equal(actual_3['min_images'], actual_3['max_images'])
|
|
67
|
+
|
|
68
|
+
# If max is less than min, it should abort
|
|
69
|
+
args_4 = ['--min', '10', '--max', '1']
|
|
70
|
+
all_flags_4 = ['min', 'max']
|
|
71
|
+
assert_raises(BadCommandLineArgException) {
|
|
72
|
+
ParseArgs.get_vals_from_args(args_4, all_flags_4, @usage)
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_table_flags
|
|
77
|
+
# Specifying a table that isn't accepted should abort
|
|
78
|
+
args_1 = ['--table', 'non-existant-table']
|
|
79
|
+
all_flags_1 = ['table']
|
|
80
|
+
assert_raises(BadCommandLineArgException) {
|
|
81
|
+
ParseArgs.get_vals_from_args(args_1, all_flags_1, @usage)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Specifying a table that is accepted should return that in the result
|
|
85
|
+
args_2 = ['--table', 'voldemort']
|
|
86
|
+
all_flags_2 = ['table']
|
|
87
|
+
expected_2 = Hash[*args_2]
|
|
88
|
+
actual_2 = ParseArgs.get_vals_from_args(args_2, all_flags_2, @usage)
|
|
89
|
+
assert_equal('voldemort', actual_2['table'])
|
|
90
|
+
|
|
91
|
+
# Failing to specify a table should default to a predefined table
|
|
92
|
+
args_3 = []
|
|
93
|
+
all_flags_3 = ['table']
|
|
94
|
+
expected_3 = {}
|
|
95
|
+
actual_3 = ParseArgs.get_vals_from_args(args_3, all_flags_3, @usage)
|
|
96
|
+
assert_equal(DEFAULT_DATASTORE, actual_3['table'])
|
|
97
|
+
|
|
98
|
+
# Specifying r or w when Voldemort isn't used should abort
|
|
99
|
+
args_4 = ['--table', 'cassandra', '-r', '1']
|
|
100
|
+
all_flags_4 = ['table', 'r', 'w']
|
|
101
|
+
assert_raises(BadCommandLineArgException) {
|
|
102
|
+
ParseArgs.get_vals_from_args(args_4, all_flags_4, @usage)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
args_5 = ['--table', 'cassandra', '-w', '1']
|
|
106
|
+
all_flags_5 = ['table', 'r', 'w']
|
|
107
|
+
assert_raises(BadCommandLineArgException) {
|
|
108
|
+
ParseArgs.get_vals_from_args(args_5, all_flags_5, @usage)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Specifying a non-positive integer for r or w with Voldemort should abort
|
|
112
|
+
args_6 = ['--table', 'voldemort', '-r', 'boo']
|
|
113
|
+
all_flags_6 = ['table', 'r', 'w']
|
|
114
|
+
assert_raises(BadCommandLineArgException) {
|
|
115
|
+
ParseArgs.get_vals_from_args(args_6, all_flags_6, @usage)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
args_7 = ['--table', 'voldemort', '-w', '0']
|
|
119
|
+
all_flags_7 = ['table', 'r', 'w']
|
|
120
|
+
assert_raises(BadCommandLineArgException) {
|
|
121
|
+
ParseArgs.get_vals_from_args(args_7, all_flags_7, @usage)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# Specifying a non-positive integer for n should abort
|
|
125
|
+
args_8 = ['--table', 'cassandra', '-n', '0']
|
|
126
|
+
all_flags_8 = ['table', 'n']
|
|
127
|
+
assert_raises(BadCommandLineArgException) {
|
|
128
|
+
ParseArgs.get_vals_from_args(args_8, all_flags_8, @usage)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# Specifying a positive integer for n should be ok
|
|
132
|
+
args_9 = ['--table', 'cassandra', '-n', '2']
|
|
133
|
+
all_flags_9 = ['table', 'n']
|
|
134
|
+
expected_9 = Hash[*args_9]
|
|
135
|
+
actual_9 = ParseArgs.get_vals_from_args(args_9, all_flags_9, @usage)
|
|
136
|
+
assert_equal(2, actual_9['replication'])
|
|
137
|
+
|
|
138
|
+
# Specifying a positive integer for r or w with Voldemort should be ok
|
|
139
|
+
args_10 = ['--table', 'voldemort', '-r', '3']
|
|
140
|
+
all_flags_10 = ['table', 'r', 'w']
|
|
141
|
+
actual_10 = ParseArgs.get_vals_from_args(args_10, all_flags_10, @usage)
|
|
142
|
+
assert_equal(3, actual_10['voldemort_r'])
|
|
143
|
+
|
|
144
|
+
args_11 = ['--table', 'voldemort', '-w', '3']
|
|
145
|
+
all_flags_11 = ['table', 'r', 'w']
|
|
146
|
+
actual_11 = ParseArgs.get_vals_from_args(args_11, all_flags_11, @usage)
|
|
147
|
+
assert_equal(3, actual_11['voldemort_w'])
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def test_developer_flags
|
|
151
|
+
# Specifying auto, force, or test should have that carried over
|
|
152
|
+
# to in the resulting hash
|
|
153
|
+
['auto', 'force', 'test'].each { |param|
|
|
154
|
+
args = ["--#{param}"]
|
|
155
|
+
all_flags = [param]
|
|
156
|
+
actual = ParseArgs.get_vals_from_args(args, all_flags, @usage)
|
|
157
|
+
assert_equal(true, actual[param])
|
|
158
|
+
}
|
|
159
|
+
end
|
|
160
|
+
end
|