ironfan 3.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +51 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +130 -0
- data/Gemfile +26 -0
- data/LICENSE.md +201 -0
- data/README.md +328 -0
- data/Rakefile +104 -0
- data/TODO.md +16 -0
- data/VERSION +1 -0
- data/chefignore +41 -0
- data/cluster_chef-knife.gemspec +123 -0
- data/cluster_chef.gemspec +111 -0
- data/config/client.rb +59 -0
- data/config/proxy.pac +12 -0
- data/config/ubuntu10.04-ironfan.erb +157 -0
- data/config/ubuntu11.10-ironfan.erb +145 -0
- data/ironfan.gemspec +121 -0
- data/lib/chef/knife/bootstrap/ubuntu10.04-ironfan.erb +157 -0
- data/lib/chef/knife/bootstrap/ubuntu11.10-ironfan.erb +145 -0
- data/lib/chef/knife/cluster_bootstrap.rb +74 -0
- data/lib/chef/knife/cluster_kick.rb +94 -0
- data/lib/chef/knife/cluster_kill.rb +73 -0
- data/lib/chef/knife/cluster_launch.rb +164 -0
- data/lib/chef/knife/cluster_list.rb +50 -0
- data/lib/chef/knife/cluster_proxy.rb +126 -0
- data/lib/chef/knife/cluster_show.rb +61 -0
- data/lib/chef/knife/cluster_ssh.rb +141 -0
- data/lib/chef/knife/cluster_start.rb +40 -0
- data/lib/chef/knife/cluster_stop.rb +43 -0
- data/lib/chef/knife/cluster_sync.rb +77 -0
- data/lib/chef/knife/generic_command.rb +66 -0
- data/lib/chef/knife/knife_common.rb +195 -0
- data/lib/ironfan.rb +143 -0
- data/lib/ironfan/chef_layer.rb +299 -0
- data/lib/ironfan/cloud.rb +412 -0
- data/lib/ironfan/cluster.rb +118 -0
- data/lib/ironfan/compute.rb +153 -0
- data/lib/ironfan/deprecated.rb +33 -0
- data/lib/ironfan/discovery.rb +177 -0
- data/lib/ironfan/dsl_object.rb +124 -0
- data/lib/ironfan/facet.rb +144 -0
- data/lib/ironfan/fog_layer.rb +150 -0
- data/lib/ironfan/private_key.rb +130 -0
- data/lib/ironfan/role_implications.rb +58 -0
- data/lib/ironfan/security_group.rb +119 -0
- data/lib/ironfan/server.rb +281 -0
- data/lib/ironfan/server_slice.rb +260 -0
- data/lib/ironfan/volume.rb +157 -0
- data/spec/ironfan/cluster_spec.rb +13 -0
- data/spec/ironfan/facet_spec.rb +69 -0
- data/spec/ironfan/server_slice_spec.rb +19 -0
- data/spec/ironfan/server_spec.rb +112 -0
- data/spec/ironfan_spec.rb +193 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/spec_helper/dummy_chef.rb +25 -0
- data/spec/test_config.rb +20 -0
- data/tasks/chef_config.rake +38 -0
- data/tasks/jeweler_use_alt_branch.rake +53 -0
- metadata +217 -0
@@ -0,0 +1,124 @@
|
|
1
|
+
Mash.class_eval do
|
2
|
+
def reverse_merge!(other_hash)
|
3
|
+
# stupid mash doesn't take a block arg, which breaks the implementation of
|
4
|
+
# reverse_merge!
|
5
|
+
other_hash.each_pair do |key, value|
|
6
|
+
key = convert_key(key)
|
7
|
+
regular_writer(key, convert_value(value)) unless has_key?(key)
|
8
|
+
end
|
9
|
+
self
|
10
|
+
end
|
11
|
+
def to_mash
|
12
|
+
self.dup
|
13
|
+
end unless method_defined?(:to_mash)
|
14
|
+
end
|
15
|
+
|
16
|
+
Hash.class_eval do
|
17
|
+
def to_mash
|
18
|
+
Mash.new(self)
|
19
|
+
end unless method_defined?(:to_mash)
|
20
|
+
end
|
21
|
+
|
22
|
+
module Ironfan
|
23
|
+
#
|
24
|
+
# Provides magic methods, defined with has_keys
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# class Mom < Ironfan::DslObject
|
28
|
+
# has_keys(:college, :combat_boots, :fat, :so_fat)
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# class Person
|
32
|
+
# def momma &block
|
33
|
+
# @momma ||= Mom.new
|
34
|
+
# @momma.configure(&block) if block
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# yo = Person.new
|
39
|
+
# yo.mamma.combat_boots :wears
|
40
|
+
# yo.momma do
|
41
|
+
# fat true
|
42
|
+
# so_fat 'When she sits around the house, she sits *AROUND* the house'
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
class DslObject
|
46
|
+
class_attribute :keys
|
47
|
+
self.keys = []
|
48
|
+
|
49
|
+
def initialize(attrs={}, &block)
|
50
|
+
@settings = Mash.new
|
51
|
+
configure(attrs, &block)
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Defines DSL attributes
|
56
|
+
#
|
57
|
+
# @params [Array(String)] key_names DSL attribute names
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# class Mom < Ironfan::DslObject
|
61
|
+
# has_keys(:fat, :so_fat)
|
62
|
+
# end
|
63
|
+
# yer_mom = Mom.new
|
64
|
+
# yer_mom.fat :quite
|
65
|
+
#
|
66
|
+
def self.has_keys(*key_names)
|
67
|
+
key_names.map!(&:to_sym)
|
68
|
+
self.keys += key_names
|
69
|
+
self.keys.uniq!
|
70
|
+
key_names.each do |key|
|
71
|
+
next if method_defined?(key)
|
72
|
+
define_method(key){|*args| set(key, *args) }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# Sets the DSL attribute, unless the given value is nil.
|
78
|
+
#
|
79
|
+
def set(key, val=nil)
|
80
|
+
@settings[key.to_s] = val unless val.nil?
|
81
|
+
@settings[key.to_s]
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_hash
|
85
|
+
@settings.to_hash
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_mash
|
89
|
+
@settings.dup
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_s
|
93
|
+
"<#{self.class} #{to_hash.inspect}>"
|
94
|
+
end
|
95
|
+
|
96
|
+
def reverse_merge!(hsh)
|
97
|
+
@settings.reverse_merge!(hsh.to_hash)
|
98
|
+
end
|
99
|
+
|
100
|
+
def configure(hsh={}, &block)
|
101
|
+
@settings.merge!(hsh.to_hash)
|
102
|
+
instance_eval(&block) if block
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
# delegate to the knife ui presenter
|
107
|
+
def ui() Ironfan.ui ; end
|
108
|
+
# delegate to the knife ui presenter
|
109
|
+
def self.ui() Ironfan.ui ; end
|
110
|
+
|
111
|
+
def step(desc, *style)
|
112
|
+
ui.info(" #{"%-15s" % (name.to_s+":")}\t#{ui.color(desc.to_s, *style)}")
|
113
|
+
end
|
114
|
+
|
115
|
+
# helper method for bombing out of a script
|
116
|
+
def die(*args) Ironfan.die(*args) ; end
|
117
|
+
|
118
|
+
# helper method for turning exceptions into warnings
|
119
|
+
def safely(*args, &block) Ironfan.safely(*args, &block) ; end
|
120
|
+
|
121
|
+
# helper method for debugging only
|
122
|
+
def dump(*args) args.each{|arg| Chef::Log.debug( arg.inspect ) } end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
module Ironfan
|
2
|
+
class Facet < Ironfan::ComputeBuilder
|
3
|
+
attr_reader :cluster
|
4
|
+
has_keys :instances
|
5
|
+
|
6
|
+
def initialize cluster, facet_name, attrs={}
|
7
|
+
super(facet_name.to_sym, attrs)
|
8
|
+
@cluster = cluster
|
9
|
+
@servers = Mash.new
|
10
|
+
@chef_roles = []
|
11
|
+
@settings[:instances] ||= 1
|
12
|
+
create_facet_role
|
13
|
+
create_facet_security_group unless attrs[:no_security_group]
|
14
|
+
end
|
15
|
+
|
16
|
+
def cluster_name
|
17
|
+
cluster.name
|
18
|
+
end
|
19
|
+
|
20
|
+
def facet_name
|
21
|
+
name
|
22
|
+
end
|
23
|
+
|
24
|
+
# The auto-generated role for this facet.
|
25
|
+
# Instance-evals the given block in the context of that role,
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# facet_role do
|
29
|
+
# override_attributes({
|
30
|
+
# :time_machine => { :transition_speed => 88 },
|
31
|
+
# })
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# @return [Chef::Role] The auto-generated role for this facet.
|
35
|
+
def facet_role(&block)
|
36
|
+
@facet_role.instance_eval( &block ) if block_given?
|
37
|
+
@facet_role
|
38
|
+
end
|
39
|
+
|
40
|
+
def assign_volume_ids(volume_name, *volume_ids)
|
41
|
+
volume_ids.flatten.zip(servers).each do |volume_id, server|
|
42
|
+
server.volume(volume_name){ volume_id(volume_id) } if server
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Retrieve or define the given server
|
48
|
+
#
|
49
|
+
# @param [Integer] idx -- the index of the desired server
|
50
|
+
# @param [Hash] attrs -- attributes to configure on the object
|
51
|
+
# @yield a block to execute in the context of the object
|
52
|
+
#
|
53
|
+
# @return [Ironfan::Facet]
|
54
|
+
#
|
55
|
+
def server(idx, attrs={}, &block)
|
56
|
+
idx = idx.to_i
|
57
|
+
@servers[idx] ||= Ironfan::Server.new(self, idx)
|
58
|
+
@servers[idx].configure(attrs, &block)
|
59
|
+
@servers[idx]
|
60
|
+
end
|
61
|
+
|
62
|
+
# if the server has been added to this facet or is in range
|
63
|
+
def has_server? idx
|
64
|
+
(idx.to_i < instances) || @servers.include?(idx.to_i)
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Slicing
|
69
|
+
#
|
70
|
+
|
71
|
+
# All servers in this facet
|
72
|
+
#
|
73
|
+
# @return [Ironfan::ServerSlice] slice containing all servers
|
74
|
+
def servers
|
75
|
+
slice(indexes)
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# A slice of servers from this facet, in index order
|
80
|
+
#
|
81
|
+
# If +slice_indexes+ is nil, returns all servers.
|
82
|
+
# Otherwise, takes slice (given by +*args+) from the requested facet.
|
83
|
+
#
|
84
|
+
# @param [Array, String] slice_indexes -- servers in that facet (or nil for all in facet).
|
85
|
+
#
|
86
|
+
# @return [Ironfan::ServerSlice] the requested slice
|
87
|
+
def slice(slice_indexes=nil)
|
88
|
+
slice_indexes = self.indexes if slice_indexes.blank?
|
89
|
+
slice_indexes = indexes_from_intervals(slice_indexes) if slice_indexes.is_a?(String)
|
90
|
+
svrs = Array(slice_indexes).map(&:to_i).sort!.select{|idx| has_server?(idx) }.map{|idx| server(idx) }
|
91
|
+
Ironfan::ServerSlice.new(self.cluster, svrs)
|
92
|
+
end
|
93
|
+
|
94
|
+
# all valid server indexes
|
95
|
+
def valid_indexes
|
96
|
+
(0 ... instances).to_a # note the '...'
|
97
|
+
end
|
98
|
+
|
99
|
+
# indexes in the 0...instances range plus bogus ones that showed up
|
100
|
+
# (probably from chef or fog)
|
101
|
+
def indexes
|
102
|
+
[@servers.keys, valid_indexes].flatten.compact.uniq.sort
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Resolve:
|
107
|
+
#
|
108
|
+
def resolve!
|
109
|
+
servers.each(&:resolve!)
|
110
|
+
end
|
111
|
+
|
112
|
+
protected
|
113
|
+
|
114
|
+
def create_facet_security_group
|
115
|
+
cloud.security_group("#{cluster_name}-#{facet_name}")
|
116
|
+
end
|
117
|
+
|
118
|
+
# Creates a chef role named for the facet
|
119
|
+
def create_facet_role
|
120
|
+
@facet_role_name = "#{cluster_name}_#{facet_name}"
|
121
|
+
@facet_role = new_chef_role(@facet_role_name, cluster, self)
|
122
|
+
role(@facet_role_name, :own)
|
123
|
+
end
|
124
|
+
|
125
|
+
#
|
126
|
+
# Given a string enumerating indexes to select returns a flat array of
|
127
|
+
# indexes. The indexes will be unique but in an arbitrary order.
|
128
|
+
#
|
129
|
+
# @example
|
130
|
+
# facet = Ironfan::Facet.new('foo', 'bar')
|
131
|
+
# facet.indexes_from_intervals('1,2-3,8-9,7') # [1, 2, 3, 8, 9, 7]
|
132
|
+
# facet.indexes_from_intervals('1,3-5,4,7') # [1, 3, 4, 5, 7]
|
133
|
+
#
|
134
|
+
def indexes_from_intervals intervals
|
135
|
+
intervals.split(",").map do |term|
|
136
|
+
if term =~ /^(\d+)-(\d+)$/ then ($1.to_i .. $2.to_i).to_a
|
137
|
+
elsif term =~ /^(\d+)$/ then $1.to_i
|
138
|
+
else ui.warn("Bad interval: #{term}") ; nil
|
139
|
+
end
|
140
|
+
end.flatten.compact.uniq
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module Ironfan
|
2
|
+
#
|
3
|
+
# Ironfan::Server methods that handle Fog action
|
4
|
+
#
|
5
|
+
Server.class_eval do
|
6
|
+
|
7
|
+
def fog_create_server
|
8
|
+
step(" creating cloud server", :green)
|
9
|
+
lint_fog
|
10
|
+
launch_desc = fog_launch_description
|
11
|
+
Chef::Log.debug(JSON.pretty_generate(launch_desc))
|
12
|
+
safely do
|
13
|
+
@fog_server = Ironfan.fog_connection.servers.create(launch_desc)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def lint_fog
|
18
|
+
unless cloud.image_id then raise "No image ID found: nothing in Chef::Config[:ec2_image_info] for AZ #{self.default_availability_zone} flavor #{cloud.flavor} backing #{cloud.backing} image name #{cloud.image_name}, and cloud.image_id was not set directly. See https://github.com/infochimps-labs/ironfan/wiki/machine-image-(AMI)-lookup-by-name - #{cloud.list_images}" end
|
19
|
+
unless cloud.image_id then cloud.list_flavors ; raise "No machine flavor found" ; end
|
20
|
+
end
|
21
|
+
|
22
|
+
def fog_launch_description
|
23
|
+
{
|
24
|
+
:image_id => cloud.image_id,
|
25
|
+
:flavor_id => cloud.flavor,
|
26
|
+
#
|
27
|
+
:groups => cloud.security_groups.keys,
|
28
|
+
:key_name => cloud.keypair.to_s,
|
29
|
+
# Fog does not actually create tags when it creates a server.
|
30
|
+
:tags => {
|
31
|
+
:cluster => cluster_name,
|
32
|
+
:facet => facet_name,
|
33
|
+
:index => facet_index, },
|
34
|
+
:user_data => JSON.pretty_generate(cloud.user_data),
|
35
|
+
:block_device_mapping => block_device_mapping,
|
36
|
+
# :disable_api_termination => cloud.permanent,
|
37
|
+
# :instance_initiated_shutdown_behavior => instance_initiated_shutdown_behavior,
|
38
|
+
:availability_zone => self.default_availability_zone,
|
39
|
+
:monitoring => cloud.monitoring,
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Takes key-value pairs and idempotently sets those tags on the cloud machine
|
45
|
+
#
|
46
|
+
def fog_create_tags(fog_obj, desc, tags)
|
47
|
+
tags_to_create = tags.reject{|key, val| fog_obj.tags[key] == val.to_s }
|
48
|
+
return if tags_to_create.empty?
|
49
|
+
step(" tagging #{desc} with #{tags_to_create.inspect}", :green)
|
50
|
+
tags_to_create.each do |key, value|
|
51
|
+
Chef::Log.debug( "tagging #{desc} with #{key} = #{value}" )
|
52
|
+
safely do
|
53
|
+
Ironfan.fog_connection.tags.create({
|
54
|
+
:key => key, :value => value.to_s, :resource_id => fog_obj.id })
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def fog_address
|
60
|
+
address_str = self.cloud.public_ip or return
|
61
|
+
Ironfan.fog_addresses[address_str]
|
62
|
+
end
|
63
|
+
|
64
|
+
def discover_volumes!
|
65
|
+
composite_volumes.each do |vol_name, vol|
|
66
|
+
my_vol = volumes[vol_name]
|
67
|
+
next if my_vol.fog_volume
|
68
|
+
next if Ironfan.chef_config[:cloud] == false
|
69
|
+
my_vol.fog_volume = Ironfan.fog_volumes.find do |fv|
|
70
|
+
( # matches the explicit volume id
|
71
|
+
(vol.volume_id && (fv.id == vol.volume_id) ) ||
|
72
|
+
# OR this server's machine exists, and this volume is attached to
|
73
|
+
# it, and in the right place
|
74
|
+
( fog_server && fv.server_id && vol.device &&
|
75
|
+
(fv.server_id == fog_server.id) &&
|
76
|
+
(fv.device.to_s == vol.device.to_s) ) ||
|
77
|
+
# OR this volume is tagged as belonging to this machine
|
78
|
+
( fv.tags.present? &&
|
79
|
+
(fv.tags['server'] == self.fullname) &&
|
80
|
+
(fv.tags['device'] == vol.device.to_s) )
|
81
|
+
)
|
82
|
+
end
|
83
|
+
next unless my_vol.fog_volume
|
84
|
+
my_vol.volume_id(my_vol.fog_volume.id) unless my_vol.volume_id.present?
|
85
|
+
my_vol.availability_zone(my_vol.fog_volume.availability_zone) unless my_vol.availability_zone.present?
|
86
|
+
check_server_id_pairing(my_vol.fog_volume, my_vol.desc)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def attach_volumes
|
91
|
+
return unless in_cloud?
|
92
|
+
discover_volumes!
|
93
|
+
return if composite_volumes.empty?
|
94
|
+
step(" attaching volumes")
|
95
|
+
composite_volumes.each do |vol_name, vol|
|
96
|
+
next if vol.volume_id.blank? || (vol.attachable != :ebs)
|
97
|
+
if (not vol.in_cloud?) then Chef::Log.debug("Volume not found: #{vol.desc}") ; next ; end
|
98
|
+
if (vol.has_server?) then check_server_id_pairing(vol.fog_volume, vol.desc) ; next ; end
|
99
|
+
step(" - attaching #{vol.desc} -- #{vol.inspect}", :blue)
|
100
|
+
safely do
|
101
|
+
vol.fog_volume.device = vol.device
|
102
|
+
vol.fog_volume.server = fog_server
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def associate_public_ip
|
108
|
+
address = self.cloud.public_ip
|
109
|
+
return unless self.in_cloud? && address
|
110
|
+
desc = "elastic ip #{address} for #{self.fullname}"
|
111
|
+
if (fog_address && fog_address.server_id) then check_server_id_pairing(fog_address, desc) ; return ; end
|
112
|
+
safely do
|
113
|
+
step(" assigning #{desc}", :blue)
|
114
|
+
Ironfan.fog_connection.associate_address(self.fog_server.id, address)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def check_server_id_pairing thing, desc
|
119
|
+
return unless thing && thing.server_id && self.in_cloud?
|
120
|
+
type_of_thing = thing.class.to_s.gsub(/.*::/,"")
|
121
|
+
if thing.server_id != self.fog_server.id
|
122
|
+
ui.warn "#{type_of_thing} mismatch: #{desc} is on #{thing.server_id} not #{self.fog_server.id}: #{thing.inspect.gsub(/\s+/m,' ')}"
|
123
|
+
false
|
124
|
+
else
|
125
|
+
Chef::Log.debug("#{type_of_thing} paired: #{desc}")
|
126
|
+
true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
class ServerSlice
|
133
|
+
def sync_keypairs
|
134
|
+
step("ensuring keypairs exist")
|
135
|
+
keypairs = servers.map{|svr| [svr.cluster.cloud.keypair, svr.cloud.keypair] }.flatten.map(&:to_s).reject(&:blank?).uniq
|
136
|
+
keypairs = keypairs - Ironfan.fog_keypairs.keys
|
137
|
+
keypairs.each do |keypair_name|
|
138
|
+
keypair_obj = Ironfan::Ec2Keypair.create!(keypair_name)
|
139
|
+
Ironfan.fog_keypairs[keypair_name] = keypair_obj
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Create security groups, their dependencies, and synchronize their permissions
|
144
|
+
def sync_security_groups
|
145
|
+
step("ensuring security groups exist and are correct")
|
146
|
+
security_groups.each{|name,group| group.run }
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Ironfan
|
4
|
+
#
|
5
|
+
# A private key -- chef client key, ssh key, etc.
|
6
|
+
#
|
7
|
+
# The key is a pro
|
8
|
+
class PrivateKey < Ironfan::DslObject
|
9
|
+
attr_reader :name
|
10
|
+
attr_reader :proxy
|
11
|
+
attr_reader :on_update
|
12
|
+
|
13
|
+
#
|
14
|
+
# PrivateKey.new('bob')
|
15
|
+
#
|
16
|
+
# @yield a block, executed in caller's context, when the body is updated
|
17
|
+
# @yieldparam the updated body
|
18
|
+
def initialize(name, proxy=nil, &on_update)
|
19
|
+
@name = name
|
20
|
+
@proxy = proxy
|
21
|
+
@on_update = on_update
|
22
|
+
end
|
23
|
+
|
24
|
+
def filename
|
25
|
+
File.join(key_dir, "#{name}.pem")
|
26
|
+
end
|
27
|
+
|
28
|
+
def save
|
29
|
+
return unless @body
|
30
|
+
if Ironfan.chef_config[:dry_run]
|
31
|
+
Chef::Log.debug(" key #{name} - dry run, not writing out key")
|
32
|
+
return
|
33
|
+
end
|
34
|
+
ui.info( " key #{name} - writing to #{filename}" )
|
35
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
36
|
+
File.open(filename, "w", 0600){|f| f.print( @body ) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def load
|
40
|
+
return unless File.exists?(filename)
|
41
|
+
self.body = File.read(filename).chomp
|
42
|
+
end
|
43
|
+
|
44
|
+
def body=(content)
|
45
|
+
@body = content
|
46
|
+
on_update.call(content) if on_update
|
47
|
+
content
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.create!(name, *args, &block)
|
51
|
+
obj = self.new(name, *args, &block)
|
52
|
+
obj.create_proxy!
|
53
|
+
obj
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
[super[0..-2], @name, @proxy, @body.to_s[32..64], '...', @body.to_s[-60..-30]].join(" ").gsub(/[\r\n\t]+/,'') + '>'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class ChefClientKey < PrivateKey
|
62
|
+
def body
|
63
|
+
return @body if @body
|
64
|
+
if proxy && proxy.private_key && (not proxy.private_key.empty?)
|
65
|
+
@body = proxy.private_key
|
66
|
+
else
|
67
|
+
load
|
68
|
+
end
|
69
|
+
@body
|
70
|
+
end
|
71
|
+
|
72
|
+
def key_dir
|
73
|
+
Chef::Config.client_key_dir || '/tmp/client_keys'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class DataBagKey < PrivateKey
|
78
|
+
def body
|
79
|
+
return @body if @body
|
80
|
+
@body
|
81
|
+
end
|
82
|
+
|
83
|
+
def random_token
|
84
|
+
require "digest/sha2"
|
85
|
+
digest = Digest::SHA512.hexdigest( Time.now.to_s + (1..10).collect{ rand.to_s }.join )
|
86
|
+
5.times{ digest = Digest::SHA512.hexdigest(digest) }
|
87
|
+
digest
|
88
|
+
end
|
89
|
+
|
90
|
+
def key_dir
|
91
|
+
return Chef::Config.data_bag_key_dir if Chef::Config.data_bag_key_dir
|
92
|
+
dir = "#{ENV['HOME']}/.chef/data_bag_keys"
|
93
|
+
warn "Please set 'data_bag_key_dir' in your knife.rb. Will use #{dir} as a default"
|
94
|
+
dir
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class Ec2Keypair < PrivateKey
|
99
|
+
def body
|
100
|
+
return @body if @body
|
101
|
+
if proxy && proxy.private_key && (not proxy.private_key.empty?)
|
102
|
+
@body = proxy.private_key
|
103
|
+
else
|
104
|
+
load
|
105
|
+
end
|
106
|
+
@body
|
107
|
+
end
|
108
|
+
|
109
|
+
def create_proxy!
|
110
|
+
safely do
|
111
|
+
step(" key #{name} - creating", :green)
|
112
|
+
@proxy = Ironfan.fog_connection.key_pairs.create(:name => name.to_s)
|
113
|
+
end
|
114
|
+
Ironfan.fog_keypairs[name] = proxy
|
115
|
+
self.body = proxy.private_key
|
116
|
+
save
|
117
|
+
end
|
118
|
+
|
119
|
+
def key_dir
|
120
|
+
if Chef::Config.ec2_key_dir
|
121
|
+
return Chef::Config.ec2_key_dir
|
122
|
+
else
|
123
|
+
dir = "#{ENV['HOME']}/.chef/ec2_keys"
|
124
|
+
warn "Please set 'ec2_key_dir' in your knife.rb. Will use #{dir} as a default"
|
125
|
+
dir
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|