Revision 68d95757

b/Makefile.am
252 252
	lib/constants.py \
253 253
	lib/daemon.py \
254 254
	lib/errors.py \
255
	lib/hooksmaster.py \
255 256
	lib/ht.py \
256 257
	lib/jqueue.py \
257 258
	lib/jstore.py \
b/lib/backend.py
60 60
from ganeti import serializer
61 61
from ganeti import netutils
62 62
from ganeti import runtime
63
from ganeti import mcpu
64 63
from ganeti import compat
65 64
from ganeti import pathutils
66 65
from ganeti import vcluster
67 66
from ganeti import ht
67
from ganeti import hooksmaster
68 68

  
69 69

  
70 70
_BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id"
......
297 297

  
298 298
      cfg = _GetConfig()
299 299
      hr = HooksRunner()
300
      hm = mcpu.HooksMaster(hook_opcode, hooks_path, nodes, hr.RunLocalHooks,
301
                            None, env_fn, logging.warning, cfg.GetClusterName(),
302
                            cfg.GetMasterNode())
303

  
300
      hm = hooksmaster.HooksMaster(hook_opcode, hooks_path, nodes,
301
                                   hr.RunLocalHooks, None, env_fn,
302
                                   logging.warning, cfg.GetClusterName(),
303
                                   cfg.GetMasterNode())
304 304
      hm.RunPhase(constants.HOOKS_PHASE_PRE)
305 305
      result = fn(*args, **kwargs)
306 306
      hm.RunPhase(constants.HOOKS_PHASE_POST)
b/lib/hooksmaster.py
1
#
2
#
3

  
4
# Copyright (C) 2006, 2007, 2011, 2012 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21

  
22
"""Module implementing the logic for running hooks.
23

  
24
"""
25

  
26
from ganeti import constants
27
from ganeti import errors
28
from ganeti import utils
29
from ganeti import compat
30
from ganeti import pathutils
31

  
32

  
33
def _RpcResultsToHooksResults(rpc_results):
34
  """Function to convert RPC results to the format expected by HooksMaster.
35

  
36
  @type rpc_results: dict(node: L{rpc.RpcResult})
37
  @param rpc_results: RPC results
38
  @rtype: dict(node: (fail_msg, offline, hooks_results))
39
  @return: RPC results unpacked according to the format expected by
40
    L({hooksmaster.HooksMaster}
41

  
42
  """
43
  return dict((node, (rpc_res.fail_msg, rpc_res.offline, rpc_res.payload))
44
              for (node, rpc_res) in rpc_results.items())
45

  
46

  
47
class HooksMaster(object):
48
  def __init__(self, opcode, hooks_path, nodes, hooks_execution_fn,
49
               hooks_results_adapt_fn, build_env_fn, log_fn, htype=None,
50
               cluster_name=None, master_name=None):
51
    """Base class for hooks masters.
52

  
53
    This class invokes the execution of hooks according to the behaviour
54
    specified by its parameters.
55

  
56
    @type opcode: string
57
    @param opcode: opcode of the operation to which the hooks are tied
58
    @type hooks_path: string
59
    @param hooks_path: prefix of the hooks directories
60
    @type nodes: 2-tuple of lists
61
    @param nodes: 2-tuple of lists containing nodes on which pre-hooks must be
62
      run and nodes on which post-hooks must be run
63
    @type hooks_execution_fn: function that accepts the following parameters:
64
      (node_list, hooks_path, phase, environment)
65
    @param hooks_execution_fn: function that will execute the hooks; can be
66
      None, indicating that no conversion is necessary.
67
    @type hooks_results_adapt_fn: function
68
    @param hooks_results_adapt_fn: function that will adapt the return value of
69
      hooks_execution_fn to the format expected by RunPhase
70
    @type build_env_fn: function that returns a dictionary having strings as
71
      keys
72
    @param build_env_fn: function that builds the environment for the hooks
73
    @type log_fn: function that accepts a string
74
    @param log_fn: logging function
75
    @type htype: string or None
76
    @param htype: None or one of L{constants.HTYPE_CLUSTER},
77
     L{constants.HTYPE_NODE}, L{constants.HTYPE_INSTANCE}
78
    @type cluster_name: string
79
    @param cluster_name: name of the cluster
80
    @type master_name: string
81
    @param master_name: name of the master
82

  
83
    """
