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,181 @@
|
|
|
1
|
+
#!/usr/bin/ruby -w
|
|
2
|
+
# Programmer: Chris Bunch
|
|
3
|
+
|
|
4
|
+
require 'openssl'
|
|
5
|
+
require 'soap/rpc/driver'
|
|
6
|
+
require 'timeout'
|
|
7
|
+
|
|
8
|
+
IP_REGEX = /\d+\.\d+\.\d+\.\d+/
|
|
9
|
+
FQDN_REGEX = /[\w\d\.\-]+/
|
|
10
|
+
IP_OR_FQDN = /#{IP_REGEX}|#{FQDN_REGEX}/
|
|
11
|
+
|
|
12
|
+
NO_TIMEOUT = 1000000
|
|
13
|
+
RETRY_ON_FAIL = true
|
|
14
|
+
ABORT_ON_FAIL = false
|
|
15
|
+
|
|
16
|
+
# A constant that indicates that verbose logging should be produced.
|
|
17
|
+
LOGS_VERBOSE = "high"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AppControllerClient
|
|
21
|
+
attr_reader :conn, :ip, :secret
|
|
22
|
+
|
|
23
|
+
def initialize(ip, secret)
|
|
24
|
+
@ip = ip
|
|
25
|
+
@secret = secret
|
|
26
|
+
|
|
27
|
+
@conn = SOAP::RPC::Driver.new("https://#{@ip}:17443")
|
|
28
|
+
@conn.add_method("set_parameters", "djinn_locations", "database_credentials", "app_names", "secret")
|
|
29
|
+
@conn.add_method("status", "secret")
|
|
30
|
+
@conn.add_method("update", "app_names", "secret")
|
|
31
|
+
@conn.add_method("done_uploading", "appname", "location", "secret")
|
|
32
|
+
@conn.add_method("is_done_initializing", "secret")
|
|
33
|
+
@conn.add_method("is_done_loading", "secret")
|
|
34
|
+
@conn.add_method("is_app_running", "appname", "secret")
|
|
35
|
+
@conn.add_method("stop_app", "app_name", "secret")
|
|
36
|
+
@conn.add_method("get_all_public_ips", "secret")
|
|
37
|
+
@conn.add_method("kill", "secret")
|
|
38
|
+
@conn.add_method("get_role_info", "secret")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def make_call(time, retry_on_except, want_output=true)
|
|
42
|
+
refused_count = 0
|
|
43
|
+
max = 10
|
|
44
|
+
|
|
45
|
+
begin
|
|
46
|
+
Timeout::timeout(time) {
|
|
47
|
+
yield if block_given?
|
|
48
|
+
}
|
|
49
|
+
rescue Errno::ECONNREFUSED
|
|
50
|
+
if refused_count > max
|
|
51
|
+
if want_output
|
|
52
|
+
abort("Connection with #{@ip} was refused. Is the AppController running?")
|
|
53
|
+
else
|
|
54
|
+
raise Exception
|
|
55
|
+
end
|
|
56
|
+
else
|
|
57
|
+
refused_count += 1
|
|
58
|
+
Kernel.sleep(1)
|
|
59
|
+
retry
|
|
60
|
+
end
|
|
61
|
+
rescue OpenSSL::SSL::SSLError, NotImplementedError, Errno::EPIPE, Timeout::Error, Errno::ECONNRESET
|
|
62
|
+
retry
|
|
63
|
+
rescue Exception => except
|
|
64
|
+
if retry_on_except
|
|
65
|
+
retry
|
|
66
|
+
else
|
|
67
|
+
if want_output
|
|
68
|
+
abort("We saw an unexpected error of the type #{except.class} with the following message:\n#{except}.")
|
|
69
|
+
else
|
|
70
|
+
raise except
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def is_live?
|
|
77
|
+
uri = "https://#{@ip}:17443"
|
|
78
|
+
|
|
79
|
+
begin
|
|
80
|
+
Timeout::timeout(5) {
|
|
81
|
+
make_call(1, ABORT_ON_FAIL, want_output=false) { @conn.status(@secret) }
|
|
82
|
+
}
|
|
83
|
+
return true
|
|
84
|
+
rescue Exception
|
|
85
|
+
return false
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def get_userappserver_ip(verbose_level="low")
|
|
90
|
+
userappserver_ip, status, state, new_state = "", "", "", ""
|
|
91
|
+
loop {
|
|
92
|
+
status = get_status()
|
|
93
|
+
|
|
94
|
+
new_state = status.scan(/Current State: ([\w\s\d\.,]+)\n/).flatten.to_s.chomp
|
|
95
|
+
if verbose_level == LOGS_VERBOSE and new_state != state
|
|
96
|
+
puts new_state
|
|
97
|
+
state = new_state
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
if status == "false: bad secret"
|
|
101
|
+
abort("\nWe were unable to verify your secret key with the head node specified in your locations file. Are you sure you have the correct secret key and locations file?\n\nSecret provided: [#{@secret}]\nHead node IP address: [#{@ip}]\n")
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
if status =~ /Database is at (#{IP_OR_FQDN})/ and $1 != "not-up-yet"
|
|
105
|
+
userappserver_ip = $1
|
|
106
|
+
break
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
sleep(10)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return userappserver_ip
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def set_parameters(locations, creds, apps_to_start)
|
|
116
|
+
result = ""
|
|
117
|
+
make_call(10, ABORT_ON_FAIL) {
|
|
118
|
+
result = conn.set_parameters(locations, creds, apps_to_start, @secret)
|
|
119
|
+
}
|
|
120
|
+
abort(result) if result =~ /Error:/
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def status()
|
|
124
|
+
return "Status of node at #{ip}:\n" + get_status()
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def get_status()
|
|
128
|
+
make_call(10, RETRY_ON_FAIL) { @conn.status(@secret) }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def stop_app(app_name)
|
|
132
|
+
make_call(30, RETRY_ON_FAIL) { @conn.stop_app(app_name, @secret) }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def update(app_names)
|
|
136
|
+
make_call(30, RETRY_ON_FAIL) { @conn.update(app_names, @secret) }
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def get_all_public_ips()
|
|
140
|
+
make_call(30, RETRY_ON_FAIL) { @conn.get_all_public_ips(@secret) }
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def kill()
|
|
144
|
+
make_call(NO_TIMEOUT, RETRY_ON_FAIL) { @conn.kill(@secret) }
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def is_done_initializing?()
|
|
148
|
+
make_call(NO_TIMEOUT, RETRY_ON_FAIL) {
|
|
149
|
+
@conn.is_done_initializing(@secret)
|
|
150
|
+
}
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def is_done_loading?()
|
|
154
|
+
make_call(NO_TIMEOUT, RETRY_ON_FAIL) { @conn.is_done_loading(@secret) }
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def done_uploading(appname, location)
|
|
158
|
+
make_call(NO_TIMEOUT, RETRY_ON_FAIL) {
|
|
159
|
+
@conn.done_uploading(appname, location, @secret)
|
|
160
|
+
}
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def app_is_running?(appname)
|
|
165
|
+
make_call(NO_TIMEOUT, RETRY_ON_FAIL) {
|
|
166
|
+
@conn.is_app_running(appname, @secret)
|
|
167
|
+
}
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# Asks the AppController to see what roles each node is running in AppScale.
|
|
172
|
+
# The result is an Array, where each item is a Hash that contains information
|
|
173
|
+
# about the given node.
|
|
174
|
+
def get_role_info()
|
|
175
|
+
make_call(NO_TIMEOUT, ABORT_ON_FAIL) {
|
|
176
|
+
@conn.get_role_info(@secret)
|
|
177
|
+
}
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
end
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# Programmer: Chris Bunch
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
$VERBOSE = nil # to supress excessive SSL cert warnings
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
require 'fileutils'
|
|
9
|
+
require 'yaml'
|
|
10
|
+
require 'soap/rpc/driver'
|
|
11
|
+
require 'timeout'
|
|
12
|
+
require 'base64'
|
|
13
|
+
require 'openssl'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
|
17
|
+
require 'app_controller_client'
|
|
18
|
+
require 'common_functions'
|
|
19
|
+
require 'custom_exceptions'
|
|
20
|
+
require 'encryption_helper'
|
|
21
|
+
require 'godinterface'
|
|
22
|
+
require 'node_layout'
|
|
23
|
+
require 'parse_args'
|
|
24
|
+
require 'remote_log'
|
|
25
|
+
require 'usage_text'
|
|
26
|
+
require 'user_app_client'
|
|
27
|
+
require 'vm_tools'
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
module AppScaleTools
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
ADD_KEYPAIR_FLAGS = ["help", "usage", "h", "ips", "keyname", "version",
|
|
34
|
+
"auto"]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
ADD_KEYPAIR_USAGE = UsageText.get_usage("appscale-add-keypair",
|
|
38
|
+
ADD_KEYPAIR_FLAGS)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
IP_REGEX = /\d+\.\d+\.\d+\.\d+/
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
FQDN_REGEX = /([\w\d\.\-]+\.){2,}/
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
IP_OR_FQDN = /#{IP_REGEX}|#{FQDN_REGEX}/
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
DESCRIBE_INSTANCES_FLAGS = ["help", "usage", "h", "keyname", "version"]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
DESCRIBE_INSTANCES_USAGE = UsageText.get_usage("appscale-describe-instances",
|
|
54
|
+
DESCRIBE_INSTANCES_FLAGS)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
NO_APPNAME_GIVEN = "You failed to specify an application to remove."
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
APP_NOT_RUNNING = "We could not stop your application because it was " +
|
|
61
|
+
"not running."
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
APP_REMOVAL_CANCELLED = "Application removal cancelled."
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
REMOVE_APP_FLAGS = ["help", "h", "usage", "appname", "version", "keyname",
|
|
68
|
+
"confirm"]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
REMOVE_APP_USAGE = UsageText.get_usage("appscale-remove-app",
|
|
72
|
+
REMOVE_APP_FLAGS)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
APPSCALE_NOT_RUNNING = "We are not able to reset your password right now, as AppScale is not currently running."
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
RESET_PASSWORD_FLAGS = ["help", "usage", "h", "keyname", "version"]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
RESET_PASSWORD_USAGE = UsageText.get_usage("appscale-reset-pwd",
|
|
82
|
+
RESET_PASSWORD_FLAGS)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
DJINN_SERVER_DIED_MSG = "\nEither the head node was unable to get IP" +
|
|
86
|
+
" addresses for any slave nodes or a bug in the head node's code" +
|
|
87
|
+
" caused it to crash. We have left your virtual machines running" +
|
|
88
|
+
" in case you wish to submit a bug report or investigate further" +
|
|
89
|
+
" via the Troubleshooting page."
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
NO_MACHINE_SET = "You failed to provide a machine image via the --machine" +
|
|
93
|
+
" flag or the APPSCALE_MACHINE environment variable."
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
RUN_INSTANCES_FLAGS = ["help", "h", "min", "max", "file", "table", "ips",
|
|
97
|
+
"v", "verbose", "machine", "instance_type", "usage", "version", "keyname",
|
|
98
|
+
"iaas", "infrastructure", "n", "r", "w", "scp", "test", "appengine",
|
|
99
|
+
"force", "restore_from_tar", "restore_neptune_info", "group"]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
RUN_INSTANCES_USAGE = UsageText.get_usage("appscale-run-instances",
|
|
103
|
+
RUN_INSTANCES_FLAGS)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
SSH_PORT = 22
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
PBSERVER_PORT = 443
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
DJINN_SERVER_PORT = 17443
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
UA_SERVER_PORT = 4343
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
USE_SSL = true
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
TERMINATE_INSTANCES_FLAGS = ["help", "h", "usage", "version", "verbose",
|
|
122
|
+
"keyname", "backup_neptune_info"]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
TERMINATE_INSTANCES_USAGE = UsageText.get_usage(
|
|
126
|
+
"appscale-terminate-instances", TERMINATE_INSTANCES_FLAGS)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
UNABLE_TO_TERMINATE_ANY_MACHINES = "We were unable to shut down any of " +
|
|
130
|
+
"your machines running AppScale. \nPlease verify that the machines are " +
|
|
131
|
+
"live, running AppScale, and reachable from your current location."
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
APPSCALE_NOT_RUNNING = "AppScale does not appear to be running. If you are " +
|
|
135
|
+
"using a cloud deployment, please manually terminate any running instances."
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
NO_FILE_PROVIDED_MSG = "You failed to provide a file to upload. Please do " +
|
|
139
|
+
"so via the --file flag and try again."
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
APP_ALREADY_EXISTS = "An app with the name you provided in app.yaml " +
|
|
143
|
+
"already exists. Please change the provided name in app.yaml and retry " +
|
|
144
|
+
"uploading your app. If you want to upload a new version of your " +
|
|
145
|
+
"application, use appscale-remove-app to remove the old version, then " +
|
|
146
|
+
"use this tool to upload the new version."
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
USER_NOT_ADMIN = "An app with the name you provided in app.yaml has already" +
|
|
150
|
+
" been reserved by a different user. Please change the provided name in " +
|
|
151
|
+
"app.yaml and retry uploading your application."
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
DJINN_SERVER_PORT = 17443
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
UPLOAD_APP_FLAGS = ["help", "h", "usage", "file", "version", "keyname",
|
|
158
|
+
"test", "email"]
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
UPLOAD_APP_USAGE = UsageText.get_usage("appscale-upload-app",
|
|
162
|
+
UPLOAD_APP_FLAGS)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def self.add_keypair(options)
|
|
166
|
+
keyname = options['keyname']
|
|
167
|
+
ips_yaml = options['ips']
|
|
168
|
+
auto = options['auto']
|
|
169
|
+
|
|
170
|
+
if ips_yaml.nil?
|
|
171
|
+
raise BadConfigurationException.new(ADD_KEYPAIR_USAGE)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
node_layout = NodeLayout.new(ips_yaml, { :database => "cassandra" } )
|
|
175
|
+
|
|
176
|
+
required_commands = ["ssh-keygen", "ssh-copy-id"]
|
|
177
|
+
if auto
|
|
178
|
+
required_commands << "expect"
|
|
179
|
+
end
|
|
180
|
+
CommonFunctions.require_commands(required_commands)
|
|
181
|
+
|
|
182
|
+
CommonFunctions.make_appscale_directory()
|
|
183
|
+
|
|
184
|
+
path = File.expand_path("~/.appscale/#{keyname}")
|
|
185
|
+
pub_key, backup_key = CommonFunctions.generate_rsa_key(keyname)
|
|
186
|
+
|
|
187
|
+
if auto
|
|
188
|
+
print "\nEnter SSH password of root: "
|
|
189
|
+
password = CommonFunctions.get_line_from_stdin_no_echo()
|
|
190
|
+
|
|
191
|
+
# Location of expect script that interacts with ssh-copy-id
|
|
192
|
+
expect_script = File.join(File.join(File.dirname(__FILE__), "..", "lib"),"sshcopyid")
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
ips = node_layout.nodes.collect { |node| node.id }
|
|
196
|
+
copy_success = true
|
|
197
|
+
|
|
198
|
+
ips.each { |ip|
|
|
199
|
+
CommonFunctions.ssh_copy_id(ip, path, auto, expect_script, password)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
head_node_ip = node_layout.head_node.id
|
|
203
|
+
CommonFunctions.scp_ssh_key_to_ip(head_node_ip, path, pub_key)
|
|
204
|
+
|
|
205
|
+
FileUtils.cp(path, backup_key)
|
|
206
|
+
puts "A new ssh key has been generated for you and placed at" +
|
|
207
|
+
" #{path}. You can now use this key to log into any of the " +
|
|
208
|
+
"machines you specified without providing a password via the" +
|
|
209
|
+
" following command:\n\tssh root@#{head_node_ip} -i #{path}"
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def self.describe_instances(options)
|
|
214
|
+
keyname = options['keyname']
|
|
215
|
+
CommonFunctions.update_locations_file(keyname)
|
|
216
|
+
secret_key = CommonFunctions.get_secret_key(keyname)
|
|
217
|
+
|
|
218
|
+
instance_info = []
|
|
219
|
+
all_ips = CommonFunctions.get_all_public_ips(keyname)
|
|
220
|
+
all_ips.each { |ip|
|
|
221
|
+
acc = AppControllerClient.new(ip, secret_key)
|
|
222
|
+
instance_info << acc.status()
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return {:error => nil, :result => instance_info }
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def self.remove_app(options)
|
|
230
|
+
CommonFunctions.update_locations_file(options['keyname'])
|
|
231
|
+
if options['appname'].nil?
|
|
232
|
+
raise BadConfigurationException.new(NO_APPNAME_GIVEN)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
result = CommonFunctions.confirm_app_removal(options['confirm'],
|
|
236
|
+
options['appname'])
|
|
237
|
+
if result == "NO"
|
|
238
|
+
raise AppScaleException.new(APP_REMOVAL_CANCELLED)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
CommonFunctions.remove_app(options['appname'], options['keyname'])
|
|
242
|
+
Kernel.puts "Done shutting down app #{options['appname']}"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def self.reset_password(options)
|
|
247
|
+
keyname = options['keyname']
|
|
248
|
+
CommonFunctions.update_locations_file(keyname)
|
|
249
|
+
secret = CommonFunctions.get_secret_key(keyname)
|
|
250
|
+
|
|
251
|
+
head_node_ip = CommonFunctions.get_load_balancer_ip(keyname)
|
|
252
|
+
if head_node_ip.empty?
|
|
253
|
+
raise BadConfigurationException.new(APPSCALE_NOT_RUNNING)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
user = CommonFunctions.get_email
|
|
257
|
+
pass = CommonFunctions.get_password
|
|
258
|
+
puts "\n"
|
|
259
|
+
encrypted_pass = CommonFunctions.encrypt_password(user, pass)
|
|
260
|
+
|
|
261
|
+
acc = AppControllerClient.new(head_node_ip, secret)
|
|
262
|
+
userappserver_ip = acc.get_userappserver_ip
|
|
263
|
+
|
|
264
|
+
uac = UserAppClient.new(userappserver_ip, secret)
|
|
265
|
+
uac.change_password(user, encrypted_pass)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def self.run_instances(options)
|
|
270
|
+
infrastructure = options['infrastructure']
|
|
271
|
+
instance_type = options['instance_type']
|
|
272
|
+
machine = options['machine']
|
|
273
|
+
max_images = options['max_images']
|
|
274
|
+
table = options['table']
|
|
275
|
+
|
|
276
|
+
CommonFunctions.make_appscale_directory()
|
|
277
|
+
CommonFunctions.validate_run_instances_options(options)
|
|
278
|
+
CommonFunctions.print_starting_message(infrastructure, instance_type)
|
|
279
|
+
RemoteLogging.remote_post(max_images, table, infrastructure, "starting", "unknown")
|
|
280
|
+
sleep(2)
|
|
281
|
+
|
|
282
|
+
apps_to_start, app_info = CommonFunctions.get_app_info_from_options(options)
|
|
283
|
+
node_layout, result = CommonFunctions.generate_node_layout(options)
|
|
284
|
+
head_node_result = CommonFunctions.start_head_node(options, node_layout,
|
|
285
|
+
apps_to_start)
|
|
286
|
+
|
|
287
|
+
print "\nPlease wait for AppScale to prepare your machines for use."
|
|
288
|
+
STDOUT.flush
|
|
289
|
+
puts "\n"
|
|
290
|
+
|
|
291
|
+
acc = head_node_result[:acc]
|
|
292
|
+
secret_key = head_node_result[:secret_key]
|
|
293
|
+
head_node_ip = head_node_result[:head_node_ip]
|
|
294
|
+
CommonFunctions.write_and_copy_node_file(options, node_layout,
|
|
295
|
+
head_node_result)
|
|
296
|
+
|
|
297
|
+
userappserver_ip = acc.get_userappserver_ip(LOGS_VERBOSE)
|
|
298
|
+
CommonFunctions.update_locations_file(options['keyname'], [head_node_ip])
|
|
299
|
+
CommonFunctions.verbose("Run instances: UserAppServer is at #{userappserver_ip}", options['verbose'])
|
|
300
|
+
uac = UserAppClient.new(userappserver_ip, secret_key)
|
|
301
|
+
user, pass = CommonFunctions.get_credentials(options['test'])
|
|
302
|
+
CommonFunctions.create_user(user, options['test'], head_node_ip,
|
|
303
|
+
secret_key, uac, pass)
|
|
304
|
+
|
|
305
|
+
uac.set_cloud_admin_status(user, new_status="true")
|
|
306
|
+
uac.set_cloud_admin_capabilities(user)
|
|
307
|
+
|
|
308
|
+
CommonFunctions.wait_for_nodes_to_load(head_node_ip, secret_key)
|
|
309
|
+
if options['file_location'].nil?
|
|
310
|
+
puts "No app uploaded. Use appscale-upload-app to upload an app later."
|
|
311
|
+
else
|
|
312
|
+
remote_file_path = CommonFunctions.scp_app_to_ip(app_info[:app_name],
|
|
313
|
+
user, app_info[:language], options['keyname'], head_node_ip,
|
|
314
|
+
app_info[:file], uac)
|
|
315
|
+
|
|
316
|
+
acc.done_uploading(app_info[:app_name], remote_file_path)
|
|
317
|
+
|
|
318
|
+
CommonFunctions.wait_for_app_to_start(head_node_ip, secret_key,
|
|
319
|
+
app_info[:app_name])
|
|
320
|
+
CommonFunctions.clear_app(app_info[:file])
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
login_ip = CommonFunctions.get_login_ip(head_node_ip, secret_key)
|
|
324
|
+
puts "The status of your AppScale instance is at the following" +
|
|
325
|
+
" URL: http://#{login_ip}/status"
|
|
326
|
+
|
|
327
|
+
CommonFunctions.write_and_copy_node_file(options, node_layout,
|
|
328
|
+
head_node_result)
|
|
329
|
+
RemoteLogging.remote_post(max_images, table, infrastructure, "started", "success")
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def self.terminate_instances(options)
|
|
334
|
+
keyname = options['keyname']
|
|
335
|
+
locations_yaml = File.expand_path("~/.appscale/locations-#{keyname}.yaml")
|
|
336
|
+
if !File.exists?(locations_yaml)
|
|
337
|
+
raise AppScaleException.new(APPSCALE_NOT_RUNNING)
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
CommonFunctions.update_locations_file(keyname)
|
|
341
|
+
shadow_ip = CommonFunctions.get_head_node_ip(keyname)
|
|
342
|
+
secret = CommonFunctions.get_secret_key(keyname)
|
|
343
|
+
|
|
344
|
+
if options['backup_neptune_info']
|
|
345
|
+
CommonFunctions.backup_neptune_info(keyname, shadow_ip,
|
|
346
|
+
options['backup_neptune_info'])
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
infrastructure = CommonFunctions.get_infrastructure(keyname, required=true)
|
|
350
|
+
if VALID_CLOUD_TYPES.include?(infrastructure)
|
|
351
|
+
CommonFunctions.terminate_via_infrastructure(infrastructure, keyname, shadow_ip, secret)
|
|
352
|
+
else
|
|
353
|
+
CommonFunctions.terminate_via_vmm(keyname, options['verbose'])
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
CommonFunctions.delete_appscale_files(keyname)
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def self.upload_app(options)
|
|
361
|
+
file_location = options['file_location']
|
|
362
|
+
if file_location.nil?
|
|
363
|
+
raise AppScaleException.new(NO_FILE_PROVIDED_MSG)
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
keyname = options['keyname']
|
|
367
|
+
CommonFunctions.update_locations_file(keyname)
|
|
368
|
+
secret_key = CommonFunctions.get_secret_key(keyname)
|
|
369
|
+
head_node_ip = CommonFunctions.get_head_node_ip(keyname)
|
|
370
|
+
database = CommonFunctions.get_table(keyname)
|
|
371
|
+
|
|
372
|
+
app_info = CommonFunctions.get_app_name_from_tar(file_location)
|
|
373
|
+
app_name, file_location, language = app_info[:app_name], app_info[:file], app_info[:language]
|
|
374
|
+
CommonFunctions.validate_app_name(app_name, database)
|
|
375
|
+
|
|
376
|
+
acc = AppControllerClient.new(head_node_ip, secret_key)
|
|
377
|
+
user = CommonFunctions.get_username_from_options(options)
|
|
378
|
+
userappserver_ip = acc.get_userappserver_ip(LOGS_VERBOSE)
|
|
379
|
+
uac = UserAppClient.new(userappserver_ip, secret_key)
|
|
380
|
+
if !uac.does_user_exist?(user)
|
|
381
|
+
CommonFunctions.create_user(user, options['test'], head_node_ip,
|
|
382
|
+
secret_key, uac)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
Kernel.puts ""
|
|
386
|
+
|
|
387
|
+
if uac.does_app_exist?(app_name)
|
|
388
|
+
raise AppScaleException.new(APP_ALREADY_EXISTS)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
app_admin = uac.get_app_admin(app_name)
|
|
392
|
+
if !app_admin.empty? and user != app_admin
|
|
393
|
+
raise AppScaleException.new(USER_NOT_ADMIN)
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
remote_file_path = CommonFunctions.scp_app_to_ip(app_name, user, language,
|
|
397
|
+
keyname, head_node_ip, file_location, uac)
|
|
398
|
+
CommonFunctions.update_appcontroller(head_node_ip, secret_key, app_name,
|
|
399
|
+
remote_file_path)
|
|
400
|
+
CommonFunctions.wait_for_app_to_start(head_node_ip, secret_key, app_name)
|
|
401
|
+
CommonFunctions.clear_app(file_location)
|
|
402
|
+
end
|
|
403
|
+
end
|