Class: Hubcap::Group

Inherits:
Object
  • Object
show all
Defined in:
lib/hubcap/group.rb

Direct Known Subclasses

Application, Hub, Server

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parent, name, &blk) ⇒ Group

Supply the parent group, the name of this new group and a block of code to evaluate in the context of this new group.

Every group must have a parent group, unless it is the top-most group: the hub. The hub must be a Hubcap::Hub.



11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/hubcap/group.rb', line 11

def initialize(parent, name, &blk)
  @name = name.to_s
  @parent = parent
  unless @parent || kind_of?(Hubcap::Hub)
    raise(Hubcap::GroupWithoutParent, self.inspect)
  end
  @cap_attributes = {}
  @cap_roles = []
  @puppet_roles = []
  @params = {}
  @children = []
  instance_eval(&blk)  if blk && processable?
end

Instance Attribute Details

#childrenObject (readonly)

Returns the value of attribute children.



3
4
5
# File 'lib/hubcap/group.rb', line 3

def children
  @children
end

#nameObject (readonly)

Returns the value of attribute name.



3
4
5
# File 'lib/hubcap/group.rb', line 3

def name
  @name
end

#parentObject (readonly)

Returns the value of attribute parent.



3
4
5
# File 'lib/hubcap/group.rb', line 3

def parent
  @parent
end

Instance Method Details

#absorb(path) ⇒ Object

Load a Ruby file and evaluate it in the context of this group. Like Ruby’s require(), the ‘.rb’ is optional in the path.



29
30
31
32
33
34
35
# File 'lib/hubcap/group.rb', line 29

def absorb(path)
  p = path
  p += '.rb'  unless File.exists?(p)
  raise("File not found: #{path}")  unless File.exists?(p)
  code = IO.read(p)
  eval(code)
end

#application(name, options = {}, &blk) ⇒ Object

Instantiate an application as a child of this group.



205
206
207
# File 'lib/hubcap/group.rb', line 205

def application(name, options = {}, &blk)
  add_child(:applications, Hubcap::Application.new(self, name, options, &blk))
end

#cap_attribute(*args) ⇒ Object

Sets an attribute in the Capistrano server() definition for all Hubcap servers to which it applies.

For eg, :primary => true or :no_release => true.

Either:

cap_attribute(:foo, 'bar')

or:

cap_attribute(:foo => 'bar')

and this works too:

cap_attribute(:foo => 'bar', :garply => 'grault')


117
118
119
120
121
122
123
124
125
# File 'lib/hubcap/group.rb', line 117

def cap_attribute(*args)
  if args.length == 2
    cap_attribute(args.first => args.last)
  elsif args.length == 1 && args.first.kind_of?(Hash)
    @cap_attributes.update(args.first)
  else
    raise ArgumentError('Must be (key, value) or (hash).')
  end
end

#cap_attributesObject



183
184
185
# File 'lib/hubcap/group.rb', line 183

def cap_attributes
  @parent ? @parent.cap_attributes.merge(@cap_attributes) : @cap_attributes
end

#cap_rolesObject



188
189
190
# File 'lib/hubcap/group.rb', line 188

def cap_roles
  @parent ? @parent.cap_roles + @cap_roles : @cap_roles
end

#cap_set(*args, &blk) ⇒ Object

Sets a variable in the Capistrano instance.

Note: when Hubcap is in application mode (not executing a default task), an exception will be raised if a variable is set twice to two different values.

Either:

cap_set(:foo, 'bar')

or:

cap_set(:foo => 'bar')

and this works too:

cap_set(:foo => 'bar', :garply => 'grault')

in fact, even this works:

cap_set(:foo) { bar }


90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/hubcap/group.rb', line 90

def cap_set(*args, &blk)
  if args.length == 2
    hub.cap_set(args.first => args.last)
  elsif args.length == 1
    if block_given?
      hub.cap_set(args.first => blk)
    elsif args.first.kind_of?(Hash)
      hub.cap_set(args.first)
    end
  else
    raise ArgumentError('Must be (key, value) or (hash) or (key) { block }.')
  end
end

#collectable?Boolean

Indicates whether we should store this group in the hub’s array of groups/applications/servers. We only store groups at the end of the filter and below.

That is, this group’s history should be the same length or longer than the filter, but identical at each point in the filter.

Returns:

  • (Boolean)


70
71
72
# File 'lib/hubcap/group.rb', line 70

def collectable?
  hub.filters.any? { |fr| history.size >= fr.size && matching_filter?(fr) }