84
    self.opcode = opcode
85
    self.hooks_path = hooks_path
86
    self.hooks_execution_fn = hooks_execution_fn
87
    self.hooks_results_adapt_fn = hooks_results_adapt_fn
88
    self.build_env_fn = build_env_fn
89
    self.log_fn = log_fn
90
    self.htype = htype
91
    self.cluster_name = cluster_name
92
    self.master_name = master_name
93

  
94
    self.pre_env = self._BuildEnv(constants.HOOKS_PHASE_PRE)
95
    (self.pre_nodes, self.post_nodes) = nodes
96

  
97
  def _BuildEnv(self, phase):
98
    """Compute the environment and the target nodes.
99

  
100
    Based on the opcode and the current node list, this builds the
101
    environment for the hooks and the target node list for the run.
102

  
103
    """
104
    if phase == constants.HOOKS_PHASE_PRE:
105
      prefix = "GANETI_"
106
    elif phase == constants.HOOKS_PHASE_POST:
107
      prefix = "GANETI_POST_"
108
    else:
109
      raise AssertionError("Unknown phase '%s'" % phase)
110

  
111
    env = {}
112

  
113
    if self.hooks_path is not None:
114
      phase_env = self.build_env_fn()
115
      if phase_env:
116
        assert not compat.any(key.upper().startswith(prefix)
117
                              for key in phase_env)
118
        env.update(("%s%s" % (prefix, key), value)
119
                   for (key, value) in phase_env.items())
120

  
121
    if phase == constants.HOOKS_PHASE_PRE:
122
      assert compat.all((key.startswith("GANETI_") and
123
                         not key.startswith("GANETI_POST_"))
124
                        for key in env)
125

  
126
    elif phase == constants.HOOKS_PHASE_POST:
127
      assert compat.all(key.startswith("GANETI_POST_") for key in env)
128
      assert isinstance(self.pre_env, dict)
129

  
130
      # Merge with pre-phase environment
131
      assert not compat.any(key.startswith("GANETI_POST_")
132
                            for key in self.pre_env)
133
      env.update(self.pre_env)
134
    else:
135
      raise AssertionError("Unknown phase '%s'" % phase)
136

  
137
    return env
138

  
139
  def _RunWrapper(self, node_list, hpath, phase, phase_env):
140
    """Simple wrapper over self.callfn.
141

  
142
    This method fixes the environment before executing the hooks.
143

  
144
    """
145
    env = {
146
      "PATH": constants.HOOKS_PATH,
147
      "GANETI_HOOKS_VERSION": constants.HOOKS_VERSION,
148
      "GANETI_OP_CODE": self.opcode,
149
      "GANETI_DATA_DIR": pathutils.DATA_DIR,
150
      "GANETI_HOOKS_PHASE": phase,
151
      "GANETI_HOOKS_PATH": hpath,
152
      }
153

  
154
    if self.htype:
155
      env["GANETI_OBJECT_TYPE"] = self.htype
156

  
157
    if self.cluster_name is not None:
158
      env["GANETI_CLUSTER"] = self.cluster_name
159

  
160
    if self.master_name is not None:
161
      env["GANETI_MASTER"] = self.master_name
162

  
163
    if phase_env:
164
      env = utils.algo.JoinDisjointDicts(env, phase_env)
165

  
166
    # Convert everything to strings
167
    env = dict([(str(key), str(val)) for key, val in env.iteritems()])
168

  
169
    assert compat.all(key == "PATH" or key.startswith("GANETI_")
170
                      for key in env)
171

  
172
    return self.hooks_execution_fn(node_list, hpath, phase, env)
