chef-provisioning-fog 0.14.0 → 0.15.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/LICENSE +201 -201
- data/README.md +3 -3
- data/Rakefile +6 -6
- data/lib/chef/provider/fog_key_pair.rb +266 -266
- data/lib/chef/provisioning/driver_init/fog.rb +3 -3
- data/lib/chef/provisioning/fog_driver/driver.rb +736 -709
- data/lib/chef/provisioning/fog_driver/providers/aws.rb +492 -492
- data/lib/chef/provisioning/fog_driver/providers/aws/credentials.rb +115 -115
- data/lib/chef/provisioning/fog_driver/providers/cloudstack.rb +44 -44
- data/lib/chef/provisioning/fog_driver/providers/digitalocean.rb +136 -136
- data/lib/chef/provisioning/fog_driver/providers/google.rb +85 -84
- data/lib/chef/provisioning/fog_driver/providers/joyent.rb +63 -59
- data/lib/chef/provisioning/fog_driver/providers/openstack.rb +117 -41
- data/lib/chef/provisioning/fog_driver/providers/rackspace.rb +42 -42
- data/lib/chef/provisioning/fog_driver/providers/softlayer.rb +36 -36
- data/lib/chef/provisioning/fog_driver/providers/vcair.rb +409 -376
- data/lib/chef/provisioning/fog_driver/providers/xenserver.rb +210 -0
- data/lib/chef/provisioning/fog_driver/recipe_dsl.rb +32 -32
- data/lib/chef/provisioning/fog_driver/version.rb +7 -7
- data/lib/chef/resource/fog_key_pair.rb +34 -34
- data/spec/spec_helper.rb +18 -18
- data/spec/support/aws/config-file.csv +2 -2
- data/spec/support/aws/ini-file.ini +10 -10
- data/spec/support/chef_metal_fog/providers/testdriver.rb +16 -16
- data/spec/unit/chef/provisioning/fog_driver/driver_spec.rb +71 -0
- data/spec/unit/fog_driver_spec.rb +32 -32
- data/spec/unit/providers/aws/credentials_spec.rb +45 -45
- data/spec/unit/providers/rackspace_spec.rb +16 -16
- metadata +5 -3
@@ -1,115 +1,115 @@
|
|
1
|
-
require 'inifile'
|
2
|
-
require 'csv'
|
3
|
-
require 'chef/mixin/deep_merge'
|
4
|
-
|
5
|
-
class Chef
|
6
|
-
module Provisioning
|
7
|
-
module FogDriver
|
8
|
-
module Providers
|
9
|
-
class AWS
|
10
|
-
# Reads in a credentials file in Amazon's download format and presents the credentials to you
|
11
|
-
class Credentials
|
12
|
-
def initialize
|
13
|
-
@credentials = {}
|
14
|
-
end
|
15
|
-
|
16
|
-
include Enumerable
|
17
|
-
include Chef::Mixin::DeepMerge
|
18
|
-
|
19
|
-
def default
|
20
|
-
if @credentials.size == 0
|
21
|
-
raise "No credentials loaded! Do you have one of ~/.aws/credentials or ~/.aws/config?"
|
22
|
-
end
|
23
|
-
@credentials[ENV['AWS_DEFAULT_PROFILE'] || 'default'] || @credentials.first[1]
|
24
|
-
end
|
25
|
-
|
26
|
-
def keys
|
27
|
-
@credentials.keys
|
28
|
-
end
|
29
|
-
|
30
|
-
def [](name)
|
31
|
-
@credentials[name]
|
32
|
-
end
|
33
|
-
|
34
|
-
def each(&block)
|
35
|
-
@credentials.each(&block)
|
36
|
-
end
|
37
|
-
|
38
|
-
def load_inis(config_ini_file, credentials_ini_file = nil)
|
39
|
-
@credentials = load_config_ini(config_ini_file)
|
40
|
-
@credentials = deep_merge!(@credentials,
|
41
|
-
load_credentials_ini(credentials_ini_file)
|
42
|
-
) if credentials_ini_file
|
43
|
-
end
|
44
|
-
|
45
|
-
def load_config_ini(config_ini_file)
|
46
|
-
inifile = IniFile.load(File.expand_path(config_ini_file))
|
47
|
-
config = {}
|
48
|
-
if inifile
|
49
|
-
inifile.each_section do |section|
|
50
|
-
if section =~ /^\s*profile\s+(.+)$/ || section =~ /^\s*(default)\s*/
|
51
|
-
profile_name = $1.strip
|
52
|
-
profile = inifile[section].inject({}) do |result, pair|
|
53
|
-
result[pair[0].to_sym] = pair[1]
|
54
|
-
result
|
55
|
-
end
|
56
|
-
profile[:name] = profile_name
|
57
|
-
config[profile_name] = profile
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
config
|
62
|
-
end
|
63
|
-
|
64
|
-
def load_credentials_ini(credentials_ini_file)
|
65
|
-
inifile = IniFile.load(File.expand_path(credentials_ini_file))
|
66
|
-
config = {}
|
67
|
-
if inifile
|
68
|
-
inifile.each_section do |section|
|
69
|
-
profile = inifile[section].inject({}) do |result, pair|
|
70
|
-
result[pair[0].to_sym] = pair[1]
|
71
|
-
result
|
72
|
-
end
|
73
|
-
profile[:name] = section
|
74
|
-
config[section] = profile
|
75
|
-
end
|
76
|
-
end
|
77
|
-
config
|
78
|
-
end
|
79
|
-
|
80
|
-
def load_csv(credentials_csv_file)
|
81
|
-
CSV.new(File.open(credentials_csv_file), :headers => :first_row).each do |row|
|
82
|
-
@credentials[row['User Name']] = {
|
83
|
-
:name => row['User Name'],
|
84
|
-
:user_name => row['User Name'],
|
85
|
-
:aws_access_key_id => row['Access Key Id'],
|
86
|
-
:aws_secret_access_key => row['Secret Access Key']
|
87
|
-
}
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def load_default
|
92
|
-
config_file = ENV['AWS_CONFIG_FILE'] || File.expand_path('~/.aws/config')
|
93
|
-
credentials_file = ENV['AWS_CREDENTIAL_FILE'] || File.expand_path('~/.aws/credentials')
|
94
|
-
if File.file?(config_file)
|
95
|
-
if File.file?(credentials_file)
|
96
|
-
load_inis(config_file, credentials_file)
|
97
|
-
else
|
98
|
-
load_inis(config_file)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def self.method_missing(name, *args, &block)
|
104
|
-
singleton.send(name, *args, &block)
|
105
|
-
end
|
106
|
-
|
107
|
-
def self.singleton
|
108
|
-
@aws_credentials ||= Credentials.new
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
1
|
+
require 'inifile'
|
2
|
+
require 'csv'
|
3
|
+
require 'chef/mixin/deep_merge'
|
4
|
+
|
5
|
+
class Chef
|
6
|
+
module Provisioning
|
7
|
+
module FogDriver
|
8
|
+
module Providers
|
9
|
+
class AWS
|
10
|
+
# Reads in a credentials file in Amazon's download format and presents the credentials to you
|
11
|
+
class Credentials
|
12
|
+
def initialize
|
13
|
+
@credentials = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
include Enumerable
|
17
|
+
include Chef::Mixin::DeepMerge
|
18
|
+
|
19
|
+
def default
|
20
|
+
if @credentials.size == 0
|
21
|
+
raise "No credentials loaded! Do you have one of ~/.aws/credentials or ~/.aws/config?"
|
22
|
+
end
|
23
|
+
@credentials[ENV['AWS_DEFAULT_PROFILE'] || 'default'] || @credentials.first[1]
|
24
|
+
end
|
25
|
+
|
26
|
+
def keys
|
27
|
+
@credentials.keys
|
28
|
+
end
|
29
|
+
|
30
|
+
def [](name)
|
31
|
+
@credentials[name]
|
32
|
+
end
|
33
|
+
|
34
|
+
def each(&block)
|
35
|
+
@credentials.each(&block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_inis(config_ini_file, credentials_ini_file = nil)
|
39
|
+
@credentials = load_config_ini(config_ini_file)
|
40
|
+
@credentials = deep_merge!(@credentials,
|
41
|
+
load_credentials_ini(credentials_ini_file)
|
42
|
+
) if credentials_ini_file
|
43
|
+
end
|
44
|
+
|
45
|
+
def load_config_ini(config_ini_file)
|
46
|
+
inifile = IniFile.load(File.expand_path(config_ini_file))
|
47
|
+
config = {}
|
48
|
+
if inifile
|
49
|
+
inifile.each_section do |section|
|
50
|
+
if section =~ /^\s*profile\s+(.+)$/ || section =~ /^\s*(default)\s*/
|
51
|
+
profile_name = $1.strip
|
52
|
+
profile = inifile[section].inject({}) do |result, pair|
|
53
|
+
result[pair[0].to_sym] = pair[1]
|
54
|
+
result
|
55
|
+
end
|
56
|
+
profile[:name] = profile_name
|
57
|
+
config[profile_name] = profile
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
config
|
62
|
+
end
|
63
|
+
|
64
|
+
def load_credentials_ini(credentials_ini_file)
|
65
|
+
inifile = IniFile.load(File.expand_path(credentials_ini_file))
|
66
|
+
config = {}
|
67
|
+
if inifile
|
68
|
+
inifile.each_section do |section|
|
69
|
+
profile = inifile[section].inject({}) do |result, pair|
|
70
|
+
result[pair[0].to_sym] = pair[1]
|
71
|
+
result
|
72
|
+
end
|
73
|
+
profile[:name] = section
|
74
|
+
config[section] = profile
|
75
|
+
end
|
76
|
+
end
|
77
|
+
config
|
78
|
+
end
|
79
|
+
|
80
|
+
def load_csv(credentials_csv_file)
|
81
|
+
CSV.new(File.open(credentials_csv_file), :headers => :first_row).each do |row|
|
82
|
+
@credentials[row['User Name']] = {
|
83
|
+
:name => row['User Name'],
|
84
|
+
:user_name => row['User Name'],
|
85
|
+
:aws_access_key_id => row['Access Key Id'],
|
86
|
+
:aws_secret_access_key => row['Secret Access Key']
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def load_default
|
92
|
+
config_file = ENV['AWS_CONFIG_FILE'] || File.expand_path('~/.aws/config')
|
93
|
+
credentials_file = ENV['AWS_CREDENTIAL_FILE'] || File.expand_path('~/.aws/credentials')
|
94
|
+
if File.file?(config_file)
|
95
|
+
if File.file?(credentials_file)
|
96
|
+
load_inis(config_file, credentials_file)
|
97
|
+
else
|
98
|
+
load_inis(config_file)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.method_missing(name, *args, &block)
|
104
|
+
singleton.send(name, *args, &block)
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.singleton
|
108
|
+
@aws_credentials ||= Credentials.new
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -1,44 +1,44 @@
|
|
1
|
-
class Chef
|
2
|
-
module Provisioning
|
3
|
-
module FogDriver
|
4
|
-
module Providers
|
5
|
-
class CloudStack < FogDriver::Driver
|
6
|
-
|
7
|
-
Driver.register_provider_class('CloudStack', FogDriver::Providers::CloudStack)
|
8
|
-
|
9
|
-
def creator
|
10
|
-
''
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.compute_options_for(provider, id, config)
|
14
|
-
new_compute_options = {}
|
15
|
-
new_compute_options[:provider] = provider
|
16
|
-
new_config = { :driver_options => { :compute_options => new_compute_options }}
|
17
|
-
new_defaults = {
|
18
|
-
:driver_options => { :compute_options => {} },
|
19
|
-
:machine_options => { :bootstrap_options => {} }
|
20
|
-
}
|
21
|
-
result = Cheffish::MergedConfig.new(new_config, config, new_defaults)
|
22
|
-
|
23
|
-
if id && id != ''
|
24
|
-
cloudstack_uri = URI.parse(id)
|
25
|
-
new_compute_options[:cloudstack_scheme] = cloudstack_uri.scheme
|
26
|
-
new_compute_options[:cloudstack_host] = cloudstack_uri.host
|
27
|
-
new_compute_options[:cloudstack_port] = cloudstack_uri.port
|
28
|
-
new_compute_options[:cloudstack_path] = cloudstack_uri.path
|
29
|
-
end
|
30
|
-
|
31
|
-
host = result[:driver_options][:compute_options][:cloudstack_host]
|
32
|
-
path = result[:driver_options][:compute_options][:cloudstack_path] || '/client/api'
|
33
|
-
port = result[:driver_options][:compute_options][:cloudstack_port] || 443
|
34
|
-
scheme = result[:driver_options][:compute_options][:cloudstack_scheme] || 'https'
|
35
|
-
id = URI.scheme_list[scheme.upcase].build(:host => host, :port => port, :path => path).to_s
|
36
|
-
|
37
|
-
[result, id]
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
1
|
+
class Chef
|
2
|
+
module Provisioning
|
3
|
+
module FogDriver
|
4
|
+
module Providers
|
5
|
+
class CloudStack < FogDriver::Driver
|
6
|
+
|
7
|
+
Driver.register_provider_class('CloudStack', FogDriver::Providers::CloudStack)
|
8
|
+
|
9
|
+
def creator
|
10
|
+
''
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.compute_options_for(provider, id, config)
|
14
|
+
new_compute_options = {}
|
15
|
+
new_compute_options[:provider] = provider
|
16
|
+
new_config = { :driver_options => { :compute_options => new_compute_options }}
|
17
|
+
new_defaults = {
|
18
|
+
:driver_options => { :compute_options => {} },
|
19
|
+
:machine_options => { :bootstrap_options => {} }
|
20
|
+
}
|
21
|
+
result = Cheffish::MergedConfig.new(new_config, config, new_defaults)
|
22
|
+
|
23
|
+
if id && id != ''
|
24
|
+
cloudstack_uri = URI.parse(id)
|
25
|
+
new_compute_options[:cloudstack_scheme] = cloudstack_uri.scheme
|
26
|
+
new_compute_options[:cloudstack_host] = cloudstack_uri.host
|
27
|
+
new_compute_options[:cloudstack_port] = cloudstack_uri.port
|
28
|
+
new_compute_options[:cloudstack_path] = cloudstack_uri.path
|
29
|
+
end
|
30
|
+
|
31
|
+
host = result[:driver_options][:compute_options][:cloudstack_host]
|
32
|
+
path = result[:driver_options][:compute_options][:cloudstack_path] || '/client/api'
|
33
|
+
port = result[:driver_options][:compute_options][:cloudstack_port] || 443
|
34
|
+
scheme = result[:driver_options][:compute_options][:cloudstack_scheme] || 'https'
|
35
|
+
id = URI.scheme_list[scheme.upcase].build(:host => host, :port => port, :path => path).to_s
|
36
|
+
|
37
|
+
[result, id]
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,136 +1,136 @@
|
|
1
|
-
# fog:DigitalOcean:<client id>
|
2
|
-
class Chef
|
3
|
-
module Provisioning
|
4
|
-
module FogDriver
|
5
|
-
module Providers
|
6
|
-
class DigitalOcean < FogDriver::Driver
|
7
|
-
Driver.register_provider_class('DigitalOcean', FogDriver::Providers::DigitalOcean)
|
8
|
-
|
9
|
-
def creator
|
10
|
-
''
|
11
|
-
end
|
12
|
-
|
13
|
-
def converge_floating_ips(action_handler, machine_spec, machine_options, server)
|
14
|
-
# DigitalOcean does not have floating IPs
|
15
|
-
end
|
16
|
-
|
17
|
-
def bootstrap_options_for(action_handler, machine_spec, machine_options)
|
18
|
-
bootstrap_options = symbolize_keys(machine_options[:bootstrap_options] || {})
|
19
|
-
if bootstrap_options[:key_path]
|
20
|
-
bootstrap_options[:key_name] ||= File.basename(bootstrap_options[:key_path])
|
21
|
-
# Verify that the provided key name and path are in line (or create the key pair if not!)
|
22
|
-
driver = self
|
23
|
-
Provisioning.inline_resource(action_handler) do
|
24
|
-
fog_key_pair bootstrap_options[:key_name] do
|
25
|
-
private_key_path bootstrap_options[:key_path]
|
26
|
-
driver driver
|
27
|
-
end
|
28
|
-
end
|
29
|
-
else
|
30
|
-
bootstrap_options[:key_name] = overwrite_default_key_willy_nilly(action_handler, machine_spec)
|
31
|
-
end
|
32
|
-
|
33
|
-
bootstrap_options[:tags] = default_tags(machine_spec, bootstrap_options[:tags] || {})
|
34
|
-
|
35
|
-
if !bootstrap_options[:image_id]
|
36
|
-
if !bootstrap_options[:image_distribution] && !bootstrap_options[:image_name]
|
37
|
-
bootstrap_options[:image_distribution] = 'CentOS'
|
38
|
-
bootstrap_options[:image_name] = '6.5 x64'
|
39
|
-
end
|
40
|
-
distributions = compute.images.select { |image| image.distribution == bootstrap_options[:image_distribution] }
|
41
|
-
if distributions.empty?
|
42
|
-
raise "No images on DigitalOcean with distribution #{bootstrap_options[:image_distribution].inspect}"
|
43
|
-
end
|
44
|
-
images = distributions.select { |image| image.name == bootstrap_options[:image_name] } if bootstrap_options[:image_name]
|
45
|
-
if images.empty?
|
46
|
-
raise "No images on DigitalOcean with distribution #{bootstrap_options[:image_distribution].inspect} and name #{bootstrap_options[:image_name].inspect}"
|
47
|
-
end
|
48
|
-
bootstrap_options[:image_id] = images.first.id
|
49
|
-
end
|
50
|
-
if !bootstrap_options[:flavor_id]
|
51
|
-
bootstrap_options[:flavor_name] ||= '512MB'
|
52
|
-
flavors = compute.flavors.select do |f|
|
53
|
-
f.name == bootstrap_options[:flavor_name]
|
54
|
-
end
|
55
|
-
if flavors.empty?
|
56
|
-
raise "Could not find flavor named '#{bootstrap_options[:flavor_name]}' on #{driver_url}"
|
57
|
-
end
|
58
|
-
bootstrap_options[:flavor_id] = flavors.first.id
|
59
|
-
end
|
60
|
-
if !bootstrap_options[:region_id]
|
61
|
-
bootstrap_options[:region_name] ||= 'San Francisco 1'
|
62
|
-
regions = compute.regions.select { |region| region.name == bootstrap_options[:region_name] }
|
63
|
-
if regions.empty?
|
64
|
-
raise "Could not find region named '#{bootstrap_options[:region_name]}' on #{driver_url}"
|
65
|
-
end
|
66
|
-
bootstrap_options[:region_id] = regions.first.id
|
67
|
-
end
|
68
|
-
keys = compute.ssh_keys.select { |k| k.name == bootstrap_options[:key_name] }
|
69
|
-
if keys.empty?
|
70
|
-
raise "Could not find key named '#{bootstrap_options[:key_name]}' on #{driver_url}"
|
71
|
-
end
|
72
|
-
found_key = keys.first
|
73
|
-
bootstrap_options[:ssh_key_ids] ||= [ found_key.id ]
|
74
|
-
|
75
|
-
# You don't get to specify name yourself
|
76
|
-
bootstrap_options[:name] = machine_spec.name
|
77
|
-
|
78
|
-
bootstrap_options
|
79
|
-
end
|
80
|
-
|
81
|
-
def destroy_machine(action_handler, machine_spec, machine_options)
|
82
|
-
server = server_for(machine_spec)
|
83
|
-
if server && server.state != 'archive'
|
84
|
-
action_handler.perform_action "destroy machine #{machine_spec.name} (#{machine_spec.location['server_id']} at #{driver_url})" do
|
85
|
-
server.destroy
|
86
|
-
end
|
87
|
-
end
|
88
|
-
machine_spec.location = nil
|
89
|
-
strategy = convergence_strategy_for(machine_spec, machine_options)
|
90
|
-
strategy.cleanup_convergence(action_handler, machine_spec)
|
91
|
-
end
|
92
|
-
|
93
|
-
def self.compute_options_for(provider, id, config)
|
94
|
-
new_compute_options = {}
|
95
|
-
new_compute_options[:provider] = provider
|
96
|
-
new_config = { :driver_options => { :compute_options => new_compute_options }}
|
97
|
-
new_defaults = {
|
98
|
-
:driver_options => { :compute_options => {} },
|
99
|
-
:machine_options => { :bootstrap_options => {}, :ssh_options => {} }
|
100
|
-
}
|
101
|
-
result = Cheffish::MergedConfig.new(new_config, config, new_defaults)
|
102
|
-
|
103
|
-
new_compute_options[:digitalocean_client_id] = id if (id && id != '')
|
104
|
-
|
105
|
-
# This uses ~/.tugboat, generated by "tugboat authorize" - see https://github.com/pearkes/tugboat
|
106
|
-
tugboat_file = File.expand_path('~/.tugboat')
|
107
|
-
if File.exist?(tugboat_file)
|
108
|
-
tugboat_data = YAML.load(IO.read(tugboat_file))
|
109
|
-
|
110
|
-
new_bootstrap_options = new_defaults[:machine_options][:bootstrap_options]
|
111
|
-
if tugboat_data['authentication']
|
112
|
-
new_compute_options[:digitalocean_client_id] = tugboat_data['authentication']['client_key'] if tugboat_data['authentication']['client_key'] && tugboat_data['authentication']['client_key'].size > 0
|
113
|
-
new_compute_options[:digitalocean_api_key] = tugboat_data['authentication']['api_key'] if tugboat_data['authentication']['api_key'] && tugboat_data['authentication']['api_key'].size > 0
|
114
|
-
end
|
115
|
-
if tugboat_data['defaults']
|
116
|
-
new_bootstrap_options[:region_id] = tugboat_data['defaults']['region'].to_i if tugboat_data['defaults']['region'] && tugboat_data['defaults']['region'].size > 0
|
117
|
-
new_bootstrap_options[:image_id] = tugboat_data['defaults']['image'].to_i if tugboat_data['defaults']['image'] && tugboat_data['defaults']['image'].size > 0
|
118
|
-
new_bootstrap_options[:size_id] = tugboat_data['defaults']['size'].to_i if tugboat_data['defaults']['size'] && tugboat_data['defaults']['size'].size > 0
|
119
|
-
new_bootstrap_options[:private_networking] = (tugboat_data['defaults']['private_networking'] == 'true') if tugboat_data['defaults']['private_networking'] && tugboat_data['defaults']['private_networking'].size > 0
|
120
|
-
new_bootstrap_options[:backups_enabled] = (tugboat_data['defaults']['backups_enabled'] == 'true') if tugboat_data['defaults']['backups_enabled'] && tugboat_data['defaults']['backups_enabled'].size > 0
|
121
|
-
new_bootstrap_options[:key_name] = tugboat_data['defaults']['ssh_key'] if tugboat_data['defaults']['ssh_key'] && tugboat_data['defaults']['ssh_key'].size > 0
|
122
|
-
end
|
123
|
-
if tugboat_data['ssh']
|
124
|
-
new_bootstrap_options[:key_path] = tugboat_data['ssh']['ssh_key_path'] if tugboat_data['ssh']['ssh_key_path'] && tugboat_data['ssh']['ssh_key_path'].size > 0
|
125
|
-
new_defaults[:machine_options][:ssh_options][:port] = tugboat_data['ssh']['ssh_port'] if tugboat_data['ssh']['ssh_port'] if tugboat_data['ssh']['ssh_port'].size > 0
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
[result, new_compute_options[:digitalocean_client_id]]
|
130
|
-
end
|
131
|
-
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
1
|
+
# fog:DigitalOcean:<client id>
|
2
|
+
class Chef
|
3
|
+
module Provisioning
|
4
|
+
module FogDriver
|
5
|
+
module Providers
|
6
|
+
class DigitalOcean < FogDriver::Driver
|
7
|
+
Driver.register_provider_class('DigitalOcean', FogDriver::Providers::DigitalOcean)
|
8
|
+
|
9
|
+
def creator
|
10
|
+
''
|
11
|
+
end
|
12
|
+
|
13
|
+
def converge_floating_ips(action_handler, machine_spec, machine_options, server)
|
14
|
+
# DigitalOcean does not have floating IPs
|
15
|
+
end
|
16
|
+
|
17
|
+
def bootstrap_options_for(action_handler, machine_spec, machine_options)
|
18
|
+
bootstrap_options = symbolize_keys(machine_options[:bootstrap_options] || {})
|
19
|
+
if bootstrap_options[:key_path]
|
20
|
+
bootstrap_options[:key_name] ||= File.basename(bootstrap_options[:key_path])
|
21
|
+
# Verify that the provided key name and path are in line (or create the key pair if not!)
|
22
|
+
driver = self
|
23
|
+
Provisioning.inline_resource(action_handler) do
|
24
|
+
fog_key_pair bootstrap_options[:key_name] do
|
25
|
+
private_key_path bootstrap_options[:key_path]
|
26
|
+
driver driver
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
bootstrap_options[:key_name] = overwrite_default_key_willy_nilly(action_handler, machine_spec)
|
31
|
+
end
|
32
|
+
|
33
|
+
bootstrap_options[:tags] = default_tags(machine_spec, bootstrap_options[:tags] || {})
|
34
|
+
|
35
|
+
if !bootstrap_options[:image_id]
|
36
|
+
if !bootstrap_options[:image_distribution] && !bootstrap_options[:image_name]
|
37
|
+
bootstrap_options[:image_distribution] = 'CentOS'
|
38
|
+
bootstrap_options[:image_name] = '6.5 x64'
|
39
|
+
end
|
40
|
+
distributions = compute.images.select { |image| image.distribution == bootstrap_options[:image_distribution] }
|
41
|
+
if distributions.empty?
|
42
|
+
raise "No images on DigitalOcean with distribution #{bootstrap_options[:image_distribution].inspect}"
|
43
|
+
end
|
44
|
+
images = distributions.select { |image| image.name == bootstrap_options[:image_name] } if bootstrap_options[:image_name]
|
45
|
+
if images.empty?
|
46
|
+
raise "No images on DigitalOcean with distribution #{bootstrap_options[:image_distribution].inspect} and name #{bootstrap_options[:image_name].inspect}"
|
47
|
+
end
|
48
|
+
bootstrap_options[:image_id] = images.first.id
|
49
|
+
end
|
50
|
+
if !bootstrap_options[:flavor_id]
|
51
|
+
bootstrap_options[:flavor_name] ||= '512MB'
|
52
|
+
flavors = compute.flavors.select do |f|
|
53
|
+
f.name == bootstrap_options[:flavor_name]
|
54
|
+
end
|
55
|
+
if flavors.empty?
|
56
|
+
raise "Could not find flavor named '#{bootstrap_options[:flavor_name]}' on #{driver_url}"
|
57
|
+
end
|
58
|
+
bootstrap_options[:flavor_id] = flavors.first.id
|
59
|
+
end
|
60
|
+
if !bootstrap_options[:region_id]
|
61
|
+
bootstrap_options[:region_name] ||= 'San Francisco 1'
|
62
|
+
regions = compute.regions.select { |region| region.name == bootstrap_options[:region_name] }
|
63
|
+
if regions.empty?
|
64
|
+
raise "Could not find region named '#{bootstrap_options[:region_name]}' on #{driver_url}"
|
65
|
+
end
|
66
|
+
bootstrap_options[:region_id] = regions.first.id
|
67
|
+
end
|
68
|
+
keys = compute.ssh_keys.select { |k| k.name == bootstrap_options[:key_name] }
|
69
|
+
if keys.empty?
|
70
|
+
raise "Could not find key named '#{bootstrap_options[:key_name]}' on #{driver_url}"
|
71
|
+
end
|
72
|
+
found_key = keys.first
|
73
|
+
bootstrap_options[:ssh_key_ids] ||= [ found_key.id ]
|
74
|
+
|
75
|
+
# You don't get to specify name yourself
|
76
|
+
bootstrap_options[:name] = machine_spec.name
|
77
|
+
|
78
|
+
bootstrap_options
|
79
|
+
end
|
80
|
+
|
81
|
+
def destroy_machine(action_handler, machine_spec, machine_options)
|
82
|
+
server = server_for(machine_spec)
|
83
|
+
if server && server.state != 'archive'
|
84
|
+
action_handler.perform_action "destroy machine #{machine_spec.name} (#{machine_spec.location['server_id']} at #{driver_url})" do
|
85
|
+
server.destroy
|
86
|
+
end
|
87
|
+
end
|
88
|
+
machine_spec.location = nil
|
89
|
+
strategy = convergence_strategy_for(machine_spec, machine_options)
|
90
|
+
strategy.cleanup_convergence(action_handler, machine_spec)
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.compute_options_for(provider, id, config)
|
94
|
+
new_compute_options = {}
|
95
|
+
new_compute_options[:provider] = provider
|
96
|
+
new_config = { :driver_options => { :compute_options => new_compute_options }}
|
97
|
+
new_defaults = {
|
98
|
+
:driver_options => { :compute_options => {} },
|
99
|
+
:machine_options => { :bootstrap_options => {}, :ssh_options => {} }
|
100
|
+
}
|
101
|
+
result = Cheffish::MergedConfig.new(new_config, config, new_defaults)
|
102
|
+
|
103
|
+
new_compute_options[:digitalocean_client_id] = id if (id && id != '')
|
104
|
+
|
105
|
+
# This uses ~/.tugboat, generated by "tugboat authorize" - see https://github.com/pearkes/tugboat
|
106
|
+
tugboat_file = File.expand_path('~/.tugboat')
|
107
|
+
if File.exist?(tugboat_file)
|
108
|
+
tugboat_data = YAML.load(IO.read(tugboat_file))
|
109
|
+
|
110
|
+
new_bootstrap_options = new_defaults[:machine_options][:bootstrap_options]
|
111
|
+
if tugboat_data['authentication']
|
112
|
+
new_compute_options[:digitalocean_client_id] = tugboat_data['authentication']['client_key'] if tugboat_data['authentication']['client_key'] && tugboat_data['authentication']['client_key'].size > 0
|
113
|
+
new_compute_options[:digitalocean_api_key] = tugboat_data['authentication']['api_key'] if tugboat_data['authentication']['api_key'] && tugboat_data['authentication']['api_key'].size > 0
|
114
|
+
end
|
115
|
+
if tugboat_data['defaults']
|
116
|
+
new_bootstrap_options[:region_id] = tugboat_data['defaults']['region'].to_i if tugboat_data['defaults']['region'] && tugboat_data['defaults']['region'].size > 0
|
117
|
+
new_bootstrap_options[:image_id] = tugboat_data['defaults']['image'].to_i if tugboat_data['defaults']['image'] && tugboat_data['defaults']['image'].size > 0
|
118
|
+
new_bootstrap_options[:size_id] = tugboat_data['defaults']['size'].to_i if tugboat_data['defaults']['size'] && tugboat_data['defaults']['size'].size > 0
|
119
|
+
new_bootstrap_options[:private_networking] = (tugboat_data['defaults']['private_networking'] == 'true') if tugboat_data['defaults']['private_networking'] && tugboat_data['defaults']['private_networking'].size > 0
|
120
|
+
new_bootstrap_options[:backups_enabled] = (tugboat_data['defaults']['backups_enabled'] == 'true') if tugboat_data['defaults']['backups_enabled'] && tugboat_data['defaults']['backups_enabled'].size > 0
|
121
|
+
new_bootstrap_options[:key_name] = tugboat_data['defaults']['ssh_key'] if tugboat_data['defaults']['ssh_key'] && tugboat_data['defaults']['ssh_key'].size > 0
|
122
|
+
end
|
123
|
+
if tugboat_data['ssh']
|
124
|
+
new_bootstrap_options[:key_path] = tugboat_data['ssh']['ssh_key_path'] if tugboat_data['ssh']['ssh_key_path'] && tugboat_data['ssh']['ssh_key_path'].size > 0
|
125
|
+
new_defaults[:machine_options][:ssh_options][:port] = tugboat_data['ssh']['ssh_port'] if tugboat_data['ssh']['ssh_port'] if tugboat_data['ssh']['ssh_port'].size > 0
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
[result, new_compute_options[:digitalocean_client_id]]
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|