chef-provisioning-fog 0.10

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.
@@ -0,0 +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
@@ -0,0 +1,122 @@
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 bootstrap_options_for(action_handler, machine_spec, machine_options)
14
+ bootstrap_options = symbolize_keys(machine_options[:bootstrap_options] || {})
15
+ if bootstrap_options[:key_path]
16
+ bootstrap_options[:key_name] ||= File.basename(bootstrap_options[:key_path])
17
+ # Verify that the provided key name and path are in line (or create the key pair if not!)
18
+ driver = self
19
+ Provisioning.inline_resource(action_handler) do
20
+ fog_key_pair bootstrap_options[:key_name] do
21
+ private_key_path bootstrap_options[:key_path]
22
+ driver driver
23
+ end
24
+ end
25
+ else
26
+ bootstrap_options[:key_name] = overwrite_default_key_willy_nilly(action_handler, machine_spec)
27
+ end
28
+
29
+ bootstrap_options[:tags] = default_tags(machine_spec, bootstrap_options[:tags] || {})
30
+
31
+ if !bootstrap_options[:image_id]
32
+ bootstrap_options[:image_name] ||= 'CentOS 6.4 x32'
33
+ bootstrap_options[:image_id] = compute.images.select { |image| image.name == bootstrap_options[:image_name] }.first.id
34
+ end
35
+ if !bootstrap_options[:flavor_id]
36
+ bootstrap_options[:flavor_name] ||= '512MB'
37
+ bootstrap_options[:flavor_id] = compute.flavors.select { |flavor| flavor.name == bootstrap_options[:flavor_name] }.first.id
38
+ end
39
+ if !bootstrap_options[:region_id]
40
+ bootstrap_options[:region_name] ||= 'San Francisco 1'
41
+ bootstrap_options[:region_id] = compute.regions.select { |region| region.name == bootstrap_options[:region_name] }.first.id
42
+ end
43
+ found_key = compute.ssh_keys.select { |k| k.name == bootstrap_options[:key_name] }.first
44
+ if !found_key
45
+ raise "Could not find key named '#{bootstrap_options[:key_name]}' on #{driver_url}"
46
+ end
47
+ bootstrap_options[:ssh_key_ids] ||= [ found_key.id ]
48
+
49
+ # You don't get to specify name yourself
50
+ bootstrap_options[:name] = machine_spec.name
51
+
52
+ bootstrap_options
53
+ end
54
+
55
+ def destroy_machine(action_handler, machine_spec, machine_options)
56
+ server = server_for(machine_spec)
57
+ if server && server.state != 'archive'
58
+ action_handler.perform_action "destroy machine #{machine_spec.name} (#{machine_spec.location['server_id']} at #{driver_url})" do
59
+ server.destroy
60
+ end
61
+ end
62
+ machine_spec.location = nil
63
+ strategy = convergence_strategy_for(machine_spec, machine_options)
64
+ strategy.cleanup_convergence(action_handler, machine_spec)
65
+ end
66
+
67
+ def self.compute_options_for(provider, id, config)
68
+ new_compute_options = {}
69
+ new_compute_options[:provider] = provider
70
+ new_config = { :driver_options => { :compute_options => new_compute_options }}
71
+ new_defaults = {
72
+ :driver_options => { :compute_options => {} },
73
+ :machine_options => { :bootstrap_options => {} }
74
+ }
75
+ result = Cheffish::MergedConfig.new(new_config, config, new_defaults)
76
+
77
+ new_compute_options[:digitalocean_client_id] = id if (id && id != '')
78
+
79
+ # This uses ~/.tugboat, generated by "tugboat authorize" - see https://github.com/pearkes/tugboat
80
+ tugboat_file = File.expand_path('~/.tugboat')
81
+ if File.exist?(tugboat_file)
82
+ tugboat_data = YAML.load(IO.read(tugboat_file))
83
+ new_compute_options.merge!(
84
+ :digitalocean_client_id => tugboat_data['authentication']['client_key'],
85
+ :digitalocean_api_key => tugboat_data['authentication']['api_key']
86
+ )
87
+ new_defaults[:machine_options].merge!(
88
+ #:ssh_username => tugboat_data['ssh']['ssh_user'],
89
+ :ssh_options => {
90
+ :port => tugboat_data['ssh']['ssh_port'],
91
+ # TODO we ignore ssh_key_path in favor of ssh_key / key_name stuff
92
+ #:key_data => [ IO.read(tugboat_data['ssh']['ssh_key_path']) ] # TODO use paths, not data?
93
+ }
94
+ )
95
+
96
+ # TODO verify that the key_name exists and matches the ssh key path
97
+
98
+ new_defaults[:machine_options][:bootstrap_options].merge!(
99
+ :region_id => tugboat_data['defaults']['region'].to_i,
100
+ :image_id => tugboat_data['defaults']['image'].to_i,
101
+ :size_id => tugboat_data['defaults']['size'].to_i,
102
+ :private_networking => tugboat_data['defaults']['private_networking'] == 'true',
103
+ :backups_enabled => tugboat_data['defaults']['backups_enabled'] == 'true',
104
+ )
105
+ if tugboat_data['ssh']['ssh_key_path']
106
+ new_defaults[:machine_options][:bootstrap_options][:key_path] = tugboat_data['ssh']['ssh_key_path']
107
+ end
108
+ ssh_key = tugboat_data['defaults']['ssh_key']
109
+ if ssh_key && ssh_key.size > 0
110
+ new_defaults[:machine_options][:bootstrap_options][:key_name] = ssh_key
111
+ end
112
+ end
113
+ id = result[:driver_options][:compute_options][:digitalocean_client_id]
114
+
115
+ [result, id]
116
+ end
117
+
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,59 @@
1
+ require 'fog/joyent'
2
+
3
+ # fog:Joyent:<joyent_url>
4
+ class Chef
5
+ module Provisioning
6
+ module FogDriver
7
+ module Providers
8
+ class Joyent < FogDriver::Driver
9
+
10
+ Driver.register_provider_class('Joyent', FogDriver::Providers::Joyent)
11
+
12
+ def creator
13
+ compute_options[:joyent_username]
14
+ end
15
+
16
+ def bootstrap_options_for(action_handler, machine_spec, machine_options)
17
+ bootstrap_options = symbolize_keys(machine_options[:bootstrap_options] || {})
18
+
19
+ bootstrap_options[:tags] = default_tags(machine_spec, bootstrap_options[:tags] || {})
20
+
21
+ bootstrap_options[:tags].each do |key, val|
22
+ bootstrap_options["tag.#{key}"] = val
23
+ end
24
+
25
+ bootstrap_options[:name] ||= machine_spec.name
26
+
27
+ bootstrap_options
28
+ end
29
+
30
+ def self.compute_options_for(provider, id, config)
31
+ new_compute_options = {}
32
+ new_compute_options[:provider] = provider
33
+ new_config = { :driver_options => { :compute_options => new_compute_options }}
34
+ new_defaults = {
35
+ :driver_options => { :compute_options => {} },
36
+ :machine_options => { :bootstrap_options => {} }
37
+ }
38
+ result = Cheffish::MergedConfig.new(new_config, config, new_defaults)
39
+
40
+ new_compute_options[:joyent_url] = id if (id && id != '')
41
+ credential = Fog.credentials
42
+
43
+ new_compute_options[:joyent_username] ||= credential[:joyent_username]
44
+ new_compute_options[:joyent_password] ||= credential[:joyent_password]
45
+ new_compute_options[:joyent_keyname] ||= credential[:joyent_keyname]
46
+ new_compute_options[:joyent_keyfile] ||= credential[:joyent_keyfile]
47
+ new_compute_options[:joyent_url] ||= credential[:joyent_url]
48
+ new_compute_options[:joyent_version] ||= credential[:joyent_version]
49
+
50
+ id = result[:driver_options][:compute_options][:joyent_url]
51
+
52
+ [result, id]
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,41 @@
1
+ # fog:OpenStack:https://identifyhost:portNumber/v2.0
2
+ class Chef
3
+ module Provisioning
4
+ module FogDriver
5
+ module Providers
6
+ class OpenStack < FogDriver::Driver
7
+
8
+ Driver.register_provider_class('OpenStack', FogDriver::Providers::OpenStack)
9
+
10
+ def creator
11
+ compute_options[:openstack_username]
12
+ end
13
+
14
+ def self.compute_options_for(provider, id, config)
15
+ new_compute_options = {}
16
+ new_compute_options[:provider] = provider
17
+ new_config = { :driver_options => { :compute_options => new_compute_options }}
18
+ new_defaults = {
19
+ :driver_options => { :compute_options => {} },
20
+ :machine_options => { :bootstrap_options => {} }
21
+ }
22
+ result = Cheffish::MergedConfig.new(new_config, config, new_defaults)
23
+
24
+ new_compute_options[:openstack_auth_url] = id if (id && id != '')
25
+ credential = Fog.credentials
26
+
27
+ new_compute_options[:openstack_username] ||= credential[:openstack_username]
28
+ new_compute_options[:openstack_api_key] ||= credential[:openstack_api_key]
29
+ new_compute_options[:openstack_auth_url] ||= credential[:openstack_auth_url]
30
+ new_compute_options[:openstack_tenant] ||= credential[:openstack_tenant]
31
+
32
+ id = result[:driver_options][:compute_options][:openstack_auth_url]
33
+
34
+ [result, id]
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,42 @@
1
+ # fog:Rackspace:https://identity.api.rackspacecloud.com/v2.0
2
+ class Chef
3
+ module Provisioning
4
+ module FogDriver
5
+ module Providers
6
+ class Rackspace < FogDriver::Driver
7
+
8
+ Driver.register_provider_class('Rackspace', FogDriver::Providers::Rackspace)
9
+
10
+ def creator
11
+ compute_options[:rackspace_username]
12
+ end
13
+
14
+ def self.compute_options_for(provider, id, config)
15
+ new_compute_options = {}
16
+ new_compute_options[:provider] = provider
17
+ new_config = { :driver_options => { :compute_options => new_compute_options }}
18
+ new_defaults = {
19
+ :driver_options => { :compute_options => {} },
20
+ :machine_options => { :bootstrap_options => {} }
21
+ }
22
+ result = Cheffish::MergedConfig.new(new_config, config, new_defaults)
23
+
24
+ new_compute_options[:rackspace_auth_url] = id if (id && id != '')
25
+ credential = Fog.credentials
26
+
27
+ new_compute_options[:rackspace_username] ||= credential[:rackspace_username]
28
+ new_compute_options[:rackspace_api_key] ||= credential[:rackspace_api_key]
29
+ new_compute_options[:rackspace_auth_url] ||= credential[:rackspace_auth_url]
30
+ new_compute_options[:rackspace_region] ||= credential[:rackspace_region]
31
+ new_compute_options[:rackspace_endpoint] ||= credential[:rackspace_endpoint]
32
+
33
+ id = result[:driver_options][:compute_options][:rackspace_auth_url]
34
+
35
+ [result, id]
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,28 @@
1
+ require 'chef/provisioning/fog_driver/driver'
2
+ require 'chef/resource/fog_key_pair'
3
+ require 'chef/provider/fog_key_pair'
4
+
5
+ class Chef
6
+ module DSL
7
+ module Recipe
8
+ def with_fog_driver(provider, driver_options = nil, &block)
9
+ config = Cheffish::MergedConfig.new({ :driver_options => driver_options }, run_context.config)
10
+ driver = Driver.from_provider(provider, config)
11
+ run_context.chef_provisioning.with_driver(driver, &block)
12
+ end
13
+
14
+ def with_fog_ec2_driver(driver_options = nil, &block)
15
+ with_fog_driver('AWS', driver_options, &block)
16
+ end
17
+
18
+ def with_fog_openstack_driver(driver_options = nil, &block)
19
+ with_fog_driver('OpenStack', driver_options, &block)
20
+ end
21
+
22
+ def with_fog_rackspace_driver(driver_options = nil, &block)
23
+ with_fog_driver('Rackspace', driver_options, &block)
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ class Chef
2
+ module Provisioning
3
+ module FogDriver
4
+ VERSION = '0.10'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,34 @@
1
+ require 'chef/provisioning'
2
+
3
+ class Chef::Resource::FogKeyPair < Chef::Resource::LWRPBase
4
+ self.resource_name = 'fog_key_pair'
5
+
6
+ def initialize(*args)
7
+ super
8
+ @driver = run_context.chef_provisioning.current_driver
9
+ end
10
+
11
+ actions :create, :delete, :nothing
12
+ default_action :create
13
+
14
+ attribute :driver
15
+ # Private key to use as input (will be generated if it does not exist)
16
+ attribute :private_key_path, :kind_of => String
17
+ # Public key to use as input (will be generated if it does not exist)
18
+ attribute :public_key_path, :kind_of => String
19
+ # List of parameters to the private_key resource used for generation of the key
20
+ attribute :private_key_options, :kind_of => Hash
21
+
22
+ # TODO what is the right default for this?
23
+ attribute :allow_overwrite, :kind_of => [TrueClass, FalseClass], :default => false
24
+
25
+ # Proc that runs after the resource completes. Called with (resource, private_key, public_key)
26
+ def after(&block)
27
+ block ? @after = block : @after
28
+ end
29
+
30
+ # We are not interested in Chef's cloning behavior here.
31
+ def load_prior_resource
32
+ Chef::Log.debug("Overloading #{resource_name}.load_prior_resource with NOOP")
33
+ end
34
+ end
@@ -0,0 +1,18 @@
1
+ $:.unshift File.expand_path('../../lib', __FILE__)
2
+ $:.unshift File.expand_path('../support', __FILE__)
3
+ require 'fog'
4
+ require 'chef/provisioning'
5
+ require 'chef/provisioning/fog_driver'
6
+
7
+ RSpec.configure do |config|
8
+ config.run_all_when_everything_filtered = true
9
+ config.filter_run :focus
10
+
11
+ # Run specs in random order to surface order dependencies. If you find an
12
+ # order dependency and want to debug it, you can fix the order by providing
13
+ # the seed, which is printed after each run.
14
+ # --seed 1234
15
+ config.order = 'random'
16
+ end
17
+
18
+ Fog.mock!
@@ -0,0 +1,2 @@
1
+ User Name,Access Key Id,Secret Access Key
2
+ test,12345,abcde
@@ -0,0 +1,10 @@
1
+ [default]
2
+ aws_access_key_id = 12345
3
+ aws_secret_access_key = abcde
4
+ aws_session_token = mysecret
5
+ region = us-east-1
6
+
7
+ [profile test]
8
+ aws_access_key_id = foobar
9
+ aws_secret_access_key = canteloupe
10
+ region = us-east-1
@@ -0,0 +1,16 @@
1
+ class Chef
2
+ module Provisioning
3
+ class FogDriver::Providers
4
+ class TestDriver < Chef::Provisioning::FogDriver
5
+ Chef::Provisioning::FogDriver.register_provider_class('TestDriver', Chef::Provisioning::FogDriver::Providers::TestDriver)
6
+
7
+ attr_reader :config
8
+ def initialize(driver_url, config)
9
+ super
10
+ end
11
+
12
+ def self.compute_options_for(provider, id, config)
13
+ [config, 'test']
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ require 'chef/provisioning/fog_driver'
3
+
4
+ describe Chef::Provisioning::FogDriver do
5
+
6
+ describe ".from_url" do
7
+ subject { Chef::Provisioning::FogDriver.from_provider('TestDriver', {}) }
8
+
9
+ it "should return the correct class" do
10
+ expect(subject).to be_an_instance_of Chef::Provisioning::FogDriver::Providers::TestDriver
11
+ end
12
+
13
+ it "should call the target compute_options_for" do
14
+ expect(Chef::Provisioning::FogDriver::Providers::TestDriver).to receive(:compute_options_for)
15
+ .with('TestDriver', anything, {}).and_return([{}, 'test']).twice
16
+ subject
17
+ end
18
+
19
+ end
20
+
21
+ describe "when creating a new class" do
22
+ it "should return the correct class" do
23
+ test = Chef::Provisioning::FogDriver.new('fog:TestDriver:foo', {})
24
+ expect(test).to be_an_instance_of Chef::Provisioning::FogDriver::Providers::TestDriver
25
+ end
26
+
27
+ it "should populate config" do
28
+ test = Chef::Provisioning::FogDriver.new('fog:TestDriver:foo', {test: "chef_provisioning"})
29
+ expect(test.config[:test]).to eq "chef_provisioning"
30
+ end
31
+ end
32
+ end