Revision dd7f6776 lib/mcpu.py

b/lib/mcpu.py
427 427
    self.callfn = callfn
428 428
    self.lu = lu
429 429
    self.op = lu.op
430
    self.env, node_list_pre, node_list_post = self._BuildEnv()
431
    self.node_list = {
432
      constants.HOOKS_PHASE_PRE: node_list_pre,
433
      constants.HOOKS_PHASE_POST: node_list_post,
434
      }
430
    self.pre_env = None
431
    self.pre_nodes = None
435 432

  
436
  def _BuildEnv(self):
433
  def _BuildEnv(self, phase):
437 434
    """Compute the environment and the target nodes.
438 435

  
439 436
    Based on the opcode and the current node list, this builds the
440 437
    environment for the hooks and the target node list for the run.
441 438

  
442 439
    """
443
    env = {
444
      "PATH": "/sbin:/bin:/usr/sbin:/usr/bin",
445
      "GANETI_HOOKS_VERSION": constants.HOOKS_VERSION,
446
      "GANETI_OP_CODE": self.op.OP_ID,
447
      "GANETI_OBJECT_TYPE": self.lu.HTYPE,
448
      "GANETI_DATA_DIR": constants.DATA_DIR,
449
      }
440
    if phase == constants.HOOKS_PHASE_PRE:
441
      prefix = "GANETI_"
442
    elif phase == constants.HOOKS_PHASE_POST:
443
      prefix = "GANETI_POST_"
444
    else:
445
      raise AssertionError("Unknown phase '%s'" % phase)
446

  
447
    env = {}
450 448

  
451 449
    if self.lu.HPATH is not None:
452 450
      (lu_env, lu_nodes_pre, lu_nodes_post) = self.lu.BuildHooksEnv()
453 451
      if lu_env:
454
        assert not compat.any(key.upper().startswith("GANETI")
452
        assert not compat.any(key.upper().startswith(prefix)
455 453
                              for key in lu_env)
456
        env.update(("GANETI_%s" % key, value) for (key, value) in lu_env)
454
        env.update(("%s%s" % (prefix, key), value)
455
                   for (key, value) in lu_env.items())
457 456
    else:
458 457
      lu_nodes_pre = lu_nodes_post = []
459 458

  
459
    if phase == constants.HOOKS_PHASE_PRE:
460
      assert compat.all((key.startswith("GANETI_") and
461
                         not key.startswith("GANETI_POST_"))
462
                        for key in env)
463

  
464
      # Record environment for any post-phase hooks
465
      self.pre_env = env
466

  
467
    elif phase == constants.HOOKS_PHASE_POST:
468
      assert compat.all(key.startswith("GANETI_POST_") for key in env)
469

  
470
      if self.pre_env:
471
        assert not compat.any(key.startswith("GANETI_POST_")
472
                              for key in self.pre_env)
473
        env.update(self.pre_env)
474
    else:
475
      raise AssertionError("Unknown phase '%s'" % phase)
476

  
460 477
    return env, frozenset(lu_nodes_pre), frozenset(lu_nodes_post)
461 478

  
462
  def _RunWrapper(self, node_list, hpath, phase):
479
  def _RunWrapper(self, node_list, hpath, phase, phase_env):
463 480
    """Simple wrapper over self.callfn.
464 481

  
465 482
    This method fixes the environment before doing the rpc call.
466 483

  
467 484
    """
468
    env = self.env.copy()
469
    env["GANETI_HOOKS_PHASE"] = phase
470
    env["GANETI_HOOKS_PATH"] = hpath
471
    if self.lu.cfg is not None:
472
      env["GANETI_CLUSTER"] = self.lu.cfg.GetClusterName()
473
      env["GANETI_MASTER"] = self.lu.cfg.GetMasterNode()
485
    cfg = self.lu.cfg
486

  
487
    env = {
488
      "PATH": "/sbin:/bin:/usr/sbin:/usr/bin",
489
      "GANETI_HOOKS_VERSION": constants.HOOKS_VERSION,
490
      "GANETI_OP_CODE": self.op.OP_ID,
491
      "GANETI_OBJECT_TYPE": self.lu.HTYPE,
492
      "GANETI_DATA_DIR": constants.DATA_DIR,
493
      "GANETI_HOOKS_PHASE": phase,
494
      "GANETI_HOOKS_PATH": hpath,
495
      }
496

  
497
    if cfg is not None:
498
      env["GANETI_CLUSTER"] = cfg.GetClusterName()
499
      env["GANETI_MASTER"] = cfg.GetMasterNode()
500

  
501
    if phase_env:
502
      assert not (set(env) & set(phase_env)), "Environment variables conflict"
503
      env.update(phase_env)
474 504

  
505
    # Convert everything to strings
475 506
    env = dict([(str(key), str(val)) for key, val in env.iteritems()])
476 507

  
477
    assert compat.all(key == key.upper() and
478
                      (key == "PATH" or key.startswith("GANETI_"))
508
    assert compat.all(key == "PATH" or key.startswith("GANETI_")
479 509
                      for key in env)
480 510

  
481 511
    return self.callfn(node_list, hpath, phase, env)
......
493 523
    @raise errors.HooksAbort: on failure of one of the hooks
494 524

  
495 525
    """
526
    (env, node_list_pre, node_list_post) = self._BuildEnv(phase)
496 527
    if nodes is None:
497
      nodes = self.node_list[phase]
528
      if phase == constants.HOOKS_PHASE_PRE:
529
        self.pre_nodes = (node_list_pre, node_list_post)
530
        nodes = node_list_pre
531
      elif phase == constants.HOOKS_PHASE_POST:
532
        post_nodes = (node_list_pre, node_list_post)
533
        assert self.pre_nodes == post_nodes, \
534
               ("Node lists returned for post-phase hook don't match pre-phase"
535
                " lists (pre %s, post %s)" % (self.pre_nodes, post_nodes))
536
        nodes = node_list_post
537
      else:
538
        raise AssertionError("Unknown phase '%s'" % phase)
498 539

  
499 540
    if not nodes:
500 541
      # empty node list, we should not attempt to run this as either
......
502 543
      # even attempt to run, or this LU doesn't do hooks at all
503 544
      return
504 545

  
505
    results = self._RunWrapper(nodes, self.lu.HPATH, phase)
546
    results = self._RunWrapper(nodes, self.lu.HPATH, phase, env)
506 547
    if not results:
507 548
      msg = "Communication Failure"
508 549
      if phase == constants.HOOKS_PHASE_PRE:
......
545 586
    top-level LI if the configuration has been updated.
546 587

  
547 588
    """
589
    if self.pre_env is None:
590
      raise AssertionError("Pre-phase must be run before configuration update")
591

  
548 592
    phase = constants.HOOKS_PHASE_POST
549 593
    hpath = constants.HOOKS_NAME_CFGUPDATE
550 594
    nodes = [self.lu.cfg.GetMasterNode()]
551
    self._RunWrapper(nodes, hpath, phase)
595
    self._RunWrapper(nodes, hpath, phase, self.pre_env)

Also available in: Unified diff