173

  
174
  def RunPhase(self, phase, nodes=None):
175
    """Run all the scripts for a phase.
176

  
177
    This is the main function of the HookMaster.
178
    It executes self.hooks_execution_fn, and after running
179
    self.hooks_results_adapt_fn on its results it expects them to be in the form
180
    {node_name: (fail_msg, [(script, result, output), ...]}).
181

  
182
    @param phase: one of L{constants.HOOKS_PHASE_POST} or
183
        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
184
    @param nodes: overrides the predefined list of nodes for the given phase
185
    @return: the processed results of the hooks multi-node rpc call
186
    @raise errors.HooksFailure: on communication failure to the nodes
187
    @raise errors.HooksAbort: on failure of one of the hooks
188

  
189
    """
190
    if phase == constants.HOOKS_PHASE_PRE:
191
      if nodes is None:
192
        nodes = self.pre_nodes
193
      env = self.pre_env
194
    elif phase == constants.HOOKS_PHASE_POST:
195
      if nodes is None:
196
        nodes = self.post_nodes
197
      env = self._BuildEnv(phase)
198
    else:
199
      raise AssertionError("Unknown phase '%s'" % phase)
200

  
201
    if not nodes:
202
      # empty node list, we should not attempt to run this as either
203
      # we're in the cluster init phase and the rpc client part can't
204
      # even attempt to run, or this LU doesn't do hooks at all
205
      return
206

  
207
    results = self._RunWrapper(nodes, self.hooks_path, phase, env)
208
    if not results:
209
      msg = "Communication Failure"
210
      if phase == constants.HOOKS_PHASE_PRE:
211
        raise errors.HooksFailure(msg)
212
      else:
213
        self.log_fn(msg)
214
        return results
215

  
216
    converted_res = results
217
    if self.hooks_results_adapt_fn:
218
      converted_res = self.hooks_results_adapt_fn(results)
219

  
220
    errs = []
221
    for node_name, (fail_msg, offline, hooks_results) in converted_res.items():
222
      if offline:
223
        continue
224

  
225
      if fail_msg:
226
        self.log_fn("Communication failure to node %s: %s", node_name, fail_msg)
227
        continue
228

  
229
      for script, hkr, output in hooks_results:
230
        if hkr == constants.HKR_FAIL:
231
          if phase == constants.HOOKS_PHASE_PRE:
232
            errs.append((node_name, script, output))
233
          else:
234
            if not output:
235
              output = "(no output)"
236
            self.log_fn("On %s script %s failed, output: %s" %
237
                        (node_name, script, output))
238

  
239
    if errs and phase == constants.HOOKS_PHASE_PRE:
240
      raise errors.HooksAbort(errs)
241

  
242
    return results
243

  
244
  def RunConfigUpdate(self):
245
    """Run the special configuration update hook
246

  
247
    This is a special hook that runs only on the master after each
248
    top-level LI if the configuration has been updated.
249

  
250
    """
251
    phase = constants.HOOKS_PHASE_POST
252
    hpath = constants.HOOKS_NAME_CFGUPDATE
253
    nodes = [self.master_name]
254
    self._RunWrapper(nodes, hpath, phase, self.pre_env)
255

  
256
  @staticmethod
257
  def BuildFromLu(hooks_execution_fn, lu):
258
    if lu.HPATH is None:
259
      nodes = (None, None)
260
    else:
261
      nodes = map(frozenset, lu.BuildHooksNodes())
262

  
263
    master_name = cluster_name = None
264
    if lu.cfg:
265
      master_name = lu.cfg.GetMasterNode()
266
      cluster_name = lu.cfg.GetClusterName()
267

  
268
    return HooksMaster(lu.op.OP_ID, lu.HPATH, nodes, hooks_execution_fn,
269
                       _RpcResultsToHooksResults, lu.BuildHooksEnv,
270
                       lu.LogWarning, lu.HTYPE, cluster_name, master_name)
