Class: ClusterChef::ServerSlice

Inherits:
DslObject show all
Includes:
Enumerable
Defined in:
lib/cluster_chef/server_slice.rb,
lib/cluster_chef/fog_layer.rb

Overview

A server group is a set of actual or implied servers.

The idea is we want to be able to smoothly roll up settings

Constant Summary collapse

MINIMAL_HEADINGS =

FIXME: this is a jumble. we need to pass it in some other way.

["Name", "Chef?", "State", "InstanceID", "Public IP", "Private IP", "Created At"].to_set.freeze
DEFAULT_HEADINGS =
(MINIMAL_HEADINGS + ['Flavor', 'AZ', 'Env']).freeze
EXPANDED_HEADINGS =
DEFAULT_HEADINGS + ['Image', 'Volumes', 'Elastic IP', 'SSH Key']
MACHINE_STATE_COLORS =
{
  'running'       => :green,
  'pending'       => :yellow,
  'stopping'      => :magenta,
  'shutting-down' => :magenta,
  'stopped'       => :cyan,
  'terminated'    => :blue,
  'not running'   => :blue,
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from DslObject

#configure, #die, #dump, has_keys, #reverse_merge!, #safely, #set, #step, #to_hash, #to_mash, ui, #ui

Constructor Details

#initialize(cluster, servers) ⇒ ServerSlice

Returns a new instance of ServerSlice.


11
12
13
14
15
16
# File 'lib/cluster_chef/server_slice.rb', line 11

def initialize cluster, servers
  super()
  @name    = "#{cluster.name} slice"
  @cluster = cluster
  @servers = servers
end

Instance Attribute Details

#clusterObject (readonly)

Returns the value of attribute cluster


9
10
11
# File 'lib/cluster_chef/server_slice.rb', line 9

def cluster
  @cluster
end

#nameObject (readonly)

Returns the value of attribute name


9
10
11
# File 'lib/cluster_chef/server_slice.rb', line 9

def name
  @name
end

#serversObject (readonly)

Returns the value of attribute servers


9
10
11
# File 'lib/cluster_chef/server_slice.rb', line 9

def servers
  @servers
end

Instance Method Details

#bogus_serversObject


42
43
44
# File 'lib/cluster_chef/server_slice.rb', line 42

def bogus_servers
  select(&:bogus?)
end

#chef_nodesObject

Info!


50
51
52
# File 'lib/cluster_chef/server_slice.rb', line 50

def chef_nodes
  servers.map(&:chef_node).compact
end

#chef_rolesObject


68
69
70
# File 'lib/cluster_chef/server_slice.rb', line 68

def chef_roles
  [ cluster.chef_roles, facets.map(&:chef_roles) ].flatten.compact.uniq
end

#create_serversObject


101
102
103
# File 'lib/cluster_chef/server_slice.rb', line 101

def create_servers
  delegate_to_servers( :create_server )
end

#delete_chefObject


105
106
107
# File 'lib/cluster_chef/server_slice.rb', line 105

def delete_chef
  delegate_to_servers( :delete_chef, true )
end

#destroyObject


92
93
94
95
# File 'lib/cluster_chef/server_slice.rb', line 92

def destroy
  delegate_to_fog_servers( :destroy )
  delegate_to_fog_servers( :reload  )
end

#display(hh = :default) ⇒ Object

This is a generic display routine for cluster-like sets of nodes. If you call it with no args, you get the basic table that knife cluster show draws. If you give it an array of strings, you can override the order and headings displayed. If you also give it a block you can add your own logic for generating content. The block is given a ClusterChef::Server instance for each item in the collection and should return a hash of Name,Value pairs to merge into the minimal fields.


149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/cluster_chef/server_slice.rb', line 149

def display hh = :default
  headings =
    case hh
    when :minimal  then MINIMAL_HEADINGS
    when :default  then DEFAULT_HEADINGS
    when :expanded then EXPANDED_HEADINGS
    else hh.to_set end
  headings += ["Bogus"] if servers.any?(&:bogus?)
  # probably not necessary any more
  # servers = servers.sort{ |a,b| (a.facet_name <=> b.facet_name) *9 + (a.facet_index.to_i <=> b.facet_index.to_i)*3 + (a.facet_index <=> b.facet_index) }
  defined_data = servers.map do |svr|
    hsh = {
      "Name"   => svr.fullname,
      "Facet"  => svr.facet_name,
      "Index"  => svr.facet_index,
      "Chef?"  => (svr.chef_node? ? "yes" : "[red]no[reset]"),
      "Bogus"  => (svr.bogus? ? "[red]#{svr.bogosity}[reset]" : ''),
      "Env"    => svr.environment,
    }
    # if (cs = svr.chef_server)
    #   hsh.merge!(
    #     "Env"    => cs.environment,
    #     )
    # end
    if (fs = svr.fog_server)
      hsh.merge!(
          "InstanceID" => (fs.id && fs.id.length > 0) ? fs.id : "???",
          "Flavor"     => fs.flavor_id,
          "Image"      => fs.image_id,
          "AZ"         => fs.availability_zone,
          "SSH Key"    => fs.key_name,
          "State"      => "[#{MACHINE_STATE_COLORS[fs.state] || 'white'}]#{fs.state}[reset]",
          "Public IP"  => fs.public_ip_address,
          "Private IP" => fs.private_ip_address,
          "Created At" => fs.created_at.strftime("%Y%m%d-%H%M%S")
        )
    else
      hsh["State"] = "not running"
    end
    hsh['Volumes'] = []
    svr.composite_volumes.each do |name, vol|
      if    vol.ephemeral_device? then next
      elsif vol.volume_id         then hsh['Volumes'] << vol.volume_id
      elsif vol.create_at_launch? then hsh['Volumes'] << vol.snapshot_id
      end
    end
    hsh['Volumes']    = hsh['Volumes'].join(',')
    hsh['Elastic IP'] = svr.cloud.public_ip if svr.cloud.public_ip
    if block_given?
      extra_info = yield(svr)
      hsh.merge!(extra_info)
      headings += extra_info.keys
    end
    hsh
  end
  if defined_data.empty?
    ui.info "Nothing to report"
  else
    Formatador.display_compact_table(defined_data, headings.to_a)
  end
end

#each(&block) ⇒ Object


22
23
24
# File 'lib/cluster_chef/server_slice.rb', line 22

def each(&block)
  @servers.each(&block)
end

#empty?Boolean

Returns:

  • (Boolean)

28
29
30
# File 'lib/cluster_chef/server_slice.rb', line 28

def empty?
  length == 0
end

#facetsObject


64
65
66
# File 'lib/cluster_chef/server_slice.rb', line 64

def facets
  servers.map(&:facet)
end

#fog_serversObject


54
55
56
# File 'lib/cluster_chef/server_slice.rb', line 54

def fog_servers
  servers.map(&:fog_server).compact
end

#joined_namesObject


216
217
218
# File 'lib/cluster_chef/server_slice.rb', line 216

def joined_names
  map(&:name).join(", ").gsub(/, ([^,]*)$/, ' and \1')
end

#lengthObject


25
26
27
# File 'lib/cluster_chef/server_slice.rb', line 25

def length
  @servers.length
end

#parallelize { ... } ⇒ Object

Calls block on each server in parallel, each in its own thread

Examples:

target = ClusterChef::Cluster.slice('web_server')
target.parallelize{|svr| svr.launch }

Yields:

  • each server, in turn


229
230
231
232
233
234
# File 'lib/cluster_chef/server_slice.rb', line 229

def parallelize
  servers.map do |svr|
    sleep(0.1) # avoid hammering with simultaneous requests
    Thread.new(svr){|svr| yield(svr) }
  end
end

#reloadObject


97
98
99
# File 'lib/cluster_chef/server_slice.rb', line 97

def reload
  delegate_to_fog_servers( :reload  )
end

#security_groupsObject


58
59
60
61
62
# File 'lib/cluster_chef/server_slice.rb', line 58

def security_groups
  sg = {}
  servers.each{|svr| sg.merge!(svr.cloud.security_groups) }
  sg
end

#ssh_identity_fileObject

hack – take the ssh_identity_file from the first server.


73
74
75
76
# File 'lib/cluster_chef/server_slice.rb', line 73

def ssh_identity_file
  return if servers.empty?
  servers.first.cloud.ssh_identity_file
end

#startObject

Actions!


82
83
84
85
# File 'lib/cluster_chef/server_slice.rb', line 82

def start
  delegate_to_fog_servers( :start  )
  delegate_to_fog_servers( :reload  )
end

#stopObject


87
88
89
90
# File 'lib/cluster_chef/server_slice.rb', line 87

def stop
  delegate_to_fog_servers( :stop )
  delegate_to_fog_servers( :reload  )
end

#sync_keypairsObject


133
134
135
136
137
138
139
140
141
# File 'lib/cluster_chef/fog_layer.rb', line 133

def sync_keypairs
  step("ensuring keypairs exist")
  keypairs  = servers.map{|svr| [svr.cluster.cloud.keypair, svr.cloud.keypair] }.flatten.map(&:to_s).reject(&:blank?).uniq
  keypairs  = keypairs - ClusterChef.fog_keypairs.keys
  keypairs.each do |keypair_name|
    keypair_obj = ClusterChef::Ec2Keypair.create!(keypair_name)
    ClusterChef.fog_keypairs[keypair_name] = keypair_obj
  end
end

#sync_security_groupsObject

Create security groups, their dependencies, and synchronize their permissions


144
145
146
147
# File 'lib/cluster_chef/fog_layer.rb', line 144

def sync_security_groups
  step("ensuring security groups exist and are correct")
  security_groups.each{|name,group| group.run }
end

#sync_to_chefObject


115
116
117
118
# File 'lib/cluster_chef/server_slice.rb', line 115

def sync_to_chef
  sync_roles
  delegate_to_servers( :sync_to_chef )
end

#sync_to_cloudObject


109
110
111
112
113
# File 'lib/cluster_chef/server_slice.rb', line 109

def sync_to_cloud
  sync_keypairs
  sync_security_groups
  delegate_to_servers( :sync_to_cloud )
end

#to_sObject


211
212
213
214
# File 'lib/cluster_chef/server_slice.rb', line 211

def to_s
  str = super
  str[0..-2] + " #{@servers.map(&:fullname)}>"
end

#uncreated_serversObject

Return the collection of servers that are not yet 'created'


38
39
40
# File 'lib/cluster_chef/server_slice.rb', line 38

def uncreated_servers
  select{|svr| not svr.created? }
end