Revision 595bc9b0

b/snf-cyclades-app/synnefo/logic/tests.py
765 765
            self.assertEqual(vm.buildpercentage, old)
766 766

  
767 767

  
768
from synnefo.logic.reconciliation import VMState
768
import logging
769
from datetime import timedelta
770

  
771

  
772
@patch("synnefo.logic.rapi_pool.GanetiRapiClient")
769 773
class ReconciliationTest(TestCase):
770
    def get_vm(self, operstate, deleted=False):
771
        flavor = mfactory.FlavorFactory(cpu=2, ram=1024)
772
        vm = mfactory.VirtualMachineFactory(deleted=deleted, flavor=flavor)
773
        vm.operstate = operstate
774
        vm.save()
775
        return vm
776

  
777
    def test_get_servers_from_db(self):
778
        """Test getting a dictionary from each server to its operstate"""
779
        backends = Backend.objects.all()
780
        vm1 = self.get_vm('STARTED')
781
        vm2 = self.get_vm('DESTROYED', deleted=True)
782
        vm3 = self.get_vm('STOPPED')
783
        self.assertEquals(reconciliation.get_servers_from_db(backends),
784
                    {vm1.id: VMState(state='STARTED', cpu=2, ram=1024, nics=[]),
785
                     vm3.id: VMState(state='STOPPED', cpu=2, ram=1024, nics=[])}
786
                    )
787

  
788
    def test_stale_servers_in_db(self):
789
        """Test discovery of stale entries in DB"""
790

  
791
        D = {1: None, 2: 'None', 3: None, 30000: 'BUILD',
792
             30002: 'None'}
793
        G = {1: True, 3: True, 30000: True}
794
        self.assertEquals(reconciliation.stale_servers_in_db(D, G),
795
                          set([2, 30002]))
796

  
797
    @patch("synnefo.db.models.get_rapi_client")
798
    def test_stale_building_vm(self, client):
799
        vm = mfactory.VirtualMachineFactory()
800
        vm.state = 'BUILD'
801
        vm.backendjobid = 42
802
        vm.save()
803
        D = {vm.id: 'BUILD'}
804
        G = {}
805
        for status in ['queued', 'waiting', 'running']:
806
            client.return_value.GetJobStatus.return_value = {'status': status}
807
            self.assertEqual(reconciliation.stale_servers_in_db(D, G), set([]))
808
            client.return_value.GetJobStatus\
809
                               .assert_called_once_with(vm.backendjobid)
810
            client.reset_mock()
811
        for status in ['success', 'error', 'canceled']:
812
            client.return_value.GetJobStatus.return_value = {'status': status}
813
            self.assertEqual(reconciliation.stale_servers_in_db(D, G), set([]))
814
            client.return_value.GetInstance\
815
                               .assert_called_once_with(vm.backend_vm_id)
816
            client.return_value.GetJobStatus\
817
                               .assert_called_once_with(vm.backendjobid)
818
            client.reset_mock()
819
        from synnefo.logic.rapi import GanetiApiError
820
        client.return_value.GetJobStatus.side_effect = GanetiApiError('Foo')
821
        self.assertEqual(reconciliation.stale_servers_in_db(D, G),
822
                         set([vm.id]))
823

  
824
    def test_orphan_instances_in_ganeti(self):
825
        """Test discovery of orphan instances in Ganeti, without a DB entry"""
826

  
827
        G = {1: True, 2: False, 3: False, 4: True, 50: True}
828
        D = {1: True, 3: False}
829
        self.assertEquals(reconciliation.orphan_instances_in_ganeti(D, G),
830
                          set([2, 4, 50]))
831

  
832
    def test_unsynced_operstate(self):
833
        """Test discovery of unsynced operstate between the DB and Ganeti"""
834
        mkstate = lambda state: VMState(state=state, cpu=1, ram=1024, nics=[])
835
        vm1 = self.get_vm("STARTED")
836
        vm2 = self.get_vm("STARTED")
837
        vm3= self.get_vm("BUILD")
838
        vm4 = self.get_vm("STARTED")
839
        vm5 = self.get_vm("BUILD")
840

  
841
        D = {1: mkstate("STARTED"), 2: mkstate("STARTED"), 3: mkstate("BUILD"),
842
             4: mkstate("STARTED"), 50: mkstate("BUILD")}
843
        G = {vm1.id: mkstate(True), vm2.id: mkstate(False),
844
             vm4.id: mkstate(True), vm4.id: mkstate(False),
845
             vm5.id: mkstate(False)}
846
        self.assertEquals(reconciliation.unsynced_operstate(D, G),
847
                          set([(vm2.id, "STARTED", False),
848
                               (vm4.id, "STARTED", False)]))
