openstudio-aws 0.7.0.alpha0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +4 -127
- data/.travis.yml +1 -2
- data/CHANGELOG.md +10 -0
- data/Gemfile +2 -2
- data/Rakefile +39 -4
- data/lib/openstudio/aws/aws.rb +32 -26
- data/lib/openstudio/aws/config.rb +3 -3
- data/lib/openstudio/aws/version.rb +36 -1
- data/lib/openstudio/core_ext/hash.rb +35 -0
- data/lib/openstudio/lib/ami_list.rb +21 -16
- data/lib/openstudio/lib/openstudio_aws_instance.rb +59 -23
- data/lib/openstudio/lib/openstudio_aws_logger.rb +2 -2
- data/lib/openstudio/lib/openstudio_aws_wrapper.rb +57 -33
- data/lib/openstudio/lib/openstudio_cloud_watch.rb +5 -4
- data/lib/openstudio-aws.rb +1 -1
- data/openstudio-aws.gemspec +5 -5
- data/spec/aws_instances/aws_spec_api.rb +38 -3
- data/spec/openstudio-aws/ami_list_spec.rb +45 -1
- data/spec/openstudio-aws/aws_instance_spec.rb +52 -1
- data/spec/openstudio-aws/aws_spec.rb +37 -2
- data/spec/openstudio-aws/aws_wrapper_spec.rb +76 -38
- data/spec/openstudio-aws/config_spec.rb +37 -2
- data/spec/openstudio-aws/openstudio_analysis_wrapper_spec.rb +52 -0
- data/spec/spec_helper.rb +35 -0
- data/update_license.rb +68 -0
- metadata +21 -18
@@ -1,5 +1,5 @@
|
|
1
1
|
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) 2008-
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
|
3
3
|
# All rights reserved.
|
4
4
|
# Redistribution and use in source and binary forms, with or without
|
5
5
|
# modification, are permitted provided that the following conditions are met:
|
@@ -156,12 +156,12 @@ class OpenStudioAwsInstance
|
|
156
156
|
t = tag.split('=')
|
157
157
|
if t.size != 2
|
158
158
|
logger.error "Tag '#{t}' not defined or does not have an equal sign"
|
159
|
-
|
159
|
+
raise "Tag '#{t}' not defined or does not have an equal sign"
|
160
160
|
next
|
161
161
|
end
|
162
|
-
if
|
162
|
+
if ['Name', 'GroupUUID', 'NumberOfProcessors', 'Purpose', 'UserID'].include? t[0]
|
163
163
|
logger.error "Tag name '#{t[0]}' is a reserved tag"
|
164
|
-
|
164
|
+
raise "Tag name '#{t[0]}' is a reserved tag"
|
165
165
|
next
|
166
166
|
end
|
167
167
|
|
@@ -238,7 +238,7 @@ class OpenStudioAwsInstance
|
|
238
238
|
}
|
239
239
|
}
|
240
240
|
else
|
241
|
-
|
241
|
+
raise 'do not know how to convert :worker instance to_os_hash. Use the os_aws.to_worker_hash method'
|
242
242
|
end
|
243
243
|
|
244
244
|
logger.info("server info #{h}")
|
@@ -258,6 +258,10 @@ class OpenStudioAwsInstance
|
|
258
258
|
@data.procs
|
259
259
|
end
|
260
260
|
|
261
|
+
# Return the total number of processors that available to run simulations. Note that this method reduces
|
262
|
+
# the number of processors on the server node by a prespecified number.
|
263
|
+
# @param instance [string], AWS instance type string
|
264
|
+
# @return [int], total number of available processors
|
261
265
|
def find_processors(instance)
|
262
266
|
lookup = {
|
263
267
|
'm3.medium' => 1,
|
@@ -296,11 +300,13 @@ class OpenStudioAwsInstance
|
|
296
300
|
end
|
297
301
|
|
298
302
|
if @openstudio_instance_type == :server
|
299
|
-
# take out
|
300
|
-
# 1 for server
|
303
|
+
# take out 5 of the processors for known processors.
|
304
|
+
# 1 for server/web
|
305
|
+
# 1 for queue (redis)
|
301
306
|
# 1 for mongodb
|
302
|
-
# 1 for
|
303
|
-
|
307
|
+
# 1 for web-background
|
308
|
+
# 1 for rserve
|
309
|
+
processors = [processors - 5, 1].max
|
304
310
|
end
|
305
311
|
|
306
312
|
processors
|
@@ -321,19 +327,26 @@ class OpenStudioAwsInstance
|
|
321
327
|
|
322
328
|
def upload_file(local_path, remote_path)
|
323
329
|
retries = 0
|
330
|
+
ssh_options = {
|
331
|
+
proxy: get_proxy,
|
332
|
+
key_data: [@private_key]
|
333
|
+
}
|
334
|
+
ssh_options.delete_if { |_k, v| v.nil? }
|
324
335
|
begin
|
325
|
-
Net::SCP.start(@data.ip, @user,
|
336
|
+
Net::SCP.start(@data.ip, @user, ssh_options) do |scp|
|
326
337
|
scp.upload! local_path, remote_path
|
327
338
|
end
|
328
339
|
rescue SystemCallError, Timeout::Error => e
|
329
340
|
# port 22 might not be available immediately after the instance finishes launching
|
330
341
|
return if retries == 5
|
342
|
+
|
331
343
|
retries += 1
|
332
344
|
sleep 2
|
333
345
|
retry
|
334
|
-
rescue
|
346
|
+
rescue StandardError
|
335
347
|
# Unknown upload error, retry
|
336
348
|
return if retries == 5
|
349
|
+
|
337
350
|
retries += 1
|
338
351
|
sleep 2
|
339
352
|
retry
|
@@ -345,22 +358,30 @@ class OpenStudioAwsInstance
|
|
345
358
|
def shell_command(command, load_env = true)
|
346
359
|
logger.info("ssh_command #{command} with load environment #{load_env}")
|
347
360
|
command = "source /etc/profile; source ~/.bash_profile; #{command}" if load_env
|
348
|
-
|
361
|
+
ssh_options = {
|
362
|
+
proxy: get_proxy,
|
363
|
+
key_data: [@private_key]
|
364
|
+
}
|
365
|
+
ssh_options.delete_if { |_k, v| v.nil? }
|
366
|
+
Net::SSH.start(@data.ip, @user, ssh_options) do |ssh|
|
349
367
|
channel = ssh.open_channel do |ch|
|
350
|
-
ch.exec
|
351
|
-
|
368
|
+
ch.exec command.to_s do |ch, success|
|
369
|
+
raise "could not execute #{command}" unless success
|
370
|
+
|
352
371
|
# "on_data" is called when the process wr_ites something to stdout
|
353
372
|
ch.on_data do |_c, data|
|
354
373
|
# $stdout.print data
|
355
|
-
logger.info(
|
374
|
+
logger.info(data.inspect.to_s)
|
356
375
|
end
|
357
376
|
# "on_extended_data" is called when the process writes something to s_tde_rr
|
358
377
|
ch.on_extended_data do |_c, _type, data|
|
359
378
|
# $stderr.print data
|
360
|
-
logger.info(
|
379
|
+
logger.info(data.inspect.to_s)
|
361
380
|
end
|
362
381
|
end
|
363
382
|
end
|
383
|
+
ssh.loop
|
384
|
+
channel.wait
|
364
385
|
end
|
365
386
|
rescue Net::SSH::HostKeyMismatch => e
|
366
387
|
e.remember_host!
|
@@ -378,13 +399,19 @@ class OpenStudioAwsInstance
|
|
378
399
|
flag = 0
|
379
400
|
while flag == 0
|
380
401
|
logger.info("wait_command #{command}")
|
381
|
-
|
402
|
+
ssh_options = {
|
403
|
+
proxy: get_proxy,
|
404
|
+
key_data: [@private_key]
|
405
|
+
}
|
406
|
+
ssh_options.delete_if { |_k, v| v.nil? }
|
407
|
+
Net::SSH.start(@data.ip, @user, ssh_options) do |ssh|
|
382
408
|
channel = ssh.open_channel do |ch|
|
383
|
-
ch.exec
|
384
|
-
|
409
|
+
ch.exec command.to_s do |ch, success|
|
410
|
+
raise "could not execute #{command}" unless success
|
411
|
+
|
385
412
|
# "on_data" is called_ when the process writes something to stdout
|
386
413
|
ch.on_data do |_c, data|
|
387
|
-
logger.info(
|
414
|
+
logger.info(data.inspect.to_s)
|
388
415
|
if data.chomp == 'true'
|
389
416
|
logger.info("wait_command #{command} is true")
|
390
417
|
flag = 1
|
@@ -394,7 +421,7 @@ class OpenStudioAwsInstance
|
|
394
421
|
end
|
395
422
|
# "on_extended_data" is called when the process writes some_thi_ng to stderr
|
396
423
|
ch.on_extended_data do |_c, _type, data|
|
397
|
-
logger.info(
|
424
|
+
logger.info(data.inspect.to_s)
|
398
425
|
if data == 'true'
|
399
426
|
logger.info("wait_command #{command} is true")
|
400
427
|
flag = 1
|
@@ -404,6 +431,8 @@ class OpenStudioAwsInstance
|
|
404
431
|
end
|
405
432
|
end
|
406
433
|
end
|
434
|
+
channel.wait
|
435
|
+
ssh.loop
|
407
436
|
end
|
408
437
|
end
|
409
438
|
rescue Net::SSH::HostKeyMismatch => e
|
@@ -420,18 +449,25 @@ class OpenStudioAwsInstance
|
|
420
449
|
|
421
450
|
def download_file(remote_path, local_path)
|
422
451
|
retries = 0
|
452
|
+
ssh_options = {
|
453
|
+
proxy: get_proxy,
|
454
|
+
key_data: [@private_key]
|
455
|
+
}
|
456
|
+
ssh_options.delete_if { |_k, v| v.nil? }
|
423
457
|
begin
|
424
|
-
Net::SCP.start(@data.ip, @user,
|
458
|
+
Net::SCP.start(@data.ip, @user, ssh_options) do |scp|
|
425
459
|
scp.download! remote_path, local_path
|
426
460
|
end
|
427
461
|
rescue SystemCallError, Timeout::Error => e
|
428
462
|
# port 22 might not be available immediately after the instance finishes launching
|
429
463
|
return if retries == 5
|
464
|
+
|
430
465
|
retries += 1
|
431
466
|
sleep 2
|
432
467
|
retry
|
433
|
-
rescue
|
468
|
+
rescue StandardError
|
434
469
|
return if retries == 5
|
470
|
+
|
435
471
|
retries += 1
|
436
472
|
sleep 2
|
437
473
|
retry
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) 2008-
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
|
3
3
|
# All rights reserved.
|
4
4
|
# Redistribution and use in source and binary forms, with or without
|
5
5
|
# modification, are permitted provided that the following conditions are met:
|
@@ -35,7 +35,7 @@
|
|
35
35
|
|
36
36
|
require 'logger'
|
37
37
|
|
38
|
-
# module for logging
|
38
|
+
# module for logging. The AWS log will be stored in the user's home directory under .aws.log.
|
39
39
|
module Logging
|
40
40
|
def logger
|
41
41
|
@logger ||= Logging.logger_for(self.class.name)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) 2008-
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
|
3
3
|
# All rights reserved.
|
4
4
|
# Redistribution and use in source and binary forms, with or without
|
5
5
|
# modification, are permitted provided that the following conditions are met:
|
@@ -48,10 +48,10 @@ class OpenStudioAwsWrapper
|
|
48
48
|
attr_accessor :private_key_file_name
|
49
49
|
attr_accessor :security_groups
|
50
50
|
|
51
|
-
VALID_OPTIONS = [:proxy, :credentials]
|
51
|
+
VALID_OPTIONS = [:proxy, :credentials].freeze
|
52
52
|
|
53
53
|
def initialize(options = {}, group_uuid = nil)
|
54
|
-
@group_uuid = group_uuid ||
|
54
|
+
@group_uuid = group_uuid || SecureRandom.uuid.delete('-')
|
55
55
|
|
56
56
|
@security_groups = []
|
57
57
|
@key_pair_name = nil
|
@@ -75,20 +75,36 @@ class OpenStudioAwsWrapper
|
|
75
75
|
@workers = []
|
76
76
|
|
77
77
|
# store an instance variable with the proxy for passing to instances for use in scp/ssh
|
78
|
-
@proxy = options[:proxy]
|
78
|
+
@proxy = options[:proxy] || nil
|
79
79
|
|
80
80
|
# need to remove the prxoy information here
|
81
81
|
@aws = Aws::EC2::Client.new(options[:credentials])
|
82
82
|
end
|
83
83
|
|
84
|
+
# Calculate the number of processors for the server and workers. This is used to scale the docker stack
|
85
|
+
# appropriately.
|
86
|
+
# @param total_procs [int] Total number of processors that are available
|
87
|
+
def calculate_processors(total_procs)
|
88
|
+
max_requests = ((total_procs + 10) * 1.2).round
|
89
|
+
mongo_cores = (total_procs / 64.0).ceil
|
90
|
+
web_cores = (total_procs / 32.0).ceil
|
91
|
+
max_pool = 16 * web_cores
|
92
|
+
rez_mem = 512 * max_pool
|
93
|
+
# what is this +2 doing here
|
94
|
+
total_procs = total_procs - mongo_cores - web_cores + 2
|
95
|
+
|
96
|
+
[total_procs, max_requests, mongo_cores, web_cores, max_pool, rez_mem]
|
97
|
+
end
|
98
|
+
|
84
99
|
def create_or_retrieve_default_security_group(tmp_name = 'openstudio-server-sg-v2.2', vpc_id = nil)
|
85
100
|
group = @aws.describe_security_groups(filters: [{ name: 'group-name', values: [tmp_name] }])
|
86
101
|
logger.info "Length of the security group is: #{group.data.security_groups.length}"
|
87
|
-
if group.data.security_groups.
|
102
|
+
if group.data.security_groups.empty?
|
88
103
|
logger.info 'security group not found --- will create a new one'
|
89
104
|
if vpc_id
|
90
|
-
r = @aws.create_security_group(
|
91
|
-
|
105
|
+
r = @aws.create_security_group(
|
106
|
+
group_name: tmp_name, description: "group dynamically created by #{__FILE__}", vpc_id: vpc_id
|
107
|
+
)
|
92
108
|
else
|
93
109
|
r = @aws.create_security_group(group_name: tmp_name, description: "group dynamically created by #{__FILE__}")
|
94
110
|
end
|
@@ -134,7 +150,7 @@ class OpenStudioAwsWrapper
|
|
134
150
|
def total_instances_count
|
135
151
|
resp = @aws.describe_instance_status
|
136
152
|
|
137
|
-
availability_zone = resp.instance_statuses.
|
153
|
+
availability_zone = !resp.instance_statuses.empty? ? resp.instance_statuses.first.availability_zone : 'no_instances'
|
138
154
|
|
139
155
|
{ total_instances: resp.instance_statuses.length, region: @region, availability_zone: availability_zone }
|
140
156
|
end
|
@@ -289,12 +305,12 @@ class OpenStudioAwsWrapper
|
|
289
305
|
resp = nil
|
290
306
|
begin
|
291
307
|
resp = @aws.describe_key_pairs(key_names: [tmp_name]).data
|
292
|
-
|
293
|
-
rescue
|
308
|
+
raise 'looks like there are 2 key pairs with the same name' if resp.key_pairs.size >= 2
|
309
|
+
rescue StandardError
|
294
310
|
logger.info "could not find key pair '#{tmp_name}'"
|
295
311
|
end
|
296
312
|
|
297
|
-
if resp.nil? || resp.key_pairs.
|
313
|
+
if resp.nil? || resp.key_pairs.empty?
|
298
314
|
# create the new key_pair
|
299
315
|
# check if the key pair name exists
|
300
316
|
# create a new key pair everytime
|
@@ -320,7 +336,7 @@ class OpenStudioAwsWrapper
|
|
320
336
|
begin
|
321
337
|
logger.info "Trying to delete key pair #{tmp_name}"
|
322
338
|
resp = @aws.delete_key_pair(key_name: tmp_name)
|
323
|
-
rescue
|
339
|
+
rescue StandardError
|
324
340
|
logger.info "could not delete the key pair '#{tmp_name}'"
|
325
341
|
end
|
326
342
|
|
@@ -335,7 +351,7 @@ class OpenStudioAwsWrapper
|
|
335
351
|
logger.info "Found key of same name in user's home ssh folder #{filename}"
|
336
352
|
# using the key in your home directory
|
337
353
|
else
|
338
|
-
|
354
|
+
raise "Could not find private key #{filename}" unless File.exist? filename
|
339
355
|
end
|
340
356
|
end
|
341
357
|
|
@@ -360,9 +376,9 @@ class OpenStudioAwsWrapper
|
|
360
376
|
logger.info "Saving server private key in #{@private_key_file_name}"
|
361
377
|
File.open(@private_key_file_name, 'w') { |f| f << @private_key }
|
362
378
|
logger.info 'Setting permissions of server private key to 0600'
|
363
|
-
File.chmod(
|
379
|
+
File.chmod(0o600, @private_key_file_name)
|
364
380
|
else
|
365
|
-
|
381
|
+
raise "No private key found in which to persist with filename #{filename}"
|
366
382
|
end
|
367
383
|
end
|
368
384
|
|
@@ -372,7 +388,7 @@ class OpenStudioAwsWrapper
|
|
372
388
|
logger.info "Saving worker private key in #{@worker_keys_filename}"
|
373
389
|
File.open(@worker_keys_filename, 'w') { |f| f << @worker_keys.private_key }
|
374
390
|
logger.info 'Setting permissions of worker private key to 0600'
|
375
|
-
File.chmod(
|
391
|
+
File.chmod(0o600, @worker_keys_filename)
|
376
392
|
|
377
393
|
wk = "#{directory}/ec2_worker_key.pub"
|
378
394
|
logger.info "Saving worker public key in #{wk}"
|
@@ -390,7 +406,7 @@ class OpenStudioAwsWrapper
|
|
390
406
|
|
391
407
|
# replace the server_script.sh.template with the keys to add
|
392
408
|
|
393
|
-
user_data = File.read(File.join(
|
409
|
+
user_data = File.read(File.join(__dir__, launch_options[:user_data_file]))
|
394
410
|
user_data.gsub!(/SERVER_HOSTNAME/, 'openstudio.server')
|
395
411
|
user_data.gsub!(/WORKER_PRIVATE_KEY_TEMPLATE/, worker_keys.private_key.gsub("\n", '\\n'))
|
396
412
|
user_data.gsub!(/WORKER_PUBLIC_KEY_TEMPLATE/, worker_keys.ssh_public_key)
|
@@ -400,8 +416,9 @@ class OpenStudioAwsWrapper
|
|
400
416
|
|
401
417
|
# TODO: create the EBS volumes instead of the ephemeral storage - needed especially for the m3 instances (SSD)
|
402
418
|
|
403
|
-
|
404
|
-
|
419
|
+
raise 'image_id is nil' unless image_id
|
420
|
+
raise 'instance type is nil' unless instance_type
|
421
|
+
|
405
422
|
@server.launch_instance(image_id, instance_type, user_data, launch_options[:user_id], launch_options)
|
406
423
|
end
|
407
424
|
|
@@ -415,7 +432,7 @@ class OpenStudioAwsWrapper
|
|
415
432
|
}
|
416
433
|
launch_options = defaults.merge(launch_options)
|
417
434
|
|
418
|
-
user_data = File.read(File.join(
|
435
|
+
user_data = File.read(File.join(__dir__, launch_options[:user_data_file]))
|
419
436
|
user_data.gsub!(/SERVER_IP/, @server.data.private_ip_address)
|
420
437
|
user_data.gsub!(/SERVER_HOSTNAME/, 'openstudio.server')
|
421
438
|
user_data.gsub!(/WORKER_PUBLIC_KEY_TEMPLATE/, worker_keys.ssh_public_key)
|
@@ -460,7 +477,7 @@ class OpenStudioAwsWrapper
|
|
460
477
|
logger.info("ips #{ips}")
|
461
478
|
@server.shell_command('chmod 664 /home/ubuntu/ip_addresses')
|
462
479
|
|
463
|
-
mongoid = File.read(
|
480
|
+
mongoid = File.read(__dir__ + '/mongoid.yml.template')
|
464
481
|
mongoid.gsub!(/SERVER_IP/, @server.data.private_ip_address)
|
465
482
|
file = Tempfile.new('mongoid.yml')
|
466
483
|
file.write(mongoid)
|
@@ -494,14 +511,20 @@ class OpenStudioAwsWrapper
|
|
494
511
|
worker_join_cmd = "#{File.read(swarm_file).strip} && echo \"true\""
|
495
512
|
@workers.each { |worker| worker.wait_command(worker_join_cmd) }
|
496
513
|
logger.info('All worker nodes have been added to the swarm. Setting environment variables and starting the cluster')
|
514
|
+
# e.g. 356 CPUs
|
515
|
+
# mongo cores = 6
|
516
|
+
# web cores = 12
|
517
|
+
# total procs = 340 (but should be 336)
|
497
518
|
total_procs = @server.procs
|
498
519
|
@workers.each { |worker| total_procs += worker.procs }
|
499
|
-
max_requests
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
520
|
+
total_procs, max_requests, mongo_cores, web_cores, max_pool, rez_mem = calculate_processors(total_procs)
|
521
|
+
logger.info('Processors allocations are:')
|
522
|
+
logger.info(" total_procs: #{total_procs}")
|
523
|
+
logger.info(" max_requests: #{max_requests}")
|
524
|
+
logger.info(" mongo_cores: #{mongo_cores}")
|
525
|
+
logger.info(" web_cores: #{web_cores}")
|
526
|
+
logger.info(" max_pool: #{max_pool}")
|
527
|
+
logger.info(" rez_mem: #{rez_mem}")
|
505
528
|
@server.shell_command("sed -i -e 's/AWS_MAX_REQUESTS/#{max_requests}/g' /home/ubuntu/docker-compose.yml && echo \"true\"")
|
506
529
|
@server.shell_command("sed -i -e 's/AWS_MONGO_CORES/#{mongo_cores}/g' /home/ubuntu/docker-compose.yml && echo \"true\"")
|
507
530
|
@server.shell_command("sed -i -e 's/AWS_WEB_CORES/#{web_cores}/g' /home/ubuntu/docker-compose.yml && echo \"true\"")
|
@@ -509,7 +532,7 @@ class OpenStudioAwsWrapper
|
|
509
532
|
@server.shell_command("sed -i -e 's/AWS_REZ_MEM/#{rez_mem}/g' /home/ubuntu/docker-compose.yml && echo \"true\"")
|
510
533
|
@server.shell_command("sed -i -e 's/AWS_OS_SERVER_NUMBER_OF_WORKERS/#{total_procs}/g' /home/ubuntu/docker-compose.yml && echo \"true\"")
|
511
534
|
@server.shell_command("echo '' >> /home/ubuntu/.env && echo \"true\"")
|
512
|
-
@server.shell_command(
|
535
|
+
@server.shell_command('docker stack deploy --compose-file docker-compose.yml osserver && echo "true"')
|
513
536
|
sleep 10
|
514
537
|
logger.info('The OpenStudio Server stack has been started. Waiting for the server to become available.')
|
515
538
|
@server.wait_command("while ( nc -zv #{@server.ip} 80 3>&1 1>&2- 2>&3- ) | awk -F \":\" '$3 != \" Connection refused\" {exit 1}'; do sleep 5; done && echo \"true\"")
|
@@ -533,13 +556,14 @@ class OpenStudioAwsWrapper
|
|
533
556
|
load_private_key(server_data_hash[:server][:private_key_file_name])
|
534
557
|
|
535
558
|
logger.info "Finding the server for GroupUUID of #{group_uuid}"
|
536
|
-
|
559
|
+
raise 'no GroupUUID defined either in member variable or method argument' if @group_uuid.nil?
|
537
560
|
|
538
561
|
# This should really just be a single call to describe running instances
|
539
562
|
@server = nil
|
540
563
|
resp = describe_running_instances(group_uuid, :server)
|
541
564
|
if resp
|
542
|
-
|
565
|
+
raise "more than one server running with group uuid of #{group_uuid} found, expecting only one" if resp.size > 1
|
566
|
+
|
543
567
|
resp = resp.first
|
544
568
|
if !@server
|
545
569
|
if resp
|
@@ -552,7 +576,7 @@ class OpenStudioAwsWrapper
|
|
552
576
|
|
553
577
|
# set the key name from AWS if it isn't yet assigned
|
554
578
|
logger.info 'Setting the keyname in the aws wrapper'
|
555
|
-
@key_pair_name
|
579
|
+
@key_pair_name ||= resp[:key_name]
|
556
580
|
|
557
581
|
@server = OpenStudioAwsInstance.new(@aws, :server, @key_pair_name, sg, @group_uuid, @private_key, @private_key_file_name, @proxy)
|
558
582
|
|
@@ -566,7 +590,7 @@ class OpenStudioAwsWrapper
|
|
566
590
|
end
|
567
591
|
|
568
592
|
# Find the worker instances.
|
569
|
-
if @workers.
|
593
|
+
if @workers.empty?
|
570
594
|
resp = describe_running_instances(group_uuid, :worker)
|
571
595
|
if resp
|
572
596
|
resp.each do |r|
|
@@ -742,7 +766,7 @@ class OpenStudioAwsWrapper
|
|
742
766
|
elsif ami[:virtualization_type] == 'hvm'
|
743
767
|
a[:amis][:cc2worker] = ami[:image_id]
|
744
768
|
else
|
745
|
-
|
769
|
+
raise "unknown virtualization_type in #{ami[:name]}"
|
746
770
|
end
|
747
771
|
elsif ami[:name] =~ /Server/
|
748
772
|
a[:amis][:server] = ami[:image_id]
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) 2008-
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
|
3
3
|
# All rights reserved.
|
4
4
|
# Redistribution and use in source and binary forms, with or without
|
5
5
|
# modification, are permitted provided that the following conditions are met:
|
@@ -41,11 +41,11 @@ class OpenStudioCloudWatch
|
|
41
41
|
attr_accessor :private_key_file_name
|
42
42
|
attr_accessor :security_groups
|
43
43
|
|
44
|
-
VALID_OPTIONS = [:proxy, :credentials]
|
44
|
+
VALID_OPTIONS = [:proxy, :credentials].freeze
|
45
45
|
|
46
46
|
def initialize(options = {})
|
47
47
|
# store an instance variable with the proxy for passing to instances for use in scp/ssh
|
48
|
-
@proxy = options[:proxy]
|
48
|
+
@proxy = options[:proxy] || nil
|
49
49
|
|
50
50
|
# need to remove the prxoy information here
|
51
51
|
@aws = Aws::CloudWatch::Client.new(options[:credentials])
|
@@ -57,7 +57,8 @@ class OpenStudioCloudWatch
|
|
57
57
|
resp = @aws.get_metric_statistics(
|
58
58
|
dimensions: [
|
59
59
|
{ name: 'ServiceName', value: 'AmazonEC2' },
|
60
|
-
{ name: 'Currency', value: 'USD' }
|
60
|
+
{ name: 'Currency', value: 'USD' }
|
61
|
+
],
|
61
62
|
metric_name: 'EstimatedCharges',
|
62
63
|
namespace: 'AWS/Billing',
|
63
64
|
start_time: start_time.iso8601,
|
data/lib/openstudio-aws.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) 2008-
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
|
3
3
|
# All rights reserved.
|
4
4
|
# Redistribution and use in source and binary forms, with or without
|
5
5
|
# modification, are permitted provided that the following conditions are met:
|
data/openstudio-aws.gemspec
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
lib = File.expand_path('
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
2
|
$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
|
3
3
|
|
4
4
|
require 'openstudio/aws/version'
|
@@ -17,13 +17,13 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.required_ruby_version = '>= 2.0.0'
|
18
18
|
s.required_rubygems_version = '>= 1.3.6'
|
19
19
|
|
20
|
-
s.add_dependency '
|
20
|
+
s.add_dependency 'aws-sdk-core', '= 2.2.37'
|
21
|
+
s.add_dependency 'net-scp', '= 2.0.0'
|
21
22
|
s.add_dependency 'net-ssh', '= 4.2.0'
|
22
|
-
s.add_dependency 'aws-sdk-core', '= 2.2.26'
|
23
23
|
s.add_dependency 'semantic', '~> 1.4'
|
24
|
-
s.add_dependency 'sshkey', '~>
|
24
|
+
s.add_dependency 'sshkey', '~> 2.0'
|
25
25
|
|
26
|
-
s.add_development_dependency 'rake', '~>
|
26
|
+
s.add_development_dependency 'rake', '~> 12.3'
|
27
27
|
|
28
28
|
s.files = `git ls-files -z`.split("\x0")
|
29
29
|
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
@@ -1,7 +1,42 @@
|
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
|
3
|
+
# All rights reserved.
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
#
|
14
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
+
# may be used to endorse or promote products derived from this software without
|
16
|
+
# specific prior written permission from the respective party.
|
17
|
+
#
|
18
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
+
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
+
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES
|
27
|
+
# GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
28
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
29
|
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
30
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
31
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
32
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
33
|
+
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
# *******************************************************************************
|
35
|
+
|
1
36
|
require 'spec_helper'
|
2
37
|
|
3
|
-
SERVER_AMI = 'ami-e0b38888'
|
4
|
-
WORKER_AMI = 'ami-a8bc87c0'
|
38
|
+
SERVER_AMI = 'ami-e0b38888'.freeze
|
39
|
+
WORKER_AMI = 'ami-a8bc87c0'.freeze
|
5
40
|
|
6
41
|
describe OpenStudio::Aws::Aws do
|
7
42
|
context 'create a new instance' do
|
@@ -383,7 +418,7 @@ describe OpenStudio::Aws::Aws do
|
|
383
418
|
|
384
419
|
shell = @aws.server.shell_command('df -h | grep /dev/xvdb.*/mnt')
|
385
420
|
expect(shell).not_to be_nil
|
386
|
-
expect(shell).to eq
|
421
|
+
expect(shell).to eq %r{/dev/xvdb.*/mnt}
|
387
422
|
ensure
|
388
423
|
@aws.terminate_instances_by_group_id(h[:group_id])
|
389
424
|
end
|
@@ -1,3 +1,38 @@
|
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
|
3
|
+
# All rights reserved.
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# (1) Redistributions of source code must retain the above copyright notice,
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
#
|
14
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors
|
15
|
+
# may be used to endorse or promote products derived from this software without
|
16
|
+
# specific prior written permission from the respective party.
|
17
|
+
#
|
18
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
19
|
+
# of modifications or other derivative works may not use the "OpenStudio"
|
20
|
+
# trademark, "OS", "os", or any other confusingly similar designation without
|
21
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
26
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES
|
27
|
+
# GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
28
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
29
|
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
30
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
31
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
32
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
33
|
+
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
# *******************************************************************************
|
35
|
+
|
1
36
|
require 'spec_helper'
|
2
37
|
|
3
38
|
describe OpenStudioAmis do
|
@@ -29,11 +64,20 @@ describe OpenStudioAmis do
|
|
29
64
|
end
|
30
65
|
|
31
66
|
context 'version 2' do
|
32
|
-
|
33
67
|
it 'should fail when trying to find a stable version for older releases' do
|
34
68
|
a = OpenStudioAmis.new(2, openstudio_version: '1.5.0', stable: true)
|
35
69
|
|
36
70
|
expect { a.get_amis }.to raise_error(/Could not find a stable version for openstudio version 1.5.0/)
|
37
71
|
end
|
38
72
|
end
|
73
|
+
|
74
|
+
context 'version 3' do
|
75
|
+
it 'should fail when trying to find a stable version for older releases' do
|
76
|
+
a = OpenStudioAmis.new(3, openstudio_version: '2.8.0', stable: true)
|
77
|
+
|
78
|
+
puts a.inspect
|
79
|
+
|
80
|
+
expect { a.get_amis }.to raise_error(/Currently the openstudio_version lookup is not supported in v3/)
|
81
|
+
end
|
82
|
+
end
|
39
83
|
end
|