chef-provisioning-fog 0.14.0 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|