bosh-bootstrap 0.5.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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +318 -0
- data/Rakefile +1 -0
- data/bin/bosh-bootstrap +8 -0
- data/bosh-bootstrap.gemspec +34 -0
- data/lib/bosh-bootstrap.rb +10 -0
- data/lib/bosh-bootstrap/cli.rb +1024 -0
- data/lib/bosh-bootstrap/commander.rb +9 -0
- data/lib/bosh-bootstrap/commander/README.md +47 -0
- data/lib/bosh-bootstrap/commander/command.rb +25 -0
- data/lib/bosh-bootstrap/commander/commands.rb +80 -0
- data/lib/bosh-bootstrap/commander/local_server.rb +68 -0
- data/lib/bosh-bootstrap/commander/remote_script_command.rb +48 -0
- data/lib/bosh-bootstrap/commander/remote_server.rb +121 -0
- data/lib/bosh-bootstrap/commander/upload_command.rb +17 -0
- data/lib/bosh-bootstrap/helpers.rb +2 -0
- data/lib/bosh-bootstrap/helpers/fog_setup.rb +50 -0
- data/lib/bosh-bootstrap/helpers/settings.rb +36 -0
- data/lib/bosh-bootstrap/stages.rb +8 -0
- data/lib/bosh-bootstrap/stages/stage_micro_bosh_delete.rb +90 -0
- data/lib/bosh-bootstrap/stages/stage_micro_bosh_delete/bosh_micro_delete +19 -0
- data/lib/bosh-bootstrap/stages/stage_micro_bosh_deploy.rb +135 -0
- data/lib/bosh-bootstrap/stages/stage_micro_bosh_deploy/bosh_micro_deploy +36 -0
- data/lib/bosh-bootstrap/stages/stage_micro_bosh_deploy/download_micro_bosh_stemcell +132 -0
- data/lib/bosh-bootstrap/stages/stage_micro_bosh_deploy/install_key_pair_for_user +23 -0
- data/lib/bosh-bootstrap/stages/stage_prepare_inception_vm.rb +52 -0
- data/lib/bosh-bootstrap/stages/stage_prepare_inception_vm/convert_salted_password +9 -0
- data/lib/bosh-bootstrap/stages/stage_prepare_inception_vm/create_vcap_user +79 -0
- data/lib/bosh-bootstrap/stages/stage_prepare_inception_vm/install_base_packages +13 -0
- data/lib/bosh-bootstrap/stages/stage_prepare_inception_vm/install_bosh +54 -0
- data/lib/bosh-bootstrap/stages/stage_prepare_inception_vm/install_ruby +33 -0
- data/lib/bosh-bootstrap/stages/stage_prepare_inception_vm/install_useful_gems +24 -0
- data/lib/bosh-bootstrap/stages/stage_prepare_inception_vm/validate_bosh_deployer +21 -0
- data/lib/bosh-bootstrap/stages/stage_setup_new_bosh.rb +52 -0
- data/lib/bosh-bootstrap/stages/stage_setup_new_bosh/cleanup_permissions +14 -0
- data/lib/bosh-bootstrap/stages/stage_setup_new_bosh/setup_bosh_user +29 -0
- data/lib/bosh-bootstrap/stages/stage_validate_inception_vm.rb +39 -0
- data/lib/bosh-bootstrap/stages/stage_validate_inception_vm/validate_ubuntu +6 -0
- data/lib/bosh-bootstrap/version.rb +5 -0
- data/lib/bosh/providers.rb +21 -0
- data/lib/bosh/providers/README.md +5 -0
- data/lib/bosh/providers/aws.rb +77 -0
- data/lib/bosh/providers/base_provider.rb +20 -0
- data/lib/bosh/providers/openstack.rb +40 -0
- metadata +239 -0
@@ -0,0 +1,9 @@
|
|
1
|
+
module Bosh::Bootstrap::Commander
|
2
|
+
end
|
3
|
+
|
4
|
+
require "bosh-bootstrap/commander/command"
|
5
|
+
require "bosh-bootstrap/commander/remote_script_command"
|
6
|
+
require "bosh-bootstrap/commander/upload_command"
|
7
|
+
require "bosh-bootstrap/commander/commands"
|
8
|
+
require "bosh-bootstrap/commander/local_server"
|
9
|
+
require "bosh-bootstrap/commander/remote_server"
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Bosh::Bootstrap::Commander
|
2
|
+
|
3
|
+
The sequence of commands that are run on an Inception VM can be either invoked locally on the Inception VM or from a remote machine. The `Commander` provides a DSL for describing the commands to be run and allows them to be sequentially run against a local or remote server.
|
4
|
+
|
5
|
+
Remote servers are accessed via SSH commands.
|
6
|
+
|
7
|
+
Example commands:
|
8
|
+
``` ruby
|
9
|
+
commands = Bosh::Bootstrap::Commander::Commands.new do |server|
|
10
|
+
server.create "vcap user", <<-BASH
|
11
|
+
#!/usr/bin/env bash
|
12
|
+
|
13
|
+
groupadd vcap
|
14
|
+
useradd vcap -m -g vcap
|
15
|
+
mkdir -p /home/vcap/.ssh
|
16
|
+
chown -R vcap:vcap /home/vcap/.ssh
|
17
|
+
BASH
|
18
|
+
|
19
|
+
server.install "rvm & ruby", <<-BASH
|
20
|
+
#!/usr/bin/env bash
|
21
|
+
|
22
|
+
if [[ -x rvm ]]
|
23
|
+
then
|
24
|
+
rvm get stable
|
25
|
+
else
|
26
|
+
curl -L get.rvm.io | bash -s stable
|
27
|
+
source /etc/profile.d/rvm.sh
|
28
|
+
fi
|
29
|
+
command rvm install 1.9.3 # oh god this takes a long time
|
30
|
+
rvm 1.9.3
|
31
|
+
rvm alias create default 1.9.3
|
32
|
+
BASH
|
33
|
+
end
|
34
|
+
|
35
|
+
@local_machine.run(commands)
|
36
|
+
@server.run(commands)
|
37
|
+
```
|
38
|
+
|
39
|
+
There is a set of predefined command methods which give nicer text output. You can also invoke any method upon `server` and it will be supported as the command name. The name of the method invoked is semantically meaningless; it is a convenience.
|
40
|
+
|
41
|
+
* `assign`
|
42
|
+
* `create`
|
43
|
+
* `download`
|
44
|
+
* `install`
|
45
|
+
* `provision`
|
46
|
+
* `store`
|
47
|
+
* `validate`
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# A single command/script to be run on a local/remote server
|
2
|
+
# For the display, it has an active ("installing") and
|
3
|
+
# past tense ("installed") verb and a noub/description ("packages")
|
4
|
+
module Bosh::Bootstrap::Commander
|
5
|
+
class Command
|
6
|
+
attr_reader :command # verb e.g. "install"
|
7
|
+
attr_reader :description # noun phrase, e.g. "packages"
|
8
|
+
|
9
|
+
attr_reader :full_present_tense # e.g. "installing packages"
|
10
|
+
attr_reader :full_past_tense # e.g. "installed packages"
|
11
|
+
|
12
|
+
def initialize(command, description, full_present_tense=nil, full_past_tense=nil)
|
13
|
+
@command = command
|
14
|
+
@description = description
|
15
|
+
@full_present_tense = full_present_tense || "#{command} #{description}"
|
16
|
+
@full_past_tense = full_past_tense || "#{command} #{description}"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Invoke this command (subclass) to call back upon
|
20
|
+
# +server+ to perform a server helper
|
21
|
+
def perform(server)
|
22
|
+
raise "please implement this method to call back upon `server`"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Bosh::Bootstrap::Commander
|
2
|
+
class Commands
|
3
|
+
attr_reader :commands
|
4
|
+
|
5
|
+
def initialize(&block)
|
6
|
+
@commands = []
|
7
|
+
yield self
|
8
|
+
end
|
9
|
+
|
10
|
+
def upload_file(target_path, file_contents)
|
11
|
+
@commands << UploadCommand.new(target_path, file_contents)
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# Generic remote script commands with custom phrases
|
16
|
+
#
|
17
|
+
|
18
|
+
def assign(description, script, options={})
|
19
|
+
@commands << RemoteScriptCommand.new(
|
20
|
+
"assign", description, script,
|
21
|
+
"assigning #{description}", "assigned #{description}", options)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Runs a script on target server, and stores the (stripped) STDOUT into
|
25
|
+
# settings.
|
26
|
+
#
|
27
|
+
# Usage:
|
28
|
+
# server.capture_value "salted password", script("convert_salted_password", "PASSWORD" => settings.bosh.password),
|
29
|
+
# :settings => "bosh.salted_password"
|
30
|
+
#
|
31
|
+
# Would store the returned STDOUT into settings[:bosh][:salted_password]
|
32
|
+
def capture_value(description, script, options)
|
33
|
+
@commands << RemoteScriptCommand.new(
|
34
|
+
"capture value", description, script,
|
35
|
+
"captures value of #{description}", "captured value of #{description}", options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def create(description, script, options={})
|
39
|
+
@commands << RemoteScriptCommand.new(
|
40
|
+
"create", description, script,
|
41
|
+
"creating #{description}", "created #{description}", options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def download(description, script, options={})
|
45
|
+
@commands << RemoteScriptCommand.new(
|
46
|
+
"download", description, script,
|
47
|
+
"downloading #{description}", "downloaded #{description}", options)
|
48
|
+
end
|
49
|
+
|
50
|
+
def install(description, script, options={})
|
51
|
+
@commands << RemoteScriptCommand.new(
|
52
|
+
"install", description, script,
|
53
|
+
"installing #{description}", "installed #{description}", options)
|
54
|
+
end
|
55
|
+
|
56
|
+
def provision(description, script, options={})
|
57
|
+
@commands << RemoteScriptCommand.new(
|
58
|
+
"provision", description, script,
|
59
|
+
"provisioning #{description}", "provisioned #{description}", options)
|
60
|
+
end
|
61
|
+
|
62
|
+
def store(description, script, options={})
|
63
|
+
@commands << RemoteScriptCommand.new(
|
64
|
+
"store", description, script,
|
65
|
+
"storing #{description}", "stored #{description}", options)
|
66
|
+
end
|
67
|
+
|
68
|
+
def validate(description, script, options={})
|
69
|
+
@commands << RemoteScriptCommand.new(
|
70
|
+
"validate", description, script,
|
71
|
+
"validating #{description}", "validated #{description}", options)
|
72
|
+
end
|
73
|
+
|
74
|
+
# catch-all for commands with generic active/past tense phrases
|
75
|
+
def method_missing(command, *args, &blk)
|
76
|
+
description, script = args[0..1]
|
77
|
+
@commands << RemoteScriptCommand.new(command.to_s, description, script)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require "popen4"
|
2
|
+
|
3
|
+
class Bosh::Bootstrap::Commander::LocalServer
|
4
|
+
attr_reader :logfile
|
5
|
+
|
6
|
+
def initialize(logfile=STDERR)
|
7
|
+
@logfile = logfile
|
8
|
+
end
|
9
|
+
|
10
|
+
# Execute the +Command+ objects, in sequential order
|
11
|
+
# upon the local server
|
12
|
+
# +commands+ is a +Commands+ container
|
13
|
+
#
|
14
|
+
# Returns false once any subcommand fails to execute successfully
|
15
|
+
def run(commands)
|
16
|
+
commands.commands.each do |command|
|
17
|
+
puts command.full_present_tense
|
18
|
+
if command.perform(self)
|
19
|
+
Thor::Base.shell.new.say "Successfully #{command.full_past_tense}", :green
|
20
|
+
else
|
21
|
+
Thor::Base.shell.new.say_status "error", "#{command.full_present_tense}", :red
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Commands performed on local server
|
29
|
+
# These map to Command subclasses, which then callback to these
|
30
|
+
# local server specific implementations
|
31
|
+
#
|
32
|
+
|
33
|
+
# Run a script
|
34
|
+
def run_script(command, script, options={})
|
35
|
+
command.as_file do |execution_command|
|
36
|
+
`chmod +x #{execution_command}`
|
37
|
+
status = POpen4::popen4(execution_command) do |stdout, stderr, stdin, pid|
|
38
|
+
out = stdout.read
|
39
|
+
logfile.puts out unless out.strip == ""
|
40
|
+
err = stderr.read
|
41
|
+
if err.strip != ""
|
42
|
+
logfile.puts err
|
43
|
+
STDERR.puts err if logfile != STDERR
|
44
|
+
end
|
45
|
+
logfile.flush
|
46
|
+
end
|
47
|
+
status.success?
|
48
|
+
end
|
49
|
+
rescue StandardError => e
|
50
|
+
logfile.puts e.message
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
# Upload a file (put a file into local filesystem)
|
55
|
+
def upload_file(command, path, contents, upload_as_user=nil)
|
56
|
+
basedir = File.dirname(path)
|
57
|
+
unless File.directory?(basedir)
|
58
|
+
logfile.puts "creating micro-bosh manifest folder: #{basedir}"
|
59
|
+
FileUtils.mkdir_p(basedir)
|
60
|
+
end
|
61
|
+
logfile.puts "creating micro-bosh manifest: #{path}"
|
62
|
+
File.open(path, "w") { |file| file << contents }
|
63
|
+
true
|
64
|
+
rescue StandardError => e
|
65
|
+
logfile.puts e.message
|
66
|
+
false
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# A single command/script to be run on a local/remote server
|
2
|
+
# For the display, it has an active ("installing") and
|
3
|
+
# past tense ("installed") verb and a noub/description ("packages")
|
4
|
+
module Bosh::Bootstrap::Commander
|
5
|
+
class RemoteScriptCommand < Command
|
6
|
+
attr_reader :command # verb e.g. "install"
|
7
|
+
attr_reader :description # noun phrase, e.g. "packages"
|
8
|
+
attr_reader :script
|
9
|
+
|
10
|
+
attr_reader :full_present_tense # e.g. "installing packages"
|
11
|
+
attr_reader :full_past_tense # e.g. "installed packages"
|
12
|
+
|
13
|
+
# Optional:
|
14
|
+
attr_reader :specific_run_as_user # e.g. ubuntu
|
15
|
+
attr_reader :settings # settings manifest (result of script might get stored back)
|
16
|
+
attr_reader :save_output_to_settings_key # e.g. bosh.salted_password
|
17
|
+
|
18
|
+
def initialize(command, description, script, full_present_tense=nil, full_past_tense=nil, options={})
|
19
|
+
super(command, description, full_present_tense, full_past_tense)
|
20
|
+
@script = script
|
21
|
+
@specific_run_as_user = options[:user]
|
22
|
+
@settings = options[:settings]
|
23
|
+
@save_output_to_settings_key = options[:save_output_to_settings_key]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Invoke this command to call back upon +server.run_script+
|
27
|
+
def perform(server)
|
28
|
+
server.run_script(self, script, :user => specific_run_as_user,
|
29
|
+
:settings => settings, :save_output_to_settings_key => save_output_to_settings_key)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Provide a filename that represents this Command
|
33
|
+
def to_filename
|
34
|
+
@to_filename ||= "#{command} #{description}".gsub(/\W+/, '_')
|
35
|
+
end
|
36
|
+
|
37
|
+
# Stores the script on the local filesystem in a temporary directory
|
38
|
+
# Returns path
|
39
|
+
def as_file(&block)
|
40
|
+
tmpdir = ENV['TMPDIR'] || "/tmp"
|
41
|
+
script_path = File.join(tmpdir, to_filename)
|
42
|
+
File.open(script_path, "w") do |f|
|
43
|
+
f << @script
|
44
|
+
end
|
45
|
+
yield script_path
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "net/scp"
|
2
|
+
require "tempfile"
|
3
|
+
|
4
|
+
class Bosh::Bootstrap::Commander::RemoteServer
|
5
|
+
|
6
|
+
attr_reader :host
|
7
|
+
attr_reader :default_username
|
8
|
+
attr_reader :logfile
|
9
|
+
|
10
|
+
def initialize(host, logfile=STDERR)
|
11
|
+
@host, @logfile = host, logfile
|
12
|
+
@default_username = "vcap" # unless overridden by a Command (before vcap exists)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Execute the +Command+ objects, in sequential order
|
16
|
+
# upon the local server
|
17
|
+
# +commands+ is a +Commands+ container
|
18
|
+
#
|
19
|
+
# Returns false once any subcommand fails to execute successfully
|
20
|
+
def run(commands)
|
21
|
+
commands.commands.each do |command|
|
22
|
+
puts command.full_present_tense
|
23
|
+
if command.perform(self)
|
24
|
+
Thor::Base.shell.new.say "Successfully #{command.full_past_tense}", :green
|
25
|
+
else
|
26
|
+
Thor::Base.shell.new.say_status "error", "#{command.full_present_tense}", :red
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Commands performed on remote server
|
34
|
+
# These map to Command subclasses, which then callback to these
|
35
|
+
# remote server specific implementations
|
36
|
+
#
|
37
|
+
|
38
|
+
# Run a script
|
39
|
+
#
|
40
|
+
# Uploads it to the remote server, makes it executable, then executes
|
41
|
+
# Stores the last line of stripped STDOUT/STDERR into a settings field,
|
42
|
+
# if :settings & :save_output_to_settings_key => "x.y.z" provided
|
43
|
+
def run_script(command, script, options={})
|
44
|
+
run_as_user = options[:user] || default_username
|
45
|
+
settings = options[:settings]
|
46
|
+
settings_key = options[:save_output_to_settings_key]
|
47
|
+
|
48
|
+
remote_path = remote_tmp_script_path(command)
|
49
|
+
upload_file(command, remote_path, script, run_as_user)
|
50
|
+
output, status = run_remote_script(remote_path, run_as_user)
|
51
|
+
output =~ /^(.*)\Z/
|
52
|
+
last_line = $1
|
53
|
+
# store output into a settings field, if requested
|
54
|
+
if settings_key
|
55
|
+
settings_key_portions = settings_key.split(".")
|
56
|
+
parent_key_portions, final_key = settings_key_portions[0..-2], settings_key_portions[-1]
|
57
|
+
target_settings_field = settings
|
58
|
+
parent_key_portions.each do |key_portion|
|
59
|
+
target_settings_field[key_portion] ||= {}
|
60
|
+
target_settings_field = target_settings_field[key_portion]
|
61
|
+
end
|
62
|
+
target_settings_field[final_key] = last_line.strip
|
63
|
+
end
|
64
|
+
status
|
65
|
+
rescue StandardError => e
|
66
|
+
logfile.puts e.message
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
# Upload a file (put a file into the remote server's filesystem)
|
71
|
+
def upload_file(command, remote_path, contents, upload_as_user=nil)
|
72
|
+
upload_as_user ||= default_username
|
73
|
+
run_remote_command("mkdir -p #{File.dirname(remote_path)}", upload_as_user)
|
74
|
+
Tempfile.open("remote_script") do |file|
|
75
|
+
file << contents
|
76
|
+
file.flush
|
77
|
+
logfile.puts "uploading #{remote_path} to Inception VM"
|
78
|
+
Net::SCP.upload!(host, upload_as_user, file.path, remote_path)
|
79
|
+
end
|
80
|
+
true
|
81
|
+
rescue StandardError => e
|
82
|
+
logfile.puts e.message
|
83
|
+
false
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
def remote_tmp_script_path(command)
|
88
|
+
"/tmp/remote_script_#{command.to_filename}"
|
89
|
+
end
|
90
|
+
|
91
|
+
# Makes +remote_path+ executable, then runs it
|
92
|
+
# Returns:
|
93
|
+
# * a String of all STDOUT/STDERR; which is also appended to +logfile+
|
94
|
+
# * status (true = success)
|
95
|
+
#
|
96
|
+
# TODO catch exceptions http://learnonthejob.blogspot.com/2010/08/exception-handling-for-netssh.html
|
97
|
+
def run_remote_script(remote_path, username)
|
98
|
+
commands = [
|
99
|
+
"chmod +x #{remote_path}",
|
100
|
+
"bash -lc 'sudo /usr/bin/env PATH=$PATH #{remote_path}'"
|
101
|
+
]
|
102
|
+
script_output = ""
|
103
|
+
results = Fog::SSH.new(host, username).run(commands) do |stdout, stderr|
|
104
|
+
[stdout, stderr].flatten.each do |data|
|
105
|
+
logfile << data
|
106
|
+
script_output << data
|
107
|
+
end
|
108
|
+
end
|
109
|
+
result = results.last
|
110
|
+
result_success = result.status == 0
|
111
|
+
[script_output, result_success]
|
112
|
+
end
|
113
|
+
|
114
|
+
def run_remote_command(command, username)
|
115
|
+
Net::SSH.start(host, username) do |ssh|
|
116
|
+
ssh.exec!("bash -lc '#{command}'") do |channel, stream, data|
|
117
|
+
logfile << data
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# A single command/script to be run on a local/remote server
|
2
|
+
# For the display, it has an active ("installing") and
|
3
|
+
# past tense ("installed") verb and a noub/description ("packages")
|
4
|
+
module Bosh::Bootstrap::Commander
|
5
|
+
class UploadCommand < Command
|
6
|
+
def initialize(target_path, file_contents)
|
7
|
+
super("upload", "file", "uploading file", "uploaded file")
|
8
|
+
@target_path = target_path
|
9
|
+
@file_contents = file_contents
|
10
|
+
end
|
11
|
+
|
12
|
+
# Invoke this command to call back upon +server.upload_file+
|
13
|
+
def perform(server)
|
14
|
+
server.upload_file(self, @target_path, @file_contents)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright (c) 2012-2013 Stark & Wayne, LLC
|
2
|
+
|
3
|
+
require "fog"
|
4
|
+
module Bosh; module Bootstrap; module Helpers; end; end; end
|
5
|
+
|
6
|
+
# A collection of methods related to getting fog_compute
|
7
|
+
# credentials for creating the inception VM
|
8
|
+
# and to provide to the MicroBOSH for its uses.
|
9
|
+
#
|
10
|
+
# Attempts to look in +settings.fog_path+ to see if there is a .fog file.
|
11
|
+
module Bosh::Bootstrap::Helpers::FogSetup
|
12
|
+
|
13
|
+
# fog connection object to Compute tasks (VMs, IP addresses)
|
14
|
+
def fog_compute
|
15
|
+
@fog_compute ||= begin
|
16
|
+
# Fog::Compute.new requires Hash with keys that are symbols
|
17
|
+
# but Settings converts all keys to strings
|
18
|
+
# So create a version of settings.fog_credentials with symbol keys
|
19
|
+
credentials_with_symbols = settings.fog_credentials.inject({}) do |creds, key_pair|
|
20
|
+
key, value = key_pair
|
21
|
+
creds[key.to_sym] = value
|
22
|
+
creds
|
23
|
+
end
|
24
|
+
Fog::Compute.new(credentials_with_symbols)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset_fog_compute
|
29
|
+
@fog_compute = nil
|
30
|
+
@provider = nil # in cli.rb - I don't like this; need one wrapper for all CPI/compute calls
|
31
|
+
# or don't create fog_compute until we know all IaaS details
|
32
|
+
end
|
33
|
+
|
34
|
+
def fog_config
|
35
|
+
@fog_config ||= begin
|
36
|
+
if File.exists?(fog_config_path)
|
37
|
+
say "Found infrastructure API credentials at #{fog_config_path} (override with --fog)"
|
38
|
+
YAML.load_file(fog_config_path)
|
39
|
+
else
|
40
|
+
say "No existing #{fog_config_path} fog configuration file", :yellow
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def fog_config_path
|
47
|
+
settings.fog_path
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|