Class: StackMate::StackExecutor

Inherits:
Stacker
  • Object
show all
Includes:
Logging
Defined in:
lib/stackmate/stack_executor.rb

Instance Attribute Summary

Attributes inherited from Stacker

#templ

Instance Method Summary collapse

Methods included from Logging

configure_logger_for, #logger, logger_for

Methods inherited from Stacker

#find_refs, #get_allowed_values, #populate_parameters, #resolve_dependencies, #tsort_each_child, #tsort_each_node, #validate_dependencies, #validate_param_values

Constructor Details

#initialize(templatefile, stackname, params, engine, create_wait_conditions, api_opts, timeout, plugins = nil, no_rollback = false) ⇒ StackExecutor

Returns a new instance of StackExecutor.



20
21
22
23
24
25
26
27
28
29
# File 'lib/stackmate/stack_executor.rb', line 20

def initialize(templatefile, stackname, params, engine, create_wait_conditions, api_opts, timeout, plugins=nil, no_rollback=false)
  stackstr = File.read(templatefile)
  super(stackstr, stackname, resolve_param_refs(params, stackname))
  @engine = engine
  @create_wait_conditions = create_wait_conditions
  @api_opts = api_opts
  @timeout = timeout
  load_plugins(plugins)
  @rollback = !no_rollback
end

Instance Method Details

#launchObject



127
128
129
130
131
132
133
134
# File 'lib/stackmate/stack_executor.rb', line 127

def launch
  p @rollback
  wfid = @engine.launch(pdef, @templ, {'do_rollback' => @rollback})
  #wfid = @engine.launch(pdef, @templ)
  timeout = @timeout.to_i * 2
  @engine.wait_for(wfid, :timeout => timeout)
  logger.error { "engine error : #{@engine.errors.first.message}"} if @engine.errors.first
end

#load_plugins(plugins) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
# File 'lib/stackmate/stack_executor.rb', line 31

def load_plugins(plugins)
  if !plugins.nil?
    dirs = plugins.split(",")
    dirs.each do |dir|
      if(File.directory?(dir))
        Dir[dir+"/*.rb"].each do |file|
          begin
            existing_classes = ObjectSpace.each_object(Class).to_a
            require file
            new_classes =  ObjectSpace.each_object(Class).to_a
            added_classes = new_classes - existing_classes
            added_classes.each do |plugin_class|
              if(plugin_class.class_variable_defined?(:@@stackmate_participant) && plugin_class.class_variable_get(:@@stackmate_participant) == true)
                if(not(plugin_class.method_defined?(:consume_workitem) && plugin_class.ancestors.include?(Ruote::Participant)))
                  #http://stackoverflow.com/questions/1901884/loading-unloading-updating-class-in-ruby
                  #recursively get class name
                  namespace = plugin_class.name.split('::')[0..-2]
                  klass = plugin_class.name.split('::')[-1]
                  parent = Object
                  namespace.each do |p|
                    parent = parent.const_get(p.to_sym)
                  end
                  logger.debug("Removing bad participant defninition #{plugin_class} from #{parent}")
                  parent.send(:remove_const,klass.to_sym)
                else
                  logger.debug("Adding method on_workitem to class #{plugin_class}")
                  plugin_class.class_eval do
                    def on_workitem
                      consume_workitem
                      reply
                    end
                  end
                end
              end
            end
          rescue Exception => e
            logger.error("Unable to load plugin #{file}. Dangling classes may exist!!")
          end
        end
      end
    end
  end
end

#pdefObject



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/stackmate/stack_executor.rb', line 93

def pdef
  begin
    #participants = self.strongly_connected_components.flatten
    participants = self.tsort
  rescue Exception => e
    raise "ERROR: Cyclic Dependency detected! " + e.message
  end
  #if we want to skip creating wait conditions (useful for automated tests)
  participants = participants.select { |p|
    StackMate.class_for(@templ['Resources'][p]['Type']) != 'StackMate::WaitCondition'
  } if !@create_wait_conditions

  logger.info("Ordered list of participants: #{participants}")

  participants.each do |p|
    t = @templ['Resources'][p]['Type']
    throw :unknown, t if !StackMate.class_for(t)
    @engine.register_participant p, StackMate.class_for(t), @api_opts
  end
  timeout = @timeout + "s"
  @engine.register_participant 'Output', StackMate.class_for('Outputs')
  @engine.register_participant 'Notify', StackMate.class_for('StackMate::StackNotifier')
  @pdef = Ruote.define @stackname.to_s() do
    cursor :timeout => timeout, :on_error => 'rollback', :on_timeout => 'rollback' do
      participants.collect{ |name| __send__(name, :operation => :create) }
      __send__('Output')
    end
    define 'rollback', :timeout => timeout do
      __send__('Notify', :if => '${v:do_rollback}')
      participants.reverse_each.collect {|name| __send__(name, :operation => :rollback, :if => '${v:do_rollback}') }
    end
  end
end

#resolve_param_refs(params, stackname) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/stackmate/stack_executor.rb', line 74

def resolve_param_refs(params, stackname)
  resolved_params = {}
  begin
    params.split(';').each do |p|
      i = p.split('=')
      resolved_params[i[0]] = i[1]
    end
  rescue
    #minimum parameters??
  end
  resolved_params['AWS::Region'] = 'us-east-1' #TODO handle this better
  resolved_params['AWS::StackName'] = stackname
  resolved_params['AWS::StackId'] = stackname
  resolved_params['CloudStack::StackName'] = stackname
  resolved_params['CloudStack::StackId'] = stackname
  resolved_params['CloudStack::StackMateApiURL'] = ENV['WAIT_COND_URL_BASE']?ENV['WAIT_COND_URL_BASE']:StackMate::WAIT_COND_URL_BASE_DEFAULT
  resolved_params
end