774
    @patch("synnefo.logic.rapi_pool.GanetiRapiClient")
775
    def setUp(self, mrapi):
776
        self.backend = mfactory.BackendFactory()
777
        log = logging.getLogger()
778
        options = {"fix_unsynced": True,
779
                   "fix_stale": True,
780
                   "fix_orphans": True,
781
                   "fix_unsynced_nics": True,
782
                   "fix_unsynced_flavors": True}
783
        self.reconciler = reconciliation.BackendReconciler(self.backend,
784
                                                           options=options,
785
                                                           logger=log)
786

  
787
    def test_building_vm(self, mrapi):
788
        mrapi = self.reconciler.client
789
        vm1 = mfactory.VirtualMachineFactory(backend=self.backend,
790
                                             backendjobid=None,
791
                                             operstate="BUILD")
792
        self.reconciler.reconcile()
793
        # Assert not deleted
794
        vm1 = VirtualMachine.objects.get(id=vm1.id)
795
        self.assertFalse(vm1.deleted)
796
        self.assertEqual(vm1.operstate, "BUILD")
797

  
798
        vm1.created = vm1.created - timedelta(seconds=120)
799
        vm1.save()
800
        with mocked_quotaholder():
801
            self.reconciler.reconcile()
802
        vm1 = VirtualMachine.objects.get(id=vm1.id)
803
        self.assertEqual(vm1.operstate, "ERROR")
804

  
805
        vm1 = mfactory.VirtualMachineFactory(backend=self.backend,
806
                                             backendjobid=1,
807
                                             deleted=False,
808
                                             operstate="BUILD")
809
        vm1.backendtime = vm1.created - timedelta(seconds=120)
810
        vm1.backendjobid = 10
811
        vm1.save()
812
        for status in ["queued", "waiting", "running"]:
813
            mrapi.GetJobStatus.return_value = {"status": status}
814
            with mocked_quotaholder():
815
                self.reconciler.reconcile()
816
            vm1 = VirtualMachine.objects.get(id=vm1.id)
817
            self.assertFalse(vm1.deleted)
818
            self.assertEqual(vm1.operstate, "BUILD")
819

  
820
        mrapi.GetJobStatus.return_value = {"status": "error"}
821
        with mocked_quotaholder():
822
            self.reconciler.reconcile()
823
        vm1 = VirtualMachine.objects.get(id=vm1.id)
824
        self.assertFalse(vm1.deleted)
825
        self.assertEqual(vm1.operstate, "ERROR")
826

  
827
        for status in ["success", "cancelled"]:
828
            vm1.deleted = False
829
            vm1.save()
830
            mrapi.GetJobStatus.return_value = {"status": status}
831
            with mocked_quotaholder():
832
                self.reconciler.reconcile()
833
            vm1 = VirtualMachine.objects.get(id=vm1.id)
834
            self.assertTrue(vm1.deleted)
835
            self.assertEqual(vm1.operstate, "DESTROYED")
836

  
837
        vm1 = mfactory.VirtualMachineFactory(backend=self.backend,
838
                                             backendjobid=1,
839
                                             operstate="BUILD")
840
        vm1.backendtime = vm1.created - timedelta(seconds=120)
841
        vm1.backendjobid = 10
842
        vm1.save()
843
        cmrapi = self.reconciler.client
844
        cmrapi.GetInstances.return_value = \
845
            [{"name": vm1.backend_vm_id,
846
             "beparams": {"maxmem": 1024,
847
                          "minmem": 1024,
848
                          "vcpus": 4},
849
             "oper_state": False,
850
             "mtime": time(),
851
             "disk.sizes": [],
852
             "nic.ips": [],
853
             "nic.macs": [],
854
             "nic.networks": [],
855
             "tags": []}]
856
        mrapi.GetJobStatus.return_value = {"status": "running"}
857
        with mocked_quotaholder():
858
            self.reconciler.reconcile()
859
        vm1 = VirtualMachine.objects.get(id=vm1.id)
860
        self.assertEqual(vm1.operstate, "BUILD")
861
        mrapi.GetJobStatus.return_value = {"status": "error"}
862
        with mocked_quotaholder():
863
            self.reconciler.reconcile()
864
        vm1 = VirtualMachine.objects.get(id=vm1.id)
865
        self.assertEqual(vm1.operstate, "ERROR")
866

  
867
    def test_stale_server(self, mrapi):
868
        mrapi.GetInstances = []
869
        vm1 = mfactory.VirtualMachineFactory(backend=self.backend,
870
                                             deleted=False,
871
                                             operstate="ERROR")
872
        with mocked_quotaholder():
873
            self.reconciler.reconcile()
874
        vm1 = VirtualMachine.objects.get(id=vm1.id)
