ironfan 3.1.7 → 3.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/CHANGELOG.md +11 -0
  2. data/Gemfile +15 -12
  3. data/Rakefile +1 -1
  4. data/VERSION +1 -1
  5. data/config/ubuntu10.04-ironfan.erb +10 -0
  6. data/config/ubuntu11.10-ironfan.erb +10 -0
  7. data/ironfan.gemspec +29 -54
  8. data/lib/chef/knife/bootstrap/centos6.2-ironfan.erb +10 -0
  9. data/lib/chef/knife/bootstrap/ubuntu10.04-ironfan.erb +10 -0
  10. data/lib/chef/knife/bootstrap/ubuntu11.10-ironfan.erb +10 -0
  11. data/lib/chef/knife/cluster_kick.rb +7 -2
  12. data/lib/chef/knife/cluster_launch.rb +3 -0
  13. data/lib/chef/knife/cluster_ssh.rb +3 -3
  14. data/lib/chef/knife/ironfan_knife_common.rb +21 -0
  15. data/lib/chef/knife/ironfan_script.rb +2 -0
  16. data/lib/ironfan/chef_layer.rb +9 -9
  17. data/lib/ironfan/cloud.rb +232 -360
  18. data/lib/ironfan/cluster.rb +3 -3
  19. data/lib/ironfan/compute.rb +26 -40
  20. data/lib/ironfan/deprecated.rb +45 -10
  21. data/lib/ironfan/discovery.rb +1 -1
  22. data/lib/ironfan/dsl_builder.rb +99 -0
  23. data/lib/ironfan/facet.rb +2 -3
  24. data/lib/ironfan/fog_layer.rb +14 -10
  25. data/lib/ironfan/private_key.rb +1 -1
  26. data/lib/ironfan/security_group.rb +46 -44
  27. data/lib/ironfan/server.rb +26 -52
  28. data/lib/ironfan/server_slice.rb +13 -19
  29. data/lib/ironfan/volume.rb +47 -59
  30. data/lib/ironfan.rb +5 -4
  31. metadata +116 -122
  32. data/lib/ironfan/dsl_object.rb +0 -124
  33. data/notes/Backup of ec2-pricing_and_capacity.numbers +0 -0
  34. data/notes/Home.md +0 -45
  35. data/notes/INSTALL-cloud_setup.md +0 -103
  36. data/notes/INSTALL.md +0 -134
  37. data/notes/Ironfan-Roadmap.md +0 -70
  38. data/notes/advanced-superpowers.md +0 -16
  39. data/notes/aws_servers.jpg +0 -0
  40. data/notes/aws_user_key.png +0 -0
  41. data/notes/cookbook-versioning.md +0 -11
  42. data/notes/core_concepts.md +0 -200
  43. data/notes/declaring_volumes.md +0 -3
  44. data/notes/design_notes-aspect_oriented_devops.md +0 -36
  45. data/notes/design_notes-ci_testing.md +0 -169
  46. data/notes/design_notes-cookbook_event_ordering.md +0 -249
  47. data/notes/design_notes-meta_discovery.md +0 -59
  48. data/notes/ec2-pricing_and_capacity.md +0 -69
  49. data/notes/ec2-pricing_and_capacity.numbers +0 -0
  50. data/notes/homebase-layout.txt +0 -102
  51. data/notes/knife-cluster-commands.md +0 -18
  52. data/notes/named-cloud-objects.md +0 -11
  53. data/notes/opscode_org_key.png +0 -0
  54. data/notes/opscode_user_key.png +0 -0
  55. data/notes/philosophy.md +0 -13
  56. data/notes/rake_tasks.md +0 -24
  57. data/notes/renamed-recipes.txt +0 -142
  58. data/notes/silverware.md +0 -85
  59. data/notes/style_guide.md +0 -300
  60. data/notes/tips_and_troubleshooting.md +0 -92
  61. data/notes/version-3_2.md +0 -273
  62. data/notes/walkthrough-hadoop.md +0 -168
  63. data/notes/walkthrough-web.md +0 -166
