appscale-tools 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/LICENSE +37 -0
  2. data/README +17 -0
  3. data/bin/appscale-add-keypair +15 -0
  4. data/bin/appscale-describe-instances +16 -0
  5. data/bin/appscale-remove-app +13 -0
  6. data/bin/appscale-reset-pwd +13 -0
  7. data/bin/appscale-run-instances +15 -0
  8. data/bin/appscale-terminate-instances +14 -0
  9. data/bin/appscale-upload-app +13 -0
  10. data/doc/AdvancedNode.html +163 -0
  11. data/doc/AppControllerClient.html +831 -0
  12. data/doc/AppEngineConfigException.html +165 -0
  13. data/doc/AppScaleException.html +165 -0
  14. data/doc/AppScaleTools.html +768 -0
  15. data/doc/BadCommandLineArgException.html +166 -0
  16. data/doc/BadConfigurationException.html +166 -0
  17. data/doc/CommonFunctions.html +2559 -0
  18. data/doc/EncryptionHelper.html +332 -0
  19. data/doc/GodInterface.html +443 -0
  20. data/doc/InfrastructureException.html +166 -0
  21. data/doc/Node.html +470 -0
  22. data/doc/NodeLayout.html +1297 -0
  23. data/doc/Object.html +539 -0
  24. data/doc/ParseArgs.html +268 -0
  25. data/doc/RemoteLogging.html +268 -0
  26. data/doc/SimpleNode.html +163 -0
  27. data/doc/UsageText.html +1204 -0
  28. data/doc/UserAppClient.html +993 -0
  29. data/doc/VMTools.html +1365 -0
  30. data/doc/bin/appscale-add-keypair.html +56 -0
  31. data/doc/bin/appscale-describe-instances.html +56 -0
  32. data/doc/bin/appscale-remove-app.html +56 -0
  33. data/doc/bin/appscale-reset-pwd.html +56 -0
  34. data/doc/bin/appscale-run-instances.html +56 -0
  35. data/doc/bin/appscale-terminate-instances.html +56 -0
  36. data/doc/bin/appscale-upload-app.html +56 -0
  37. data/doc/created.rid +21 -0
  38. data/doc/images/add.png +0 -0
  39. data/doc/images/brick.png +0 -0
  40. data/doc/images/brick_link.png +0 -0
  41. data/doc/images/bug.png +0 -0
  42. data/doc/images/bullet_black.png +0 -0
  43. data/doc/images/bullet_toggle_minus.png +0 -0
  44. data/doc/images/bullet_toggle_plus.png +0 -0
  45. data/doc/images/date.png +0 -0
  46. data/doc/images/delete.png +0 -0
  47. data/doc/images/find.png +0 -0
  48. data/doc/images/loadingAnimation.gif +0 -0
  49. data/doc/images/macFFBgHack.png +0 -0
  50. data/doc/images/package.png +0 -0
  51. data/doc/images/page_green.png +0 -0
  52. data/doc/images/page_white_text.png +0 -0
  53. data/doc/images/page_white_width.png +0 -0
  54. data/doc/images/plugin.png +0 -0
  55. data/doc/images/ruby.png +0 -0
  56. data/doc/images/tag_blue.png +0 -0
  57. data/doc/images/tag_green.png +0 -0
  58. data/doc/images/transparent.png +0 -0
  59. data/doc/images/wrench.png +0 -0
  60. data/doc/images/wrench_orange.png +0 -0
  61. data/doc/images/zoom.png +0 -0
  62. data/doc/index.html +116 -0
  63. data/doc/js/darkfish.js +153 -0
  64. data/doc/js/jquery.js +18 -0
  65. data/doc/js/navigation.js +142 -0
  66. data/doc/js/quicksearch.js +114 -0
  67. data/doc/js/search.js +94 -0
  68. data/doc/js/search_index.js +1 -0
  69. data/doc/js/searcher.js +228 -0
  70. data/doc/js/thickbox-compressed.js +10 -0
  71. data/doc/lib/app_controller_client_rb.html +60 -0
  72. data/doc/lib/appscale_tools_rb.html +88 -0
  73. data/doc/lib/common_functions_rb.html +78 -0
  74. data/doc/lib/custom_exceptions_rb.html +54 -0
  75. data/doc/lib/encryption_helper_rb.html +60 -0
  76. data/doc/lib/godinterface_rb.html +52 -0
  77. data/doc/lib/node_layout_rb.html +55 -0
  78. data/doc/lib/parse_args_rb.html +58 -0
  79. data/doc/lib/remote_log_rb.html +58 -0
  80. data/doc/lib/sshcopyid.html +174 -0
  81. data/doc/lib/usage_text_rb.html +58 -0
  82. data/doc/lib/user_app_client_rb.html +62 -0
  83. data/doc/lib/vm_tools_rb.html +62 -0
  84. data/doc/table_of_contents.html +496 -0
  85. data/lib/app_controller_client.rb +181 -0
  86. data/lib/appscale_tools.rb +403 -0
  87. data/lib/common_functions.rb +1467 -0
  88. data/lib/custom_exceptions.rb +25 -0
  89. data/lib/encryption_helper.rb +86 -0
  90. data/lib/godinterface.rb +152 -0
  91. data/lib/node_layout.rb +665 -0
  92. data/lib/parse_args.rb +415 -0
  93. data/lib/remote_log.rb +46 -0
  94. data/lib/sshcopyid +65 -0
  95. data/lib/usage_text.rb +144 -0
  96. data/lib/user_app_client.rb +245 -0
  97. data/lib/vm_tools.rb +549 -0
  98. data/test/tc_app_controller_client.rb +10 -0
  99. data/test/tc_appscale_add_keypair.rb +44 -0
  100. data/test/tc_appscale_describe_instances.rb +69 -0
  101. data/test/tc_appscale_remove_app.rb +128 -0
  102. data/test/tc_appscale_reset_pwd.rb +156 -0
  103. data/test/tc_appscale_run_instances.rb +48 -0
  104. data/test/tc_appscale_terminate_instances.rb +104 -0
  105. data/test/tc_appscale_upload_app.rb +166 -0
  106. data/test/tc_common_functions.rb +56 -0
  107. data/test/tc_encryption_helper.rb +10 -0
  108. data/test/tc_god_interface.rb +10 -0
  109. data/test/tc_node_layout.rb +93 -0
  110. data/test/tc_parse_args.rb +160 -0
  111. data/test/tc_user_app_client.rb +10 -0
  112. data/test/tc_vm_tools.rb +10 -0
  113. data/test/ts_all.rb +20 -0
  114. 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