openstudio-aws 0.1
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 +7 -0
- data/README.md +18 -0
- data/Rakefile +75 -0
- data/lib/openstudio-aws.rb +9 -0
- data/lib/openstudio/aws/aws.rb +97 -0
- data/lib/openstudio/aws/config.rb +39 -0
- data/lib/openstudio/aws/send_data.rb +42 -0
- data/lib/openstudio/aws/version.rb +6 -0
- data/lib/openstudio/lib/mongoid.yml.template +19 -0
- data/lib/openstudio/lib/os-aws.rb +556 -0
- data/lib/openstudio/lib/server_script.sh +46 -0
- data/lib/openstudio/lib/worker_script.sh.template +39 -0
- data/spec/openstudio-aws/aws_spec.rb +53 -0
- data/spec/spec_helper.rb +8 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3f236cadc25bfed979fd052337a7cc9712186075
|
4
|
+
data.tar.gz: 79ece9147f4fc4408fb39cdba032c4ef5c4cfa0c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 644b891e5a9cdb2476df32d3b7847bad5f30aa0d9ba9adab099ab9c99df4b9be44f87d78f0ca5ef74653eb0f3a97070b5bf848485e9b617f733ae361439fd54d
|
7
|
+
data.tar.gz: bdc69e4e5293cedb1ee3454143a7f226197e5adac1810378426c90a7f7ea809ad1044d0e1aa99949d16057d12408227c294cb2b424ff9b0dabeff1cf729f0324
|
data/README.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
OpenStudio AWS Gem
|
2
|
+
==================
|
3
|
+
|
4
|
+
OpenStudio AWS uses the OpenStudio AWS ruby class to launch a server and multiple workers for doing
|
5
|
+
OpenStudio/EnergyPlus Analyses using Amazon AWS/EC2
|
6
|
+
|
7
|
+
Instructions
|
8
|
+
------------
|
9
|
+
|
10
|
+
Typically this gem is used in conjunction with other gems such as OpenStudio-Analysis.
|
11
|
+
|
12
|
+
To use this make sure to have ruby 2.0 in your path.
|
13
|
+
|
14
|
+
Development Notes
|
15
|
+
-----------------
|
16
|
+
|
17
|
+
There is an underlying attempt to merge several OpenStudio based gems into one and have a general
|
18
|
+
OpenStudio namespace for ruby classes.
|
data/Rakefile
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require "bundler"
|
2
|
+
Bundler.setup
|
3
|
+
|
4
|
+
require "rake"
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
8
|
+
require "openstudio/aws/version"
|
9
|
+
|
10
|
+
task :gem => :build
|
11
|
+
task :build do
|
12
|
+
system "gem build openstudio-aws.gemspec"
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "build and install gem locally"
|
16
|
+
task :install => :build do
|
17
|
+
system "gem install openstudio-aws-#{OpenStudio::Aws::VERSION}.gem --no-ri --no-rdoc"
|
18
|
+
end
|
19
|
+
|
20
|
+
task :release => :build do
|
21
|
+
# system "git tag -a v#{OpenStudio::Aws::VERSION} -m 'Tagging #{OpenStudio::Aws::VERSION}'"
|
22
|
+
# system "git push --tags"
|
23
|
+
system "gem push openstudio-aws-#{OpenStudio::Aws::VERSION}.gem"
|
24
|
+
system "rm openstudio-aws-#{OpenStudio::Aws::VERSION}.gem"
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
RSpec::Core::RakeTask.new("spec") do |spec|
|
29
|
+
spec.pattern = "spec/**/*_spec.rb"
|
30
|
+
end
|
31
|
+
|
32
|
+
RSpec::Core::RakeTask.new('spec:progress') do |spec|
|
33
|
+
spec.rspec_opts = %w(--format progress)
|
34
|
+
spec.pattern = "spec/**/*_spec.rb"
|
35
|
+
end
|
36
|
+
|
37
|
+
task :default => :spec
|
38
|
+
|
39
|
+
desc "import files from other repos"
|
40
|
+
task :import_files do
|
41
|
+
puts "Importing data from other repos until this repo is self contained"
|
42
|
+
# Copy data from github openstudio source
|
43
|
+
|
44
|
+
os_file = "./lib/openstudio/lib/os-aws.rb"
|
45
|
+
system "curl -S -s -L -o #{os_file} https://raw.github.com/NREL/OpenStudio/develop/openstudiocore/ruby/cloud/aws.rb.in"
|
46
|
+
if File.exists?(os_file)
|
47
|
+
system "ruby -i -pe 'puts \"# NOTE: Do not modify this file as it is copied over. Modify the source file and rerun rake import_files\" if $.==1' #{os_file}"
|
48
|
+
system "sed -i '' 's/\${CMAKE_VERSION_MAJOR}.\${CMAKE_VERSION_MINOR}.\${CMAKE_VERSION_PATCH}/#{OpenStudio::Aws::OPENSTUDIO_VERSION}/g' #{os_file}"
|
49
|
+
end
|
50
|
+
|
51
|
+
os_file = "./lib/openstudio/lib/mongoid.yml.template"
|
52
|
+
system "curl -S -s -L -o #{os_file} https://raw.github.com/NREL/OpenStudio/develop/openstudiocore/ruby/cloud/mongoid.yml.template"
|
53
|
+
|
54
|
+
os_file = "./lib/openstudio/lib/server_script.sh"
|
55
|
+
system "curl -S -s -L -o #{os_file} https://raw.github.com/NREL/OpenStudio/develop/openstudiocore/ruby/cloud/server_script.sh"
|
56
|
+
if File.exists?(os_file)
|
57
|
+
system "ruby -i -pe 'puts \"# NOTE: Do not modify this file as it is copied over. Modify the source file and rerun rake import_files\" if $.==2' #{os_file}"
|
58
|
+
end
|
59
|
+
|
60
|
+
os_file = "./lib/openstudio/lib/worker_script.sh.template"
|
61
|
+
system "curl -S -s -L -o #{os_file} https://raw.github.com/NREL/OpenStudio/develop/openstudiocore/ruby/cloud/worker_script.sh.template"
|
62
|
+
if File.exists?(os_file)
|
63
|
+
system "ruby -i -pe 'puts \"# NOTE: Do not modify this file as it is copied over. Modify the source file and rerun rake import_files\" if $.==2' #{os_file}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "uninstall all openstudio-aws gems"
|
68
|
+
task :uninstall do
|
69
|
+
|
70
|
+
system "gem uninstall openstudio-aws -a"
|
71
|
+
end
|
72
|
+
|
73
|
+
desc "reinstall the gem (uninstall, build, and reinstall"
|
74
|
+
task :reinstall => [:uninstall, :install]
|
75
|
+
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# This class is a wrapper around the command line version that is in the OpenStudio repository.
|
2
|
+
|
3
|
+
|
4
|
+
module OpenStudio
|
5
|
+
module Aws
|
6
|
+
class Aws
|
7
|
+
attr_reader :server_data
|
8
|
+
attr_reader :worker_data
|
9
|
+
|
10
|
+
def initialize()
|
11
|
+
# read in the config.yml file to get the secret/private key
|
12
|
+
@config = OpenStudio::Aws::Config.new()
|
13
|
+
@server_data = nil
|
14
|
+
@worker_data = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# command line call to create a new instance. This should be more tightly integrated with teh os-aws.rb gem
|
18
|
+
def create_server(instance_data = {})
|
19
|
+
# TODO: find a way to override the instance ids here in case we want to prototype
|
20
|
+
defaults = {instance_type: "m2.xlarge"}
|
21
|
+
instance_data = defaults.merge(instance_data)
|
22
|
+
|
23
|
+
# Since this is a command line call then make sure to escape the quotes in the JSON
|
24
|
+
instance_string = instance_data.to_json.gsub("\"", "\\\\\"")
|
25
|
+
|
26
|
+
|
27
|
+
# Call the openstudio script to start the ec2 instance
|
28
|
+
start_string = "ruby #{os_aws_file_location} #{@config.access_key} #{@config.secret_key} us-east-1 EC2 launch_server \"#{instance_string}\""
|
29
|
+
puts "Server Command: #{start_string}"
|
30
|
+
server_data_str = `#{start_string}`
|
31
|
+
@server_data = JSON.parse(server_data_str, :symbolize_names => true)
|
32
|
+
|
33
|
+
# Save pieces of the data for passing to the worker node
|
34
|
+
server_key_file = "ec2_server_key.pem"
|
35
|
+
File.open(server_key_file, "w") { |f| f << @server_data[:private_key] }
|
36
|
+
File.chmod(0600, server_key_file)
|
37
|
+
|
38
|
+
# Save off the server data to be loaded into the worker nodes. The Private key needs to e read from a
|
39
|
+
# file in the worker node, so save that name instead in the HASH along with a couple other changes
|
40
|
+
@server_data[:private_key] = server_key_file
|
41
|
+
if @server_data[:server]
|
42
|
+
@server_data[:server_id] = @server_data[:server][:id]
|
43
|
+
@server_data[:server_ip] = @server_data[:server][:ip]
|
44
|
+
@server_data[:server_dns] = @server_data[:server][:dns]
|
45
|
+
end
|
46
|
+
|
47
|
+
File.open("server_data.json", "w") { |f| f << JSON.pretty_generate(@server_data) }
|
48
|
+
|
49
|
+
# Print out some debugging commands (probably work on mac/linux only)
|
50
|
+
puts ""
|
51
|
+
puts "Server SSH Command:"
|
52
|
+
|
53
|
+
puts "ssh -i #{server_key_file} ubuntu@#{@server_data[:server_dns]}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_workers(number_of_instances, instance_data = {})
|
57
|
+
defaults = {instance_type: "m2.4xlarge"}
|
58
|
+
instance_data = defaults.merge(instance_data)
|
59
|
+
|
60
|
+
raise "Can't create workers without a server instance running" if @server_data.nil?
|
61
|
+
|
62
|
+
# append the information to the server_data hash that already exists
|
63
|
+
@server_data[:instance_type] = instance_data[:instance_type]
|
64
|
+
@server_data[:num] = number_of_instances
|
65
|
+
server_string = @server_data.to_json.gsub("\"", "\\\\\"")
|
66
|
+
|
67
|
+
start_string = "ruby #{os_aws_file_location} #{@config.access_key} #{@config.secret_key} us-east-1 EC2 launch_workers \"#{server_string}\""
|
68
|
+
puts "Worker Command: #{start_string}"
|
69
|
+
worker_data_string = `#{start_string}`
|
70
|
+
@worker_data = JSON.parse(worker_data_string, :symbolize_names => true)
|
71
|
+
File.open("worker_data.json", "w") { |f| f << JSON.pretty_generate(worker_data) }
|
72
|
+
|
73
|
+
# Print out some debugging commands (probably work on mac/linux only)
|
74
|
+
@worker_data[:workers].each do |worker|
|
75
|
+
puts ""
|
76
|
+
puts "Worker SSH Command:"
|
77
|
+
puts "ssh -i #{@server_data[:private_key]} ubuntu@#{worker[:dns]}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def kill_instances()
|
82
|
+
# Add this method to kill all the running instances
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def os_aws_file_location
|
88
|
+
# Get the location of the os-aws.rb file. Use the relative path from where this file exists
|
89
|
+
os_aws_file = File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "os-aws.rb"))
|
90
|
+
raise "os_aws_file does not exist where it is expected: #{os_aws_file}" unless File.exists?(os_aws_file)
|
91
|
+
|
92
|
+
os_aws_file
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module OpenStudio
|
2
|
+
module Aws
|
3
|
+
class Config
|
4
|
+
attr_accessor :access_key
|
5
|
+
attr_accessor :secret_key
|
6
|
+
|
7
|
+
def initialize(yml_config_file = nil)
|
8
|
+
@yml_config_file = yml_config_file
|
9
|
+
@config = nil
|
10
|
+
if @yml_config_file.nil?
|
11
|
+
@yml_config_file = File.join(File.expand_path("~"), "aws_config.yml")
|
12
|
+
puts @yml_config_file
|
13
|
+
if !File.exists?(@yml_config_file)
|
14
|
+
write_config_file
|
15
|
+
puts "No Config File in user home directory. A template has been added, please edit and save: #{@yml_config_file}"
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
@config = YAML.load(File.read(@yml_config_file))
|
22
|
+
@access_key = @config['access_key_id']
|
23
|
+
@secret_key = @config['secret_access_key']
|
24
|
+
rescue
|
25
|
+
raise "Couldn't read config file #{@yml_config_file}. Delete file then recreate by rerunning script"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def write_config_file
|
32
|
+
File.open(@yml_config_file, 'w') do |f|
|
33
|
+
f << "access_key_id: YOUR_ACCESS_KEY_ID\n"
|
34
|
+
f << "secret_access_key: YOUR_SECRET_ACCESS_KEY\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# This is taken out of the OpenStudio AWS config file to do some testing
|
2
|
+
#def send_command(host, command, key)
|
3
|
+
# require 'net/http'
|
4
|
+
# require 'net/scp'
|
5
|
+
# require 'net/ssh'
|
6
|
+
#
|
7
|
+
# retries = 0
|
8
|
+
# begin
|
9
|
+
# puts "connecting.."
|
10
|
+
# output = ''
|
11
|
+
# Net::SSH.start(host, 'ubuntu', :key_data => [key]) do |ssh|
|
12
|
+
# response = ssh.exec!(command)
|
13
|
+
# output += response if !response.nil?
|
14
|
+
# end
|
15
|
+
# return output
|
16
|
+
# rescue Net::SSH::HostKeyMismatch => e
|
17
|
+
# e.remember_host!
|
18
|
+
# # key mismatch, retry
|
19
|
+
# return if retries == 2
|
20
|
+
# retries += 1
|
21
|
+
# sleep 1
|
22
|
+
# retry
|
23
|
+
# rescue Net::SSH::AuthenticationFailed
|
24
|
+
# error(-1, "Incorrect private key")
|
25
|
+
# rescue SystemCallError, Timeout::Error => e
|
26
|
+
# # port 22 might not be available immediately after the instance finishes launching
|
27
|
+
# return if retries == 2
|
28
|
+
# retries += 1
|
29
|
+
# sleep 1
|
30
|
+
# retry
|
31
|
+
# rescue Exception => e
|
32
|
+
# puts e.message
|
33
|
+
# puts e.backtrace.inspect
|
34
|
+
# end
|
35
|
+
#end
|
36
|
+
#
|
37
|
+
#server_json = JSON.parse(File.read("server_data.json"), :symbolize_names => true)
|
38
|
+
#
|
39
|
+
#b = Time.now
|
40
|
+
#delta = b.to_f - a.to_f
|
41
|
+
#puts "startup time is #{delta}"
|
42
|
+
##puts send_command(server_json[:server_ip], 'nproc | tr -d "\n"', File.read("ec2_server_key.pem"))
|
@@ -0,0 +1,19 @@
|
|
1
|
+
development:
|
2
|
+
sessions:
|
3
|
+
default:
|
4
|
+
database: os_dev
|
5
|
+
hosts:
|
6
|
+
- SERVER_IP:27017
|
7
|
+
options:
|
8
|
+
allow_dynamic_fields: true
|
9
|
+
raise_not_found_error: false
|
10
|
+
production:
|
11
|
+
sessions:
|
12
|
+
default:
|
13
|
+
database: os_prod
|
14
|
+
hosts:
|
15
|
+
- SERVER_IP:27017
|
16
|
+
options:
|
17
|
+
allow_dynamic_fields: true
|
18
|
+
raise_not_found_error: false
|
19
|
+
|
@@ -0,0 +1,556 @@
|
|
1
|
+
# NOTE: Do not modify this file as it is copied over. Modify the source file and rerun rake import_files
|
2
|
+
######################################################################
|
3
|
+
# Copyright (c) 2008-2013, Alliance for Sustainable Energy.
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# This library is free software; you can redistribute it and/or
|
7
|
+
# modify it under the terms of the GNU Lesser General Public
|
8
|
+
# License as published by the Free Software Foundation; either
|
9
|
+
# version 2.1 of the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This library is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this library; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
19
|
+
######################################################################
|
20
|
+
|
21
|
+
######################################################################
|
22
|
+
# == Synopsis
|
23
|
+
#
|
24
|
+
# Uses the aws-sdk gem to communicate with AWS
|
25
|
+
#
|
26
|
+
# == Usage
|
27
|
+
#
|
28
|
+
# ruby aws.rb access_key secret_key us-east-1 EC2 launch_server "{\"instance_type\":\"t1.micro\"}"
|
29
|
+
#
|
30
|
+
# ARGV[0] - Access Key
|
31
|
+
# ARGV[1] - Secret Key
|
32
|
+
# ARGV[2] - Region
|
33
|
+
# ARGV[3] - Service (e.g. "EC2" or "CloudWatch")
|
34
|
+
# ARGV[4] - Command (e.g. "launch_server")
|
35
|
+
# ARGV[5] - Optional json with parameters associated with command
|
36
|
+
#
|
37
|
+
######################################################################
|
38
|
+
|
39
|
+
require 'aws-sdk'
|
40
|
+
require 'json'
|
41
|
+
require 'logger'
|
42
|
+
require 'net/http'
|
43
|
+
require 'net/scp'
|
44
|
+
require 'net/ssh'
|
45
|
+
require 'tempfile'
|
46
|
+
require 'time'
|
47
|
+
|
48
|
+
OPENSTUDIO_VERSION='1.1.2'
|
49
|
+
|
50
|
+
def error(code, msg)
|
51
|
+
puts ({:error => {:code => code, :message => msg},
|
52
|
+
:arguments => ARGV[2..-1]}.to_json)
|
53
|
+
exit(1)
|
54
|
+
end
|
55
|
+
|
56
|
+
if ARGV.length < 5
|
57
|
+
error(-1, 'Invalid number of args')
|
58
|
+
end
|
59
|
+
|
60
|
+
if ARGV[0].empty? || ARGV[1].empty?
|
61
|
+
error(401, 'Missing authentication arguments')
|
62
|
+
end
|
63
|
+
|
64
|
+
if ARGV[2].empty?
|
65
|
+
error(-1, 'Missing region argument')
|
66
|
+
end
|
67
|
+
|
68
|
+
if ARGV[3].empty?
|
69
|
+
error(-1, 'Missing service argument')
|
70
|
+
end
|
71
|
+
|
72
|
+
if ARGV[4].empty?
|
73
|
+
error(-1, 'Missing command argument')
|
74
|
+
end
|
75
|
+
|
76
|
+
AWS.config(
|
77
|
+
:access_key_id => ARGV[0],
|
78
|
+
:secret_access_key => ARGV[1],
|
79
|
+
:region => ARGV[2],
|
80
|
+
:ssl_verify_peer => false
|
81
|
+
)
|
82
|
+
|
83
|
+
if ARGV[3] == 'EC2'
|
84
|
+
@aws = AWS::EC2.new
|
85
|
+
elsif ARGV[3] == 'CloudWatch'
|
86
|
+
@aws = AWS::CloudWatch.new
|
87
|
+
else
|
88
|
+
error(-1, "Unrecognized AWS service: #{ARGV[3]}")
|
89
|
+
end
|
90
|
+
|
91
|
+
if ARGV.length == 6
|
92
|
+
@params = JSON.parse(ARGV[5])
|
93
|
+
end
|
94
|
+
|
95
|
+
resp = Net::HTTP.get_response('developer.nrel.gov','/downloads/buildings/openstudio/rsrc/amis.json')
|
96
|
+
if resp.code == '200'
|
97
|
+
result = JSON.parse(resp.body)
|
98
|
+
version = result.has_key?(OPENSTUDIO_VERSION) ? OPENSTUDIO_VERSION : 'default'
|
99
|
+
|
100
|
+
@server_image_id = result[version]['server']
|
101
|
+
if ARGV.length >= 6 && @params['instance_type'] == 'cc2.8xlarge'
|
102
|
+
@worker_image_id = result[version]['cc2worker']
|
103
|
+
else
|
104
|
+
@worker_image_id = result[version]['worker']
|
105
|
+
end
|
106
|
+
else
|
107
|
+
error(resp.code, 'Unable to download AMI IDs')
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_struct(instance, procs)
|
111
|
+
instance_struct = Struct.new(:instance, :id, :ip, :dns, :procs)
|
112
|
+
return instance_struct.new(instance, instance.instance_id, instance.ip_address, instance.dns_name, procs)
|
113
|
+
end
|
114
|
+
|
115
|
+
def find_processors(instance)
|
116
|
+
processors = 1
|
117
|
+
case instance
|
118
|
+
when 'cc2.8xlarge'
|
119
|
+
processors = 16
|
120
|
+
when 'c1.xlarge'
|
121
|
+
processors = 8
|
122
|
+
when 'm2.4xlarge'
|
123
|
+
processors = 8
|
124
|
+
when 'm2.2xlarge'
|
125
|
+
processors = 4
|
126
|
+
when 'm2.xlarge'
|
127
|
+
processors = 2
|
128
|
+
when 'm1.xlarge'
|
129
|
+
processors = 4
|
130
|
+
when 'm1.large'
|
131
|
+
processors = 2
|
132
|
+
when 'm3.xlarge'
|
133
|
+
processors = 2
|
134
|
+
when 'm3.2xlarge'
|
135
|
+
processors = 4
|
136
|
+
end
|
137
|
+
|
138
|
+
return processors
|
139
|
+
end
|
140
|
+
|
141
|
+
def launch_server
|
142
|
+
user_data = File.read(File.expand_path(File.dirname(__FILE__))+'/server_script.sh')
|
143
|
+
@logger.info("server user_data #{user_data.inspect}")
|
144
|
+
@server = @aws.instances.create(:image_id => @server_image_id,
|
145
|
+
:key_pair => @key_pair,
|
146
|
+
:security_groups => @group,
|
147
|
+
:user_data => user_data,
|
148
|
+
:instance_type => @server_instance_type)
|
149
|
+
@server.add_tag('Name', :value => "OpenStudio-Server V#{OPENSTUDIO_VERSION}")
|
150
|
+
sleep 5 while @server.status == :pending
|
151
|
+
if @server.status != :running
|
152
|
+
error(-1, "Server status: #{@server.status}")
|
153
|
+
end
|
154
|
+
|
155
|
+
processors = find_processors(@server_instance_type)
|
156
|
+
#processors = send_command(@server.ip_address, 'nproc | tr -d "\n"')
|
157
|
+
#processors = 0 if processors.nil? # sometimes this returns nothing, so put in a default
|
158
|
+
@server = create_struct(@server, processors)
|
159
|
+
end
|
160
|
+
|
161
|
+
def launch_workers(num, server_ip)
|
162
|
+
user_data = File.read(File.expand_path(File.dirname(__FILE__))+'/worker_script.sh.template')
|
163
|
+
user_data.gsub!(/SERVER_IP/, server_ip)
|
164
|
+
user_data.gsub!(/SERVER_HOSTNAME/, 'master')
|
165
|
+
user_data.gsub!(/SERVER_ALIAS/, '')
|
166
|
+
@logger.info("worker user_data #{user_data.inspect}")
|
167
|
+
instances = []
|
168
|
+
num.times do
|
169
|
+
worker = @aws.instances.create(:image_id => @worker_image_id,
|
170
|
+
:key_pair => @key_pair,
|
171
|
+
:security_groups => @group,
|
172
|
+
:user_data => user_data,
|
173
|
+
:instance_type => @worker_instance_type)
|
174
|
+
worker.add_tag('Name', :value => "OpenStudio-Worker V#{OPENSTUDIO_VERSION}")
|
175
|
+
instances.push(worker)
|
176
|
+
end
|
177
|
+
sleep 5 while instances.any? { |instance| instance.status == :pending }
|
178
|
+
if instances.any? { |instance| instance.status != :running }
|
179
|
+
error(-1, "Worker status: Not running")
|
180
|
+
end
|
181
|
+
|
182
|
+
# todo: fix this - sometimes returns nil
|
183
|
+
processors = find_processors(@worker_instance_type)
|
184
|
+
#processors = send_command(instances[0].ip_address, 'nproc | tr -d "\n"')
|
185
|
+
#processors = 0 if processors.nil? # sometimes this returns nothing, so put in a default
|
186
|
+
instances.each { |instance| @workers.push(create_struct(instance, processors)) }
|
187
|
+
end
|
188
|
+
|
189
|
+
def upload_file(host, local_path, remote_path)
|
190
|
+
retries = 0
|
191
|
+
begin
|
192
|
+
Net::SCP.start(host, 'ubuntu', :key_data => [@private_key]) do |scp|
|
193
|
+
scp.upload! local_path, remote_path
|
194
|
+
end
|
195
|
+
rescue SystemCallError, Timeout::Error => e
|
196
|
+
# port 22 might not be available immediately after the instance finishes launching
|
197
|
+
return if retries == 5
|
198
|
+
retries += 1
|
199
|
+
sleep 1
|
200
|
+
retry
|
201
|
+
rescue
|
202
|
+
# Unknown upload error, retry
|
203
|
+
return if retries == 5
|
204
|
+
retries += 1
|
205
|
+
sleep 1
|
206
|
+
retry
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
|
211
|
+
def send_command(host, command)
|
212
|
+
#retries = 0
|
213
|
+
begin
|
214
|
+
output = ''
|
215
|
+
Net::SSH.start(host, 'ubuntu', :key_data => [@private_key]) do |ssh|
|
216
|
+
response = ssh.exec!(command)
|
217
|
+
output += response if !response.nil?
|
218
|
+
end
|
219
|
+
return output
|
220
|
+
rescue Net::SSH::HostKeyMismatch => e
|
221
|
+
e.remember_host!
|
222
|
+
# key mismatch, retry
|
223
|
+
#return if retries == 5
|
224
|
+
#retries += 1
|
225
|
+
sleep 1
|
226
|
+
retry
|
227
|
+
rescue Net::SSH::AuthenticationFailed
|
228
|
+
error(-1, "Incorrect private key")
|
229
|
+
rescue SystemCallError, Timeout::Error => e
|
230
|
+
# port 22 might not be available immediately after the instance finishes launching
|
231
|
+
#return if retries == 5
|
232
|
+
#retries += 1
|
233
|
+
sleep 1
|
234
|
+
retry
|
235
|
+
rescue Exception => e
|
236
|
+
puts e.message
|
237
|
+
puts e.backtrace.inspect
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
#======================= send command ======================#
|
242
|
+
# Send a command through SSH Shell to an instance.
|
243
|
+
# Need to pass instance object and the command as a string.
|
244
|
+
def shell_command(host, command)
|
245
|
+
begin
|
246
|
+
@logger.info("ssh_command #{command}")
|
247
|
+
Net::SSH.start(host, 'ubuntu', :key_data => [@private_key]) do |ssh|
|
248
|
+
channel = ssh.open_channel do |ch|
|
249
|
+
ch.exec "#{command}" do |ch, success|
|
250
|
+
raise "could not execute #{command}" unless success
|
251
|
+
|
252
|
+
# "on_data" is called when the process writes something to stdout
|
253
|
+
ch.on_data do |c, data|
|
254
|
+
#$stdout.print data
|
255
|
+
@logger.info("#{data.inspect}")
|
256
|
+
end
|
257
|
+
|
258
|
+
# "on_extended_data" is called when the process writes something to stderr
|
259
|
+
ch.on_extended_data do |c, type, data|
|
260
|
+
#$stderr.print data
|
261
|
+
@logger.info("#{data.inspect}")
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
rescue Net::SSH::HostKeyMismatch => e
|
267
|
+
e.remember_host!
|
268
|
+
@logger.info("key mismatch, retry")
|
269
|
+
sleep 1
|
270
|
+
retry
|
271
|
+
rescue SystemCallError, Timeout::Error => e
|
272
|
+
# port 22 might not be available immediately after the instance finishes launching
|
273
|
+
sleep 1
|
274
|
+
@logger.info("Not Yet")
|
275
|
+
retry
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def wait_command(host, command)
|
280
|
+
begin
|
281
|
+
flag = 0
|
282
|
+
while flag == 0 do
|
283
|
+
@logger.info("wait_command #{command}")
|
284
|
+
Net::SSH.start(host, 'ubuntu', :key_data => [@private_key]) do |ssh|
|
285
|
+
channel = ssh.open_channel do |ch|
|
286
|
+
ch.exec "#{command}" do |ch, success|
|
287
|
+
raise "could not execute #{command}" unless success
|
288
|
+
|
289
|
+
# "on_data" is called when the process writes something to stdout
|
290
|
+
ch.on_data do |c, data|
|
291
|
+
@logger.info("#{data.inspect}")
|
292
|
+
if data.chomp == "true"
|
293
|
+
@logger.info("wait_command #{command} is true")
|
294
|
+
flag = 1
|
295
|
+
else
|
296
|
+
sleep 5
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# "on_extended_data" is called when the process writes something to stderr
|
301
|
+
ch.on_extended_data do |c, type, data|
|
302
|
+
@logger.info("#{data.inspect}")
|
303
|
+
if data == "true"
|
304
|
+
@logger.info("wait_command #{command} is true")
|
305
|
+
flag = 1
|
306
|
+
else
|
307
|
+
sleep 5
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
rescue Net::SSH::HostKeyMismatch => e
|
315
|
+
e.remember_host!
|
316
|
+
@logger.info("key mismatch, retry")
|
317
|
+
sleep 1
|
318
|
+
retry
|
319
|
+
rescue SystemCallError, Timeout::Error => e
|
320
|
+
# port 22 might not be available immediately after the instance finishes launching
|
321
|
+
sleep 1
|
322
|
+
@logger.info("Not Yet")
|
323
|
+
retry
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
def download_file(host, remote_path, local_path)
|
328
|
+
retries = 0
|
329
|
+
begin
|
330
|
+
Net::SCP.start(host, 'ubuntu', :key_data => [@private_key]) do |scp|
|
331
|
+
scp.download! remote_path, local_path
|
332
|
+
end
|
333
|
+
rescue SystemCallError, Timeout::Error => e
|
334
|
+
# port 22 might not be available immediately after the instance finishes launching
|
335
|
+
return if retries == 5
|
336
|
+
retries += 1
|
337
|
+
sleep 1
|
338
|
+
retry
|
339
|
+
rescue
|
340
|
+
return if retries == 5
|
341
|
+
retries += 1
|
342
|
+
sleep 1
|
343
|
+
retry
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
begin
|
348
|
+
@logger = Logger.new("aws.log")
|
349
|
+
@logger.info("initialized")
|
350
|
+
case ARGV[4]
|
351
|
+
when 'describe_availability_zones'
|
352
|
+
resp = @aws.client.describe_availability_zones
|
353
|
+
puts resp.data.to_json
|
354
|
+
@logger.info("availability_zones #{resp.data.to_json}")
|
355
|
+
when 'total_instances'
|
356
|
+
resp = @aws.client.describe_instance_status
|
357
|
+
puts ({:total_instances => resp.data[:instance_status_set].length,
|
358
|
+
:region => ARGV[2]}.to_json)
|
359
|
+
when 'instance_status'
|
360
|
+
resp = nil
|
361
|
+
if ARGV.length < 6
|
362
|
+
resp = @aws.client.describe_instance_status
|
363
|
+
else
|
364
|
+
resp = @aws.client.describe_instance_status({:instance_ids => [@params['instance_id']]})
|
365
|
+
end
|
366
|
+
output = Hash.new
|
367
|
+
resp.data[:instance_status_set].each { |instance|
|
368
|
+
output[instance[:instance_id]] = instance[:instance_state][:name]
|
369
|
+
}
|
370
|
+
puts output.to_json
|
371
|
+
when 'launch_server'
|
372
|
+
if ARGV.length < 6
|
373
|
+
error(-1, 'Invalid number of args')
|
374
|
+
end
|
375
|
+
|
376
|
+
@timestamp = Time.now.to_i
|
377
|
+
|
378
|
+
# find if an existing openstudio-server-vX security group exists and use that
|
379
|
+
@group = @aws.security_groups.filter('group-name', 'openstudio-server-sg-v1').first
|
380
|
+
if @group.nil?
|
381
|
+
@group = @aws.security_groups.create('openstudio-server-sg-v1')
|
382
|
+
@group.allow_ping() # allow ping
|
383
|
+
@group.authorize_ingress(:tcp, 1..65535) # all traffic
|
384
|
+
end
|
385
|
+
@logger.info("server_group #{@group}")
|
386
|
+
@server_instance_type = @params['instance_type']
|
387
|
+
|
388
|
+
@key_pair = @aws.key_pairs.create("key-pair-#{@timestamp}")
|
389
|
+
@private_key = @key_pair.private_key
|
390
|
+
|
391
|
+
launch_server()
|
392
|
+
|
393
|
+
puts ({:timestamp => @timestamp,
|
394
|
+
:private_key => @private_key,
|
395
|
+
:server => {
|
396
|
+
:id => @server.id,
|
397
|
+
:ip => 'http://' + @server.ip,
|
398
|
+
:dns => @server.dns,
|
399
|
+
:procs => @server.procs
|
400
|
+
}}.to_json)
|
401
|
+
@logger.info("server info #{({:timestamp => @timestamp, :private_key => @private_key, :server => {:id => @server.id, :ip => @server.ip, :dns => @server.dns, :procs => @server.procs}}.to_json)}")
|
402
|
+
when 'launch_workers'
|
403
|
+
if ARGV.length < 6
|
404
|
+
error(-1, 'Invalid number of args')
|
405
|
+
end
|
406
|
+
if @params['num'] < 1
|
407
|
+
error(-1, 'Invalid number of worker nodes, must be greater than 0')
|
408
|
+
end
|
409
|
+
|
410
|
+
@workers = []
|
411
|
+
@timestamp = @params['timestamp']
|
412
|
+
|
413
|
+
# find if an existing openstudio-server-vX security group exists and use that
|
414
|
+
@group = @aws.security_groups.filter('group-name', 'openstudio-worker-sg-v1').first
|
415
|
+
if @group.nil?
|
416
|
+
@group = @aws.security_groups.create('openstudio-worker-sg-v1')
|
417
|
+
@group.allow_ping() # allow ping
|
418
|
+
@group.authorize_ingress(:tcp, 1..65535) # all traffic
|
419
|
+
end
|
420
|
+
@logger.info("worker_group #{@group}")
|
421
|
+
@key_pair = @aws.key_pairs.filter('key-name', "key-pair-#{@timestamp}").first
|
422
|
+
@private_key = File.read(@params['private_key'])
|
423
|
+
@worker_instance_type = @params['instance_type']
|
424
|
+
@server = @aws.instances[@params['server_id']]
|
425
|
+
error(-1, 'Server node does not exist') unless @server.exists?
|
426
|
+
@server = create_struct(@server, @params['server_procs'])
|
427
|
+
|
428
|
+
launch_workers(@params['num'], @server.ip)
|
429
|
+
#@workers.push(create_struct(@aws.instances['i-xxxxxxxx'], 1))
|
430
|
+
#processors = send_command(@workers[0].ip, 'nproc | tr -d "\n"')
|
431
|
+
#@workers[0].procs = processors
|
432
|
+
|
433
|
+
#wait for user_data to complete execution
|
434
|
+
@logger.info("server user_data")
|
435
|
+
wait_command(@server.ip, '[ -e /home/ubuntu/user_data_done ] && echo "true"')
|
436
|
+
@logger.info("worker user_data")
|
437
|
+
@workers.each { |worker| wait_command(worker.ip, '[ -e /home/ubuntu/user_data_done ] && echo "true"') }
|
438
|
+
#wait_command(@workers.first.ip, "[ -e /home/ubuntu/user_data_done ] && echo 'true'")
|
439
|
+
|
440
|
+
|
441
|
+
ips = "master|#{@server.ip}|#{@server.dns}|#{@server.procs}|ubuntu|ubuntu\n"
|
442
|
+
@workers.each { |worker| ips << "worker|#{worker.ip}|#{worker.dns}|#{worker.procs}|ubuntu|ubuntu|true\n" }
|
443
|
+
file = Tempfile.new('ip_addresses')
|
444
|
+
file.write(ips)
|
445
|
+
file.close
|
446
|
+
upload_file(@server.ip, file.path, 'ip_addresses')
|
447
|
+
file.unlink
|
448
|
+
@logger.info("ips #{ips}")
|
449
|
+
shell_command(@server.ip, 'chmod 664 /home/ubuntu/ip_addresses')
|
450
|
+
shell_command(@server.ip, '~/setup-ssh-keys.sh')
|
451
|
+
shell_command(@server.ip, '~/setup-ssh-worker-nodes.sh ip_addresses')
|
452
|
+
|
453
|
+
mongoid = File.read(File.expand_path(File.dirname(__FILE__))+'/mongoid.yml.template')
|
454
|
+
mongoid.gsub!(/SERVER_IP/, @server.ip)
|
455
|
+
file = Tempfile.new('mongoid.yml')
|
456
|
+
file.write(mongoid)
|
457
|
+
file.close
|
458
|
+
upload_file(@server.ip, file.path, '/mnt/openstudio/rails-models/mongoid.yml')
|
459
|
+
@workers.each { |worker| upload_file(worker.ip, file.path, '/mnt/openstudio/rails-models/mongoid.yml') }
|
460
|
+
file.unlink
|
461
|
+
|
462
|
+
# Does this command crash it?
|
463
|
+
shell_command(@server.ip, 'chmod 664 /mnt/openstudio/rails-models/mongoid.yml')
|
464
|
+
@workers.each { |worker| shell_command(worker.ip, 'chmod 664 /mnt/openstudio/rails-models/mongoid.yml') }
|
465
|
+
|
466
|
+
worker_json = []
|
467
|
+
@workers.each { |worker|
|
468
|
+
worker_json.push({
|
469
|
+
:id => worker.id,
|
470
|
+
:ip => 'http://' + worker.ip,
|
471
|
+
:dns => worker.dns,
|
472
|
+
:procs => worker.procs
|
473
|
+
})
|
474
|
+
}
|
475
|
+
puts ({:workers => worker_json}.to_json)
|
476
|
+
@logger.info("workers #{({:workers => worker_json}.to_json)}")
|
477
|
+
when 'terminate_session'
|
478
|
+
if ARGV.length < 6
|
479
|
+
error(-1, 'Invalid number of args')
|
480
|
+
end
|
481
|
+
instances = []
|
482
|
+
|
483
|
+
server = @aws.instances[@params['server_id']]
|
484
|
+
error(-1, "Server node #{@params['server_id']} does not exist") unless server.exists?
|
485
|
+
|
486
|
+
#@timestamp = @aws.client.describe_instances({:instance_ids=>[@params['server_id']]}).data[:instance_index][@params['server_id']][:key_name][9,10]
|
487
|
+
@timestamp = server.key_name[9, 10]
|
488
|
+
|
489
|
+
instances.push(server)
|
490
|
+
@params['worker_ids'].each { |worker_id|
|
491
|
+
worker = @aws.instances[worker_id]
|
492
|
+
error(-1, "Worker node #{worker_id} does not exist") unless worker.exists?
|
493
|
+
instances.push(worker)
|
494
|
+
}
|
495
|
+
|
496
|
+
instances.each { |instance|
|
497
|
+
instance.terminate
|
498
|
+
}
|
499
|
+
sleep 5 while instances.any? { |instance| instance.status != :terminated }
|
500
|
+
|
501
|
+
# When session is fully terminated, then delete the key pair
|
502
|
+
#@aws.client.delete_security_group({:group_name=>'openstudio-server-sg-v1'}"})
|
503
|
+
#@aws.client.delete_security_group({:group_name=>'openstudio-worker-sg-v1'}"})
|
504
|
+
@aws.client.delete_key_pair({:key_name => "key-pair-#{@timestamp}"})
|
505
|
+
|
506
|
+
when 'termination_status'
|
507
|
+
if ARGV.length < 6
|
508
|
+
error(-1, 'Invalid number of args')
|
509
|
+
end
|
510
|
+
notTerminated = 0
|
511
|
+
|
512
|
+
server = @aws.instances[@params['server_id']]
|
513
|
+
notTerminated += 1 if (server.exists? && server.status != :terminated)
|
514
|
+
|
515
|
+
@params['worker_ids'].each { |worker_id|
|
516
|
+
worker = @aws.instances[worker_id]
|
517
|
+
notTerminated += 1 if (worker.exists? && worker.status != :terminated)
|
518
|
+
}
|
519
|
+
|
520
|
+
puts ({:all_instances_terminated => (notTerminated == 0)}.to_json)
|
521
|
+
|
522
|
+
when 'session_uptime'
|
523
|
+
if ARGV.length < 6
|
524
|
+
error(-1, 'Invalid number of args')
|
525
|
+
end
|
526
|
+
server_id = @params['server_id']
|
527
|
+
#No need to call AWS, but we can
|
528
|
+
#minutes = (Time.now.to_i - @aws.client.describe_instances({:instance_ids=>[server_id]}).data[:instance_index][server_id][:launch_time].to_i)/60
|
529
|
+
minutes = (Time.now.to_i - @params['timestamp'].to_i)/60
|
530
|
+
puts ({:session_uptime => minutes}.to_json)
|
531
|
+
|
532
|
+
when 'estimated_charges'
|
533
|
+
endTime = Time.now.utc
|
534
|
+
startTime = endTime - 86400
|
535
|
+
resp = @aws.client.get_metric_statistics({:dimensions => [{:name => 'ServiceName', :value => 'AmazonEC2'}, {:name => 'Currency', :value => 'USD'}], :metric_name => 'EstimatedCharges', :namespace => 'AWS/Billing', :start_time => startTime.iso8601, :end_time => endTime.iso8601, :period => 300, :statistics => ['Maximum']})
|
536
|
+
error(-1, 'No Billing Data') if resp.data[:datapoints].length == 0
|
537
|
+
datapoints = resp.data[:datapoints]
|
538
|
+
datapoints.sort! { |a, b| a[:timestamp] <=> b[:timestamp] }
|
539
|
+
puts ({:estimated_charges => datapoints[-1][:maximum],
|
540
|
+
:timestamp => datapoints[-1][:timestamp].to_i}.to_json)
|
541
|
+
|
542
|
+
else
|
543
|
+
error(-1, "Unknown command: #{ARGV[4]} (#{ARGV[3]})")
|
544
|
+
end
|
545
|
+
#puts \"Status: #{resp.http_response.status}\"
|
546
|
+
rescue SystemExit => e
|
547
|
+
rescue Exception => e
|
548
|
+
if e.message == 'getaddrinfo: No such host is known. '
|
549
|
+
error(503, 'Offline')
|
550
|
+
elsif defined? e.http_response
|
551
|
+
error(e.http_response.status, e.code)
|
552
|
+
else
|
553
|
+
error(-1, "#{e}: #{e.backtrace}")
|
554
|
+
end
|
555
|
+
|
556
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
# NOTE: Do not modify this file as it is copied over. Modify the source file and rerun rake import_files
|
3
|
+
|
4
|
+
# Change Host File Entries
|
5
|
+
ENTRY="localhost localhost master"
|
6
|
+
FILE=/etc/hosts
|
7
|
+
if grep -q "$ENTRY" $FILE; then
|
8
|
+
echo "entry already exists"
|
9
|
+
else
|
10
|
+
sudo sh -c "echo $ENTRY >> /etc/hosts"
|
11
|
+
fi
|
12
|
+
|
13
|
+
# copy all the setup scripts to the appropriate home directory
|
14
|
+
cp /data/launch-instance/setup* /home/ubuntu/
|
15
|
+
chmod 775 /home/ubuntu/setup*
|
16
|
+
chown ubuntu:ubuntu /home/ubuntu/setup*
|
17
|
+
|
18
|
+
# Set permissions on rails apps folders
|
19
|
+
sudo chmod 777 /var/www/rails/openstudio/public
|
20
|
+
|
21
|
+
# Force the generation of OpenStudio on the EBS mount and copy worker files
|
22
|
+
sudo rm -rf /mnt/openstudio
|
23
|
+
sudo mkdir -p /mnt/openstudio
|
24
|
+
sudo chmod -R 777 /mnt/openstudio
|
25
|
+
cp -rf /data/worker-nodes/* /mnt/openstudio/
|
26
|
+
|
27
|
+
# Unzip the worker files (including Mongoid models) and set permissions one last time
|
28
|
+
# Note that the 777 is redundant but needed until we actually deploy ACL
|
29
|
+
cd /mnt/openstudio/rails-models && unzip -o rails-models.zip
|
30
|
+
sudo chmod -R 777 /mnt/openstudio
|
31
|
+
|
32
|
+
# Force the generation of MongoDB dbpath on the EBS mount
|
33
|
+
sudo rm -rf /mnt/mongodb/data
|
34
|
+
sudo mkdir -p /mnt/mongodb/data
|
35
|
+
sudo chown mongodb:nogroup /mnt/mongodb/data
|
36
|
+
sudo service mongodb restart
|
37
|
+
sudo service delayed_job restart
|
38
|
+
|
39
|
+
# Add database indexes after it gets mounted for the first time
|
40
|
+
cd /var/www/rails/openstudio
|
41
|
+
sudo rake db:mongoid:create_indexes
|
42
|
+
|
43
|
+
#file flag the user_data has completed
|
44
|
+
cat /dev/null > /home/ubuntu/user_data_done
|
45
|
+
|
46
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
# NOTE: Do not modify this file as it is copied over. Modify the source file and rerun rake import_files
|
3
|
+
|
4
|
+
# AWS Worker Bootstrap File
|
5
|
+
|
6
|
+
# Change Host File Entries
|
7
|
+
ENTRY="SERVER_IP SERVER_HOSTNAME SERVER_ALIAS"
|
8
|
+
FILE=/etc/hosts
|
9
|
+
if grep -q "$ENTRY" $FILE; then
|
10
|
+
echo "entry already exists"
|
11
|
+
else
|
12
|
+
sudo sh -c "echo $ENTRY >> /etc/hosts"
|
13
|
+
fi
|
14
|
+
|
15
|
+
# copy all the setup scripts to the appropriate home directory
|
16
|
+
cp /data/launch-instance/setup* /home/ubuntu/
|
17
|
+
chmod 775 /home/ubuntu/setup*
|
18
|
+
chown ubuntu:ubuntu /home/ubuntu/setup*
|
19
|
+
|
20
|
+
# Force the generation of OpenStudio on the EBS mount and copy worker files
|
21
|
+
sudo rm -rf /mnt/openstudio
|
22
|
+
sudo mkdir -p /mnt/openstudio
|
23
|
+
sudo chmod -R 777 /mnt/openstudio
|
24
|
+
cp -rf /data/worker-nodes/* /mnt/openstudio/
|
25
|
+
|
26
|
+
# Unzip the worker files (including Mongoid models) and set permissions one last time
|
27
|
+
# Note that the 777 is redundant but needed until we actually deploy ACL
|
28
|
+
cd /mnt/openstudio/rails-models && unzip -o rails-models.zip
|
29
|
+
sudo chmod -R 777 /mnt/openstudio
|
30
|
+
|
31
|
+
#turn off hyperthreading
|
32
|
+
for cpunum in $(
|
33
|
+
cat /sys/devices/system/cpu/cpu*/topology/thread_siblings_list |
|
34
|
+
cut -s -d, -f2- | tr ',' '\n' | sort -un); do
|
35
|
+
echo 0 > /sys/devices/system/cpu/cpu$cpunum/online
|
36
|
+
done
|
37
|
+
|
38
|
+
#file flag the user_data has completed
|
39
|
+
cat /dev/null > /home/ubuntu/user_data_done
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OpenStudio::Aws do
|
4
|
+
context "create a new instance" do
|
5
|
+
before(:all) do
|
6
|
+
@aws = OpenStudio::Aws::Aws.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should create a new instance" do
|
10
|
+
@aws.should_not be_nil
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should ask the user to create a new config file" do
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should create a server" do
|
17
|
+
# use the default instance type
|
18
|
+
#options = {instance_type: "t1.micro" }
|
19
|
+
options = {instance_type: "m1.small" }
|
20
|
+
@aws.create_server(options)
|
21
|
+
@aws.server_data[:server_dns].should_not be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should create a 1 worker" do
|
25
|
+
#options = {instance_type: "t1.micro" }
|
26
|
+
options = {instance_type: "m1.small" }
|
27
|
+
#server_json[:instance_type] = "m2.4xlarge"
|
28
|
+
#server_json[:instance_type] = "m2.2xlarge"
|
29
|
+
#server_json[:instance_type] = "t1.micro"
|
30
|
+
@aws.create_workers(1, options)
|
31
|
+
|
32
|
+
@aws.worker_data[:workers].size.should eq(1)
|
33
|
+
@aws.worker_data[:workers][0][:dns].should_not be_nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "workers before server" do
|
38
|
+
before(:all) do
|
39
|
+
@aws = OpenStudio::Aws::Aws.new
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should not create any workers" do
|
43
|
+
|
44
|
+
expect {@aws.create_workers(5)}.to raise_error
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
context "larger cluster" do
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: openstudio-aws
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicholas Long
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: net-scp
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: aws-sdk
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.26.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.26.0
|
55
|
+
description: Custom classes for configuring clusters for OpenStudio & EnergyPlus analyses
|
56
|
+
email:
|
57
|
+
- Nicholas.Long@nrel.gov
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- lib/openstudio/aws/aws.rb
|
63
|
+
- lib/openstudio/aws/config.rb
|
64
|
+
- lib/openstudio/aws/send_data.rb
|
65
|
+
- lib/openstudio/aws/version.rb
|
66
|
+
- lib/openstudio/lib/mongoid.yml.template
|
67
|
+
- lib/openstudio/lib/os-aws.rb
|
68
|
+
- lib/openstudio/lib/server_script.sh
|
69
|
+
- lib/openstudio/lib/worker_script.sh.template
|
70
|
+
- lib/openstudio-aws.rb
|
71
|
+
- README.md
|
72
|
+
- Rakefile
|
73
|
+
- spec/openstudio-aws/aws_spec.rb
|
74
|
+
- spec/spec_helper.rb
|
75
|
+
homepage: http://openstudio.nrel.gov
|
76
|
+
licenses:
|
77
|
+
- LGPL
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '2.0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 1.3.6
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.0.2
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Start AWS EC2 instances for running distributed OpenStudio-based analyses
|
99
|
+
test_files:
|
100
|
+
- spec/openstudio-aws/aws_spec.rb
|
101
|
+
- spec/spec_helper.rb
|