openstudio-aws 0.7.0.alpha0 → 0.7.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.
- 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
|