@@ -51,7 +51,7 @@ module Ironfan
51
51
  def facet(facet_name, attrs={}, &block)
52
52
  facet_name = facet_name.to_sym
53
53
  @facets[facet_name] ||= Ironfan::Facet.new(self, facet_name)
54
- @facets[facet_name].configure(attrs, &block)
54
+ @facets[facet_name].receive!(attrs, &block)
55
55
  @facets[facet_name]
56
56
  end
57
57
 
@@ -83,7 +83,7 @@ module Ironfan
83
83
  #
84
84
  # @return [Ironfan::ServerSlice] the requested slice
85
85
  def slice facet_name=nil, slice_indexes=nil
86
- return Ironfan::ServerSlice.new(self, self.servers) if facet_name.nil?
86
+ return servers if facet_name.nil?
87
87
  find_facet(facet_name).slice(slice_indexes)
88
88
  end
89
89
 
@@ -103,7 +103,7 @@ module Ironfan
103
103
  # Create a security group named for the cluster
104
104
  # that is friends with everything in the cluster
105
105
  def create_cluster_security_group
106
- clname = self.name # put it in scope
106
+ clname = self.name.to_s # put it in scope
107
107
  cloud.security_group(clname){ authorize_group(clname) }
108
108
  end
109
109
 
@@ -1,18 +1,23 @@
1
+ require 'ironfan/volume' # configure external and internal volumes
1
2
  module Ironfan
2
3
  #
3
4
  # Base class allowing us to layer settings for facet over cluster
4
5
  #
5
- class ComputeBuilder < Ironfan::DslObject
6
- attr_reader :cloud, :volumes, :chef_roles
7
- has_keys :name, :bogosity, :environment
6
+ class ComputeBuilder < Ironfan::DslBuilder
7
+ magic :name, String
8
+ magic :bogosity, String, :default => false
9
+ magic :environment, String
10
+ collection :volumes, Ironfan::Volume, :resolution => ->(f) { merge_resolve(f) }
11
+
12
+ attr_reader :cloud, :chef_roles
8
13
  @@role_implications ||= Mash.new
9
14
  @@run_list_rank ||= 0
10
15
 
11
16
  def initialize(builder_name, attrs={})
12
17
  super(attrs)
13
- set :name, builder_name
18
+ name builder_name
14
19
  @run_list_info = attrs[:run_list] || Mash.new
15
- @volumes = Mash.new
20
+ @clouds = Mash.new
16
21
  end
17
22
 
18
23
  # set the bogosity to a descriptive reason. Anything truthy implies bogusness
@@ -36,11 +41,18 @@ module Ironfan
36
41
  # region 'us-east-1d'
37
42
  # end
38
43
  #
39
- def cloud(cloud_provider=nil, attrs={}, &block)
40
- raise "Only have ec2 so far" if cloud_provider && (cloud_provider != :ec2)
41
- @cloud ||= Ironfan::Cloud::Ec2.new(self)
42
- @cloud.configure(attrs, &block)
43
- @cloud
44
+ def cloud(cloud_provider=:ec2, attrs={}, &block)
45
+ case cloud_provider
46
+ when :ec2
47
+ klass = Ironfan::CloudDsl::Ec2
48
+ when :virtualbox
49
+ klass = Ironfan::CloudDsl::VirtualBox
50
+ else
51
+ raise "Only have EC2 and VirtualBox so far"
52
+ end
53
+ @clouds[cloud_provider] ||= klass.new(self)
54
+ @clouds[cloud_provider].receive!(attrs, &block)
55
+ @clouds[cloud_provider]
44
56
  end
45
57
 
46
58
  # sugar for cloud(:ec2)
@@ -48,39 +60,13 @@ module Ironfan
48
60
  cloud(:ec2, attrs, &block)
49
61
  end
50
62
 
