ironfan 3.2.2 → 4.0.0

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.
Files changed (66) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/VERSION +1 -1
  3. data/ironfan.gemspec +33 -20
  4. data/lib/chef/knife/cluster_kick.rb +17 -17
  5. data/lib/chef/knife/cluster_kill.rb +13 -7
  6. data/lib/chef/knife/cluster_launch.rb +60 -66
  7. data/lib/chef/knife/cluster_pry.rb +2 -2
  8. data/lib/chef/knife/cluster_show.rb +3 -6
  9. data/lib/chef/knife/cluster_ssh.rb +5 -11
  10. data/lib/chef/knife/cluster_start.rb +2 -4
  11. data/lib/chef/knife/cluster_stop.rb +1 -3
  12. data/lib/chef/knife/cluster_sync.rb +13 -21
  13. data/lib/chef/knife/ironfan_knife_common.rb +11 -9
  14. data/lib/chef/knife/ironfan_script.rb +2 -1
  15. data/lib/gorillib/resolution.rb +119 -0
  16. data/lib/ironfan/broker/computer.rb +316 -0
  17. data/lib/ironfan/broker/drive.rb +21 -0
  18. data/lib/ironfan/broker.rb +37 -0
  19. data/lib/ironfan/builder.rb +14 -0
  20. data/lib/ironfan/deprecated.rb +16 -58
  21. data/lib/ironfan/dsl/cloud.rb +21 -0
  22. data/lib/ironfan/dsl/cluster.rb +27 -0
  23. data/lib/ironfan/dsl/compute.rb +84 -0
  24. data/lib/ironfan/dsl/ec2.rb +260 -0
  25. data/lib/ironfan/dsl/facet.rb +25 -0
  26. data/lib/ironfan/dsl/role.rb +19 -0
  27. data/lib/ironfan/dsl/server.rb +31 -0
  28. data/lib/ironfan/dsl/virtualbox.rb +8 -0
  29. data/lib/ironfan/dsl/volume.rb +45 -0
  30. data/lib/ironfan/dsl.rb +7 -0
  31. data/lib/ironfan/headers.rb +58 -0
  32. data/lib/ironfan/provider/chef/client.rb +77 -0
  33. data/lib/ironfan/provider/chef/node.rb +133 -0
  34. data/lib/ironfan/provider/chef/role.rb +69 -0
  35. data/lib/ironfan/provider/chef.rb +28 -0
  36. data/lib/ironfan/provider/ec2/ebs_volume.rb +137 -0
  37. data/lib/ironfan/provider/ec2/elastic_ip.rb +10 -0
  38. data/lib/ironfan/provider/ec2/key_pair.rb +65 -0
  39. data/lib/ironfan/provider/ec2/machine.rb +258 -0
  40. data/lib/ironfan/provider/ec2/placement_group.rb +24 -0
  41. data/lib/ironfan/provider/ec2/security_group.rb +118 -0
  42. data/lib/ironfan/provider/ec2.rb +47 -0
  43. data/lib/ironfan/provider/virtualbox/machine.rb +10 -0
  44. data/lib/ironfan/provider/virtualbox.rb +8 -0
  45. data/lib/ironfan/provider.rb +139 -0
  46. data/lib/ironfan/requirements.rb +52 -0
  47. data/lib/ironfan.rb +44 -33
  48. metadata +34 -21
  49. data/lib/chef/knife/cluster_vagrant.rb +0 -144
  50. data/lib/chef/knife/vagrant/ironfan_environment.rb +0 -18
  51. data/lib/chef/knife/vagrant/ironfan_provisioners.rb +0 -27
  52. data/lib/chef/knife/vagrant/skeleton_vagrantfile.rb +0 -119
  53. data/lib/ironfan/chef_layer.rb +0 -300
  54. data/lib/ironfan/cloud.rb +0 -323
  55. data/lib/ironfan/cluster.rb +0 -118
  56. data/lib/ironfan/compute.rb +0 -139
  57. data/lib/ironfan/discovery.rb +0 -190
  58. data/lib/ironfan/dsl_builder.rb +0 -99
  59. data/lib/ironfan/facet.rb +0 -143
  60. data/lib/ironfan/fog_layer.rb +0 -196
  61. data/lib/ironfan/private_key.rb +0 -130
  62. data/lib/ironfan/role_implications.rb +0 -58
  63. data/lib/ironfan/security_group.rb +0 -133
  64. data/lib/ironfan/server.rb +0 -291
  65. data/lib/ironfan/server_slice.rb +0 -265
  66. data/lib/ironfan/volume.rb +0 -146
