appscale-tools 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|