51
- # Magic method to describe a volume
52
- # * returns the named volume, creating it if necessary.
53
- # * executes the block (if any) in the volume's context
54
- #
55
- # @example
56
- # # a 1 GB volume at '/data' from the given snapshot
57
- # volume(:data) do
58
- # size 1
59
- # mount_point '/data'
60
- # snapshot_id 'snap-12345'
61
- # end
62
- #
63
- # @param volume_name [String] an arbitrary handle -- you can use the device
64
- # name, or a descriptive symbol.
65
- # @param attrs [Hash] a hash of attributes to pass down.
66
- #
67
- def volume(volume_name, attrs={}, &block)
68
- volumes[volume_name] ||= Ironfan::Volume.new(:parent => self, :name => volume_name)
69
- volumes[volume_name].configure(attrs, &block)
70
- volumes[volume_name]
71
- end
72
-
73
63
  def raid_group(rg_name, attrs={}, &block)
74
- volumes[rg_name] ||= Ironfan::RaidGroup.new(:parent => self, :name => rg_name)
75
- volumes[rg_name].configure(attrs, &block)
76
- volumes[rg_name].sub_volumes.each do |sv_name|
64
+ raid = volumes[rg_name] || Ironfan::RaidGroup.new(:parent => self, :name => rg_name)
65
+ raid.receive!(attrs, &block)
66
+ raid.sub_volumes.each do |sv_name|
77
67
  volume(sv_name){ in_raid(rg_name) ; mountable(false) ; tags({}) }
78
68
  end
79
- volumes[rg_name]
80
- end
81
-
82
- def root_volume(attrs={}, &block)
83
- volume(:root, attrs, &block)
69
+ volumes[rg_name] = raid
84
70
  end
85
71
 
86
72
  #
@@ -1,33 +1,68 @@
1
1
  module Ironfan
2
+ def self.deprecated call, replacement=nil
3
+ correction = ", use #{replacement} instead" if replacement
4
+ ui.warn "The '#{call}' statement is deprecated #{caller(2).first.inspect}#{correction}"
5
+ end
6
+
7
+ class DslBuilder
8
+ def to_hash
9
+ Ironfan.deprecated 'to_hash', 'attributes'
10
+ attributes
11
+ end
12
+ def to_mash
13
+ Ironfan.deprecated 'to_mash', 'attributes'
14
+ attributes
15
+ end
16
+ def reverse_merge!(attrs={})
17
+ Ironfan.deprecated 'reverse_merge!', 'receive!'
18
+ receive!(attrs)
19
+ end
20
+ def configure(attrs={},&block)
21
+ Ironfan.deprecated 'configure', 'receive!'
22
+ receive!(attrs, &block)
23
+ end
24
+ end
25
+
26
+ class ComputeBuilder
27
+ def root_volume(attrs={}, &block)
28
+ Ironfan.deprecated 'root_volume', 'volume(:root)'
29
+ volume(:root, attrs, &block)
30
+ end
31
+ end
2
32
 
3
33
  class Cluster
4
- #
5
- # **DEPRECATED**: This doesn't really work -- use +reverse_merge!+ instead
6
- #
7
34
  def use(*clusters)
8
- ui.warn "The 'use' statement is deprecated #{caller.inspect}"
35
+ Ironfan.deprecated 'use', 'underlay'
9
36
  clusters.each do |c|
10
37
  other_cluster = Ironfan.load_cluster(c)
11
- reverse_merge! other_cluster
38
+ cluster.underlay other_cluster
12
39
  end
13
40
  self
14
41
  end
15
-
16
42
  end
17
43
 
18
44
  class Server
19
- # **DEPRECATED**: Please use +fullname+ instead.
20
45
  def chef_node_name name
21
- ui.warn "[DEPRECATION] `chef_node_name` is deprecated. Please use `fullname` instead."
46
+ Ironfan.deprecated 'chef_node_name', 'fullname'
22
47
  fullname name
23
48
  end
49
+
50
+ def composite_volumes
51
+ Ironfan.deprecated 'composite_volumes', 'volumes'
52
+ volumes
53
+ end
24
54
  end
25
55
 