@@ -1,118 +0,0 @@
1
- module Ironfan
2
- #
3
- # A cluster has many facets. Any setting applied here is merged with the facet
4
- # at resolve time; if the facet explicitly sets any attributes they will win out.
5
- #
6
- class Cluster < Ironfan::ComputeBuilder
7
- attr_reader :facets, :undefined_servers
8
-
9
- def initialize(name, attrs={})
10
- super(name.to_sym, attrs)
11
- @facets = Mash.new
12
- @chef_roles = []
13
- environment :_default if environment.blank?
14
- create_cluster_role
15
- create_cluster_security_group unless attrs[:no_security_group]
16
- end
17
-
18
- def cluster
19
- self
20
- end
21
-
22
- def cluster_name
23
- name
24
- end
25
-
26
- # The auto-generated role for this cluster.
27
- # Instance-evals the given block in the context of that role
28
- #
29
- # @example
30
- # cluster_role do
31
- # override_attributes({
32
- # :time_machine => { :transition_speed => 88 },
33
- # })
34
- # end
35
- #
36
- # @return [Chef::Role] The auto-generated role for this facet.
37
- def cluster_role(&block)
38
- @cluster_role.instance_eval( &block ) if block_given?
39
- @cluster_role
40
- end
41
-
42
- #
43
- # Retrieve or define the given facet
44
- #
45
- # @param [String] facet_name -- name of the desired facet
46
- # @param [Hash] attrs -- attributes to configure on the object
47
- # @yield a block to execute in the context of the object
48
- #
49
- # @return [Ironfan::Facet]
50
- #
51
- def facet(facet_name, attrs={}, &block)
52
- facet_name = facet_name.to_sym
53
- @facets[facet_name] ||= Ironfan::Facet.new(self, facet_name)
54
- @facets[facet_name].receive!(attrs, &block)
55
- @facets[facet_name]
56
- end
57
-
58
- def has_facet? facet_name
59
- @facets.include?(facet_name)
60
- end
61
-
62
- def find_facet(facet_name)
63
- @facets[facet_name] or raise("Facet '#{facet_name}' is not defined in cluster '#{cluster_name}'")
64
- end
65
-
66
- # All servers in this facet, sorted by facet name and index
67
- #
68
- # @return [Ironfan::ServerSlice] slice containing all servers
69
- def servers
70
- svrs = @facets.sort.map{|name, facet| facet.servers.to_a }
71
- Ironfan::ServerSlice.new(self, svrs.flatten)
72
- end
73
-
74
- #
75
- # A slice of a cluster:
76
- #
77
- # If +facet_name+ is nil, returns all servers.
78
- # Otherwise, takes slice (given by +*args+) from the requested facet.
79
- #
80
- # @param [String] facet_name -- facet to slice (or nil for all in cluster)
81
- # @param [Array, String] slice_indexes -- servers in that facet (or nil for all in facet).
82
- # You must specify a facet if you use slice_indexes.
83
- #
84
- # @return [Ironfan::ServerSlice] the requested slice
85
- def slice facet_name=nil, slice_indexes=nil
86
- return servers if facet_name.nil?
87
- find_facet(facet_name).slice(slice_indexes)
88
- end
89
-
90
- def to_s
91
- "#{super[0..-3]} @facets=>#{@facets.keys.inspect}}>"
92
- end
93
-
94
- #
95
- # Resolve:
96
- #
97
- def resolve!
98
- facets.values.each(&:resolve!)
99
- end
100
-
101
- protected
102
-
103
- # Create a security group named for the cluster
104
- # that is friends with everything in the cluster
105
- def create_cluster_security_group
106
- clname = self.name.to_s # put it in scope
107
- cloud.security_group(clname){ authorize_group(clname) }
108
- end
109
-
110
- # Creates a chef role named for the cluster
111
- def create_cluster_role
112
- @cluster_role_name = "#{name}_cluster"
113
- @cluster_role = new_chef_role(@cluster_role_name, cluster)
114
- role(@cluster_role_name, :own)
115
- end
116
-
117
- end
118
- end
@@ -1,139 +0,0 @@
1
- require 'ironfan/volume' # configure external and internal volumes
2
- module Ironfan
3
- #
4
- # Base class allowing us to layer settings for facet over cluster
5
- #
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
13
- @@role_implications ||= Mash.new
14
- @@run_list_rank ||= 0
15
-
16
- def initialize(builder_name, attrs={})
17
- super(attrs)
18
- name builder_name
19
- @run_list_info = attrs[:run_list] || Mash.new
20
- @clouds = Mash.new
21
- end
22
-
23
- # set the bogosity to a descriptive reason. Anything truthy implies bogusness
24
- def bogus?
25
- !! self.bogosity
26
- end
27
-
28
- # Magic method to produce cloud instance:
29
- # * returns the cloud instance, creating it if necessary.
30
- # * executes the block in the cloud's object context
31
- #
32
- # @example
33
- # cloud do
34
- # image_name 'maverick'
35
- # security_group :nagios
36
- # end
37
- #
38
- # # defines ec2-specific behavior
39
- # cloud(:ec2) do
40
- # public_ip '1.2.3.4'
41
- # region 'us-east-1d'
42
- # end
43
- #
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]
56
- end
57
-
58
- # sugar for cloud(:ec2)
59
- def ec2(attrs={}, &block)
60
- cloud(:ec2, attrs, &block)
61
- end
62
-
63
- def raid_group(rg_name, attrs={}, &block)
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|
67
- volume(sv_name){ in_raid(rg_name) ; mountable(false) ; tags({}) }
68
- end
69
- volumes[rg_name] = raid
70
- end
71
-
72
- #
73
- # Adds the given role to the run list, and invokes any role_implications it
74
- # implies (for instance, defining and applying the 'ssh' security group if
75
- # the 'ssh' role is applied.)
76
- #
77
- # You can specify placement of `:first`, `:normal` (or nil) or `:last`; the
78
- # final runlist is assembled as
79
- #
80
- # * run_list :first items -- cluster, then facet, then server
81
- # * run_list :normal items -- cluster, then facet, then server
82
- # * run_list :last items -- cluster, then facet, then server
83
- #
84
- # (see Ironfan::Server#combined_run_list for full details though)
85
- #
86
- def role(role_name, placement=nil)
87
- add_to_run_list("role[#{role_name}]", placement)
88
- self.instance_eval(&@@role_implications[role_name]) if @@role_implications[role_name]
89
- end
90
-
91
- # Add the given recipe to the run list. You can specify placement of
92
- # `:first`, `:normal` (or nil) or `:last`; the final runlist is assembled as
93
- #
94
- # * run_list :first items -- cluster, then facet, then server
95
- # * run_list :normal items -- cluster, then facet, then server
96
- # * run_list :last items -- cluster, then facet, then server
97
- #
98
- # (see Ironfan::Server#combined_run_list for full details though)
99
- #
100
- def recipe(name, placement=nil)
101
- add_to_run_list(name, placement)
102
- end
103
-
104
- # Roles and recipes for this element only.
105
- #
106
- # See Ironfan::Server#combined_run_list for run_list order resolution
107
- def run_list
108
- groups = run_list_groups
109
- [ groups[:first], groups[:normal], groups[:last] ].flatten.compact.uniq
110
- end
111
-
112
- # run list elements grouped into :first, :normal and :last
113
- def run_list_groups
114
- @run_list_info.keys.sort_by{|item| @run_list_info[item][:rank] }.group_by{|item| @run_list_info[item][:placement] }
115
- end
116
-
117
- #
118
- # Some roles imply aspects of the machine that have to exist at creation.
119
- # For instance, on an ec2 machine you may wish the 'ssh' role to imply a
120
- # security group explicity opening port 22.
121
- #
122
- # @param [String] role_name -- the role that triggers the block
123
- # @yield block will be instance_eval'd in the object that calls 'role'
124
- #
125
- def self.role_implication(name, &block)
126
- @@role_implications[name] = block
127
- end
128
-
129
- protected
130
-
131
- def add_to_run_list(item, placement)
132
- raise "run_list placement must be one of :first, :normal, :last or nil (also means :normal)" unless [:first, :last, :own, nil].include?(placement)
133
- @@run_list_rank += 1
134
- placement ||= :normal
135
- @run_list_info[item] ||= { :rank => @@run_list_rank, :placement => placement }
136
- end
137
-
138
- end
139
- end
@@ -1,190 +0,0 @@
1
- module Ironfan
2
- class Cluster
3
-
4
- def discover!
5
- @aws_instance_hash = {}
6
- discover_ironfan!
7
- discover_chef_nodes!
8
- discover_fog_servers! unless Ironfan.chef_config[:cloud] == false
9
- discover_chef_clients!
10
- discover_volumes!
11
- end
12
-
13
- def chef_clients
14
- return @chef_clients if @chef_clients
15
- @chef_clients = []
16
-
17
- # Oh for fuck's sake -- the key used to index clients changed from
18
- # 'clientname' in 0.10.4-and-prev to 'name' in 0.10.8. Rather than index
19
- # both 'clientname' and 'name', they switched it -- so we have to fall
20
- # back. FIXME: While the Opscode platform is 0.10.4 I have clientname
21
- # first (sorry, people of the future). When it switches to 0.10.8 we'll
22
- # reverse them (suck it people of the past).
23
- # Also sometimes the server returns results that are nil on
24
- # recently-expired clients, so that's annoying too.
25
- clients, wtf, num = Chef::Search::Query.new.search(:client, "clientname:#{cluster_name}-*") ; clients.compact!
26
- clients, wtf, num = Chef::Search::Query.new.search(:client, "name:#{cluster_name}-*") if clients.blank?
27
- clients.each do |client_hsh|
28
- next if client_hsh.nil?
29
- # Return values from Chef::Search seem to be inconsistent across chef
30
- # versions (sometimes a hash, sometimes an object). Fix if necessary.
31
- client_hsh = Chef::ApiClient.json_create(client_hsh) unless client_hsh.is_a?(Chef::ApiClient)
32
- @chef_clients.push( client_hsh )
33
- end
34
- @chef_clients
35
- end
36
-
37
- # returns client with the given name if in catalog, nil otherwise
38
- def find_client(cl_name)
39
- chef_clients.find{|ccl| ccl.name == cl_name }
40
- end
41
-
42
- def chef_nodes
43
- return @chef_nodes if @chef_nodes
44
- @chef_nodes = []
45
- Chef::Search::Query.new.search(:node,"cluster_name:#{cluster_name}") do |n|
46
- @chef_nodes.push(n) unless n.blank? || (n.cluster_name != cluster_name.to_s)
47
- end
48
- @chef_nodes
49
- end
50
-
51
- # returns node with the given name if in catalog, nil otherwise
52
- def find_node(nd_name)
53
- chef_nodes.find{|nd| nd.name == nd_name }
54
- end
55
-
56
- protected
57
-
58
- def fog_servers
59
- @fog_servers ||= Ironfan.fog_servers.select{|fs| fs.key_name == cluster_name.to_s && (fs.state != "terminated") }
60
- end
61
-
62
- # Walk the list of chef nodes and
63
- # * vivify the server,
64
- # * associate the chef node
65
- # * if the chef node knows about its instance id, memorize that for lookup
66
- # when we discover cloud instances.
67
- def discover_chef_nodes!
68
- chef_nodes.each do |chef_node|
69
- if chef_node["cluster_name"] && chef_node["facet_name"] && chef_node["facet_index"]
70
- cluster_name = chef_node["cluster_name"]
71
- facet_name = chef_node["facet_name"]
72
- facet_index = chef_node["facet_index"]
73
- elsif chef_node.name
74
- ( cluster_name, facet_name, facet_index ) = chef_node.name.split(/-/)
75
- else
76
- next
77
- end
78
- svr = Ironfan::Server.get(cluster_name, facet_name, facet_index)
79
- svr.chef_node chef_node
80
- @aws_instance_hash[ chef_node.ec2.instance_id ] = svr if chef_node[:ec2] && chef_node.ec2.instance_id
81
- end
82
- end
83
-
84
- # Walk the list of servers, asking each to discover its chef client.
85
- def discover_chef_clients!
86
- servers.each(&:chef_client)
87
- end
88
-
89
- # calling #servers vivifies each facet's Ironfan::Server instances
90
- def discover_ironfan!
91
- self.servers
92
- end
93
-
94
- def discover_fog_servers!
95
- # If the fog server is tagged with cluster/facet/index, then try to
96
- # locate the corresponding machine in the cluster def
97
- # Otherwise, try to get to it through mapping the aws instance id
98
- # to the chef node name found in the chef node
99
- fog_servers.each do |fs|
100
- if fs.tags["cluster"] && fs.tags["facet"] && fs.tags["index"] && fs.tags["cluster"] == cluster_name.to_s
101
- svr = Ironfan::Server.get(fs.tags["cluster"], fs.tags["facet"], fs.tags["index"])
102
- elsif @aws_instance_hash[fs.id]
103
- svr = @aws_instance_hash[fs.id]
104
- else
105
- next
106
- end
107
-
108
- # If there already is a fog server there, then issue a warning and slap
109
- # the just-discovered one onto a server with an arbitrary index, and
110
- # mark both bogus
111
- if existing_fs = svr.fog_server
112
- if existing_fs.id != fs.id
113
- ui.warn "Duplicate fog instance found for #{svr.fullname}: #{fs.id} and #{existing_fs.id}!!"
114
- old_svr = svr
115
- svr = old_svr.facet.server(1_000 + svr.facet_index.to_i)
116
- old_svr.bogosity :duplicate
117
- svr.bogosity :duplicate
118
- end
119
- end
120
- svr.fog_server = fs
121
- end
122
- end
123
-
124
- def discover_volumes!
125
- servers.each(&:discover_volumes!)
126
- end
127
-
128
- def discover_addresses!
129
- servers.each(&:discover_addresses!)
130
- end
131
-
132
- end # Ironfan::Cluster
133
- end
134
-
135
- module Ironfan
136
-
137
- def self.fog_connection
138
- @fog_connection ||= Fog::Compute.new({
139
- :provider => 'AWS',
140
- :aws_access_key_id => Chef::Config[:knife][:aws_access_key_id],
141
- :aws_secret_access_key => Chef::Config[:knife][:aws_secret_access_key],
142
- :region => Chef::Config[:knife][:region]
143
- })
144
- end
145
-
146
- def self.fog_servers
147
- return @fog_servers if @fog_servers
148
- Chef::Log.debug("Using fog to catalog all servers")
149
- @fog_servers = Ironfan.fog_connection.servers.all
150
- end
151
-
152
- def self.fog_addresses
153
- return @fog_addresses if @fog_addresses
154
- Chef::Log.debug("Using fog to catalog all addresses")
155
- @fog_addresses = {}.tap{|hsh| Ironfan.fog_connection.addresses.each{|fa| hsh[fa.public_ip] = fa } }
156
- end
157
-
158
- def self.fog_volumes
159
- @fog_volumes || fetch_fog_volumes
160
- end
161
-
162
- def self.fetch_fog_volumes
163
- Chef::Log.debug("Using fog to catalog all volumes")
164
- @fog_volumes = Ironfan.fog_connection.volumes
165
- end
166
-
167
- def self.fog_keypairs
168
- return @fog_keypairs if @fog_keypairs
169
- Chef::Log.debug("Using fog to catalog all keypairs")
170
- @fog_keypairs = {}.tap{|hsh| Ironfan.fog_connection.key_pairs.each{|kp| hsh[kp.name] = kp } }
171
- end
172
-
173
- def self.dry_run?
174
- Ironfan.chef_config[:dry_run]
175
- end
176
-
177
- def self.placement_groups
178
- return @placement_groups if @placement_groups
179
- Chef::Log.debug("Using fog to catalog all placement_groups")
180
- resp = self.fog_connection.describe_placement_groups unless dry_run?
181
- return {} unless resp.respond_to?(:body) && resp.body.present?
182
- arr = resp.body['placementGroupSet']
183
- @placement_groups = arr.inject({}){|acc, pg| acc[pg['groupName']] = pg ; acc }
184
- end
185
-
186
- def safely *args, &block
187
- Ironfan.safely(*args, &block)
188
- end
189
-
190
- end
@@ -1,99 +0,0 @@
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 DELETED
@@ -1,143 +0,0 @@
1
- module Ironfan
2
- class Facet < Ironfan::ComputeBuilder
3
- attr_reader :cluster
4
- magic :instances, Integer, :default => 1
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
- create_facet_role
12
- create_facet_security_group unless attrs[:no_security_group]
13
- end
14
-
15
- def cluster_name
16
- cluster.name
17
- end
18
-
19
- def facet_name
20
- name
21
- end
22
-
23
- # The auto-generated role for this facet.
24
- # Instance-evals the given block in the context of that role,
25
- #
26
- # @example
27
- # facet_role do
28
- # override_attributes({
29
- # :time_machine => { :transition_speed => 88 },
30
- # })
31
- # end
32
- #
33
- # @return [Chef::Role] The auto-generated role for this facet.
34
- def facet_role(&block)
35
- @facet_role.instance_eval( &block ) if block_given?
36
- @facet_role
37
- end
38
-
39
- def assign_volume_ids(volume_name, *volume_ids)
40
- volume_ids.flatten.zip(servers).each do |volume_id, server|
41
- server.volume(volume_name){ volume_id(volume_id) } if server
42
- end
43
- end
44
-
45
- #
46
- # Retrieve or define the given server
47
- #
48
- # @param [Integer] idx -- the index of the desired server
49
- # @param [Hash] attrs -- attributes to configure on the object
50
- # @yield a block to execute in the context of the object
51
- #
52
- # @return [Ironfan::Facet]
53
- #
54
- def server(idx, attrs={}, &block)
55
- idx = idx.to_i
56
- @servers[idx] ||= Ironfan::Server.new(self, idx)
57
- @servers[idx].receive!(attrs, &block)
58
- @servers[idx]
59
- end
60
-
61
- # if the server has been added to this facet or is in range
62
- def has_server? idx
63
- (idx.to_i < instances) || @servers.include?(idx.to_i)
64
- end
65
-
66
- #
67
- # Slicing
68
- #
69
-
70
- # All servers in this facet
71
- #
72
- # @return [Ironfan::ServerSlice] slice containing all servers
73
- def servers
74
- slice(indexes)
75
- end
76
-
77
- #
78
- # A slice of servers from this facet, in index order
79
- #
80
- # If +slice_indexes+ is nil, returns all servers.
81
- # Otherwise, takes slice (given by +*args+) from the requested facet.
82
- #
83
- # @param [Array, String] slice_indexes -- servers in that facet (or nil for all in facet).
84
- #
85
- # @return [Ironfan::ServerSlice] the requested slice
86
- def slice(slice_indexes=nil)
87
- slice_indexes = self.indexes if slice_indexes.blank?
88
- slice_indexes = indexes_from_intervals(slice_indexes) if slice_indexes.is_a?(String)
89
- svrs = Array(slice_indexes).map(&:to_i).sort!.select{|idx| has_server?(idx) }.map{|idx| server(idx) }
90
- Ironfan::ServerSlice.new(self.cluster, svrs)
91
- end
92
-
93
- # all valid server indexes
94
- def valid_indexes
95
- (0 ... instances).to_a # note the '...'
96
- end
97
-
98
- # indexes in the 0...instances range plus bogus ones that showed up
99
- # (probably from chef or fog)
100
- def indexes
101
- [@servers.keys, valid_indexes].flatten.compact.uniq.sort
102
- end
103
-
104
- #
105
- # Resolve:
106
- #
107
- def resolve!
108
- servers.each(&:resolve!)
109
- end
110
-
111
- protected
112
-
113
- def create_facet_security_group
114
- cloud.security_group("#{cluster_name}-#{facet_name}")
115
- end
116
-
117
- # Creates a chef role named for the facet
118
- def create_facet_role
119
- @facet_role_name = "#{cluster_name}_#{facet_name}"
120
- @facet_role = new_chef_role(@facet_role_name, cluster, self)
121
- role(@facet_role_name, :own)
122
- end
123
-
124
- #
125
- # Given a string enumerating indexes to select returns a flat array of
126
- # indexes. The indexes will be unique but in an arbitrary order.
127
- #
128
- # @example
129
- # facet = Ironfan::Facet.new('foo', 'bar')
130
- # facet.indexes_from_intervals('1,2-3,8-9,7') # [1, 2, 3, 8, 9, 7]
131
- # facet.indexes_from_intervals('1,3-5,4,7') # [1, 3, 4, 5, 7]
132
- #
133
- def indexes_from_intervals intervals
134
- intervals.split(",").map do |term|
135
- if term =~ /^(\d+)-(\d+)$/ then ($1.to_i .. $2.to_i).to_a
136
- elsif term =~ /^(\d+)$/ then $1.to_i
137
- else ui.warn("Bad interval: #{term}") ; nil
138
- end
139
- end.flatten.compact.uniq
140
- end
141
-
142
- end
143
- end