b/lib/mcpu.py
38 38
from ganeti import opcodes
39 39
from ganeti import constants
40 40
from ganeti import errors
41
from ganeti import hooksmaster
41 42
from ganeti import cmdlib
42 43
from ganeti import locking
43 44
from ganeti import utils
44 45
from ganeti import compat
45
from ganeti import pathutils
46 46

  
47 47

  
48 48
_OP_PREFIX = "Op"
......
245 245
                               " queries) can not submit jobs")
246 246

  
247 247

  
248
def _RpcResultsToHooksResults(rpc_results):
249
  """Function to convert RPC results to the format expected by HooksMaster.
250

  
251
  @type rpc_results: dict(node: L{rpc.RpcResult})
252
  @param rpc_results: RPC results
253
  @rtype: dict(node: (fail_msg, offline, hooks_results))
254
  @return: RPC results unpacked according to the format expected by
255
    L({mcpu.HooksMaster}
256

  
257
  """
258
  return dict((node, (rpc_res.fail_msg, rpc_res.offline, rpc_res.payload))
259
              for (node, rpc_res) in rpc_results.items())
260

  
261

  
262 248
def _VerifyLocks(lu, glm, _mode_whitelist=_NODE_ALLOC_MODE_WHITELIST,
263 249
                 _nal_whitelist=_NODE_ALLOC_WHITELIST):
264 250
  """Performs consistency checks on locks acquired by a logical unit.
......
314 300
    self._ec_id = ec_id
315 301
    self._cbs = None
316 302
    self.rpc = context.rpc
317
    self.hmclass = HooksMaster
303
    self.hmclass = hooksmaster.HooksMaster
318 304
    self._enable_locks = enable_locks
319 305

  
320 306
  def _CheckLocksEnabled(self):
......
603 589
      raise errors.ProgrammerError("Tried to use execution context id when"
604 590
                                   " not set")
605 591
    return self._ec_id
606

  
607

  
608
class HooksMaster(object):
609
  def __init__(self, opcode, hooks_path, nodes, hooks_execution_fn,
610
               hooks_results_adapt_fn, build_env_fn, log_fn, htype=None,
611
               cluster_name=None, master_name=None):
612
    """Base class for hooks masters.
613

  
614
    This class invokes the execution of hooks according to the behaviour
615
    specified by its parameters.
616

  
617
    @type opcode: string
618
    @param opcode: opcode of the operation to which the hooks are tied
619
    @type hooks_path: string
620
    @param hooks_path: prefix of the hooks directories
621
    @type nodes: 2-tuple of lists
622
    @param nodes: 2-tuple of lists containing nodes on which pre-hooks must be
623
      run and nodes on which post-hooks must be run
624
    @type hooks_execution_fn: function that accepts the following parameters:
625
      (node_list, hooks_path, phase, environment)
626
    @param hooks_execution_fn: function that will execute the hooks; can be
627
      None, indicating that no conversion is necessary.
628
    @type hooks_results_adapt_fn: function
629
    @param hooks_results_adapt_fn: function that will adapt the return value of
630
      hooks_execution_fn to the format expected by RunPhase
631
    @type build_env_fn: function that returns a dictionary having strings as
632
      keys
633
    @param build_env_fn: function that builds the environment for the hooks
634
    @type log_fn: function that accepts a string
635
    @param log_fn: logging function
636
    @type htype: string or None
637
    @param htype: None or one of L{constants.HTYPE_CLUSTER},
638
     L{constants.HTYPE_NODE}, L{constants.HTYPE_INSTANCE}
639
    @type cluster_name: string
640
    @param cluster_name: name of the cluster
641
    @type master_name: string
642
    @param master_name: name of the master