26
- class Cloud::Ec2
27
- # **DEPRECATED**: Please use +public_ip+ instead.
56
+ class CloudDsl::Ec2
28
57
  def elastic_ip(*args, &block)
58
+ Ironfan.deprecated 'elastic_ip', 'public_ip'
29
59
  public_ip(*args, &block)
30
60
  end
31
61
  end
32
62
 
63
+ class Volume
64
+ def defaults
65
+ Ironfan.deprecated 'defaults'
66
+ end
67
+ end
33
68
  end
@@ -76,7 +76,7 @@ module Ironfan
76
76
  next
77
77
  end
78
78
  svr = Ironfan::Server.get(cluster_name, facet_name, facet_index)
79
- svr.chef_node = chef_node
79
+ svr.chef_node chef_node
80
80
  @aws_instance_hash[ chef_node.ec2.instance_id ] = svr if chef_node[:ec2] && chef_node.ec2.instance_id
81
81
  end
82
82
  end
@@ -0,0 +1,99 @@
1
+ module Gorillib
2
+ module Model
3
+ Field.class_eval do
4
+ field :resolution, Whatever
5
+ end
6
+ end
7
+ module Underlies
8
+ include Gorillib::FancyBuilder
9
+ attr_accessor :underlay
10
+
11
+ def read_attribute(field_name)
12
+ field = self.class.fields[field_name] or return
13
+ return override_resolve(field_name) unless field.resolution.is_a? Proc
14
+ return self.instance_exec(field_name, &field.resolution)
15
+ end
16
+
17
+ def override_resolve(field_name)
18
+ result = read_set_or_underlay(field_name)
19
+ return result unless result.nil?
20
+ read_unset_attribute(field_name)
21
+ end
22
+
23
+ def merge_resolve(field_name)
24
+ attr = {}
25
+ if self.class.fields[field_name].respond_to? :item_type
26
+ attr[:item_type] = self.class.fields[field_name].item_type
27
+ end
28
+ result = self.class.fields[field_name].type.new(attr)
29
+ result.receive! read_underlay_attribute(field_name) || {}
30
+ result.receive! read_set_attribute(field_name) || {}
31
+ return result unless result.empty?
32
+ read_unset_attribute(field_name)
33
+ end
34
+
35
+ def read_set_attribute(field_name)
36
+ attr_name = "@#{field_name}"
37
+ instance_variable_get(attr_name) if instance_variable_defined?(attr_name)
38
+ end
39
+
40
+ def read_underlay_attribute(field_name)
41
+ return if @underlay.nil?
42
+ underlay.read_set_or_underlay(field_name)
43
+ end
44
+
45
+ def read_set_or_underlay(field_name)
46
+ result = read_set_attribute(field_name)
47
+ return result unless result.nil?
48
+ read_underlay_attribute(field_name)
49
+ end
50
+
51
+ end
52
+ end
53
+
54
+ module Ironfan
55
+ #
56
+ # This class is intended as a drop-in replacement for DslObject, using
57
+ # Gorillib::Builder setup, instead its half-baked predecessor.
58
+ #
59
+ # The magic attribute :underlay provides an object (preferably another
60
+ # Gorillib::Model or the like) that will respond with defaults. If
61
+ # fields are declared with a resolution lambda, it will apply that
62
+ # lambda in preference to the normal resolution rules (self.field
63
+ # -> underlay.magic -> self.field.default )
64
+ #
65
+ module DslHooks
66
+ def self.ui() Ironfan.ui ; end
67
+ def ui() Ironfan.ui ; end
68
+
69
+ # helper method for turning exceptions into warnings
70
+ def safely(*args, &block) Ironfan.safely(*args, &block) ; end
71
+
72
+ def step(desc, *style)
73
+ ui.info(" #{"%-15s" % (name.to_s+":")}\t#{ui.color(desc.to_s, *style)}")
74
+ end
75
+ end
76
+
77
+ class DslBuilder
78
+ include Gorillib::FancyBuilder
79
+ include Gorillib::Underlies
80
+ include Ironfan::DslHooks
81
+ end
82
+
83
+ class DslBuilderCollection < Gorillib::ModelCollection
84
+ include Ironfan::DslHooks
85
+ include Enumerable
86
+ # #
87
+ # # Enumerable
88
+ # #
89
+ # def each(&block)
90
+ # @servers.each(&block)
91
+ # end
92
+ # def length
93
+ # @servers.length
94
+ # end
95
+ # def empty?
96
+ # length == 0
97
+ # end
98
+ end
99
+ end
data/lib/ironfan/facet.rb CHANGED
@@ -1,14 +1,13 @@
1
1
  module Ironfan