875
        self.assertTrue(vm1.deleted)
876

  
877
    def test_orphan_server(self, mrapi):
878
        cmrapi = self.reconciler.client
879
        mrapi().GetInstances.return_value =\
880
            [{"name": "%s22" % settings.BACKEND_PREFIX_ID,
881
             "beparams": {"maxmem": 1024,
882
                          "minmem": 1024,
883
                          "vcpus": 4},
884
             "oper_state": True,
885
             "mtime": time(),
886
             "disk.sizes": [],
887
             "nic.ips": [],
888
             "nic.macs": [],
889
             "nic.networks": [],
890
             "tags": []}]
891
        self.reconciler.reconcile()
892
        cmrapi.DeleteInstance.assert_called_once_with(
893
                "%s22" % settings.BACKEND_PREFIX_ID)
894

  
895
    def test_unsynced_operstate(self, mrapi):
896
        vm1 = mfactory.VirtualMachineFactory(backend=self.backend,
897
                                             deleted=False,
898
                                             operstate="STOPPED")
899
        mrapi().GetInstances.return_value =\
900
            [{"name": vm1.backend_vm_id,
901
             "beparams": {"maxmem": 1024,
902
                          "minmem": 1024,
903
                          "vcpus": 4},
904
             "oper_state": True,
905
             "mtime": time(),
906
             "disk.sizes": [],
907
             "nic.ips": [],
908
             "nic.macs": [],
909
             "nic.networks": [],
910
             "tags": []}]
911
        with mocked_quotaholder():
912
            self.reconciler.reconcile()
913
        vm1 = VirtualMachine.objects.get(id=vm1.id)
914
        self.assertEqual(vm1.operstate, "STARTED")
915

  
916
    def test_unsynced_flavor(self, mrapi):
917
        flavor1 = mfactory.FlavorFactory(cpu=2, ram=1024, disk=1,
918
                                         disk_template="drbd")
919
        flavor2 = mfactory.FlavorFactory(cpu=4, ram=2048, disk=1,
920
                                         disk_template="drbd")
921
        vm1 = mfactory.VirtualMachineFactory(backend=self.backend,
922
                                             deleted=False,
923
                                             flavor=flavor1,
924
                                             operstate="STARTED")
925
        mrapi().GetInstances.return_value =\
926
            [{"name": vm1.backend_vm_id,
927
             "beparams": {"maxmem": 2048,
928
                          "minmem": 2048,
929
                          "vcpus": 4},
930
             "oper_state": True,
931
             "mtime": time(),
932
             "disk.sizes": [],
933
             "nic.ips": [],
934
             "nic.macs": [],
935
             "nic.networks": [],
936
             "tags": []}]
937
        with mocked_quotaholder():
938
            self.reconciler.reconcile()
939
        vm1 = VirtualMachine.objects.get(id=vm1.id)
940
        self.assertEqual(vm1.flavor, flavor2)
941
        self.assertEqual(vm1.operstate, "STARTED")
942

  
943
    def test_unsynced_nics(self, mrapi):
944
        network1 = mfactory.NetworkFactory(subnet="10.0.0.0/24")
945
        network2 = mfactory.NetworkFactory(subnet="192.168.2.0/24")
946
        vm1 = mfactory.VirtualMachineFactory(backend=self.backend,
947
                                             deleted=False,
948
                                             operstate="STOPPED")
949
        mfactory.NetworkInterfaceFactory(machine=vm1, network=network1,
950
                                         ipv4="10.0.0.0")
951
        mrapi().GetInstances.return_value =\
952
            [{"name": vm1.backend_vm_id,
953
             "beparams": {"maxmem": 2048,
954
                          "minmem": 2048,
955
                          "vcpus": 4},
956
             "oper_state": True,
957
             "mtime": time(),
958
             "disk.sizes": [],
959
             "nic.ips": ["192.168.2.1"],
960
             "nic.macs": ["aa:00:bb:cc:dd:ee"],
961
             "nic.networks": [network2.backend_id],
962
             "tags": []}]
963
        with mocked_quotaholder():
964
            self.reconciler.reconcile()
965
        vm1 = VirtualMachine.objects.get(id=vm1.id)
966
        self.assertEqual(vm1.operstate, "STARTED")
967
        nic = vm1.nics.all()[0]
968
        self.assertEqual(nic.network, network2)
969
        self.assertEqual(nic.ipv4, "192.168.2.1")
970
        self.assertEqual(nic.mac, "aa:00:bb:cc:dd:ee")
971

  
849 972

  
850 973
from synnefo.logic.test.rapi_pool_tests import *
851 974
from synnefo.logic.test.utils_tests import *

Also available in: Unified diff