1818
1919from marvin .cloudstackTestCase import cloudstackTestCase
2020from marvin .lib .utils import (cleanup_resources )
21- from marvin .lib .base import (Account , ServiceOffering , VirtualMachine , BackupOffering , Configurations , Backup )
21+ from marvin .lib .base import (Account , ServiceOffering , DiskOffering , VirtualMachine , BackupOffering , Configurations , Backup , Volume , createVMFromBackup )
2222from marvin .lib .common import (get_domain , get_zone , get_template )
2323from nose .plugins .attrib import attr
2424from marvin .codes import FAILED
25+ import time
2526
2627class TestDummyBackupAndRecovery (cloudstackTestCase ):
2728
@@ -59,18 +60,19 @@ def setUpClass(cls):
5960
6061 cls .account = Account .create (cls .api_client , cls .services ["account" ], domainid = cls .domain .id )
6162 cls .offering = ServiceOffering .create (cls .api_client ,cls .services ["service_offerings" ]["small" ])
63+ cls .diskoffering = DiskOffering .create (cls .api_client , cls .services ["disk_offering" ])
6264 cls .vm = VirtualMachine .create (cls .api_client , cls .services ["small" ], accountid = cls .account .name ,
6365 domainid = cls .account .domainid , serviceofferingid = cls .offering .id ,
64- mode = cls .services ["mode" ])
65- cls ._cleanup = [cls .offering , cls .account ]
66+ diskofferingid = cls . diskoffering . id , mode = cls .services ["mode" ])
67+ cls ._cleanup = [cls .offering , cls .diskoffering , cls . account ]
6668
6769 # Import a dummy backup offering to use on tests
6870
6971 cls .provider_offerings = BackupOffering .listExternal (cls .api_client , cls .zone .id )
7072 cls .debug ("Importing backup offering %s - %s" % (cls .provider_offerings [0 ].externalid , cls .provider_offerings [0 ].name ))
71- cls .offering = BackupOffering .importExisting (cls .api_client , cls .zone .id , cls .provider_offerings [0 ].externalid ,
73+ cls .backup_offering = BackupOffering .importExisting (cls .api_client , cls .zone .id , cls .provider_offerings [0 ].externalid ,
7274 cls .provider_offerings [0 ].name , cls .provider_offerings [0 ].description )
73- cls ._cleanup .append (cls .offering )
75+ cls ._cleanup .append (cls .backup_offering )
7476
7577 @classmethod
7678 def tearDownClass (cls ):
@@ -139,7 +141,7 @@ def test_vm_backup_lifecycle(self):
139141 self .assertEqual (backups , None , "There should not exist any backup for the VM" )
140142
141143 # Assign VM to offering and create ad-hoc backup
142- self .offering .assignOffering (self .apiclient , self .vm .id )
144+ self .backup_offering .assignOffering (self .apiclient , self .vm .id )
143145 Backup .create (self .apiclient , self .vm .id )
144146
145147 # Verify backup is created for the VM
@@ -155,4 +157,66 @@ def test_vm_backup_lifecycle(self):
155157 self .assertEqual (backups , None , "There should not exist any backup for the VM" )
156158
157159 # Remove VM from offering
158- self .offering .removeOffering (self .apiclient , self .vm .id )
160+ self .backup_offering .removeOffering (self .apiclient , self .vm .id )
161+
162+ @attr (tags = ["advanced" , "backup" ], required_hardware = "false" )
163+ def test_vm_backup_create_vm_from_backup (self ):
164+ """
165+ Test creating a new VM from a backup
166+ """
167+ self .backup_offering .assignOffering (self .apiclient , self .vm .id )
168+
169+ Backup .create (self .apiclient , self .vm .id , "backup1" )
170+ Backup .create (self .apiclient , self .vm .id , "backup2" )
171+
172+ # Verify backup is created for the VM
173+ backups = Backup .list (self .apiclient , self .vm .id )
174+ #self.cleanup.extend(backups)
175+ #self.cleanup.append(backups[0])
176+ self .assertEqual (len (backups ), 2 , "There should exist two backups for the VM" )
177+
178+ # Remove VM from offering
179+ self .backup_offering .removeOffering (self .apiclient , self .vm .id )
180+
181+ # Verify no. of backups after removing the backup offering
182+ backups = Backup .list (self .apiclient , self .vm .id )
183+ self .assertEqual (len (backups ), 2 , "There should exist two backups for the VM" )
184+
185+ # Create a new VM from first backup
186+ new_vm_name = "vm-from-backup1-" + str (int (time .time ()))
187+ new_vm = Backup .createVMFromBackup (
188+ self .apiclient ,
189+ backupid = backups [0 ].id ,
190+ vmname = new_vm_name ,
191+ accountname = self .account .name ,
192+ domainid = self .account .domainid ,
193+ zoneid = self .zone .id
194+ )
195+ self .cleanup .append (new_vm )
196+
197+ # Verify the new VM was created successfully
198+ self .assertIsNotNone (new_vm , "Failed to create VM from backup" )
199+ self .assertEqual (new_vm .name , new_vm_name , "VM name does not match the requested name" )
200+
201+ # Verify the new VM is running
202+ self .assertEqual (new_vm .state , "Running" , "New VM should be in Running state" )
203+
204+ # Verify the new VM has the correct service offering
205+ self .assertEqual (new_vm .serviceofferingid , self .offering .id ,
206+ "New VM should have the correct service offering" )
207+
208+ # Verify the new VM has the correct zone
209+ self .assertEqual (new_vm .zoneid , self .zone .id , "New VM should be in the correct zone" )
210+
211+ # Verify the new VM has the correct number of volumes (ROOT + DATADISK)
212+ volumes = Volume .list (
213+ self .apiclient ,
214+ virtualmachineid = new_vm .id ,
215+ listall = True
216+ )
217+ self .assertTrue (isinstance (volumes , list ), "List volumes should return a valid list" )
218+ self .assertEqual (2 , len (volumes ), "The new VM should have 2 volumes (ROOT + DATADISK)" )
219+
220+ # Delete backups
221+ Backup .delete (self .apiclient , backups [0 ].id )
222+ Backup .delete (self .apiclient , backups [1 ].id )
0 commit comments