2
2
  class Facet < Ironfan::ComputeBuilder
3
3
  attr_reader :cluster
4
- has_keys :instances
4
+ magic :instances, Integer, :default => 1
5
5
 
6
6
  def initialize cluster, facet_name, attrs={}
7
7
  super(facet_name.to_sym, attrs)
8
8
  @cluster = cluster
9
9
  @servers = Mash.new
10
10
  @chef_roles = []
11
- @settings[:instances] ||= 1
12
11
  create_facet_role
13
12
  create_facet_security_group unless attrs[:no_security_group]
14
13
  end
@@ -55,7 +54,7 @@ module Ironfan
55
54
  def server(idx, attrs={}, &block)
56
55
  idx = idx.to_i
57
56
  @servers[idx] ||= Ironfan::Server.new(self, idx)
58
- @servers[idx].configure(attrs, &block)
57
+ @servers[idx].receive!(attrs, &block)
59
58
  @servers[idx]
60
59
  end
61
60
 
@@ -33,6 +33,7 @@ module Ironfan
33
33
  :key_name => cloud.keypair.to_s,
34
34
  # Fog does not actually create tags when it creates a server.
35
35
  :tags => {
36
+ :name => self.fullname,
36
37
  :cluster => cluster_name,
37
38
  :facet => facet_name,
38
39
  :index => facet_index, },
@@ -72,11 +73,12 @@ module Ironfan
72
73
  end
73
74
 
74
75
  def discover_volumes!
75
- composite_volumes.each do |vol_name, vol|
76
- my_vol = volumes[vol_name]
77
- next if my_vol.fog_volume
76
+ result = self.class.fields[:volumes].type.new
77
+ volumes.each_pair do |vol_name, definition|
78
+ next if definition.fog_volume
78
79
  next if Ironfan.chef_config[:cloud] == false
79
- my_vol.fog_volume = Ironfan.fog_volumes.find do |fv|
80
+ vol = definition.dup
81
+ vol.fog_volume = Ironfan.fog_volumes.find do |fv|
80
82
  ( # matches the explicit volume id
81
83
  (vol.volume_id && (fv.id == vol.volume_id) ) ||
82
84
  # OR this server's machine exists, and this volume is attached to
@@ -90,19 +92,21 @@ module Ironfan
90
92
  (fv.tags['device'] == vol.device.to_s) )
91
93
  )
92
94
  end
93
- next unless my_vol.fog_volume
94
- my_vol.volume_id(my_vol.fog_volume.id) unless my_vol.volume_id.present?
95
- my_vol.availability_zone(my_vol.fog_volume.availability_zone) unless my_vol.availability_zone.present?
96
- check_server_id_pairing(my_vol.fog_volume, my_vol.desc)
95
+ next unless vol.fog_volume
96
+ vol.volume_id(vol.fog_volume.id) unless vol.volume_id.present?
97
+ vol.availability_zone(vol.fog_volume.availability_zone) unless vol.availability_zone.present?
98
+ check_server_id_pairing(vol.fog_volume, vol.desc)
99
+ result[vol.name] = vol
97
100
  end
101
+ write_attribute(:volumes,result)
98
102
  end
99
103
 
100
104
  def attach_volumes
101
105
  return unless in_cloud?
102
106
  discover_volumes!
103
- return if composite_volumes.empty?
107
+ return if volumes.empty?
104
108
  step(" attaching volumes")
