Class: MotherBrain::Gear::DynamicService

Inherits:
Base
  • Object
show all
Includes:
MB::Mixin::Locks, MB::Mixin::Services, Logging
Defined in:
lib/mb/gears/dynamic_service.rb

Constant Summary collapse

START =
"start".freeze
STOP =
"stop".freeze
RESTART =
"restart".freeze
COMMON_STATES =
[
  START,
  STOP,
  RESTART
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Logging

add_argument_header, dev, filename, #log_exception, logger, #logger, reset, set_logger, setup

Methods inherited from Base

register_gear, #run

Constructor Details

#initialize(component, name) ⇒ DynamicService

Returns a new instance of DynamicService.



26
27
28
29
# File 'lib/mb/gears/dynamic_service.rb', line 26

def initialize(component, name)
  @name      = name
  @component = component
end

Instance Attribute Details

#componentString (readonly)

Returns:

  • (String)


22
23
24
# File 'lib/mb/gears/dynamic_service.rb', line 22

def component
  @component
end

#nameString (readonly)

Returns:

  • (String)


24
25
26
# File 'lib/mb/gears/dynamic_service.rb', line 24

def name
  @name
end

Instance Method Details

#get_chef_environment(environment) ⇒ Ridley::EnvironmentObject

Finds and returns the current Chef environment

Parameters:

  • environment (String)

Returns:

  • (Ridley::EnvironmentObject)


136
137
138
# File 'lib/mb/gears/dynamic_service.rb', line 136

def get_chef_environment(environment)
  chef_connection.environment.find(environment)
end

#node_state_change(job, plugin, node, state, run_chef = true) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/mb/gears/dynamic_service.rb', line 84

def node_state_change(job, plugin, node, state, run_chef = true)
  log.warn {
    "Component's service state is being changed to #{state}, which is not one of #{COMMON_STATES}"
  } unless COMMON_STATES.include?(state)

  component_object = plugin.component(component)
  service = component_object.get_service(name)
  set_node_attributes(job, [node], service.service_attribute, state)
  if run_chef
    node_querier.bulk_chef_run(job, [node], service.service_recipe)
  end
end

#remove_node_state_change(job, plugin, node, run_chef = true) ⇒ Object



97
98
99
100
101
102
103
104
105
# File 'lib/mb/gears/dynamic_service.rb', line 97

def remove_node_state_change(job, plugin, node, run_chef = true)
  component_object = plugin.component(component)
  service = component_object.get_service(name)

  unset_node_attributes(job, [node], service.service_attribute)
  if run_chef
    node_querier.bulk_chef_run(job, [node], service.service_recipe)
  end
end

#set_environment_attribute(job, environment, attribute_keys, state) ⇒ Boolean

Finds the environment object, sets an attribute at the override level, and saves the environment back to the Chef server

Parameters:

  • job (MB::Job)

    the job to track status

  • environment (String)

    the environment being operated on

  • attribute_keys (Array<String>)

    an array of dotted paths to attribute keys

  • state (String)

    the state to set the attribute to

Returns:

  • (Boolean)


121
122
123
124
125
126
127
128
129
# File 'lib/mb/gears/dynamic_service.rb', line 121

def set_environment_attribute(job, environment, attribute_keys, state)
  chef_environment = get_chef_environment(environment)

  attribute_keys.each do |attribute_key|
    job.set_status("Setting environment attribute '#{attribute_key}' to #{state} on #{environment}")
    chef_environment.set_override_attribute(attribute_key, state)
  end
  chef_environment.save
end

#set_node_attributes(job, nodes, attribute_keys, state) ⇒ Boolean

Sets a default node attribute on the provided array of nodes.

Parameters:

  • job (MB::Job)

    the job to track status

  • nodes (Array<Ridley::NodeObject>)

    the nodes being operated on

  • attribute_keys (Array<String>)

    an array of dotted paths to attribute keys

  • state (String)

    the state to set the attribute to

Returns:

  • (Boolean)


170
171
172
173
174
175
176
177
178
179
# File 'lib/mb/gears/dynamic_service.rb', line 170

def set_node_attributes(job, nodes, attribute_keys, state)
  nodes.concurrent_map do |node|
    node.reload
    attribute_keys.each do |attribute_key|
      job.set_status("Setting node attribute '#{attribute_key}' to #{state.nil? ? 'nil' : state} on #{node.name}")
      node.set_chef_attribute(attribute_key, state)
    end
    node.save
  end
end

#state_change(job, plugin, environment, state, run_chef = true, options = {}) ⇒ MB::JobTicket

Executes a bulk chef run on a group of nodes using the service recipe. Default behavior is to set a node attribute on each individual node serially and then execute the chef run.

Parameters:

  • job (MB::Job)
  • plugin (MB::Plugin)

    the plugin currently in use

  • environment (String)

    the environment to execute on

  • state (String)

    the state to change the service to

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • node_filter (String)

    filter to apply to the list of nodes

Returns:



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/mb/gears/dynamic_service.rb', line 46

def state_change(job, plugin, environment, state, run_chef = true, options = {})
  job.report_running
  job.set_status("Transitioning #{@component}.#{@name} to #{state}...")
  log.warn {
    "Component's service state is being changed to #{state}, which is not one of #{COMMON_STATES}"
  } unless COMMON_STATES.include?(state)

  chef_synchronize(chef_environment: environment, force: options[:force]) do
    unless valid_dynamic_service?(plugin)
      job.report_failure("#{@component}.#{@name} is not a valid service in #{plugin.name}")
      return job
    end

   component_object = plugin.component(component)
    service_object = component_object.get_service(name)
    group = component_object.group(service_object.service_group)
    nodes = group.nodes(environment)
    nodes = MB::NodeFilter.filter(options[:node_filter], nodes) if options[:node_filter]

    if options[:cluster_override]
      set_environment_attribute(job, environment, service_object.service_attribute, state)
    else
      unset_environment_attribute(job, environment, service_object.service_attribute)
      set_node_attributes(job, nodes, service_object.service_attribute, state)
    end
    if run_chef
      node_querier.bulk_chef_run(job, nodes, service_object.service_recipe)
    end
  end
  job.set_status("Finished transitioning #{@component}.#{@name} to #{state}!")
  job.report_success
  job.ticket
rescue => ex
  job.report_failure(ex)
ensure
  job.terminate if job && job.alive?
end

#unset_environment_attribute(job, environment, attribute_keys) ⇒ Boolean

Deletes an override attribute from the environment

Parameters:

  • job (MB::Job)
  • environment (String)
  • attribute_keys (Array<String>)

Returns:

  • (Boolean)


147
148
149
150
151
152
153
154
155
# File 'lib/mb/gears/dynamic_service.rb', line 147

def unset_environment_attribute(job, environment, attribute_keys)
  chef_environment = get_chef_environment(environment)

  attribute_keys.each do |attribute_key|
    job.set_status("Unsetting environment attribute '#{attribute_key}' on #{environment}")
    chef_environment.delete_override_attribute(attribute_key)
  end
  chef_environment.save
end

#unset_node_attributes(job, nodes, attribute_keys) ⇒ Boolean

Removes a default node attribute on the provided array of nodes.

Parameters:

  • job (MB::Job)

    the job to track status

  • nodes (Array<Ridley::NodeObject>)

    the nodes being operated on

  • attribute_keys (Array<String>)

    an array of dotted paths to attribute keys

Returns:

  • (Boolean)


192
193
194
195
196
197
198
199
200
201
# File 'lib/mb/gears/dynamic_service.rb', line 192

def unset_node_attributes(job, nodes, attribute_keys)
  nodes.concurrent_map do |node|
    node.reload
    attribute_keys.each do |attribute_key|
      job.set_status("Unsetting node attribute '#{attribute_key}' to respect default and environment attributes.")
      node.unset_chef_attribute(attribute_key)
    end
    node.save
  end
end