643

  
644
    """
645
    self.opcode = opcode
646
    self.hooks_path = hooks_path
647
    self.hooks_execution_fn = hooks_execution_fn
648
    self.hooks_results_adapt_fn = hooks_results_adapt_fn
649
    self.build_env_fn = build_env_fn
650
    self.log_fn = log_fn
651
    self.htype = htype
652
    self.cluster_name = cluster_name
653
    self.master_name = master_name
654

  
655
    self.pre_env = self._BuildEnv(constants.HOOKS_PHASE_PRE)
656
    (self.pre_nodes, self.post_nodes) = nodes
657

  
658
  def _BuildEnv(self, phase):
659
    """Compute the environment and the target nodes.
660

  
661
    Based on the opcode and the current node list, this builds the
662
    environment for the hooks and the target node list for the run.
663

  
664
    """
665
    if phase == constants.HOOKS_PHASE_PRE:
666
      prefix = "GANETI_"
667
    elif phase == constants.HOOKS_PHASE_POST:
668
      prefix = "GANETI_POST_"
669
    else:
670
      raise AssertionError("Unknown phase '%s'" % phase)
671

  
672
    env = {}
673

  
674
    if self.hooks_path is not None:
675
      phase_env = self.build_env_fn()
676
      if phase_env:
677
        assert not compat.any(key.upper().startswith(prefix)
678
                              for key in phase_env)
679
        env.update(("%s%s" % (prefix, key), value)
680
                   for (key, value) in phase_env.items())
681

  
682
    if phase == constants.HOOKS_PHASE_PRE:
683
      assert compat.all((key.startswith("GANETI_") and
684
                         not key.startswith("GANETI_POST_"))
685
                        for key in env)
686

  
687
    elif phase == constants.HOOKS_PHASE_POST:
688
      assert compat.all(key.startswith("GANETI_POST_") for key in env)
689
      assert isinstance(self.pre_env, dict)
690

  
691
      # Merge with pre-phase environment
692
      assert not compat.any(key.startswith("GANETI_POST_")
693
                            for key in self.pre_env)
694
      env.update(self.pre_env)
695
    else:
696
      raise AssertionError("Unknown phase '%s'" % phase)
697

  
698
    return env
699

  
700
  def _RunWrapper(self, node_list, hpath, phase, phase_env):
701
    """Simple wrapper over self.callfn.
702

  
703
    This method fixes the environment before executing the hooks.
704

  
705
    """
706
    env = {
707
      "PATH": constants.HOOKS_PATH,
708
      "GANETI_HOOKS_VERSION": constants.HOOKS_VERSION,
709
      "GANETI_OP_CODE": self.opcode,
710
      "GANETI_DATA_DIR": pathutils.DATA_DIR,
711
      "GANETI_HOOKS_PHASE": phase,
712
      "GANETI_HOOKS_PATH": hpath,
713
      }
714

  
715
    if self.htype:
716
      env["GANETI_OBJECT_TYPE"] = self.htype
717

  
718
    if self.cluster_name is not None:
719
      env["GANETI_CLUSTER"] = self.cluster_name
720

  
721
    if self.master_name is not None:
722
      env["GANETI_MASTER"] = self.master_name
723

  
724
    if phase_env:
725
      env = utils.algo.JoinDisjointDicts(env, phase_env)
726

  
727
    # Convert everything to strings
728
    env = dict([(str(key), str(val)) for key, val in env.iteritems()])
729

  
730
    assert compat.all(key == "PATH" or key.startswith("GANETI_")
731
                      for key in env)
732

  
733
    return self.hooks_execution_fn(node_list, hpath, phase, env)
734

  
735
  def RunPhase(self, phase, nodes=None):
736
    """Run all the scripts for a phase.
737

  
738
    This is the main function of the HookMaster.
739
    It executes self.hooks_execution_fn, and after running
740
    self.hooks_results_adapt_fn on its results it expects them to be in the form
741
    {node_name: (fail_msg, [(script, result, output), ...]}).
742

  
743
    @param phase: one of L{constants.HOOKS_PHASE_POST} or
744
        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
745
    @param nodes: overrides the predefined list of nodes for the given phase
746
    @return: the processed results of the hooks multi-node rpc call
747
    @raise errors.HooksFailure: on communication failure to the nodes