105
- composite_volumes.each do |vol_name, vol|
109
+ volumes.each_pair do |vol_name, vol|
106
110
  next if vol.volume_id.blank? || (vol.attachable != :ebs)
107
111
  if (not vol.in_cloud?) then Chef::Log.debug("Volume not found: #{vol.desc}") ; next ; end
108
112
  if (vol.has_server?) then check_server_id_pairing(vol.fog_volume, vol.desc) ; next ; end
@@ -5,7 +5,7 @@ module Ironfan
5
5
  # A private key -- chef client key, ssh key, etc.
6
6
  #
7
7
  # The key is a pro
8
- class PrivateKey < Ironfan::DslObject
8
+ class PrivateKey < Ironfan::DslBuilder
9
9
  attr_reader :name
10
10
  attr_reader :proxy
11
11
  attr_reader :on_update
@@ -1,20 +1,22 @@
1
1
  module Ironfan
2
- module Cloud
2
+ module CloudDsl
3
+ class SecurityGroup < Ironfan::DslBuilder
4
+ magic :name, String
5
+ magic :description, String
6
+ magic :group_authorizations, Array
7
+ magic :group_authorized_by, Array
8
+ magic :range_authorizations, Array
3
9
 
4
- class SecurityGroup < DslObject
5
- has_keys :name, :description, :owner_id
6
- attr_reader :group_authorizations
7
- attr_reader :range_authorizations
10
+ def initialize params
11
+ name params[:name].to_s
12
+ description "ironfan generated group #{name}"
13
+ group_authorizations []
14
+ group_authorized_by []
15
+ range_authorizations []
16
+ end
8
17
 
9
- def initialize cloud, group_name, group_description=nil, group_owner_id=nil
10
- super()
11
- set :name, group_name.to_s
12
- description group_description || "ironfan generated group #{group_name}"
13
- @cloud = cloud
14
- @group_authorizations = []
15
- @group_authorized_by = []
16
- @range_authorizations = []
17
- owner_id(group_owner_id || Chef::Config[:knife][:aws_account_id])
18
+ def to_key
19
+ name
18
20
  end
19
21
 
20
22
  @@all = nil
@@ -52,34 +54,34 @@ module Ironfan
52
54
  end
53
55
 
54
56
  def authorize_group(group_name, owner_id=nil)
55
- @group_authorizations << [group_name.to_s, owner_id]
57
+ group_authorizations << [group_name.to_s, owner_id]
56
58
  end
57
59
 
58
60
  def authorized_by_group(other_name)
59
- @group_authorized_by << other_name.to_s
61
+ group_authorized_by << other_name.to_s
60
62
  end
61
63
 
62
64
  def authorize_port_range(range, cidr_ip = '0.0.0.0/0', ip_protocol = 'tcp')
63
65
  range = (range .. range) if range.is_a?(Integer)
64
- @range_authorizations << [range, cidr_ip, ip_protocol]
65
- end
66
-
67
- def group_permission_already_set?(fog_group, other_name, authed_owner)
68
- return false if fog_group.ip_permissions.nil?
69
- fog_group.ip_permissions.any? do |existing_permission|
70
- existing_permission["groups"].include?({"userId" => authed_owner, "groupName" => other_name}) &&
71
- existing_permission["fromPort"] == 1 &&
72
- existing_permission["toPort"] == 65535
73
- end
66
+ range_authorizations << [range, cidr_ip, ip_protocol]
74
67
  end