end

#group(name, &blk) ⇒ Object

Instantiate a group as a child of this group.



219
220
221
# File 'lib/hubcap/group.rb', line 219

def group(name, &blk)
  add_child(:groups, Hubcap::Group.new(self, name, &blk))
end

#historyObject

An array of names, from the oldest ancestor to the parent to self.



47
48
49
# File 'lib/hubcap/group.rb', line 47

def history
  @parent ? @parent.history + [@name] : []
end

#hubObject

Finds the top-level Hubcap::Hub to which this group belongs.



40
41
42
# File 'lib/hubcap/group.rb', line 40

def hub
  @parent ? @parent.hub : self
end

#param(hash) ⇒ Object

Adds values to a hash that is supplied to Puppet when it is provisioning the server.

If you do this…

params(:foo => 'bar')

…then Puppet will have a top-level variable called $foo, containing ‘bar’.

Note that hash keys that are not strings or symbols will raise an error, and symbol keys will be converted to strings. ie, :foo becomes ‘foo’ in the above example.



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/hubcap/group.rb', line 165

def param(hash)
  hash.each_key { |k|
    unless k.kind_of?(String) || k.kind_of?(Symbol)
      raise(Hubcap::InvalidParamKeyType, k.inspect)
    end
  }

  recurse = lambda { |dest, src|
    src.each_pair { |k, v|
      v = recurse.call({}, v)  if v.is_a?(Hash)
      dest.update(k.to_s => v)
    }
    dest
  }
  recurse.call(@params, hash)
end

#paramsObject



198
199
200
# File 'lib/hubcap/group.rb', line 198

def params
  @parent ? @parent.params.merge(@params) : @params
end

#processable?Boolean

Indicates whether we should process this group. We process all groups that match any of the filters or are below the furthest point in the filter.

“Match the filter” means that this group’s history and the filter are identical to the end of the shortest of the two arrays.

Returns:

  • (Boolean)


58
59
60
# File 'lib/hubcap/group.rb', line 58

def processable?
  hub.filters.any? { |fr| matching_filter?(fr) }
end

#puppet_rolesObject



193
194
195
# File 'lib/hubcap/group.rb', line 193

def puppet_roles
  @parent ? @parent.puppet_roles + @puppet_roles : @puppet_roles
end

#role(*args) ⇒ Object

Sets the Capistrano role and/or Puppet class for all Hubcap servers to which it applies.

When declared multiple times (even in parents), it’s additive.

Either:

role(:app)

or:

role(:app, :db)

or:

role(:cap => :app, :puppet => 'relishapp')

or:

role(:cap => [:app, :db], :puppet => 'relishapp')


142
143
144
145
146
147
148
149
150
151
# File 'lib/hubcap/group.rb', line 142

def role(*args)
  if args.length == 1 && args.first.kind_of?(Hash)
    h = args.first
    @cap_roles += [h[:cap]].flatten  if h.has_key?(:cap)
    @puppet_roles += [h[:puppet]].flatten  if h.has_key?(:puppet)
  else
    @cap_roles += args
    @puppet_roles += args
  end
end

#server(name, options = {}, &blk) ⇒ Object

Instantiate a server as a child of this group.



212
213
214
# File 'lib/hubcap/group.rb', line 212

def server(name, options = {}, &blk)
  add_child(:servers, Hubcap::Server.new(self, name, options, &blk))
end

#tree(indent = " ") ⇒ Object

Returns a formatted string of all the key details for this group, and recurses into each child.



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/hubcap/group.rb', line 227

def tree(indent = "  ")
  outs = [self.class.name.split('::').last.upcase, "Name: #{@name}"]
  outs << "Atts: #{@cap_attributes.inspect}"  if @cap_attributes.any?
  if @cap_roles == @puppet_roles
    outs << "Role: #{@cap_roles.inspect}"  if @cap_roles.any?
  else
    cr = @cap_roles.any? ? 'Cap - '+@cap_roles.inspect : nil
    pr = @puppet_roles.any? ? 'Puppet - '+@puppet_roles.inspect : nil
    outs << "Role: #{[cr,pr].compact.join(' ')}"  if cr || pr
  end
  outs << "Pram: #{@params.inspect}"  if @params.any?
  extend_tree(outs)  if respond_to?(:extend_tree)
  if @children.any?
    @children.each { |child| outs << child.tree(indent+"  ") }
  end
  outs.join("\n#{indent}")
end