chef-provisioning-fog 0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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