75
-
76
- def range_permission_already_set?(fog_group, range, cidr_ip, ip_protocol)
77
- return false if fog_group.ip_permissions.nil?
78
- fog_group.ip_permissions.include?(
79
- { "groups"=>[], "ipRanges"=>[{"cidrIp"=>cidr_ip}],
80
- "ipProtocol"=>ip_protocol, "fromPort"=>range.first, "toPort"=>range.last})
81
- end
82
-
68
+ #
69
+ # def group_permission_already_set?(fog_group, other_name, authed_owner)
70
+ # return false if fog_group.ip_permissions.nil?
71
+ # fog_group.ip_permissions.any? do |existing_permission|
72
+ # existing_permission["groups"].include?({"userId" => authed_owner, "groupName" => other_name}) &&
73
+ # existing_permission["fromPort"] == 1 &&
74
+ # existing_permission["toPort"] == 65535
75
+ # end
76
+ # end
77
+ #
78
+ # def range_permission_already_set?(fog_group, range, cidr_ip, ip_protocol)
79
+ # return false if fog_group.ip_permissions.nil?
80
+ # fog_group.ip_permissions.include?(
81
+ # { "groups"=>[], "ipRanges"=>[{"cidrIp"=>cidr_ip}],
82
+ # "ipProtocol"=>ip_protocol, "fromPort"=>range.first, "toPort"=>range.last})
83
+ # end
84
+ #
83
85
  # FIXME: so if you're saying to yourself, "self, this is some soupy gooey
84
86
  # code right here" then you and your self are correct. Much of this is to
85
87
  # work around old limitations in the EC2 api. You can now treat range and
@@ -110,22 +112,22 @@ module Ironfan
110
112
  rescue StandardError => err ; handle_security_group_error(err) ; end
111
113
  end
112
114
  end
113
-
114
- def handle_security_group_error(err)
115
- if (/has already been authorized/ =~ err.to_s)
116
- Chef::Log.debug err
117
- else
118
- ui.warn(err)
119
- end
120
- end
121
-
115
+ #
116
+ # def handle_security_group_error(err)
117
+ # if (/has already been authorized/ =~ err.to_s)
118
+ # Chef::Log.debug err
119
+ # else
120
+ # ui.warn(err)
121
+ # end
122
+ # end
123
+ #
122
124
  def self.step(group_name, desc, *style)
123
125
  ui.info(" group #{"%-15s" % (group_name+":")}\t#{ui.color(desc.to_s, *style)}")
124
126
  end
125
127
  def step(desc, *style)
126
128
  self.class.step(self.name, desc, *style)
127
129
  end
128
-
129
130
  end
131
+
130
132
  end
131
133
  end
@@ -7,15 +7,20 @@ module Ironfan
7
7
  # or if it exists in the real world (as revealed by Fog)
8
8
  #
9
9
  class Server < Ironfan::ComputeBuilder
10
- attr_reader :cluster, :facet, :facet_index, :tags
11
- attr_accessor :chef_node, :fog_server
10
+ magic :cluster, Cluster
11
+ magic :facet, Facet
12
+ magic :facet_index, Integer
13
+ attr_reader :tags
14
+
15
+ magic :chef_node, Whatever, :default => -> owner,name { owner.cluster.find_node(name) || false }
16
+ attr_accessor :fog_server
12
17
 
13
18
  @@all ||= Mash.new
14
19
 
15
20
  def initialize facet, idx
16
- @cluster = facet.cluster
17
- @facet = facet
18
- @facet_index = idx
21
+ cluster facet.cluster
22
+ facet facet
23
+ facet_index idx
19
24
  @fullname = [cluster_name, facet_name, facet_index].join('-')
20
25
  super(@fullname)
21
26
  @tags = { "name" => name, "cluster" => cluster_name, "facet" => facet_name, "index" => facet_index, }
@@ -40,13 +45,13 @@ module Ironfan
40
45
  Ironfan::ServerSlice.new(cluster, [self])
41
46
  end
42
47
 
43
- def bogosity val=nil
44
- @settings[:bogosity] = val if not val.nil?
45
- return @settings[:bogosity] if not @settings[:bogosity].nil?
46
- return :bogus_facet if facet.bogus?
47
- # return :out_of_range if (self.facet_index.to_i >= facet.instances)
48
- false
49
- end
48
+ # def bogosity val=nil
49
+ # @settings[:bogosity] = val if not val.nil?
50
+ # return @settings[:bogosity] if not @settings[:bogosity].nil?
51
+ # return :bogus_facet if facet.bogus?
52
+ # # return :out_of_range if (self.facet_index.to_i >= facet.instances)
53
+ # false
54
+ # end
50
55
 