748
    @raise errors.HooksAbort: on failure of one of the hooks
749

  
750
    """
751
    if phase == constants.HOOKS_PHASE_PRE:
752
      if nodes is None:
753
        nodes = self.pre_nodes
754
      env = self.pre_env
755
    elif phase == constants.HOOKS_PHASE_POST:
756
      if nodes is None:
757
        nodes = self.post_nodes
758
      env = self._BuildEnv(phase)
759
    else:
760
      raise AssertionError("Unknown phase '%s'" % phase)
761

  
762
    if not nodes:
763
      # empty node list, we should not attempt to run this as either
764
      # we're in the cluster init phase and the rpc client part can't
765
      # even attempt to run, or this LU doesn't do hooks at all
766
      return
767

  
768
    results = self._RunWrapper(nodes, self.hooks_path, phase, env)
769
    if not results:
770
      msg = "Communication Failure"
771
      if phase == constants.HOOKS_PHASE_PRE:
772
        raise errors.HooksFailure(msg)
773
      else:
774
        self.log_fn(msg)
775
        return results
776

  
777
    converted_res = results
778
    if self.hooks_results_adapt_fn:
779
      converted_res = self.hooks_results_adapt_fn(results)
780

  
781
    errs = []
782
    for node_name, (fail_msg, offline, hooks_results) in converted_res.items():
783
      if offline:
784
        continue
785

  
786
      if fail_msg:
787
        self.log_fn("Communication failure to node %s: %s", node_name, fail_msg)
788
        continue
789

  
790
      for script, hkr, output in hooks_results:
791
        if hkr == constants.HKR_FAIL:
792
          if phase == constants.HOOKS_PHASE_PRE:
793
            errs.append((node_name, script, output))
794
          else:
795
            if not output:
796
              output = "(no output)"
797
            self.log_fn("On %s script %s failed, output: %s" %
798
                        (node_name, script, output))
799

  
800
    if errs and phase == constants.HOOKS_PHASE_PRE:
801
      raise errors.HooksAbort(errs)
802

  
803
    return results
804

  
805
  def RunConfigUpdate(self):
806
    """Run the special configuration update hook
807

  
808
    This is a special hook that runs only on the master after each
809
    top-level LI if the configuration has been updated.
