Revision 08a6c581

b/lib/locking.py
669 669
#   - at levels LEVEL_NODE and LEVEL_INSTANCE reside node and instance locks.
670 670
#   If you need more than one node, or more than one instance, acquire them at
671 671
#   the same time.
672
#  - level LEVEL_CONFIG contains the configuration lock, which you must acquire
673
#  before reading or changing the config file.
674 672
LEVEL_CLUSTER = 0
675 673
LEVEL_NODE = 1
676 674
LEVEL_INSTANCE = 2
677
LEVEL_CONFIG = 3
678 675

  
679 676
LEVELS = [LEVEL_CLUSTER,
680 677
          LEVEL_NODE,
681
          LEVEL_INSTANCE,
682
          LEVEL_CONFIG]
678
          LEVEL_INSTANCE]
683 679

  
684 680
# Lock levels which are modifiable
685 681
LEVELS_MOD = [LEVEL_NODE, LEVEL_INSTANCE]
686 682

  
687
# Constant for the big ganeti lock and config lock
683
# Constant for the big ganeti lock
688 684
BGL = 'BGL'
689
CONFIG = 'config'
690 685

  
691 686

  
692 687
class GanetiLockManager:
......
720 715
      LEVEL_CLUSTER: LockSet([BGL]),
721 716
      LEVEL_NODE: LockSet(nodes),
722 717
      LEVEL_INSTANCE: LockSet(instances),
723
      LEVEL_CONFIG: LockSet([CONFIG]),
724 718
    }
725 719

  
726 720
  def _names(self, level):
b/test/ganeti.locking_unittest.py
583 583
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
584 584
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
585 585
                     set(self.instances))
586
    self.assertEqual(self.GL._names(locking.LEVEL_CONFIG), set(['config']))
587 586

  
588 587
  def testInitAndResources(self):
589 588
    locking.GanetiLockManager._instance = None
......
591 590
    self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
592 591
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
593 592
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
594
    self.assertEqual(self.GL._names(locking.LEVEL_CONFIG), set(['config']))
595 593

  
596 594
    locking.GanetiLockManager._instance = None
597 595
    self.GL = locking.GanetiLockManager(nodes=self.nodes)
598 596
    self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
599 597
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
600 598
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
601
    self.assertEqual(self.GL._names(locking.LEVEL_CONFIG), set(['config']))
602 599

  
603 600
    locking.GanetiLockManager._instance = None
604 601
    self.GL = locking.GanetiLockManager(instances=self.instances)
......
606 603
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
607 604
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
608 605
                     set(self.instances))
609
    self.assertEqual(self.GL._names(locking.LEVEL_CONFIG), set(['config']))
610 606

  
611 607
  def testAcquireRelease(self):
612 608
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
......
616 612
    self.GL.acquire(locking.LEVEL_NODE, ['n1'])
617 613
    self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE), set(['n1']))
618 614
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i1', 'i2'])
619
    self.GL.acquire(locking.LEVEL_CONFIG, ['config'])
620 615
    self.GL.release(locking.LEVEL_INSTANCE, ['i2'])
621 616
    self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i1']))
622 617
    self.GL.release(locking.LEVEL_NODE)
623 618
    self.GL.release(locking.LEVEL_INSTANCE)
624
    self.GL.release(locking.LEVEL_CONFIG)
625 619
    self.assertRaises(errors.LockError, self.GL.acquire,
626 620
                      locking.LEVEL_INSTANCE, ['i5'])
627 621
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'], shared=1)
......
645 639
    self.assertRaises(AssertionError, self.GL.release,
646 640
                      locking.LEVEL_CLUSTER)
647 641
    self.GL.release(locking.LEVEL_INSTANCE)
648
    self.GL.acquire(locking.LEVEL_CONFIG, ['config'])
649
    self.assertRaises(AssertionError, self.GL.release,
650
                      locking.LEVEL_CLUSTER)
651 642

  
652 643
  def testWrongOrder(self):
653 644
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
......
656 647
                      locking.LEVEL_NODE, ['n1'])
657 648
    self.assertRaises(AssertionError, self.GL.acquire,
658 649
                      locking.LEVEL_INSTANCE, ['i2'])
659
    self.GL.acquire(locking.LEVEL_CONFIG, ['config'])
660
    self.assertRaises(AssertionError, self.GL.acquire,
661
                      locking.LEVEL_CONFIG, ['config'])
662
    self.GL.release(locking.LEVEL_INSTANCE)
663
    self.assertRaises(AssertionError, self.GL.acquire,
664
                      locking.LEVEL_NODE, ['n1'])
665
    self.assertRaises(AssertionError, self.GL.acquire,
666
                      locking.LEVEL_INSTANCE, ['i2'])
667
    self.assertRaises(AssertionError, self.GL.acquire,
668
                      locking.LEVEL_CONFIG, ['config'])
669 650

  
670 651
  # Helper function to run as a thread that shared the BGL and then acquires
671 652
  # some locks at another level.
......
685 666
    self.assertEqual(self.done.get(True, 1), 'DONE')
686 667
    self.GL.acquire(locking.LEVEL_NODE, ['n1'])
687 668
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'])
688
    self.GL.acquire(locking.LEVEL_CONFIG, ['config'])
689 669
    Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i1', 1)).start()
690 670
    self.assertEqual(self.done.get(True, 1), 'DONE')
691 671
    Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i3', 1)).start()
692 672
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
693
    self.GL.release(locking.LEVEL_CONFIG)
694 673
    self.GL.release(locking.LEVEL_INSTANCE)
695 674
    self.assertEqual(self.done.get(True, 1), 'DONE')
696 675
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i2'], shared=1)

Also available in: Unified diff