51
56
  def in_cloud?
52
57
  !! fog_server
@@ -85,7 +90,7 @@ module Ironfan
85
90
  end
86
91
 
87
92
  def permanent?
88
- !! self.cloud.permanent
93
+ [true, :true, 'true'].include?(self.cloud.permanent)
89
94
  end
90
95
 
91
96
  def killable?
@@ -118,13 +123,12 @@ module Ironfan
118
123
  # Resolve:
119
124
  #
120
125
  def resolve!
121
- reverse_merge!(facet)
122
- reverse_merge!(cluster)
123
- @settings[:run_list] = combined_run_list
124
- #
125
- cloud.reverse_merge!(facet.cloud)
126
- cloud.reverse_merge!(cluster.cloud)
127
- #
126
+ facet.underlay = cluster
127
+ self.underlay = facet
128
+
129
+ facet.cloud.underlay = cluster.cloud
130
+ cloud.underlay = facet.cloud
131
+
128
132
  cloud.user_data({
129
133
  :chef_server => chef_server_url,
130
134
  :validation_client_name => validation_client_name,
@@ -185,36 +189,6 @@ module Ironfan
185
189
  cg[:last], fg[:last], sg[:last], ].flatten.compact.uniq
186
190
  end
187
191
 
188
- #
189
- # This prepares a composited view of the volumes -- it shows the cluster
190
- # definition overlaid by the facet definition overlaid by the server
191
- # definition.
192
- #
193
- # This method *does* auto-vivify an empty volume declaration on the server,
194
- # but doesn't modify it.
195
- #
196
- # This code is pretty smelly, but so is the resolve! behavior. advice welcome.
197
- #
198
- def composite_volumes
199
- vols = {}
200
- self.volumes.each do |vol_name, vol|
201
- vols[vol_name] ||= self.volumes[vol_name].dup
202
- vols[vol_name].reverse_merge!(vol)
203
- end
204
- facet.volumes.each do |vol_name, vol|
205
- self.volumes[vol_name] ||= Ironfan::Volume.new(:parent => self, :name => vol_name)
206
- vols[vol_name] ||= self.volumes[vol_name].dup
207
- vols[vol_name].reverse_merge!(vol)
208
- end
209
- cluster.volumes.each do |vol_name, vol|
210
- self.volumes[vol_name] ||= Ironfan::Volume.new(:parent => self, :name => vol_name)
211
- vols[vol_name] ||= self.volumes[vol_name].dup
212
- vols[vol_name].reverse_merge!(vol)
213
- end
214
- vols.each{|vol_name, vol| vol.availability_zone self.default_availability_zone }
215
- vols
216
- end
217
-
218
192
  # FIXME -- this will break on some edge case wehre a bogus node is
219
193
  # discovered after everything is resolve!d
220
194
  def default_availability_zone
@@ -269,7 +243,7 @@ module Ironfan
269
243
  return unless created?
270
244
  step(" labeling servers and volumes")
271
245
  fog_create_tags(fog_server, self.fullname, tags)
272
- composite_volumes.each do |vol_name, vol|
246
+ volumes.each_pair do |vol_name, vol|
273
247
  if vol.fog_volume
274
248
  fog_create_tags(vol.fog_volume, vol.desc,
275
249
  { "server" => self.fullname, "name" => "#{name}-#{vol.name}", "device" => vol.device, "mount_point" => vol.mount_point, "cluster" => cluster_name, "facet" => facet_name, "index" => facet_index, })
@@ -278,7 +252,7 @@ module Ironfan
278
252
  end
279
253
 
280
254
  def block_device_mapping
281
- composite_volumes.values.map(&:block_device_mapping).compact
255
+ volumes.values.map(&:block_device_mapping).compact
282
256
  end
283
257
 
284
258
  # ugh. non-dry below.