810

  
811
    """
812
    phase = constants.HOOKS_PHASE_POST
813
    hpath = constants.HOOKS_NAME_CFGUPDATE
814
    nodes = [self.master_name]
815
    self._RunWrapper(nodes, hpath, phase, self.pre_env)
816

  
817
  @staticmethod
818
  def BuildFromLu(hooks_execution_fn, lu):
819
    if lu.HPATH is None:
820
      nodes = (None, None)
821
    else:
822
      nodes = map(frozenset, lu.BuildHooksNodes())
823

  
824
    master_name = cluster_name = None
825
    if lu.cfg:
826
      master_name = lu.cfg.GetMasterNode()
827
      cluster_name = lu.cfg.GetClusterName()
828

  
829
    return HooksMaster(lu.op.OP_ID, lu.HPATH, nodes, hooks_execution_fn,
830
                       _RpcResultsToHooksResults, lu.BuildHooksEnv,
831
                       lu.LogWarning, lu.HTYPE, cluster_name, master_name)
b/test/py/ganeti.hooks_unittest.py
30 30

  
31 31
from ganeti import errors
32 32
from ganeti import opcodes
33
from ganeti import mcpu
33
from ganeti import hooksmaster
34 34
from ganeti import backend
35 35
from ganeti import constants
36 36
from ganeti import cmdlib
......
250 250

  
251 251
  def testTotalFalse(self):
252 252
    """Test complete rpc failure"""
253
    hm = mcpu.HooksMaster.BuildFromLu(self._call_false, self.lu)
253
    hm = hooksmaster.HooksMaster.BuildFromLu(self._call_false, self.lu)
254 254
    self.failUnlessRaises(errors.HooksFailure,
255 255
                          hm.RunPhase, constants.HOOKS_PHASE_PRE)
256 256
    hm.RunPhase(constants.HOOKS_PHASE_POST)
257 257

  
258 258
  def testIndividualFalse(self):
259 259
    """Test individual node failure"""
260
    hm = mcpu.HooksMaster.BuildFromLu(self._call_nodes_false, self.lu)
260
    hm = hooksmaster.HooksMaster.BuildFromLu(self._call_nodes_false, self.lu)
261 261
    hm.RunPhase(constants.HOOKS_PHASE_PRE)
262 262
    #self.failUnlessRaises(errors.HooksFailure,
263 263
    #                      hm.RunPhase, constants.HOOKS_PHASE_PRE)
......
265 265

  
266 266
  def testScriptFalse(self):
267 267
    """Test individual rpc failure"""
268
    hm = mcpu.HooksMaster.BuildFromLu(self._call_script_fail, self.lu)
268
    hm = hooksmaster.HooksMaster.BuildFromLu(self._call_script_fail, self.lu)
269 269
    self.failUnlessRaises(errors.HooksAbort,
270 270
                          hm.RunPhase, constants.HOOKS_PHASE_PRE)
271 271
    hm.RunPhase(constants.HOOKS_PHASE_POST)
272 272

  
273 273
  def testScriptSucceed(self):
274 274
    """Test individual rpc failure"""
275
    hm = mcpu.HooksMaster.BuildFromLu(FakeHooksRpcSuccess, self.lu)
275
    hm = hooksmaster.HooksMaster.BuildFromLu(FakeHooksRpcSuccess, self.lu)
276 276
    for phase in (constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST):
277 277
      hm.RunPhase(phase)
278 278

  
......
323 323
  def testEmptyEnv(self):
324 324
    # Check pre-phase hook
325 325
    self.lu.hook_env = {}
326
    hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
326
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
327 327
    hm.RunPhase(constants.HOOKS_PHASE_PRE)
328 328

  
329 329
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
......
349 349
    self.lu.hook_env = {
350 350
      "FOO": "pre-foo-value",
351 351
      }
352
    hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
352
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
353 353
    hm.RunPhase(constants.HOOKS_PHASE_PRE)
354 354

  
355 355
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
......
396 396
      self.lu.hook_env = { name: "value" }
397 397

  
398 398
      # Test using a clean HooksMaster instance
399
      hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
399
      hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
400 400

  
401 401
      for phase in [constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST]:
402 402
        self.assertRaises(AssertionError, hm.RunPhase, phase)
......
404 404

  
405 405
  def testNoNodes(self):
406 406
    self.lu.hook_env = {}
407
    hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
407
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
408 408
    hm.RunPhase(constants.HOOKS_PHASE_PRE, nodes=[])
409 409
    self.assertRaises(IndexError, self._rpcs.pop)
410 410

  
......
416 416
      "node93782.example.net",
417 417
      ]
418 418

  
419
    hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
419
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
420 420

  
421 421
    for phase in [constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST]:
422 422
      hm.RunPhase(phase, nodes=nodes)
......
434 434
      "FOO": "value",
435 435
      }
436 436

  
437
    hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
437
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
438 438
    hm.RunConfigUpdate()
439 439

  
440 440
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
......
453 453
      "FOO": "value",
454 454
      }
455 455

  
456
    hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
456
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
457 457
    hm.RunPhase(constants.HOOKS_PHASE_POST)
458 458

  
459 459
    (node_list, hpath, phase, env) = self._rpcs.pop(0)
......
471 471
    self.assertRaises(AssertionError, self.lu.BuildHooksEnv)
472 472
    self.assertRaises(AssertionError, self.lu.BuildHooksNodes)
473 473

  
474
    hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
474
    hm = hooksmaster.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
475 475
    self.assertEqual(hm.pre_env, {})
476 476
    self.assertRaises(IndexError, self._rpcs.pop)
477 477

  

Also available in: Unified diff