/** * Created with IntelliJ IDEA. User: frank Time: 12:48 PM To change this template use File | * Settings | File Templates. */ public class TestGetPrimaryStoragesType { CLogger logger = Utils.getLogger(TestGetPrimaryStoragesType.class); Api api; ComponentLoader loader; @Before public void setUp() throws Exception { BeanConstructor con = new BeanConstructor(); /* This loads spring application context */ loader = con.addXml("PortalForUnitTest.xml") .addXml("Simulator.xml") .addXml("PrimaryStorageManager.xml") .addXml("ZoneManager.xml") .addXml("ClusterManager.xml") .addXml("ConfigurationManager.xml") .addXml("AccountManager.xml") .build(); api = new Api(); api.startServer(); } @Test public void test() throws ApiSenderException { List<String> types = api.getPrimaryStorageTypes(); Assert.assertFalse(types.isEmpty()); } }
public class TestUpdateL3Network { CLogger logger = Utils.getLogger(TestUpdateL3Network.class); Api api; ComponentLoader loader; DatabaseFacade dbf; @Before public void setUp() throws Exception { DBUtil.reDeployDB(); BeanConstructor con = new BeanConstructor(); /* This loads spring application context */ loader = con.addXml("PortalForUnitTest.xml") .addXml("ZoneManager.xml") .addXml("NetworkManager.xml") .addXml("AccountManager.xml") .build(); dbf = loader.getComponent(DatabaseFacade.class); api = new Api(); api.startServer(); } @Test public void test() throws ApiSenderException { ZoneInventory zone = api.createZones(1).get(0); L2NetworkInventory linv = api.createNoVlanL2Network(zone.getUuid(), "eth0"); L3NetworkInventory l3inv = api.createL3BasicNetwork(linv.getUuid()); l3inv.setName("1"); l3inv.setDescription("xxx"); l3inv = api.updateL3Network(l3inv); Assert.assertEquals("1", l3inv.getName()); Assert.assertEquals("xxx", l3inv.getDescription()); } }
/** Created by frank on 11/10/2015. */ @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE) public class LocalStorageCapacityUpdater { private static CLogger logger = Utils.getLogger(LocalStorageCapacityUpdater.class); @Autowired private DatabaseFacade dbf; @Transactional public void updatePhysicalCapacityByKvmAgentResponse( String psUuid, String hostUuid, AgentResponse rsp) { LocalStorageHostRefVO ref = dbf.getEntityManager() .find(LocalStorageHostRefVO.class, hostUuid, LockModeType.PESSIMISTIC_WRITE); if (ref == null) { return; } if (ref.getAvailablePhysicalCapacity() == rsp.getAvailableCapacity() && ref.getTotalPhysicalCapacity() == rsp.getTotalCapacity()) { return; } long originalPhysicalTotal = ref.getTotalPhysicalCapacity(); long originalPhysicalAvailable = ref.getAvailablePhysicalCapacity(); ref.setTotalPhysicalCapacity(rsp.getTotalCapacity()); ref.setAvailablePhysicalCapacity(rsp.getAvailableCapacity()); dbf.getEntityManager().merge(ref); if (logger.isTraceEnabled()) { logger.trace( String.format( "[Local Storage Capacity] changed the physical capacity of the host[uuid:%s] of " + "the local primary storage[uuid:%s] as:\n" + "physical total: %s --> %s\n" + "physical available: %s --> %s\n", hostUuid, psUuid, originalPhysicalTotal, ref.getTotalPhysicalCapacity(), originalPhysicalAvailable, ref.getAvailablePhysicalCapacity())); } final long totalChange = rsp.getTotalCapacity() - ref.getTotalPhysicalCapacity(); final long availChange = rsp.getAvailableCapacity() - ref.getAvailablePhysicalCapacity(); new PrimaryStorageCapacityUpdater(psUuid) .run( new PrimaryStorageCapacityUpdaterRunnable() { @Override public PrimaryStorageCapacityVO call(PrimaryStorageCapacityVO cap) { cap.setTotalPhysicalCapacity(cap.getTotalPhysicalCapacity() + totalChange); cap.setAvailablePhysicalCapacity(cap.getAvailablePhysicalCapacity() + availChange); return cap; } }); } }
public class TestDeleteDataVolume { CLogger logger = Utils.getLogger(TestDeleteDataVolume.class); Api api; ComponentLoader loader; DatabaseFacade dbf; CloudBus bus; @Before public void setUp() throws Exception { DBUtil.reDeployDB(); BeanConstructor con = new BeanConstructor(); /* This loads spring application context */ loader = con.addXml("PortalForUnitTest.xml") .addXml("Simulator.xml") .addXml("ZoneManager.xml") .addXml("PrimaryStorageManager.xml") .addXml("ConfigurationManager.xml") .addXml("VolumeManager.xml") .addXml("AccountManager.xml") .build(); dbf = loader.getComponent(DatabaseFacade.class); bus = loader.getComponent(CloudBus.class); api = new Api(); api.startServer(); } @After public void tearDown() throws Exception { api.stopServer(); } @Test public void test() throws ApiSenderException { DiskOfferingInventory dinv = new DiskOfferingInventory(); dinv.setDiskSize(SizeUnit.GIGABYTE.toByte(10)); dinv.setName("Test"); dinv.setDescription("Test"); dinv = api.addDiskOffering(dinv); VolumeInventory vinv = api.createDataVolume("TestData", dinv.getUuid()); Assert.assertEquals(VolumeStatus.NotInstantiated.toString(), vinv.getStatus()); Assert.assertEquals(VolumeType.Data.toString(), vinv.getType()); Assert.assertFalse(vinv.isAttached()); api.deleteDataVolume(vinv.getUuid()); VolumeVO vo = dbf.findByUuid(vinv.getUuid(), VolumeVO.class); Assert.assertNull(vo); } }
public class TestStartVirtualRouter { CLogger logger = Utils.getLogger(TestStartVirtualRouter.class); Deployer deployer; Api api; ComponentLoader loader; CloudBus bus; DatabaseFacade dbf; SessionInventory session; VirtualRouterSimulatorConfig vconfig; KVMSimulatorConfig kconfig; @Before public void setUp() throws Exception { DBUtil.reDeployDB(); WebBeanConstructor con = new WebBeanConstructor(); deployer = new Deployer("deployerXml/virtualRouter/startVirtualRouter.xml", con); deployer.addSpringConfig("VirtualRouter.xml"); deployer.addSpringConfig("VirtualRouterSimulator.xml"); deployer.addSpringConfig("KVMRelated.xml"); deployer.build(); api = deployer.getApi(); loader = deployer.getComponentLoader(); vconfig = loader.getComponent(VirtualRouterSimulatorConfig.class); kconfig = loader.getComponent(KVMSimulatorConfig.class); bus = loader.getComponent(CloudBus.class); dbf = loader.getComponent(DatabaseFacade.class); session = api.loginAsAdmin(); } @Test public void test() throws ApiSenderException { ImageInventory iminv = deployer.images.get("TestImage"); InstanceOfferingInventory ioinv = deployer.instanceOfferings.get("TestInstanceOffering"); L3NetworkInventory l3inv = deployer.l3Networks.get("TestL3Network2"); APICreateVmInstanceMsg msg = new APICreateVmInstanceMsg(); msg.setImageUuid(iminv.getUuid()); msg.setInstanceOfferingUuid(ioinv.getUuid()); List<String> l3uuids = new ArrayList<String>(); l3uuids.add(l3inv.getUuid()); msg.setL3NetworkUuids(l3uuids); msg.setName("TestVm"); msg.setSession(session); msg.setServiceId(ApiMediatorConstant.SERVICE_ID); msg.setType(VmInstanceConstant.USER_VM_TYPE); ApiSender sender = api.getApiSender(); sender.send(msg, APICreateVmInstanceEvent.class); } }
/** * 1. attach a nic to vm 2. detach the nic * * <p>confirm the nic detached successfully */ public class TestDetachNicOnKvm { CLogger logger = Utils.getLogger(TestSftpBackupStorageDeleteImage2.class); Deployer deployer; Api api; ComponentLoader loader; CloudBus bus; DatabaseFacade dbf; SessionInventory session; KVMSimulatorConfig config; @Before public void setUp() throws Exception { DBUtil.reDeployDB(); WebBeanConstructor con = new WebBeanConstructor(); deployer = new Deployer("deployerXml/kvm/TestCreateVmOnKvm.xml", con); deployer.addSpringConfig("KVMRelated.xml"); deployer.build(); api = deployer.getApi(); loader = deployer.getComponentLoader(); bus = loader.getComponent(CloudBus.class); dbf = loader.getComponent(DatabaseFacade.class); config = loader.getComponent(KVMSimulatorConfig.class); session = api.loginAsAdmin(); } @Test public void test() throws ApiSenderException { final L3NetworkInventory l3 = deployer.l3Networks.get("TestL3Network4"); VmInstanceInventory vm = deployer.vms.get("TestVm"); vm = api.attachNic(vm.getUuid(), l3.getUuid()); Assert.assertEquals(4, vm.getVmNics().size()); VmNicInventory nic = vm.getVmNics().get(0); vm = api.detachNic(nic.getUuid()); Assert.assertEquals(3, vm.getVmNics().size()); Assert.assertFalse(config.detachNicCommands.isEmpty()); String l3Uuid = nic.getL3NetworkUuid(); nic = vm.findNic(l3Uuid); Assert.assertNull(nic); api.stopVmInstance(vm.getUuid()); vm = api.startVmInstance(vm.getUuid()); Assert.assertEquals(3, vm.getVmNics().size()); nic = vm.findNic(l3Uuid); Assert.assertNull(nic); } }
public class ComponentLoaderWebListener implements ServletContextListener { private static final CLogger logger = Utils.getLogger(ComponentLoaderWebListener.class); private static boolean isInit = false; private ManagementNodeManager node; private CloudBus bus; @Override public void contextDestroyed(ServletContextEvent arg0) { logger.warn("web listener issued context destroy event, start stropping process"); if (isInit) { throwableSafe( new Runnable() { @Override public void run() { node.stop(); } }); } } @Override public void contextInitialized(ServletContextEvent event) { try { if (!isInit) { Platform.createComponentLoaderFromWebApplicationContext( WebApplicationContextUtils.getWebApplicationContext(event.getServletContext())); node = Platform.getComponentLoader().getComponent(ManagementNodeManager.class); bus = Platform.getComponentLoader().getComponent(CloudBus.class); node.startNode(); isInit = true; } } catch (Throwable t) { logger.warn("failed to start management server", t); // have to call bus.stop() because its init has been called by spring if (bus != null) { bus.stop(); } Throwable root = ExceptionDSL.getRootThrowable(t); new BootErrorLog().write(root.getMessage()); if (CoreGlobalProperty.EXIT_JVM_ON_BOOT_FAILURE) { System.exit(1); } else { throw new CloudRuntimeException(t); } } } }
/** * 1. make the host where the VM runs down * * <p>confirm the VM is HA started on another host */ public class TestHaOnKvm10 { CLogger logger = Utils.getLogger(TestHaOnKvm10.class); Deployer deployer; Api api; ComponentLoader loader; CloudBus bus; DatabaseFacade dbf; SessionInventory session; KVMSimulatorConfig config; HaKvmSimulatorConfig hconfig; @Before public void setUp() throws Exception { DBUtil.reDeployDB(); WebBeanConstructor con = new WebBeanConstructor(); deployer = new Deployer("deployerXml/ha/TestHaOnKvm9.xml", con); deployer.addSpringConfig("KVMRelated.xml"); deployer.addSpringConfig("ha.xml"); deployer.addSpringConfig("haSimulator.xml"); deployer.build(); api = deployer.getApi(); loader = deployer.getComponentLoader(); bus = loader.getComponent(CloudBus.class); dbf = loader.getComponent(DatabaseFacade.class); config = loader.getComponent(KVMSimulatorConfig.class); hconfig = loader.getComponent(HaKvmSimulatorConfig.class); session = api.loginAsAdmin(); } @Test public void test() throws ApiSenderException, InterruptedException { VmInstanceInventory vm1 = deployer.vms.get("TestVm1"); VmInstanceInventory vm2 = deployer.vms.get("TestVm2"); api.setVmHaLevel(vm1.getUuid(), VmHaLevel.NeverStop, null); api.setVmHaLevel(vm2.getUuid(), VmHaLevel.OnHostFailure, null); api.maintainHost(vm1.getHostUuid()); HostInventory host2 = deployer.hosts.get("host2"); VmInstanceVO vmvo1 = dbf.findByUuid(vm1.getUuid(), VmInstanceVO.class); VmInstanceVO vmvo2 = dbf.findByUuid(vm2.getUuid(), VmInstanceVO.class); Assert.assertEquals(VmInstanceState.Running, vmvo1.getState()); Assert.assertEquals(host2.getUuid(), vmvo1.getHostUuid()); Assert.assertEquals(VmInstanceState.Stopped, vmvo2.getState()); } }
/** * 1. don't specify backup storage uuid * * <p>confirm creating image succeeds */ public class TestCreateTemplateFromRootVolume1 { CLogger logger = Utils.getLogger(TestSftpBackupStorageDeleteImage2.class); Deployer deployer; Api api; ComponentLoader loader; CloudBus bus; DatabaseFacade dbf; SessionInventory session; SftpBackupStorageSimulatorConfig config; @Before public void setUp() throws Exception { DBUtil.reDeployDB(); WebBeanConstructor con = new WebBeanConstructor(); deployer = new Deployer("deployerXml/image/TestCreateTemplateFromRootVolume.xml", con); deployer.addSpringConfig("KVMRelated.xml"); deployer.build(); api = deployer.getApi(); loader = deployer.getComponentLoader(); bus = loader.getComponent(CloudBus.class); dbf = loader.getComponent(DatabaseFacade.class); config = loader.getComponent(SftpBackupStorageSimulatorConfig.class); session = api.loginAsAdmin(); } @Test public void test() throws ApiSenderException { VmInstanceInventory vm = deployer.vms.get("TestVm"); api.stopVmInstance(vm.getUuid()); String rootVolumeUuid = vm.getRootVolumeUuid(); VolumeVO vol = dbf.findByUuid(rootVolumeUuid, VolumeVO.class); BackupStorageInventory sftp = deployer.backupStorages.get("sftp"); ImageInventory image = api.createTemplateFromRootVolume("testImage", rootVolumeUuid, (List) null); Assert.assertEquals(sftp.getUuid(), image.getBackupStorageRefs().get(0).getBackupStorageUuid()); Assert.assertEquals(ImageStatus.Ready.toString(), image.getStatus()); Assert.assertEquals(vol.getSize(), image.getSize()); Assert.assertEquals(String.format("volume://%s", vol.getUuid()), image.getUrl()); ImageVO ivo = dbf.findByUuid(image.getUuid(), ImageVO.class); Assert.assertNotNull(ivo); } }
public class TestAsyncBackup6 { CLogger logger = Utils.getLogger(TestAsyncBackup6.class); boolean success; ComponentLoader loader; CloudBus bus; @Before public void setUp() throws Exception { BeanConstructor con = new BeanConstructor(); loader = con.build(); bus = loader.getComponent(CloudBus.class); } @AsyncThread private void testMethod(final Completion completion) { new FlowErrorHandler(completion) { @Override public void handle(ErrorCode errCode, Map data) { throw new RuntimeException("on purpose"); } }.handle(null, null); } @Test public void test() throws InterruptedException { testMethod( new Completion() { @Override public void success() {} @Override public void fail(ErrorCode errorCode) { success = true; logger.debug(errorCode.toString()); } }); TimeUnit.SECONDS.sleep(1); Assert.assertTrue(success); } }
public class SimulatorBackupStorageFactory implements BackupStorageFactory { private static final CLogger logger = Utils.getLogger(SimulatorBackupStorageFactory.class); private static final BackupStorageType type = new BackupStorageType( SimulatorBackupStorageConstant.SIMULATOR_BACKUP_STORAGE_TYPE, CoreGlobalProperty.EXPOSE_SIMULATOR_TYPE, BackupStorageConstant.SCHEME_HTTP, BackupStorageConstant.SCHEME_HTTPS, BackupStorageConstant.SCHEME_NFS); @Autowired private DatabaseFacade dbf; @Autowired private CloudBus bus; @Override public BackupStorageType getBackupStorageType() { return type; } @Override public BackupStorageInventory createBackupStorage( BackupStorageVO vo, APIAddBackupStorageMsg msg) { APIAddSimulatorBackupStorageMsg smsg = (APIAddSimulatorBackupStorageMsg) msg; vo.setTotalCapacity(smsg.getTotalCapacity()); vo.setAvailableCapacity(smsg.getAvailableCapacity()); vo = dbf.persistAndRefresh(vo); return BackupStorageInventory.valueOf(vo); } @Override public BackupStorage getBackupStorage(BackupStorageVO vo) { return new SimulatorBackupStorage(vo); } @Override public BackupStorageInventory reload(String uuid) { BackupStorageVO vo = dbf.findByUuid(uuid, BackupStorageVO.class); return BackupStorageInventory.valueOf(vo); } }
public class TestUpdateDiskOffering { CLogger logger = Utils.getLogger(TestUpdateDiskOffering.class); Api api; ComponentLoader loader; DatabaseFacade dbf; @Before public void setUp() throws Exception { DBUtil.reDeployDB(); BeanConstructor con = new BeanConstructor(); /* This loads spring application context */ loader = con.addXml("ZoneManager.xml") .addXml("PortalForUnitTest.xml") .addXml("ConfigurationManager.xml") .addXml("Simulator.xml") .addXml("PrimaryStorageManager.xml") .addXml("AccountManager.xml") .build(); dbf = loader.getComponent(DatabaseFacade.class); api = new Api(); api.startServer(); } @Test public void test() throws InterruptedException, ApiSenderException { DiskOfferingInventory inv = new DiskOfferingInventory(); inv.setDiskSize(SizeUnit.GIGABYTE.toByte(10)); inv.setName("Test"); inv.setDescription("Test"); inv = api.addDiskOffering(inv); inv.setName("1"); inv.setDescription("xxx"); inv = api.updateDiskOffering(inv); Assert.assertEquals("1", inv.getName()); Assert.assertEquals("xxx", inv.getDescription()); } }
/** * Created with IntelliJ IDEA. User: frank Time: 3:33 PM To change this template use File | Settings * | File Templates. */ public class TestSimpleFlow1 { CLogger logger = Utils.getLogger(TestSimpleFlow1.class); @Test public void test() throws WorkFlowException { final int[] count = {0}; new SimpleFlowChain() .then( new NoRollbackFlow() { @Override public void run(FlowTrigger chain, Map data) { count[0]++; chain.next(); } }) .then( new NoRollbackFlow() { @Override public void run(FlowTrigger chain, Map data) { count[0]++; chain.fail(null); } }) .then( new NoRollbackFlow() { @Override public void run(FlowTrigger chain, Map data) { count[0]++; chain.next(); } }) .start(); Assert.assertEquals(2, count[0]); } }
public class TestKvmAttachL2Network { static CLogger logger = Utils.getLogger(TestKvmAttachL2Network.class); static Deployer deployer; static Api api; static ComponentLoader loader; static CloudBus bus; static DatabaseFacade dbf; static KVMHostFactory kvmFactory; static SessionInventory session; static KVMSimulatorConfig config; @BeforeClass public static void setUp() throws Exception { DBUtil.reDeployDB(); WebBeanConstructor con = new WebBeanConstructor(); deployer = new Deployer("deployerXml/kvm/TestKvmAttachL2Network.xml", con); deployer.addSpringConfig("Kvm.xml"); deployer.addSpringConfig("KVMSimulator.xml"); deployer.build(); api = deployer.getApi(); loader = deployer.getComponentLoader(); kvmFactory = loader.getComponent(KVMHostFactory.class); bus = loader.getComponent(CloudBus.class); dbf = loader.getComponent(DatabaseFacade.class); config = loader.getComponent(KVMSimulatorConfig.class); session = api.loginAsAdmin(); } @Test public void test() throws ApiSenderException { L2NetworkInventory l2 = deployer.l2Networks.get("TestL2Network"); ClusterInventory cluster = deployer.clusters.get("Cluster1"); api.attachL2NetworkToCluster(l2.getUuid(), cluster.getUuid()); Assert.assertEquals(2, config.createBridgeCmds.size()); } }
/** * 1. migrate the vm with local storage * * <p>confirm the volumes of the vm are inc-copied */ public class TestLocalStorage30 { CLogger logger = Utils.getLogger(TestLocalStorage30.class); Deployer deployer; Api api; ComponentLoader loader; CloudBus bus; DatabaseFacade dbf; SessionInventory session; KVMSimulatorConfig kconfig; LocalStorageSimulatorConfig config; PrimaryStorageOverProvisioningManager ratioMgr; long totalSize = SizeUnit.GIGABYTE.toByte(100); @Before public void setUp() throws Exception { DBUtil.reDeployDB(); WebBeanConstructor con = new WebBeanConstructor(); deployer = new Deployer("deployerXml/localStorage/TestLocalStorage30.xml", con); deployer.addSpringConfig("KVMRelated.xml"); deployer.addSpringConfig("localStorageSimulator.xml"); deployer.addSpringConfig("localStorage.xml"); deployer.load(); loader = deployer.getComponentLoader(); bus = loader.getComponent(CloudBus.class); dbf = loader.getComponent(DatabaseFacade.class); config = loader.getComponent(LocalStorageSimulatorConfig.class); kconfig = loader.getComponent(KVMSimulatorConfig.class); ratioMgr = loader.getComponent(PrimaryStorageOverProvisioningManager.class); Capacity c = new Capacity(); c.total = totalSize; c.avail = totalSize; config.capacityMap.put("host1", c); config.capacityMap.put("host2", c); deployer.build(); api = deployer.getApi(); session = api.loginAsAdmin(); } @Test public void test() throws ApiSenderException, InterruptedException { HostInventory host2 = deployer.hosts.get("host2"); HostInventory host1 = deployer.hosts.get("host1"); VmInstanceInventory vm = deployer.vms.get("TestVm"); PrimaryStorageInventory local = deployer.primaryStorages.get("local"); List<VolumeVO> vols = dbf.listAll(VolumeVO.class); List<VolumeVO> volumesOnLocal = new ArrayList<VolumeVO>(); ImageCacheVO cacheVO = dbf.listAll(ImageCacheVO.class).get(0); long imageSize = cacheVO.getSize(); long usedVolumeSize = 0; for (VolumeVO vol : vols) { if (vol.getPrimaryStorageUuid().equals(local.getUuid())) { volumesOnLocal.add(vol); usedVolumeSize += ratioMgr.calculateByRatio(vol.getPrimaryStorageUuid(), vol.getSize()); } } config.createEmptyVolumeCmds.clear(); config.deleteBitsCmds.clear(); vm = api.migrateVmInstance(vm.getUuid(), host2.getUuid()); TimeUnit.SECONDS.sleep(5); LocalStorageHostRefVO ref1 = dbf.findByUuid(host1.getUuid(), LocalStorageHostRefVO.class); Assert.assertEquals(ref1.getTotalCapacity() - imageSize, ref1.getAvailableCapacity()); LocalStorageHostRefVO ref2 = dbf.findByUuid(host2.getUuid(), LocalStorageHostRefVO.class); Assert.assertEquals( ref2.getTotalCapacity() - imageSize - usedVolumeSize, ref2.getAvailableCapacity()); Assert.assertEquals(volumesOnLocal.size(), config.createEmptyVolumeCmds.size()); for (final VolumeVO vol : volumesOnLocal) { // volumes are created on dst host CreateEmptyVolumeCmd cmd = CollectionUtils.find( config.createEmptyVolumeCmds, new Function<CreateEmptyVolumeCmd, CreateEmptyVolumeCmd>() { @Override public CreateEmptyVolumeCmd call(CreateEmptyVolumeCmd arg) { return arg.getVolumeUuid().equals(vol.getUuid()) ? arg : null; } }); Assert.assertNotNull(cmd); Assert.assertEquals(vol.getInstallPath(), cmd.getInstallUrl()); LocalStorageResourceRefVO r = dbf.findByUuid(vol.getUuid(), LocalStorageResourceRefVO.class); Assert.assertEquals(host2.getUuid(), r.getHostUuid()); // volumes are deleted on src host DeleteBitsCmd dcmd = CollectionUtils.find( config.deleteBitsCmds, new Function<DeleteBitsCmd, DeleteBitsCmd>() { @Override public DeleteBitsCmd call(DeleteBitsCmd arg) { return arg.getPath().equals(vol.getInstallPath()) ? arg : null; } }); Assert.assertNotNull( String.format( "no delete command for volume[uuid:%s, path:%s]", vol.getUuid(), vol.getInstallPath()), dcmd); } Assert.assertFalse(kconfig.migrateVmCmds.isEmpty()); MigrateVmCmd mcmd = kconfig.migrateVmCmds.get(0); Assert.assertEquals(host2.getManagementIp(), mcmd.getDestHostIp()); Assert.assertEquals(vm.getUuid(), mcmd.getVmUuid()); Assert.assertEquals( StorageMigrationPolicy.IncCopy.toString(), mcmd.getStorageMigrationPolicy()); } }
/** * 1. attach 50 nic to vm concurrently 2. detach the 50 nic concurrently * * <p>confirm all nics attached/detached successfully */ public class TestDetachNicOnKvm8 { CLogger logger = Utils.getLogger(TestDetachNicOnKvm8.class); Deployer deployer; Api api; ComponentLoader loader; CloudBus bus; DatabaseFacade dbf; SessionInventory session; KVMSimulatorConfig config; @Before public void setUp() throws Exception { DBUtil.reDeployDB(); WebBeanConstructor con = new WebBeanConstructor(); deployer = new Deployer("deployerXml/kvm/TestCreateVmOnKvm.xml", con); deployer.addSpringConfig("KVMRelated.xml"); ThreadGlobalProperty.MAX_THREAD_NUM = 500; deployer.build(); api = deployer.getApi(); loader = deployer.getComponentLoader(); bus = loader.getComponent(CloudBus.class); dbf = loader.getComponent(DatabaseFacade.class); config = loader.getComponent(KVMSimulatorConfig.class); session = api.loginAsAdmin(); } @Test public void test() throws ApiSenderException, InterruptedException { final L3NetworkInventory l3 = deployer.l3Networks.get("TestL3Network4"); VmInstanceInventory vm = deployer.vms.get("TestVm"); APIGetIpAddressCapacityReply ipcap = api.getIpAddressCapacityByAll(); long avail1 = ipcap.getAvailableCapacity(); int num = 50; final CountDownLatch latch = new CountDownLatch(num); final String vmUuid = vm.getUuid(); class Ret { int count; } final Ret ret = new Ret(); for (int i = 0; i < num; i++) { new Runnable() { @Override @AsyncThread public void run() { try { VmInstanceInventory v = api.attachNic(vmUuid, l3.getUuid()); ret.count += 1; } catch (Exception e) { logger.warn(e.getMessage(), e); } finally { latch.countDown(); } } }.run(); } latch.await(120, TimeUnit.SECONDS); VmInstanceVO vmvo = dbf.findByUuid(vmUuid, VmInstanceVO.class); final CountDownLatch latch1 = new CountDownLatch(vmvo.getVmNics().size()); for (final VmNicVO nic : vmvo.getVmNics()) { new Runnable() { @Override @AsyncThread public void run() { try { api.detachNic(nic.getUuid()); } catch (Exception e) { logger.warn(e.getMessage(), e); } finally { latch1.countDown(); } } }.run(); } latch1.await(120, TimeUnit.SECONDS); TimeUnit.SECONDS.sleep(5); ipcap = api.getIpAddressCapacityByAll(); long avail2 = ipcap.getAvailableCapacity(); Assert.assertEquals(avail1, avail2 - 3); } }
public class TestCreate1000Vm2 { CLogger logger = Utils.getLogger(TestCreate1000Vm2.class); Deployer deployer; Api api; ComponentLoader loader; CloudBus bus; DatabaseFacade dbf; int vmNum = 500000; CountDownLatch latch = new CountDownLatch(vmNum); List<Long> timeCost = new ArrayList<Long>(); @Before public void setUp() throws Exception { // DBUtil.reDeployDB(); WebBeanConstructor con = new WebBeanConstructor(); con.addAllConfigInZstackXml(); loader = con.build(); bus = loader.getComponent(CloudBus.class); dbf = loader.getComponent(DatabaseFacade.class); api = new Api(); api.startServer(); api.setTimeout(600); } @SyncThread(level = 1000) private void createVm( VmInstanceInventory vm, String rootDiskUuid, List<String> nws, List<String> disks) throws ApiSenderException { StopWatch watch = new StopWatch(); watch.start(); try { api.createVmByFullConfig(vm, rootDiskUuid, nws, disks); } finally { watch.stop(); timeCost.add(watch.getTime()); latch.countDown(); } } @Test public void test() throws ApiSenderException, InterruptedException { CoreGlobalProperty.VM_TRACER_ON = false; IdentityGlobalConfig.SESSION_TIMEOUT.updateValue(TimeUnit.HOURS.toSeconds(1000)); api.prepare(); InstanceOfferingInventory ioinv = api.listInstanceOffering(null).get(0); ImageInventory iminv = api.listImage(null).get(0); List<DiskOfferingInventory> dinvs = api.listDiskOffering(null); List<L3NetworkInventory> nwinvs = api.listL3Network(null); List<String> nws = new ArrayList<String>(nwinvs.size()); for (L3NetworkInventory nwinv : nwinvs) { nws.add(nwinv.getUuid()); } for (int i = 0; i < vmNum; i++) { VmInstanceInventory vm = new VmInstanceInventory(); vm.setDescription("TestVm"); vm.setName("TestVm"); vm.setType(VmInstanceConstant.USER_VM_TYPE); vm.setInstanceOfferingUuid(ioinv.getUuid()); vm.setImageUuid(iminv.getUuid()); createVm(vm, dinvs.get(0).getUuid(), nws, new ArrayList<String>()); } latch.await(600, TimeUnit.MINUTES); long totalTime = 0; long minTime = 0; long maxTime = 0; for (Long t : timeCost) { minTime = Math.min(minTime, t); maxTime = Math.max(maxTime, t); totalTime += t; } System.out.println( String.format( "total time: %s, min time: %s, max time: %s, avg time: %s", TimeUnit.MILLISECONDS.toSeconds(totalTime), TimeUnit.MILLISECONDS.toSeconds(minTime), TimeUnit.MILLISECONDS.toSeconds(maxTime), TimeUnit.MILLISECONDS.toSeconds(totalTime / timeCost.size()))); /* SimpleQuery<VmInstanceVO> q = dbf.createQuery(VmInstanceVO.class); q.add(VmInstanceVO_.state, Op.EQ, VmInstanceState.Running); long count = q.count(); Assert.assertEquals(vmNum, count); */ TimeUnit.HOURS.sleep(1000); } }
public class TestChainTask4 { CLogger logger = Utils.getLogger(TestChainTask4.class); ComponentLoader loader; ThreadFacade thdf; int threadNum = 100000; List<Integer> res = new ArrayList<Integer>(threadNum); CountDownLatch latch = new CountDownLatch(threadNum); class Tester extends ChainTask { int index; Tester(int index) { this.index = index; } @Override public String getName() { return "Test"; } @Override public String getSyncSignature() { return "Test"; } @Override public void run(SyncTaskChain chain) { logger.debug(String.valueOf(index)); synchronized (res) { res.add(index); } latch.countDown(); /* try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } */ chain.next(); } @Override protected int getSyncLevel() { return 10; } } @Before public void setUp() throws Exception { BeanConstructor con = new BeanConstructor(); loader = con.build(); thdf = loader.getComponent(ThreadFacade.class); } @Test public void test() throws InterruptedException { for (int i = 0; i < threadNum; i++) { Tester t = new Tester(i); thdf.chainSubmit(t); } latch.await(2, TimeUnit.MINUTES); Assert.assertEquals(threadNum, res.size()); } }
public class RandomIpAllocatorStrategy extends AbstractIpAllocatorStrategy { private static final CLogger logger = Utils.getLogger(RandomIpAllocatorStrategy.class); public static final IpAllocatorType type = new IpAllocatorType(L3NetworkConstant.RANDOM_IP_ALLOCATOR_STRATEGY); @Override public IpAllocatorType getType() { return type; } @Override public UsedIpInventory allocateIp(IpAllocateMessage msg) { if (msg.getRequiredIp() != null) { return allocateRequiredIp(msg); } SimpleQuery<IpRangeVO> query = dbf.createQuery(IpRangeVO.class); query.add(IpRangeVO_.l3NetworkUuid, Op.EQ, msg.getL3NetworkUuid()); List<IpRangeVO> ranges = query.list(); Collections.shuffle(ranges); do { String ip = null; IpRangeVO tr = null; for (IpRangeVO r : ranges) { ip = allocateIp(r); tr = r; if (ip != null) { break; } } if (ip == null) { /* No available ip in ranges */ return null; } UsedIpInventory inv = l3NwMgr.reserveIp(IpRangeInventory.valueOf(tr), ip); if (inv != null) { return inv; } } while (true); } private String steppingAllocate(long s, long e, int total, String rangeUuid) { int step = 254; int failureCount = 0; int failureCheckPoint = 5; while (s < e) { // if failing failureCheckPoint times, the range is probably full, // we check the range. // why don't we check before steppingAllocate()? because in that case we // have to count the used IP every time allocating a IP, and count operation // is a full scan in DB, which is very costly if (failureCheckPoint == failureCount++) { SimpleQuery<UsedIpVO> q = dbf.createQuery(UsedIpVO.class); q.add(UsedIpVO_.ipRangeUuid, Op.EQ, rangeUuid); long count = q.count(); if (count == total) { logger.debug( String.format("ip range[uuid:%s] has no ip available, try next one", rangeUuid)); return null; } else { failureCount = 0; } } long te = s + step; te = te > e ? e : te; SimpleQuery<UsedIpVO> q = dbf.createQuery(UsedIpVO.class); q.select(UsedIpVO_.ipInLong); q.add(UsedIpVO_.ipInLong, Op.GTE, s); q.add(UsedIpVO_.ipInLong, Op.LTE, te); q.add(UsedIpVO_.ipRangeUuid, Op.EQ, rangeUuid); List<Long> used = q.listValue(); if (te - s + 1 == used.size()) { s += step; continue; } Collections.sort(used); return NetworkUtils.randomAllocateIpv4Address(s, te, used); } return null; } private String allocateIp(IpRangeVO vo) { int total = vo.size(); Random random = new Random(); long s = random.nextInt(total) + NetworkUtils.ipv4StringToLong(vo.getStartIp()); long e = NetworkUtils.ipv4StringToLong(vo.getEndIp()); String ret = steppingAllocate(s, e, total, vo.getUuid()); if (ret != null) { return ret; } e = s; s = NetworkUtils.ipv4StringToLong(vo.getStartIp()); return steppingAllocate(s, e, total, vo.getUuid()); } }
/** Created by frank on 6/30/2015. */ public class LocalStorageFactory implements PrimaryStorageFactory, Component, MarshalVmOperationFlowExtensionPoint, HostDeleteExtensionPoint, VmAttachVolumeExtensionPoint, GetAttachableVolumeExtensionPoint, RecalculatePrimaryStorageCapacityExtensionPoint, HostMaintenancePolicyExtensionPoint, AddExpandedQueryExtensionPoint, VolumeGetAttachableVmExtensionPoint, RecoverDataVolumeExtensionPoint, RecoverVmExtensionPoint, VmPreMigrationExtensionPoint, CreateTemplateFromVolumeSnapshotExtensionPoint, HostAfterConnectedExtensionPoint { private static final CLogger logger = Utils.getLogger(LocalStorageFactory.class); public static PrimaryStorageType type = new PrimaryStorageType(LocalStorageConstants.LOCAL_STORAGE_TYPE); static { type.setSupportVmLiveMigration(false); type.setSupportVolumeMigration(true); type.setSupportVolumeMigrationInCurrentPrimaryStorage(true); type.setOrder(999); } @Autowired private DatabaseFacade dbf; @Autowired private PluginRegistry pluginRgty; @Autowired private CloudBus bus; @Autowired private ErrorFacade errf; private Map<String, LocalStorageBackupStorageMediator> backupStorageMediatorMap = new HashMap<String, LocalStorageBackupStorageMediator>(); @Override public WorkflowTemplate createTemplateFromVolumeSnapshot(final ParamIn paramIn) { WorkflowTemplate template = new WorkflowTemplate(); class Context { String temporaryInstallPath; String hostUuid; } final Context ctx = new Context(); template.setCreateTemporaryTemplate( new Flow() { String __name__ = "create-temporary-template"; @Override public void run(final FlowTrigger trigger, final Map data) { CreateTemporaryVolumeFromSnapshotMsg msg = new CreateTemporaryVolumeFromSnapshotMsg(); msg.setSnapshot(paramIn.getSnapshot()); msg.setPrimaryStorageUuid(paramIn.getPrimaryStorageUuid()); msg.setImageUuid(paramIn.getImage().getUuid()); bus.makeTargetServiceIdByResourceUuid( msg, PrimaryStorageConstant.SERVICE_ID, paramIn.getPrimaryStorageUuid()); bus.send( msg, new CloudBusCallBack(trigger) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { trigger.fail(reply.getError()); } else { ParamOut out = (ParamOut) data.get(ParamOut.class); CreateTemporaryVolumeFromSnapshotReply r = reply.castReply(); out.setActualSize(r.getActualSize()); out.setSize(r.getSize()); ctx.temporaryInstallPath = r.getInstallPath(); ctx.hostUuid = r.getHostUuid(); trigger.next(); } } }); } @Override public void rollback(FlowRollback trigger, Map data) { if (ctx.temporaryInstallPath != null) { LocalStorageDirectlyDeleteBitsMsg msg = new LocalStorageDirectlyDeleteBitsMsg(); msg.setPrimaryStorageUuid(paramIn.getPrimaryStorageUuid()); msg.setHostUuid(ctx.hostUuid); msg.setPath(ctx.temporaryInstallPath); bus.makeTargetServiceIdByResourceUuid( msg, PrimaryStorageConstant.SERVICE_ID, paramIn.getPrimaryStorageUuid()); bus.send(msg); } trigger.rollback(); } }); template.setUploadToBackupStorage( new Flow() { String __name__ = "upload-to-backup-storage"; @Override public void run(final FlowTrigger trigger, final Map data) { BackupStorageAskInstallPathMsg ask = new BackupStorageAskInstallPathMsg(); ask.setBackupStorageUuid(paramIn.getBackupStorageUuid()); ask.setImageMediaType(paramIn.getImage().getMediaType()); ask.setImageUuid(paramIn.getImage().getUuid()); bus.makeTargetServiceIdByResourceUuid( ask, BackupStorageConstant.SERVICE_ID, paramIn.getBackupStorageUuid()); MessageReply areply = bus.call(ask); if (!areply.isSuccess()) { trigger.fail(areply.getError()); return; } String bsInstallPath = ((BackupStorageAskInstallPathReply) areply).getInstallPath(); UploadBitsFromLocalStorageToBackupStorageMsg msg = new UploadBitsFromLocalStorageToBackupStorageMsg(); msg.setHostUuid(ctx.hostUuid); msg.setPrimaryStorageInstallPath(ctx.temporaryInstallPath); msg.setPrimaryStorageUuid(paramIn.getPrimaryStorageUuid()); msg.setBackupStorageUuid(paramIn.getBackupStorageUuid()); msg.setBackupStorageInstallPath(bsInstallPath); bus.makeTargetServiceIdByResourceUuid( msg, PrimaryStorageConstant.SERVICE_ID, paramIn.getPrimaryStorageUuid()); bus.send( msg, new CloudBusCallBack(trigger) { @Override public void run(MessageReply reply) { ParamOut out = (ParamOut) data.get(ParamOut.class); if (!reply.isSuccess()) { trigger.fail(reply.getError()); } else { out.setBackupStorageInstallPath(bsInstallPath); trigger.next(); } } }); } @Override public void rollback(FlowRollback trigger, Map data) { ParamOut out = (ParamOut) data.get(ParamOut.class); if (out.getBackupStorageInstallPath() != null) { DeleteBitsOnBackupStorageMsg msg = new DeleteBitsOnBackupStorageMsg(); msg.setBackupStorageUuid(paramIn.getBackupStorageUuid()); msg.setInstallPath(out.getBackupStorageInstallPath()); bus.makeTargetServiceIdByResourceUuid( msg, BackupStorageConstant.SERVICE_ID, paramIn.getBackupStorageUuid()); bus.send(msg); } trigger.rollback(); } }); template.setDeleteTemporaryTemplate( new NoRollbackFlow() { String __name__ = "delete-temporary-volume"; @Override public void run(FlowTrigger trigger, Map data) { LocalStorageDirectlyDeleteBitsMsg msg = new LocalStorageDirectlyDeleteBitsMsg(); msg.setHostUuid(ctx.hostUuid); msg.setPath(ctx.temporaryInstallPath); msg.setPrimaryStorageUuid(paramIn.getPrimaryStorageUuid()); bus.makeTargetServiceIdByResourceUuid( msg, PrimaryStorageConstant.SERVICE_ID, paramIn.getPrimaryStorageUuid()); bus.send(msg); trigger.next(); } }); return template; } @Override public String createTemplateFromVolumeSnapshotPrimaryStorageType() { return type.toString(); } @Override public String getPrimaryStorageTypeForRecalculateCapacityExtensionPoint() { return type.toString(); } @Override public void afterRecalculatePrimaryStorageCapacity( RecalculatePrimaryStorageCapacityStruct struct) { new LocalStorageCapacityRecalculator() .calculateByPrimaryStorageUuid(struct.getPrimaryStorageUuid()); } @Override public void beforeRecalculatePrimaryStorageCapacity( RecalculatePrimaryStorageCapacityStruct struct) { new LocalStorageCapacityRecalculator().calculateTotalCapacity(struct.getPrimaryStorageUuid()); } @Override public PrimaryStorageType getPrimaryStorageType() { return type; } @Override public PrimaryStorageInventory createPrimaryStorage( PrimaryStorageVO vo, APIAddPrimaryStorageMsg msg) { vo.setMountPath(msg.getUrl()); vo = dbf.persistAndRefresh(vo); return PrimaryStorageInventory.valueOf(vo); } @Override public PrimaryStorage getPrimaryStorage(PrimaryStorageVO vo) { return new LocalStorageBase(vo); } @Override public PrimaryStorageInventory getInventory(String uuid) { return PrimaryStorageInventory.valueOf(dbf.findByUuid(uuid, PrimaryStorageVO.class)); } private String makeMediatorKey(String hvType, String bsType) { return hvType + "-" + bsType; } public LocalStorageBackupStorageMediator getBackupStorageMediator(String hvType, String bsType) { LocalStorageBackupStorageMediator m = backupStorageMediatorMap.get(makeMediatorKey(hvType, bsType)); if (m == null) { throw new CloudRuntimeException( String.format( "no LocalStorageBackupStorageMediator supporting hypervisor[%s] and backup storage[%s] ", hvType, bsType)); } return m; } @Override public boolean start() { for (LocalStorageBackupStorageMediator m : pluginRgty.getExtensionList(LocalStorageBackupStorageMediator.class)) { for (String hvType : m.getSupportedHypervisorTypes()) { String key = makeMediatorKey(hvType, m.getSupportedBackupStorageType().toString()); LocalStorageBackupStorageMediator old = backupStorageMediatorMap.get(key); if (old != null) { throw new CloudRuntimeException( String.format( "duplicate LocalStorageBackupStorageMediator[%s, %s] for hypervisor type[%s] and backup storage type[%s]", m, old, hvType, m.getSupportedBackupStorageType())); } backupStorageMediatorMap.put(key, m); } } return true; } @Override public boolean stop() { return true; } @Transactional(readOnly = true) private String getLocalStorageInCluster(String clusterUuid) { String sql = "select pri.uuid from PrimaryStorageVO pri, PrimaryStorageClusterRefVO ref where pri.uuid = ref.primaryStorageUuid and ref.clusterUuid = :cuuid and pri.type = :ptype"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("cuuid", clusterUuid); q.setParameter("ptype", LocalStorageConstants.LOCAL_STORAGE_TYPE); List<String> ret = q.getResultList(); if (ret.isEmpty()) { return null; } return ret.get(0); } private boolean isRootVolumeOnLocalStorage(String rootVolumeUuid) { SimpleQuery<LocalStorageResourceRefVO> q = dbf.createQuery(LocalStorageResourceRefVO.class); q.add(LocalStorageResourceRefVO_.resourceUuid, Op.EQ, rootVolumeUuid); return q.isExists(); } @Override public Flow marshalVmOperationFlow( String previousFlowName, String nextFlowName, FlowChain chain, VmInstanceSpec spec) { if (VmAllocatePrimaryStorageFlow.class.getName().equals(nextFlowName)) { if (spec.getCurrentVmOperation() == VmOperation.NewCreate) { if (getLocalStorageInCluster(spec.getDestHost().getClusterUuid()) != null) { return new LocalStorageAllocateCapacityFlow(); } } } else if (spec.getCurrentVmOperation() == VmOperation.AttachVolume) { VolumeInventory volume = spec.getDestDataVolumes().get(0); if (VolumeStatus.NotInstantiated.toString().equals(volume.getStatus()) && VmAllocatePrimaryStorageForAttachingDiskFlow.class.getName().equals(nextFlowName)) { if (isRootVolumeOnLocalStorage(spec.getVmInventory().getRootVolumeUuid())) { return new LocalStorageAllocateCapacityForAttachingVolumeFlow(); } } } else if (spec.getCurrentVmOperation() == VmOperation.Migrate && isRootVolumeOnLocalStorage(spec.getVmInventory().getRootVolumeUuid()) && VmMigrateOnHypervisorFlow.class.getName().equals(nextFlowName)) { if (KVMConstant.KVM_HYPERVISOR_TYPE.equals(spec.getVmInventory().getHypervisorType())) { return new LocalStorageKvmMigrateVmFlow(); } else { throw new OperationFailureException( errf.stringToOperationError( String.format( "local storage doesn't support live migration for hypervisor[%s]", spec.getVmInventory().getHypervisorType()))); } } return null; } @Override public void preDeleteHost(HostInventory inventory) throws HostException {} @Override public void beforeDeleteHost(final HostInventory inventory) { SimpleQuery<LocalStorageHostRefVO> q = dbf.createQuery(LocalStorageHostRefVO.class); q.select(LocalStorageHostRefVO_.primaryStorageUuid); q.add(LocalStorageHostRefVO_.hostUuid, Op.EQ, inventory.getUuid()); final String psUuid = q.findValue(); if (psUuid == null) { return; } logger.debug( String.format( "the host[uuid:%s] belongs to the local storage[uuid:%s], starts to delete vms and" + " volumes on the host", inventory.getUuid(), psUuid)); final List<String> vmUuids = new Callable<List<String>>() { @Override @Transactional(readOnly = true) public List<String> call() { String sql = "select vm.uuid from VolumeVO vol, LocalStorageResourceRefVO ref, VmInstanceVO vm where ref.primaryStorageUuid = :psUuid" + " and vol.type = :vtype and ref.resourceUuid = vol.uuid and ref.resourceType = :rtype and ref.hostUuid = :huuid" + " and vm.uuid = vol.vmInstanceUuid"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("vtype", VolumeType.Root); q.setParameter("rtype", VolumeVO.class.getSimpleName()); q.setParameter("huuid", inventory.getUuid()); q.setParameter("psUuid", psUuid); return q.getResultList(); } }.call(); // destroy vms if (!vmUuids.isEmpty()) { List<DestroyVmInstanceMsg> msgs = CollectionUtils.transformToList( vmUuids, new Function<DestroyVmInstanceMsg, String>() { @Override public DestroyVmInstanceMsg call(String uuid) { DestroyVmInstanceMsg msg = new DestroyVmInstanceMsg(); msg.setVmInstanceUuid(uuid); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, uuid); return msg; } }); final FutureCompletion completion = new FutureCompletion(); bus.send( msgs, new CloudBusListCallBack(completion) { @Override public void run(List<MessageReply> replies) { for (MessageReply r : replies) { if (!r.isSuccess()) { String vmUuid = vmUuids.get(replies.indexOf(r)); // TODO logger.warn( String.format("failed to destroy the vm[uuid:%s], %s", vmUuid, r.getError())); } } completion.success(); } }); completion.await(TimeUnit.MINUTES.toMillis(15)); } final List<String> volUuids = new Callable<List<String>>() { @Override @Transactional(readOnly = true) public List<String> call() { String sql = "select vol.uuid from VolumeVO vol, LocalStorageResourceRefVO ref where ref.primaryStorageUuid = :psUuid" + " and vol.type = :vtype and ref.resourceUuid = vol.uuid and ref.resourceType = :rtype and ref.hostUuid = :huuid"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("psUuid", psUuid); q.setParameter("vtype", VolumeType.Data); q.setParameter("rtype", VolumeVO.class.getSimpleName()); q.setParameter("huuid", inventory.getUuid()); return q.getResultList(); } }.call(); // delete data volumes if (!volUuids.isEmpty()) { List<DeleteVolumeMsg> msgs = CollectionUtils.transformToList( volUuids, new Function<DeleteVolumeMsg, String>() { @Override public DeleteVolumeMsg call(String uuid) { DeleteVolumeMsg msg = new DeleteVolumeMsg(); msg.setUuid(uuid); msg.setDetachBeforeDeleting(true); bus.makeTargetServiceIdByResourceUuid(msg, VolumeConstant.SERVICE_ID, uuid); return msg; } }); final FutureCompletion completion = new FutureCompletion(); bus.send( msgs, new CloudBusListCallBack(completion) { @Override public void run(List<MessageReply> replies) { for (MessageReply r : replies) { if (!r.isSuccess()) { String uuid = volUuids.get(replies.indexOf(r)); // TODO logger.warn( String.format( "failed to delete the data volume[uuid:%s], %s", uuid, r.getError())); } } completion.success(); } }); completion.await(TimeUnit.MINUTES.toMillis(15)); } } @Override public void afterDeleteHost(final HostInventory inventory) { final String priUuid = getLocalStorageInCluster(inventory.getClusterUuid()); if (priUuid != null) { RemoveHostFromLocalStorageMsg msg = new RemoveHostFromLocalStorageMsg(); msg.setPrimaryStorageUuid(priUuid); msg.setHostUuid(inventory.getUuid()); bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, priUuid); MessageReply reply = bus.call(msg); if (!reply.isSuccess()) { // TODO logger.warn( String.format( "failed to remove host[uuid:%s] from local primary storage[uuid:%s], %s", inventory.getUuid(), priUuid, reply.getError())); } else { logger.debug( String.format( "removed host[uuid:%s] from local primary storage[uuid:%s]", inventory.getUuid(), priUuid)); } } } @Override public void preAttachVolume(VmInstanceInventory vm, final VolumeInventory volume) { SimpleQuery<LocalStorageResourceRefVO> q = dbf.createQuery(LocalStorageResourceRefVO.class); q.add( LocalStorageResourceRefVO_.resourceUuid, Op.IN, list(vm.getRootVolumeUuid(), volume.getUuid())); q.groupBy(LocalStorageResourceRefVO_.hostUuid); long count = q.count(); if (count < 2) { return; } q = dbf.createQuery(LocalStorageResourceRefVO.class); q.select(LocalStorageResourceRefVO_.hostUuid); q.add(LocalStorageResourceRefVO_.resourceUuid, Op.EQ, vm.getRootVolumeUuid()); String rootHost = q.findValue(); q = dbf.createQuery(LocalStorageResourceRefVO.class); q.select(LocalStorageResourceRefVO_.hostUuid); q.add(LocalStorageResourceRefVO_.resourceUuid, Op.EQ, volume.getUuid()); String dataHost = q.findValue(); if (!rootHost.equals(dataHost)) { throw new OperationFailureException( errf.stringToOperationError( String.format( "cannot attach the data volume[uuid:%s] to the vm[uuid:%s]. Both vm's root volume and the data volume are" + " on local primary storage, but they are on different hosts. The root volume[uuid:%s] is on the host[uuid:%s] but the data volume[uuid: %s]" + " is on the host[uuid: %s]", volume.getUuid(), vm.getUuid(), vm.getRootVolumeUuid(), rootHost, volume.getUuid(), dataHost))); } } @Override public void beforeAttachVolume(VmInstanceInventory vm, VolumeInventory volume) {} @Override public void afterAttachVolume(VmInstanceInventory vm, VolumeInventory volume) {} @Override public void failedToAttachVolume( VmInstanceInventory vm, VolumeInventory volume, ErrorCode errorCode) {} @Override @Transactional(readOnly = true) public List<VolumeVO> returnAttachableVolumes(VmInstanceInventory vm, List<VolumeVO> candidates) { // find instantiated volumes List<String> volUuids = CollectionUtils.transformToList( candidates, new Function<String, VolumeVO>() { @Override public String call(VolumeVO arg) { return VolumeStatus.Ready == arg.getStatus() ? arg.getUuid() : null; } }); if (volUuids.isEmpty()) { return candidates; } List<VolumeVO> uninstantiatedVolumes = CollectionUtils.transformToList( candidates, new Function<VolumeVO, VolumeVO>() { @Override public VolumeVO call(VolumeVO arg) { return arg.getStatus() == VolumeStatus.NotInstantiated ? arg : null; } }); String sql = "select ref.hostUuid from LocalStorageResourceRefVO ref where ref.resourceUuid = :volUuid and ref.resourceType = :rtype"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("volUuid", vm.getRootVolumeUuid()); q.setParameter("rtype", VolumeVO.class.getSimpleName()); List<String> ret = q.getResultList(); if (ret.isEmpty()) { return candidates; } String hostUuid = ret.get(0); sql = "select ref.resourceUuid from LocalStorageResourceRefVO ref where ref.resourceUuid in (:uuids) and ref.resourceType = :rtype" + " and ref.hostUuid != :huuid"; q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("uuids", volUuids); q.setParameter("huuid", hostUuid); q.setParameter("rtype", VolumeVO.class.getSimpleName()); final List<String> toExclude = q.getResultList(); candidates = CollectionUtils.transformToList( candidates, new Function<VolumeVO, VolumeVO>() { @Override public VolumeVO call(VolumeVO arg) { return toExclude.contains(arg.getUuid()) ? null : arg; } }); candidates.addAll(uninstantiatedVolumes); return candidates; } @Override @Transactional(readOnly = true) public HostMaintenancePolicy getHostMaintenancePolicy(HostInventory host) { String sql = "select count(ps) from PrimaryStorageVO ps, PrimaryStorageClusterRefVO ref where ps.uuid = ref.primaryStorageUuid" + " and ps.type = :type and ref.clusterUuid = :cuuid"; TypedQuery<Long> q = dbf.getEntityManager().createQuery(sql, Long.class); q.setParameter("type", LocalStorageConstants.LOCAL_STORAGE_TYPE); q.setParameter("cuuid", host.getClusterUuid()); q.setMaxResults(1); Long count = q.getSingleResult(); return count > 0 ? HostMaintenancePolicy.StopVm : null; } @Override public List<ExpandedQueryStruct> getExpandedQueryStructs() { List<ExpandedQueryStruct> structs = new ArrayList<ExpandedQueryStruct>(); ExpandedQueryStruct s = new ExpandedQueryStruct(); s.setExpandedField("localStorageHostRef"); s.setExpandedInventoryKey("resourceUuid"); s.setForeignKey("uuid"); s.setInventoryClass(LocalStorageResourceRefInventory.class); s.setInventoryClassToExpand(VolumeInventory.class); structs.add(s); s = new ExpandedQueryStruct(); s.setExpandedField("localStorageHostRef"); s.setExpandedInventoryKey("resourceUuid"); s.setForeignKey("uuid"); s.setInventoryClass(LocalStorageResourceRefInventory.class); s.setInventoryClassToExpand(VolumeSnapshotInventory.class); structs.add(s); return structs; } @Override public List<ExpandedQueryAliasStruct> getExpandedQueryAliasesStructs() { return null; } @Override @Transactional(readOnly = true) public List<VmInstanceVO> returnAttachableVms( VolumeInventory vol, List<VmInstanceVO> candidates) { String sql = "select ref.hostUuid from LocalStorageResourceRefVO ref where ref.resourceUuid = :uuid" + " and ref.resourceType = :rtype"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("uuid", vol.getUuid()); q.setParameter("rtype", VolumeVO.class.getSimpleName()); List<String> ret = q.getResultList(); if (ret.isEmpty()) { return candidates; } String hostUuid = ret.get(0); List<String> vmRootVolumeUuids = CollectionUtils.transformToList( candidates, new Function<String, VmInstanceVO>() { @Override public String call(VmInstanceVO arg) { return arg.getRootVolumeUuid(); } }); sql = "select ref.resourceUuid from LocalStorageResourceRefVO ref where ref.hostUuid = :huuid" + " and ref.resourceUuid in (:rootVolumeUuids) and ref.resourceType = :rtype"; q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("huuid", hostUuid); q.setParameter("rootVolumeUuids", vmRootVolumeUuids); q.setParameter("rtype", VolumeVO.class.getSimpleName()); final List<String> toInclude = q.getResultList(); candidates = CollectionUtils.transformToList( candidates, new Function<VmInstanceVO, VmInstanceVO>() { @Override public VmInstanceVO call(VmInstanceVO arg) { return toInclude.contains(arg.getRootVolumeUuid()) ? arg : null; } }); return candidates; } @Override public void preRecoverDataVolume(VolumeInventory vol) { if (vol.getPrimaryStorageUuid() == null) { return; } SimpleQuery<PrimaryStorageVO> q = dbf.createQuery(PrimaryStorageVO.class); q.select(PrimaryStorageVO_.type); q.add(PrimaryStorageVO_.uuid, Op.EQ, vol.getPrimaryStorageUuid()); String type = q.findValue(); if (!LocalStorageConstants.LOCAL_STORAGE_TYPE.equals(type)) { return; } SimpleQuery<LocalStorageResourceRefVO> rq = dbf.createQuery(LocalStorageResourceRefVO.class); rq.add(LocalStorageResourceRefVO_.resourceUuid, Op.EQ, vol.getUuid()); rq.add(LocalStorageResourceRefVO_.resourceType, Op.EQ, VolumeVO.class.getSimpleName()); if (!rq.isExists()) { throw new OperationFailureException( errf.stringToOperationError( String.format( "the data volume[name:%s, uuid:%s] is on the local storage[uuid:%s]; however," + "the host on which the data volume is has been deleted. Unable to recover this volume", vol.getName(), vol.getUuid(), vol.getPrimaryStorageUuid()))); } } @Override public void beforeRecoverDataVolume(VolumeInventory vol) {} @Override public void afterRecoverDataVolume(VolumeInventory vol) {} @Override @Transactional(readOnly = true) public void preRecoverVm(VmInstanceInventory vm) { String rootVolUuid = vm.getRootVolumeUuid(); String sql = "select ps.uuid from PrimaryStorageVO ps, VolumeVO vol where ps.uuid = vol.primaryStorageUuid" + " and vol.uuid = :uuid and ps.type = :pstype"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("uuid", rootVolUuid); q.setParameter("pstype", LocalStorageConstants.LOCAL_STORAGE_TYPE); String psuuid = dbf.find(q); if (psuuid == null) { return; } sql = "select count(ref) from LocalStorageResourceRefVO ref where ref.resourceUuid = :uuid and ref.resourceType = :rtype"; TypedQuery<Long> rq = dbf.getEntityManager().createQuery(sql, Long.class); rq.setParameter("uuid", rootVolUuid); rq.setParameter("rtype", VolumeVO.class.getSimpleName()); long count = rq.getSingleResult(); if (count == 0) { throw new OperationFailureException( errf.stringToOperationError( String.format( "unable to recover the vm[uuid:%s, name:%s]. The vm's root volume is on the local" + " storage[uuid:%s]; however, the host on which the root volume is has been deleted", vm.getUuid(), vm.getName(), psuuid))); } } @Override public void beforeRecoverVm(VmInstanceInventory vm) {} @Override public void afterRecoverVm(VmInstanceInventory vm) {} @Override @Transactional( readOnly = true, noRollbackForClassName = {"org.zstack.header.errorcode.OperationFailureException"}) public void preVmMigration(VmInstanceInventory vm) { List<String> volUuids = CollectionUtils.transformToList( vm.getAllVolumes(), new Function<String, VolumeInventory>() { @Override public String call(VolumeInventory arg) { return arg.getUuid(); } }); String sql = "select count(ps) from PrimaryStorageVO ps, VolumeVO vol where ps.uuid = vol.primaryStorageUuid and" + " vol.uuid in (:volUuids) and ps.type = :ptype"; TypedQuery<Long> q = dbf.getEntityManager().createQuery(sql, Long.class); q.setParameter("volUuids", volUuids); q.setParameter("ptype", LocalStorageConstants.LOCAL_STORAGE_TYPE); q.setMaxResults(1); Long count = q.getSingleResult(); if (count > 0) { throw new OperationFailureException( errf.stringToOperationError( String.format( "unable to live migrate with local storage. The vm[uuid:%s] has volumes on local storage," + "to protect your data, please stop the vm and do the volume migration", vm.getUuid()))); } } @Override public void afterHostConnected(HostInventory host) { SimpleQuery<LocalStorageHostRefVO> q = dbf.createQuery(LocalStorageHostRefVO.class); q.add(LocalStorageHostRefVO_.hostUuid, Op.EQ, host.getUuid()); LocalStorageHostRefVO ref = q.find(); if (ref != null) { RecalculatePrimaryStorageCapacityMsg msg = new RecalculatePrimaryStorageCapacityMsg(); msg.setPrimaryStorageUuid(ref.getPrimaryStorageUuid()); bus.makeTargetServiceIdByResourceUuid( msg, PrimaryStorageConstant.SERVICE_ID, ref.getPrimaryStorageUuid()); bus.send(msg); } } }
public class VmCascadeExtension extends AbstractAsyncCascadeExtension { private static final CLogger logger = Utils.getLogger(VmCascadeExtension.class); @Autowired private DatabaseFacade dbf; @Autowired protected VmInstanceExtensionPointEmitter extEmitter; @Autowired private CloudBus bus; private static final String NAME = VmInstanceVO.class.getSimpleName(); private static final int OP_NOPE = 0; private static final int OP_STOP = 1; private static final int OP_DELETION = 2; private static final int OP_REMOVE_INSTANCE_OFFERING = 3; private static final int OP_DETACH_NIC = 4; private int toDeletionOpCode(CascadeAction action) { if (!CascadeConstant.DELETION_CODES.contains(action.getActionCode())) { return OP_NOPE; } if (PrimaryStorageVO.class.getSimpleName().equals(action.getParentIssuer())) { return OP_DELETION; } if (HostVO.class.getSimpleName().equals(action.getParentIssuer())) { if (ZoneVO.class.getSimpleName().equals(action.getRootIssuer())) { return OP_DELETION; } else { return OP_STOP; } } if (L3NetworkVO.class.getSimpleName().equals(action.getParentIssuer())) { return OP_DETACH_NIC; } if (IpRangeVO.class.getSimpleName().equals(action.getParentIssuer()) && IpRangeVO.class.getSimpleName().equals(action.getRootIssuer())) { return OP_STOP; } if (VmInstanceVO.class.getSimpleName().equals(action.getParentIssuer())) { return OP_DELETION; } if (InstanceOfferingVO.class.getSimpleName().equals(action.getParentIssuer())) { return OP_REMOVE_INSTANCE_OFFERING; } if (AccountVO.class.getSimpleName().equals(action.getParentIssuer())) { return OP_DELETION; } return OP_NOPE; } @Override public void asyncCascade(CascadeAction action, Completion completion) { if (action.isActionCode(CascadeConstant.DELETION_CHECK_CODE)) { handleDeletionCheck(action, completion); } else if (action.isActionCode( CascadeConstant.DELETION_DELETE_CODE, CascadeConstant.DELETION_FORCE_DELETE_CODE)) { handleDeletion(action, completion); } else if (action.isActionCode(CascadeConstant.DELETION_CLEANUP_CODE)) { handleDeletionCleanup(action, completion); } else if (action.isActionCode(PrimaryStorageConstant.PRIMARY_STORAGE_DETACH_CODE)) { handlePrimaryStorageDetach(action, completion); } else if (action.isActionCode(L2NetworkConstant.DETACH_L2NETWORK_CODE)) { handleL2NetworkDetach(action, completion); } else { completion.success(); } } @Transactional(readOnly = true) private List<String> getVmUuidFromL2NetworkDetached(List<L2NetworkDetachStruct> structs) { List<String> vmUuids = new ArrayList<String>(); for (L2NetworkDetachStruct s : structs) { String sql = "select vm.uuid from VmInstanceVO vm, L2NetworkVO l2, L3NetworkVO l3, VmNicVO nic where vm.type = :vmType and vm.clusterUuid = :clusterUuid and vm.state not in (:vmStates) and vm.uuid = nic.vmInstanceUuid and nic.l3NetworkUuid = l3.uuid and l3.l2NetworkUuid = l2.uuid and l2.uuid = :l2Uuid"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("vmType", VmInstanceConstant.USER_VM_TYPE); q.setParameter( "vmStates", Arrays.asList( VmInstanceState.Stopped, VmInstanceState.Migrating, VmInstanceState.Stopping)); q.setParameter("clusterUuid", s.getClusterUuid()); q.setParameter("l2Uuid", s.getL2NetworkUuid()); vmUuids.addAll(q.getResultList()); } return vmUuids; } private void handleL2NetworkDetach(CascadeAction action, final Completion completion) { List<L2NetworkDetachStruct> structs = action.getParentIssuerContext(); final List<String> vmUuids = getVmUuidFromL2NetworkDetached(structs); if (vmUuids.isEmpty()) { completion.success(); return; } List<StopVmInstanceMsg> msgs = CollectionUtils.transformToList( vmUuids, new Function<StopVmInstanceMsg, String>() { @Override public StopVmInstanceMsg call(String arg) { StopVmInstanceMsg msg = new StopVmInstanceMsg(); msg.setVmInstanceUuid(arg); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, arg); return msg; } }); bus.send( msgs, 20, new CloudBusListCallBack(completion) { @Override public void run(List<MessageReply> replies) { for (MessageReply r : replies) { if (!r.isSuccess()) { String vmUuid = vmUuids.get(replies.indexOf(r)); logger.warn( String.format( "failed to stop vm[uuid:%s] for l2Network detached, %s. However, detaching will go on", vmUuid, r.getError())); } } completion.success(); } }); } @Transactional(readOnly = true) private List<String> getVmUuidForPrimaryStorageDetached( List<PrimaryStorageDetachStruct> structs) { List<String> vmUuids = new ArrayList<String>(); for (PrimaryStorageDetachStruct s : structs) { String sql = "select vm.uuid from VmInstanceVO vm, PrimaryStorageVO ps, VolumeVO vol where vm.type = :vmType and vm.state not in (:vmStates) and vm.clusterUuid = :clusterUuid and vm.uuid = vol.vmInstanceUuid and vol.primaryStorageUuid = :psUuid"; TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class); q.setParameter("vmType", VmInstanceConstant.USER_VM_TYPE); q.setParameter( "vmStates", Arrays.asList( VmInstanceState.Stopped, VmInstanceState.Migrating, VmInstanceState.Stopping)); q.setParameter("clusterUuid", s.getClusterUuid()); q.setParameter("psUuid", s.getPrimaryStorageUuid()); vmUuids.addAll(q.getResultList()); } return vmUuids; } private void handlePrimaryStorageDetach(CascadeAction action, final Completion completion) { List<PrimaryStorageDetachStruct> structs = action.getParentIssuerContext(); final List<String> vmUuids = getVmUuidForPrimaryStorageDetached(structs); if (vmUuids.isEmpty()) { completion.success(); return; } List<StopVmInstanceMsg> msgs = CollectionUtils.transformToList( vmUuids, new Function<StopVmInstanceMsg, String>() { @Override public StopVmInstanceMsg call(String arg) { StopVmInstanceMsg msg = new StopVmInstanceMsg(); msg.setVmInstanceUuid(arg); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, arg); return msg; } }); bus.send( msgs, 20, new CloudBusListCallBack(completion) { @Override public void run(List<MessageReply> replies) { for (MessageReply r : replies) { if (!r.isSuccess()) { String vmUuid = vmUuids.get(replies.indexOf(r)); logger.warn( String.format( "failed to stop vm[uuid:%s] for primary storage detached, %s. However, detaching will go on", vmUuid, r.getError())); } } completion.success(); } }); } private void handleDeletionCleanup(CascadeAction action, Completion completion) { dbf.eoCleanup(VmInstanceVO.class); completion.success(); } private void handleDeletion(final CascadeAction action, final Completion completion) { int op = toDeletionOpCode(action); if (op == OP_NOPE) { completion.success(); return; } if (op == OP_REMOVE_INSTANCE_OFFERING) { if (VmGlobalConfig.UPDATE_INSTANCE_OFFERING_TO_NULL_WHEN_DELETING.value(Boolean.class)) { new Runnable() { @Override @Transactional public void run() { List<InstanceOfferingInventory> offerings = action.getParentIssuerContext(); List<String> offeringUuids = CollectionUtils.transformToList( offerings, new Function<String, InstanceOfferingInventory>() { @Override public String call(InstanceOfferingInventory arg) { return arg.getUuid(); } }); String sql = "update VmInstanceVO vm set vm.instanceOfferingUuid = null where vm.instanceOfferingUuid in (:offeringUuids)"; Query q = dbf.getEntityManager().createQuery(sql); q.setParameter("offeringUuids", offeringUuids); q.executeUpdate(); } }.run(); } completion.success(); return; } final List<VmInstanceInventory> vminvs = vmFromDeleteAction(action); if (vminvs == null) { completion.success(); return; } if (op == OP_STOP) { List<StopVmInstanceMsg> msgs = new ArrayList<StopVmInstanceMsg>(); for (VmInstanceInventory inv : vminvs) { StopVmInstanceMsg msg = new StopVmInstanceMsg(); msg.setVmInstanceUuid(inv.getUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, inv.getUuid()); msgs.add(msg); } bus.send( msgs, 20, new CloudBusListCallBack(completion) { @Override public void run(List<MessageReply> replies) { if (!action.isActionCode(CascadeConstant.DELETION_FORCE_DELETE_CODE)) { for (MessageReply r : replies) { if (!r.isSuccess()) { completion.fail(r.getError()); return; } } } completion.success(); } }); } else if (op == OP_DELETION) { List<VmInstanceDeletionMsg> msgs = new ArrayList<VmInstanceDeletionMsg>(); for (VmInstanceInventory inv : vminvs) { VmInstanceDeletionMsg msg = new VmInstanceDeletionMsg(); msg.setForceDelete(action.isActionCode(CascadeConstant.DELETION_FORCE_DELETE_CODE)); msg.setVmInstanceUuid(inv.getUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, inv.getUuid()); msgs.add(msg); } bus.send( msgs, 20, new CloudBusListCallBack(completion) { @Override public void run(List<MessageReply> replies) { if (!action.isActionCode(CascadeConstant.DELETION_FORCE_DELETE_CODE)) { for (MessageReply r : replies) { if (!r.isSuccess()) { completion.fail(r.getError()); return; } } } completion.success(); } }); } else if (op == OP_DETACH_NIC) { List<DetachNicFromVmMsg> msgs = new ArrayList<DetachNicFromVmMsg>(); List<L3NetworkInventory> l3s = action.getParentIssuerContext(); for (VmInstanceInventory vm : vminvs) { for (L3NetworkInventory l3 : l3s) { DetachNicFromVmMsg msg = new DetachNicFromVmMsg(); msg.setVmInstanceUuid(vm.getUuid()); msg.setVmNicUuid(vm.findNic(l3.getUuid()).getUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vm.getUuid()); msgs.add(msg); } } bus.send( msgs, new CloudBusListCallBack(completion) { @Override public void run(List<MessageReply> replies) { if (!action.isActionCode(CascadeConstant.DELETION_FORCE_DELETE_CODE)) { for (MessageReply r : replies) { if (!r.isSuccess()) { completion.fail(r.getError()); return; } } } completion.success(); } }); } } private void handleDeletionCheck(CascadeAction action, Completion completion) { int op = toDeletionOpCode(action); if (op == OP_NOPE || op == OP_STOP) { completion.success(); return; } List<VmInstanceInventory> vminvs = vmFromDeleteAction(action); if (vminvs == null) { completion.success(); return; } for (VmInstanceInventory inv : vminvs) { ErrorCode err = extEmitter.preDestroyVm(inv); if (err != null) { completion.fail(err); return; } } completion.success(); } @Override public List<String> getEdgeNames() { return Arrays.asList( HostVO.class.getSimpleName(), L3NetworkVO.class.getSimpleName(), IpRangeVO.class.getSimpleName(), PrimaryStorageVO.class.getSimpleName(), L2NetworkVO.class.getSimpleName(), InstanceOfferingVO.class.getSimpleName(), AccountVO.class.getSimpleName()); } @Override public String getCascadeResourceName() { return NAME; } private List<VmInstanceInventory> vmFromDeleteAction(CascadeAction action) { List<VmInstanceInventory> ret = null; if (HostVO.class.getSimpleName().equals(action.getParentIssuer())) { List<HostInventory> hosts = action.getParentIssuerContext(); List<String> huuids = CollectionUtils.transformToList( hosts, new Function<String, HostInventory>() { @Override public String call(HostInventory arg) { return arg.getUuid(); } }); Map<String, VmInstanceVO> vmvos = new HashMap<String, VmInstanceVO>(); SimpleQuery<VmInstanceVO> q = dbf.createQuery(VmInstanceVO.class); q.add(VmInstanceVO_.hostUuid, SimpleQuery.Op.IN, huuids); q.add(VmInstanceVO_.type, Op.EQ, VmInstanceConstant.USER_VM_TYPE); List<VmInstanceVO> lst = q.list(); for (VmInstanceVO vo : lst) { vmvos.put(vo.getUuid(), vo); } if (ClusterVO.class.getSimpleName().equals(action.getRootIssuer())) { List<ClusterInventory> clusters = action.getRootIssuerContext(); List<String> clusterUuids = CollectionUtils.transformToList( clusters, new Function<String, ClusterInventory>() { @Override public String call(ClusterInventory arg) { return arg.getUuid(); } }); q = dbf.createQuery(VmInstanceVO.class); q.add(VmInstanceVO_.clusterUuid, Op.IN, clusterUuids); q.add(VmInstanceVO_.type, Op.EQ, VmInstanceConstant.USER_VM_TYPE); lst = q.list(); for (VmInstanceVO vo : lst) { vmvos.put(vo.getUuid(), vo); } } else if (ZoneVO.class.getSimpleName().equals(action.getRootIssuer())) { List<ZoneInventory> zones = action.getRootIssuerContext(); List<String> zoneUuids = CollectionUtils.transformToList( zones, new Function<String, ZoneInventory>() { @Override public String call(ZoneInventory arg) { return arg.getUuid(); } }); q = dbf.createQuery(VmInstanceVO.class); q.add(VmInstanceVO_.zoneUuid, Op.IN, zoneUuids); q.add(VmInstanceVO_.type, Op.EQ, VmInstanceConstant.USER_VM_TYPE); lst = q.list(); for (VmInstanceVO vo : lst) { vmvos.put(vo.getUuid(), vo); } } if (!vmvos.isEmpty()) { ret = VmInstanceInventory.valueOf(vmvos.values()); } } else if (NAME.equals(action.getParentIssuer())) { return action.getParentIssuerContext(); } else if (PrimaryStorageVO.class.getSimpleName().equals(action.getParentIssuer())) { final List<String> pruuids = CollectionUtils.transformToList( (List<PrimaryStorageInventory>) action.getParentIssuerContext(), new Function<String, PrimaryStorageInventory>() { @Override public String call(PrimaryStorageInventory arg) { return arg.getUuid(); } }); List<VmInstanceVO> vmvos = new Callable<List<VmInstanceVO>>() { @Override @Transactional(readOnly = true) public List<VmInstanceVO> call() { String sql = "select vm from VmInstanceVO vm, VolumeVO vol, PrimaryStorageVO pr where vm.type = :vmType and vm.uuid = vol.vmInstanceUuid" + " and vol.primaryStorageUuid = pr.uuid and vol.type = :volType and pr.uuid in (:uuids) group by vm.uuid"; TypedQuery<VmInstanceVO> q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); q.setParameter("vmType", VmInstanceConstant.USER_VM_TYPE); q.setParameter("uuids", pruuids); q.setParameter("volType", VolumeType.Root); return q.getResultList(); } }.call(); if (!vmvos.isEmpty()) { ret = VmInstanceInventory.valueOf(vmvos); } } else if (L3NetworkVO.class.getSimpleName().equals(action.getParentIssuer())) { final List<String> l3uuids = CollectionUtils.transformToList( (List<L3NetworkInventory>) action.getParentIssuerContext(), new Function<String, L3NetworkInventory>() { @Override public String call(L3NetworkInventory arg) { return arg.getUuid(); } }); List<VmInstanceVO> vmvos = new Callable<List<VmInstanceVO>>() { @Override @Transactional(readOnly = true) public List<VmInstanceVO> call() { String sql = "select vm from VmInstanceVO vm, L3NetworkVO l3, VmNicVO nic where vm.type = :vmType and vm.uuid = nic.vmInstanceUuid and vm.state not in (:vmStates)" + " and nic.l3NetworkUuid = l3.uuid and l3.uuid in (:uuids) group by vm.uuid"; TypedQuery<VmInstanceVO> q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); q.setParameter("vmType", VmInstanceConstant.USER_VM_TYPE); q.setParameter( "vmStates", Arrays.asList(VmInstanceState.Stopped, VmInstanceState.Stopping)); q.setParameter("uuids", l3uuids); return q.getResultList(); } }.call(); if (!vmvos.isEmpty()) { ret = VmInstanceInventory.valueOf(vmvos); } } else if (IpRangeVO.class.getSimpleName().equals(action.getParentIssuer())) { final List<String> ipruuids = CollectionUtils.transformToList( (List<IpRangeInventory>) action.getParentIssuerContext(), new Function<String, IpRangeInventory>() { @Override public String call(IpRangeInventory arg) { return arg.getUuid(); } }); List<VmInstanceVO> vmvos = new Callable<List<VmInstanceVO>>() { @Override @Transactional(readOnly = true) public List<VmInstanceVO> call() { String sql = "select vm from VmInstanceVO vm, VmNicVO nic, UsedIpVO ip, IpRangeVO ipr where vm.type = :vmType and vm.uuid = nic.vmInstanceUuid and vm.state not in (:vmStates)" + " and nic.usedIpUuid = ip.uuid and ip.ipRangeUuid = ipr.uuid and ipr.uuid in (:uuids) group by vm.uuid"; TypedQuery<VmInstanceVO> q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); q.setParameter("vmType", VmInstanceConstant.USER_VM_TYPE); q.setParameter( "vmStates", Arrays.asList(VmInstanceState.Stopped, VmInstanceState.Stopping)); q.setParameter("uuids", ipruuids); return q.getResultList(); } }.call(); if (!vmvos.isEmpty()) { ret = VmInstanceInventory.valueOf(vmvos); } } else if (AccountVO.class.getSimpleName().equals(action.getParentIssuer())) { final List<String> auuids = CollectionUtils.transformToList( (List<AccountInventory>) action.getParentIssuerContext(), new Function<String, AccountInventory>() { @Override public String call(AccountInventory arg) { return arg.getUuid(); } }); List<VmInstanceVO> vmvos = new Callable<List<VmInstanceVO>>() { @Override @Transactional(readOnly = true) public List<VmInstanceVO> call() { String sql = "select d from VmInstanceVO d, AccountResourceRefVO r where d.uuid = r.resourceUuid and" + " r.resourceType = :rtype and r.accountUuid in (:auuids) group by d.uuid"; TypedQuery<VmInstanceVO> q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); q.setParameter("rtype", VmInstanceVO.class.getSimpleName()); q.setParameter("auuids", auuids); return q.getResultList(); } }.call(); if (!vmvos.isEmpty()) { ret = VmInstanceInventory.valueOf(vmvos); } } return ret; } @Override public CascadeAction createActionForChildResource(CascadeAction action) { if (CascadeConstant.DELETION_CODES.contains(action.getActionCode())) { int op = toDeletionOpCode(action); if (op == OP_NOPE || op == OP_STOP || op == OP_REMOVE_INSTANCE_OFFERING) { return null; } List<VmInstanceInventory> vms = vmFromDeleteAction(action); if (vms == null) { return null; } return action.copy().setParentIssuer(NAME).setParentIssuerContext(vms); } return null; } }
public class ZoneManagerImpl extends AbstractService implements ZoneManager { private static final CLogger logger = Utils.getLogger(ZoneManager.class); @Autowired private CloudBus bus; @Autowired private DatabaseFacade dbf; @Autowired private PluginRegistry pluginRgty; @Autowired private DbEntityLister dl; @Autowired private LogFacade logf; @Autowired private ErrorFacade errf; @Autowired private TagManager tagMgr; private Map<String, ZoneFactory> zoneFactories = Collections.synchronizedMap(new HashMap<String, ZoneFactory>()); private static final Set<Class> allowedMessageAfterSoftDeletion = new HashSet<Class>(); static { allowedMessageAfterSoftDeletion.add(ZoneDeletionMsg.class); } @Override @MessageSafe public void handleMessage(Message msg) { if (msg instanceof APIMessage) { handleApiMessage((APIMessage) msg); } else { handleLocalMessage(msg); } } private void handleLocalMessage(Message msg) { if (msg instanceof ZoneMessage) { passThrough((ZoneMessage) msg); } else { bus.dealWithUnknownMessage(msg); } } private void handleApiMessage(APIMessage msg) { if (msg instanceof APICreateZoneMsg) { handle((APICreateZoneMsg) msg); } else if (msg instanceof ZoneMessage) { passThrough((ZoneMessage) msg); } else if (msg instanceof APIListZonesMsg) { handle((APIListZonesMsg) msg); } else if (msg instanceof APISearchZoneMsg) { handle((APISearchZoneMsg) msg); } else if (msg instanceof APIGetZoneMsg) { handle((APIGetZoneMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } private void handle(APIGetZoneMsg msg) { GetQuery query = new GetQuery(); String inv = query.getAsString(msg.getUuid(), ZoneInventory.class); APIGetZoneReply reply = new APIGetZoneReply(); reply.setInventory(inv); bus.reply(msg, reply); } private void handle(APISearchZoneMsg msg) { SearchQuery<ZoneInventory> query = SearchQuery.create(msg, ZoneInventory.class); String res = query.listAsString(); APISearchZoneReply reply = new APISearchZoneReply(); reply.setContent(res); bus.reply(msg, reply); } private void passThrough(ZoneMessage msg) { ZoneVO vo = dbf.findByUuid(msg.getZoneUuid(), ZoneVO.class); if (vo == null && allowedMessageAfterSoftDeletion.contains(msg.getClass())) { ZoneEO eo = dbf.findByUuid(msg.getZoneUuid(), ZoneEO.class); vo = ObjectUtils.newAndCopy(eo, ZoneVO.class); } if (vo == null) { ErrorCode err = errf.instantiateErrorCode( SysErrors.RESOURCE_NOT_FOUND, String.format( "unable to find zone[uuid:%s], it may have been deleted", msg.getZoneUuid())); bus.replyErrorByMessageType((Message) msg, err); return; } ZoneFactory factory = this.getZoneFactory(ZoneType.valueOf(vo.getType())); Zone zone = factory.getZone(vo); zone.handleMessage((Message) msg); } private void handle(APIListZonesMsg msg) { APIListZonesReply reply = new APIListZonesReply(); List<ZoneVO> vos = dl.listByApiMessage(msg, ZoneVO.class); List<ZoneInventory> invs = ZoneInventory.valueOf(vos); reply.setInventories(invs); bus.reply(msg, reply); } private void handle(APICreateZoneMsg msg) { String zoneType = msg.getType(); if (zoneType == null) { zoneType = BaseZoneFactory.type.toString(); } ZoneFactory factory = this.getZoneFactory(ZoneType.valueOf(zoneType)); APICreateZoneEvent evt = new APICreateZoneEvent(msg.getId()); ZoneVO vo = new ZoneVO(); if (msg.getResourceUuid() != null) { vo.setUuid(msg.getResourceUuid()); } else { vo.setUuid(Platform.getUuid()); } vo.setName(msg.getName()); vo.setDescription(msg.getDescription()); vo = factory.createZone(vo, msg); tagMgr.createTagsFromAPICreateMessage(msg, vo.getUuid(), ZoneVO.class.getSimpleName()); evt.setInventory(ZoneInventory.valueOf(vo)); logger.debug("Created zone: " + vo.getName() + " uuid:" + vo.getUuid()); if (logf.isEnabled()) { logf.info(vo.getUuid(), String.format("Create zone successfully")); } bus.publish(evt); } @Override public String getId() { return bus.makeLocalServiceId(ZoneConstant.SERVICE_ID); } private void populateExtensions() { for (ZoneFactory f : pluginRgty.getExtensionList(ZoneFactory.class)) { ZoneFactory old = zoneFactories.get(f.getType().toString()); if (old != null) { throw new CloudRuntimeException( String.format( "duplicate ZoneFactory[%s, %s] for type[%s]", f.getClass().getName(), old.getClass().getName(), f.getType())); } zoneFactories.put(f.getType().toString(), f); } } @Override public boolean start() { populateExtensions(); return true; } @Override public boolean stop() { return true; } private ZoneFactory getZoneFactory(ZoneType type) { ZoneFactory factory = zoneFactories.get(type.toString()); if (factory == null) { throw new CloudRuntimeException(String.format("No ZoneFactory of type[%s] found", type)); } return factory; } }
public class TestStartVmOnTargetHost1 { CLogger logger = Utils.getLogger(TestSftpBackupStorageDeleteImage2.class); Deployer deployer; Api api; ComponentLoader loader; CloudBus bus; DatabaseFacade dbf; SessionInventory session; SftpBackupStorageSimulatorConfig config; @Before public void setUp() throws Exception { DBUtil.reDeployDB(); WebBeanConstructor con = new WebBeanConstructor(); deployer = new Deployer("deployerXml/kvm/TestStartVmOnTargetHost.xml", con); deployer.addSpringConfig("KVMRelated.xml"); deployer.build(); api = deployer.getApi(); loader = deployer.getComponentLoader(); bus = loader.getComponent(CloudBus.class); dbf = loader.getComponent(DatabaseFacade.class); config = loader.getComponent(SftpBackupStorageSimulatorConfig.class); session = api.loginAsAdmin(); } class VmStarter { String vmUuid; String clusterUuid; String hostUuid; VmInstanceInventory start() throws ApiSenderException { APIStartVmInstanceMsg msg = new APIStartVmInstanceMsg(); msg.setUuid(vmUuid); msg.setHostUuid(hostUuid); msg.setClusterUuid(clusterUuid); msg.setSession(api.getAdminSession()); ApiSender sender = new ApiSender(); APIStartVmInstanceEvent evt = sender.send(msg, APIStartVmInstanceEvent.class); return evt.getInventory(); } } @Test public void test() throws ApiSenderException { VmInstanceInventory vm = deployer.vms.get("TestVm"); ClusterInventory cluster1 = deployer.clusters.get("Cluster1"); HostInventory host1 = deployer.hosts.get("host1"); ClusterInventory cluster2 = deployer.clusters.get("Cluster2"); HostInventory host2 = deployer.hosts.get("host2"); boolean s = false; try { // vm is running, failure api.getVmStartingCandidateHosts(vm.getUuid(), null); } catch (ApiSenderException e) { s = true; } Assert.assertTrue(s); api.stopVmInstance(vm.getUuid()); APIGetVmStartingCandidateClustersHostsReply reply = api.getVmStartingCandidateHosts(vm.getUuid(), null); Assert.assertEquals(2, reply.getClusterInventories().size()); Assert.assertEquals(2, reply.getHostInventories().size()); } }
/** * Created with IntelliJ IDEA. User: frank Time: 9:20 PM To change this template use File | Settings * | File Templates. */ @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE) public class VolumeBase implements Volume { private static final CLogger logger = Utils.getLogger(VolumeBase.class); @Autowired private CloudBus bus; @Autowired private DatabaseFacade dbf; @Autowired private ThreadFacade thdf; @Autowired private ErrorFacade errf; @Autowired private CascadeFacade casf; @Autowired private AccountManager acntMgr; @Autowired private TagManager tagMgr; @Autowired private PluginRegistry pluginRgty; @Autowired private VolumeDeletionPolicyManager deletionPolicyMgr; private VolumeVO self; public VolumeBase(VolumeVO vo) { self = vo; } protected void refreshVO() { self = dbf.reload(self); } @Override public void handleMessage(Message msg) { try { if (msg instanceof APIMessage) { handleApiMessage((APIMessage) msg); } else { handleLocalMessage(msg); } } catch (Exception e) { bus.logExceptionWithMessageDump(msg, e); bus.replyErrorByMessageType(msg, e); } } private void handleLocalMessage(Message msg) { if (msg instanceof VolumeDeletionMsg) { handle((VolumeDeletionMsg) msg); } else if (msg instanceof DeleteVolumeMsg) { handle((DeleteVolumeMsg) msg); } else if (msg instanceof CreateDataVolumeTemplateFromDataVolumeMsg) { handle((CreateDataVolumeTemplateFromDataVolumeMsg) msg); } else if (msg instanceof ExpungeVolumeMsg) { handle((ExpungeVolumeMsg) msg); } else if (msg instanceof RecoverVolumeMsg) { handle((RecoverVolumeMsg) msg); } else if (msg instanceof SyncVolumeSizeMsg) { handle((SyncVolumeSizeMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } private void handle(final SyncVolumeSizeMsg msg) { final SyncVolumeSizeReply reply = new SyncVolumeSizeReply(); syncVolumeVolumeSize( new ReturnValueCompletion<VolumeSize>(msg) { @Override public void success(VolumeSize ret) { reply.setActualSize(ret.actualSize); reply.setSize(ret.size); bus.reply(msg, reply); } @Override public void fail(ErrorCode errorCode) { reply.setError(errorCode); bus.reply(msg, reply); } }); } private void handle(final RecoverVolumeMsg msg) { final RecoverVolumeReply reply = new RecoverVolumeReply(); recoverVolume( new Completion(msg) { @Override public void success() { bus.reply(msg, reply); } @Override public void fail(ErrorCode errorCode) { reply.setError(errorCode); bus.reply(msg, reply); } }); } private void expunge(final Completion completion) { if (self.getStatus() != VolumeStatus.Deleted) { throw new OperationFailureException( errf.stringToOperationError( String.format( "the volume[uuid:%s, name:%s] is not deleted yet, can't expunge it", self.getUuid(), self.getName()))); } final VolumeInventory inv = getSelfInventory(); CollectionUtils.safeForEach( pluginRgty.getExtensionList(VolumeBeforeExpungeExtensionPoint.class), new ForEachFunction<VolumeBeforeExpungeExtensionPoint>() { @Override public void run(VolumeBeforeExpungeExtensionPoint arg) { arg.volumeBeforeExpunge(inv); } }); if (self.getPrimaryStorageUuid() != null) { DeleteVolumeOnPrimaryStorageMsg dmsg = new DeleteVolumeOnPrimaryStorageMsg(); dmsg.setVolume(getSelfInventory()); dmsg.setUuid(self.getPrimaryStorageUuid()); bus.makeTargetServiceIdByResourceUuid( dmsg, PrimaryStorageConstant.SERVICE_ID, self.getPrimaryStorageUuid()); bus.send( dmsg, new CloudBusCallBack(completion) { @Override public void run(MessageReply r) { if (!r.isSuccess()) { completion.fail(r.getError()); } else { ReturnPrimaryStorageCapacityMsg msg = new ReturnPrimaryStorageCapacityMsg(); msg.setPrimaryStorageUuid(self.getPrimaryStorageUuid()); msg.setDiskSize(self.getSize()); bus.makeTargetServiceIdByResourceUuid( msg, PrimaryStorageConstant.SERVICE_ID, self.getPrimaryStorageUuid()); bus.send(msg); CollectionUtils.safeForEach( pluginRgty.getExtensionList(VolumeAfterExpungeExtensionPoint.class), new ForEachFunction<VolumeAfterExpungeExtensionPoint>() { @Override public void run(VolumeAfterExpungeExtensionPoint arg) { arg.volumeAfterExpunge(inv); } }); dbf.remove(self); completion.success(); } } }); } else { CollectionUtils.safeForEach( pluginRgty.getExtensionList(VolumeAfterExpungeExtensionPoint.class), new ForEachFunction<VolumeAfterExpungeExtensionPoint>() { @Override public void run(VolumeAfterExpungeExtensionPoint arg) { arg.volumeAfterExpunge(inv); } }); dbf.remove(self); completion.success(); } } private void handle(final ExpungeVolumeMsg msg) { final ExpungeVmReply reply = new ExpungeVmReply(); expunge( new Completion(msg) { @Override public void success() { bus.reply(msg, reply); } @Override public void fail(ErrorCode errorCode) { reply.setError(errorCode); bus.reply(msg, reply); } }); } private void handle(final CreateDataVolumeTemplateFromDataVolumeMsg msg) { final CreateTemplateFromVolumeOnPrimaryStorageMsg cmsg = new CreateTemplateFromVolumeOnPrimaryStorageMsg(); cmsg.setBackupStorageUuid(msg.getBackupStorageUuid()); cmsg.setImageInventory( ImageInventory.valueOf(dbf.findByUuid(msg.getImageUuid(), ImageVO.class))); cmsg.setVolumeInventory(getSelfInventory()); bus.makeTargetServiceIdByResourceUuid( cmsg, PrimaryStorageConstant.SERVICE_ID, self.getPrimaryStorageUuid()); bus.send( cmsg, new CloudBusCallBack(msg) { @Override public void run(MessageReply r) { CreateDataVolumeTemplateFromDataVolumeReply reply = new CreateDataVolumeTemplateFromDataVolumeReply(); if (!r.isSuccess()) { reply.setError(r.getError()); } else { CreateTemplateFromVolumeOnPrimaryStorageReply creply = r.castReply(); String backupStorageInstallPath = creply.getTemplateBackupStorageInstallPath(); reply.setFormat(creply.getFormat()); reply.setInstallPath(backupStorageInstallPath); reply.setMd5sum(null); reply.setBackupStorageUuid(msg.getBackupStorageUuid()); } bus.reply(msg, reply); } }); } private void handle(final DeleteVolumeMsg msg) { final DeleteVolumeReply reply = new DeleteVolumeReply(); delete( true, msg.isDetachBeforeDeleting(), new Completion(msg) { @Override public void success() { logger.debug(String.format("deleted data volume[uuid: %s]", msg.getUuid())); bus.reply(msg, reply); } @Override public void fail(ErrorCode errorCode) { reply.setError(errorCode); bus.reply(msg, reply); } }); } private void deleteVolume(final VolumeDeletionMsg msg, final NoErrorCompletion completion) { final VolumeDeletionReply reply = new VolumeDeletionReply(); for (VolumeDeletionExtensionPoint extp : pluginRgty.getExtensionList(VolumeDeletionExtensionPoint.class)) { extp.preDeleteVolume(getSelfInventory()); } CollectionUtils.safeForEach( pluginRgty.getExtensionList(VolumeDeletionExtensionPoint.class), new ForEachFunction<VolumeDeletionExtensionPoint>() { @Override public void run(VolumeDeletionExtensionPoint arg) { arg.beforeDeleteVolume(getSelfInventory()); } }); FlowChain chain = FlowChainBuilder.newShareFlowChain(); chain.setName(String.format("delete-volume-%s", self.getUuid())); // for NotInstantiated Volume, no flow to execute chain.allowEmptyFlow(); chain .then( new ShareFlow() { VolumeDeletionPolicy deletionPolicy; { if (msg.getDeletionPolicy() == null) { deletionPolicy = deletionPolicyMgr.getDeletionPolicy(self.getUuid()); } else { deletionPolicy = VolumeDeletionPolicy.valueOf(msg.getDeletionPolicy()); } } @Override public void setup() { if (self.getVmInstanceUuid() != null && self.getType() == VolumeType.Data && msg.isDetachBeforeDeleting()) { flow( new NoRollbackFlow() { String __name__ = "detach-volume-from-vm"; public void run(final FlowTrigger trigger, Map data) { DetachDataVolumeFromVmMsg dmsg = new DetachDataVolumeFromVmMsg(); dmsg.setVolume(getSelfInventory()); bus.makeTargetServiceIdByResourceUuid( dmsg, VmInstanceConstant.SERVICE_ID, dmsg.getVmInstanceUuid()); bus.send( dmsg, new CloudBusCallBack(trigger) { @Override public void run(MessageReply reply) { self.setVmInstanceUuid(null); self = dbf.updateAndRefresh(self); trigger.next(); } }); } }); } if (deletionPolicy == VolumeDeletionPolicy.Direct) { flow( new NoRollbackFlow() { String __name__ = "delete-data-volume-from-primary-storage"; @Override public void run(final FlowTrigger trigger, Map data) { if (self.getStatus() == VolumeStatus.Ready) { DeleteVolumeOnPrimaryStorageMsg dmsg = new DeleteVolumeOnPrimaryStorageMsg(); dmsg.setVolume(getSelfInventory()); dmsg.setUuid(self.getPrimaryStorageUuid()); bus.makeTargetServiceIdByResourceUuid( dmsg, PrimaryStorageConstant.SERVICE_ID, self.getPrimaryStorageUuid()); logger.debug( String.format( "Asking primary storage[uuid:%s] to remove data volume[uuid:%s]", self.getPrimaryStorageUuid(), self.getUuid())); bus.send( dmsg, new CloudBusCallBack(trigger) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { logger.warn( String.format( "failed to delete volume[uuid:%s, name:%s], %s", self.getUuid(), self.getName(), reply.getError())); } trigger.next(); } }); } else { trigger.next(); } } }); } if (self.getPrimaryStorageUuid() != null && deletionPolicy == VolumeDeletionPolicy.Direct) { flow( new NoRollbackFlow() { String __name__ = "return-primary-storage-capacity"; @Override public void run(FlowTrigger trigger, Map data) { ReturnPrimaryStorageCapacityMsg rmsg = new ReturnPrimaryStorageCapacityMsg(); rmsg.setPrimaryStorageUuid(self.getPrimaryStorageUuid()); rmsg.setDiskSize(self.getSize()); bus.makeTargetServiceIdByResourceUuid( rmsg, PrimaryStorageConstant.SERVICE_ID, self.getPrimaryStorageUuid()); bus.send(rmsg); trigger.next(); } }); } done( new FlowDoneHandler(msg) { @Override public void handle(Map data) { VolumeStatus oldStatus = self.getStatus(); if (deletionPolicy == VolumeDeletionPolicy.Direct) { dbf.remove(self); } else if (deletionPolicy == VolumeDeletionPolicy.Delay) { self.setStatus(VolumeStatus.Deleted); self = dbf.updateAndRefresh(self); } else if (deletionPolicy == VolumeDeletionPolicy.Never) { self.setStatus(VolumeStatus.Deleted); self = dbf.updateAndRefresh(self); } new FireVolumeCanonicalEvent() .fireVolumeStatusChangedEvent(oldStatus, getSelfInventory()); CollectionUtils.safeForEach( pluginRgty.getExtensionList(VolumeDeletionExtensionPoint.class), new ForEachFunction<VolumeDeletionExtensionPoint>() { @Override public void run(VolumeDeletionExtensionPoint arg) { arg.afterDeleteVolume(getSelfInventory()); } }); bus.reply(msg, reply); } }); error( new FlowErrorHandler(msg) { @Override public void handle(final ErrorCode errCode, Map data) { CollectionUtils.safeForEach( pluginRgty.getExtensionList(VolumeDeletionExtensionPoint.class), new ForEachFunction<VolumeDeletionExtensionPoint>() { @Override public void run(VolumeDeletionExtensionPoint arg) { arg.failedToDeleteVolume(getSelfInventory(), errCode); } }); reply.setError(errCode); bus.reply(msg, reply); } }); Finally( new FlowFinallyHandler() { @Override public void Finally() { completion.done(); } }); } }) .start(); } private void handle(final VolumeDeletionMsg msg) { thdf.chainSubmit( new ChainTask() { @Override public String getSyncSignature() { return getName(); } @Override public void run(final SyncTaskChain chain) { self = dbf.reload(self); if (self.getStatus() == VolumeStatus.Deleted) { // the volume has been deleted // we run into this case because the cascading framework // will send duplicate messages when deleting a vm as the cascading // framework has no knowledge about if the volume has been deleted VolumeDeletionReply reply = new VolumeDeletionReply(); bus.reply(msg, reply); chain.next(); return; } deleteVolume( msg, new NoErrorCompletion(chain) { @Override public void done() { chain.next(); } }); } @Override public String getName() { return String.format("delete-volume-%s", self.getUuid()); } }); } private void handleApiMessage(APIMessage msg) { if (msg instanceof APIChangeVolumeStateMsg) { handle((APIChangeVolumeStateMsg) msg); } else if (msg instanceof APICreateVolumeSnapshotMsg) { handle((APICreateVolumeSnapshotMsg) msg); } else if (msg instanceof APIDeleteDataVolumeMsg) { handle((APIDeleteDataVolumeMsg) msg); } else if (msg instanceof APIDetachDataVolumeFromVmMsg) { handle((APIDetachDataVolumeFromVmMsg) msg); } else if (msg instanceof APIAttachDataVolumeToVmMsg) { handle((APIAttachDataVolumeToVmMsg) msg); } else if (msg instanceof APIGetDataVolumeAttachableVmMsg) { handle((APIGetDataVolumeAttachableVmMsg) msg); } else if (msg instanceof APIUpdateVolumeMsg) { handle((APIUpdateVolumeMsg) msg); } else if (msg instanceof APIRecoverDataVolumeMsg) { handle((APIRecoverDataVolumeMsg) msg); } else if (msg instanceof APIExpungeDataVolumeMsg) { handle((APIExpungeDataVolumeMsg) msg); } else if (msg instanceof APISyncVolumeSizeMsg) { handle((APISyncVolumeSizeMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } class VolumeSize { long size; long actualSize; } private void syncVolumeVolumeSize(final ReturnValueCompletion<VolumeSize> completion) { SyncVolumeSizeOnPrimaryStorageMsg smsg = new SyncVolumeSizeOnPrimaryStorageMsg(); smsg.setPrimaryStorageUuid(self.getPrimaryStorageUuid()); smsg.setVolumeUuid(self.getUuid()); smsg.setInstallPath(self.getInstallPath()); bus.makeTargetServiceIdByResourceUuid( smsg, PrimaryStorageConstant.SERVICE_ID, self.getPrimaryStorageUuid()); bus.send( smsg, new CloudBusCallBack(completion) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { completion.fail(reply.getError()); return; } SyncVolumeSizeOnPrimaryStorageReply r = reply.castReply(); self.setActualSize(r.getActualSize()); self.setSize(r.getSize()); self = dbf.updateAndRefresh(self); VolumeSize size = new VolumeSize(); size.actualSize = r.getActualSize(); size.size = r.getSize(); completion.success(size); } }); } private void handle(APISyncVolumeSizeMsg msg) { final APISyncVolumeSizeEvent evt = new APISyncVolumeSizeEvent(msg.getId()); if (self.getStatus() != VolumeStatus.Ready) { evt.setInventory(getSelfInventory()); bus.publish(evt); return; } syncVolumeVolumeSize( new ReturnValueCompletion<VolumeSize>(msg) { @Override public void success(VolumeSize ret) { evt.setInventory(getSelfInventory()); bus.publish(evt); } @Override public void fail(ErrorCode errorCode) { evt.setErrorCode(errorCode); bus.publish(evt); } }); } private void handle(APIExpungeDataVolumeMsg msg) { final APIExpungeDataVolumeEvent evt = new APIExpungeDataVolumeEvent(msg.getId()); expunge( new Completion(msg) { @Override public void success() { bus.publish(evt); } @Override public void fail(ErrorCode errorCode) { evt.setErrorCode(errorCode); bus.publish(evt); } }); } protected void recoverVolume(Completion completion) { final VolumeInventory vol = getSelfInventory(); List<RecoverDataVolumeExtensionPoint> exts = pluginRgty.getExtensionList(RecoverDataVolumeExtensionPoint.class); for (RecoverDataVolumeExtensionPoint ext : exts) { ext.preRecoverDataVolume(vol); } CollectionUtils.safeForEach( exts, new ForEachFunction<RecoverDataVolumeExtensionPoint>() { @Override public void run(RecoverDataVolumeExtensionPoint ext) { ext.beforeRecoverDataVolume(vol); } }); VolumeStatus oldStatus = self.getStatus(); if (self.getInstallPath() != null) { self.setStatus(VolumeStatus.Ready); } else { self.setStatus(VolumeStatus.NotInstantiated); } self = dbf.updateAndRefresh(self); new FireVolumeCanonicalEvent().fireVolumeStatusChangedEvent(oldStatus, getSelfInventory()); CollectionUtils.safeForEach( exts, new ForEachFunction<RecoverDataVolumeExtensionPoint>() { @Override public void run(RecoverDataVolumeExtensionPoint ext) { ext.afterRecoverDataVolume(vol); } }); completion.success(); } private void handle(APIRecoverDataVolumeMsg msg) { final APIRecoverDataVolumeEvent evt = new APIRecoverDataVolumeEvent(msg.getId()); recoverVolume( new Completion(msg) { @Override public void success() { evt.setInventory(getSelfInventory()); bus.publish(evt); } @Override public void fail(ErrorCode errorCode) { evt.setInventory(getSelfInventory()); evt.setErrorCode(errorCode); bus.publish(evt); } }); } private void handle(APIUpdateVolumeMsg msg) { boolean update = false; if (msg.getName() != null) { self.setName(msg.getName()); update = true; } if (msg.getDescription() != null) { self.setDescription(msg.getDescription()); update = true; } if (update) { self = dbf.updateAndRefresh(self); } APIUpdateVolumeEvent evt = new APIUpdateVolumeEvent(msg.getId()); evt.setInventory(getSelfInventory()); bus.publish(evt); } @Transactional(readOnly = true) private List<VmInstanceVO> getCandidateVmForAttaching(String accountUuid) { List<String> vmUuids = acntMgr.getResourceUuidsCanAccessByAccount(accountUuid, VmInstanceVO.class); if (vmUuids != null && vmUuids.isEmpty()) { return new ArrayList<VmInstanceVO>(); } TypedQuery<VmInstanceVO> q = null; String sql; if (vmUuids == null) { // all vms if (self.getStatus() == VolumeStatus.Ready) { sql = "select vm from VmInstanceVO vm, PrimaryStorageClusterRefVO ref, VolumeVO vol where vm.state in (:vmStates) and vol.uuid = :volUuid and vm.hypervisorType in (:hvTypes) and vm.clusterUuid = ref.clusterUuid and ref.primaryStorageUuid = vol.primaryStorageUuid group by vm.uuid"; q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); q.setParameter("volUuid", self.getUuid()); List<String> hvTypes = VolumeFormat.valueOf(self.getFormat()) .getHypervisorTypesSupportingThisVolumeFormatInString(); q.setParameter("hvTypes", hvTypes); } else if (self.getStatus() == VolumeStatus.NotInstantiated) { sql = "select vm from VmInstanceVO vm where vm.state in (:vmStates) group by vm.uuid"; q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); } else { DebugUtils.Assert( false, String.format("should not reach here, volume[uuid:%s]", self.getUuid())); } } else { if (self.getStatus() == VolumeStatus.Ready) { sql = "select vm from VmInstanceVO vm, PrimaryStorageClusterRefVO ref, VolumeVO vol where vm.uuid in (:vmUuids) and vm.state in (:vmStates) and vol.uuid = :volUuid and vm.hypervisorType in (:hvTypes) and vm.clusterUuid = ref.clusterUuid and ref.primaryStorageUuid = vol.primaryStorageUuid group by vm.uuid"; q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); q.setParameter("volUuid", self.getUuid()); List<String> hvTypes = VolumeFormat.valueOf(self.getFormat()) .getHypervisorTypesSupportingThisVolumeFormatInString(); q.setParameter("hvTypes", hvTypes); } else if (self.getStatus() == VolumeStatus.NotInstantiated) { sql = "select vm from VmInstanceVO vm where vm.uuid in (:vmUuids) and vm.state in (:vmStates) group by vm.uuid"; q = dbf.getEntityManager().createQuery(sql, VmInstanceVO.class); } else { DebugUtils.Assert( false, String.format("should not reach here, volume[uuid:%s]", self.getUuid())); } q.setParameter("vmUuids", vmUuids); } q.setParameter("vmStates", Arrays.asList(VmInstanceState.Running, VmInstanceState.Stopped)); List<VmInstanceVO> vms = q.getResultList(); if (vms.isEmpty()) { return vms; } VolumeInventory vol = getSelfInventory(); for (VolumeGetAttachableVmExtensionPoint ext : pluginRgty.getExtensionList(VolumeGetAttachableVmExtensionPoint.class)) { vms = ext.returnAttachableVms(vol, vms); } return vms; } private void handle(APIGetDataVolumeAttachableVmMsg msg) { APIGetDataVolumeAttachableVmReply reply = new APIGetDataVolumeAttachableVmReply(); reply.setInventories( VmInstanceInventory.valueOf(getCandidateVmForAttaching(msg.getSession().getAccountUuid()))); bus.reply(msg, reply); } private void handle(final APIAttachDataVolumeToVmMsg msg) { self.setVmInstanceUuid(msg.getVmInstanceUuid()); self = dbf.updateAndRefresh(self); AttachDataVolumeToVmMsg amsg = new AttachDataVolumeToVmMsg(); amsg.setVolume(getSelfInventory()); amsg.setVmInstanceUuid(msg.getVmInstanceUuid()); bus.makeTargetServiceIdByResourceUuid( amsg, VmInstanceConstant.SERVICE_ID, amsg.getVmInstanceUuid()); bus.send( amsg, new CloudBusCallBack(msg) { @Override public void run(MessageReply reply) { final APIAttachDataVolumeToVmEvent evt = new APIAttachDataVolumeToVmEvent(msg.getId()); self = dbf.reload(self); if (reply.isSuccess()) { AttachDataVolumeToVmReply ar = reply.castReply(); self.setVmInstanceUuid(msg.getVmInstanceUuid()); self.setFormat( VolumeFormat.getVolumeFormatByMasterHypervisorType(ar.getHypervisorType()) .toString()); self = dbf.updateAndRefresh(self); evt.setInventory(getSelfInventory()); } else { self.setVmInstanceUuid(null); dbf.update(self); evt.setErrorCode(reply.getError()); } bus.publish(evt); } }); } private void handle(final APIDetachDataVolumeFromVmMsg msg) { DetachDataVolumeFromVmMsg dmsg = new DetachDataVolumeFromVmMsg(); dmsg.setVolume(getSelfInventory()); bus.makeTargetServiceIdByResourceUuid( dmsg, VmInstanceConstant.SERVICE_ID, dmsg.getVmInstanceUuid()); bus.send( dmsg, new CloudBusCallBack(msg) { @Override public void run(MessageReply reply) { APIDetachDataVolumeFromVmEvent evt = new APIDetachDataVolumeFromVmEvent(msg.getId()); if (reply.isSuccess()) { self.setVmInstanceUuid(null); self.setDeviceId(null); self = dbf.updateAndRefresh(self); evt.setInventory(getSelfInventory()); } else { evt.setErrorCode(reply.getError()); } bus.publish(evt); } }); } protected VolumeInventory getSelfInventory() { return VolumeInventory.valueOf(self); } private void delete(boolean forceDelete, final Completion completion) { delete(forceDelete, true, completion); } private void delete( boolean forceDelete, boolean detachBeforeDeleting, final Completion completion) { final String issuer = VolumeVO.class.getSimpleName(); VolumeDeletionStruct struct = new VolumeDeletionStruct(); struct.setInventory(getSelfInventory()); struct.setDetachBeforeDeleting(detachBeforeDeleting); struct.setDeletionPolicy(deletionPolicyMgr.getDeletionPolicy(self.getUuid()).toString()); final List<VolumeDeletionStruct> ctx = list(struct); FlowChain chain = FlowChainBuilder.newSimpleFlowChain(); chain.setName("delete-data-volume"); if (!forceDelete) { chain .then( new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade( CascadeConstant.DELETION_CHECK_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }) .then( new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade( CascadeConstant.DELETION_DELETE_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); } else { chain.then( new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade( CascadeConstant.DELETION_FORCE_DELETE_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); } chain .done( new FlowDoneHandler(completion) { @Override public void handle(Map data) { casf.asyncCascadeFull( CascadeConstant.DELETION_CLEANUP_CODE, issuer, ctx, new NopeCompletion()); completion.success(); } }) .error( new FlowErrorHandler(completion) { @Override public void handle(ErrorCode errCode, Map data) { completion.fail(errCode); } }) .start(); } private void handle(APIDeleteDataVolumeMsg msg) { final APIDeleteDataVolumeEvent evt = new APIDeleteDataVolumeEvent(msg.getId()); delete( msg.getDeletionMode() == DeletionMode.Enforcing, new Completion(msg) { @Override public void success() { bus.publish(evt); } @Override public void fail(ErrorCode errorCode) { evt.setErrorCode(errf.instantiateErrorCode(SysErrors.DELETE_RESOURCE_ERROR, errorCode)); bus.publish(evt); } }); } private void handle(final APICreateVolumeSnapshotMsg msg) { thdf.chainSubmit( new ChainTask(msg) { @Override public String getSyncSignature() { return String.format("create-snapshot-for-volume-%s", self.getUuid()); } @Override public void run(final SyncTaskChain chain) { CreateVolumeSnapshotMsg cmsg = new CreateVolumeSnapshotMsg(); cmsg.setName(msg.getName()); cmsg.setDescription(msg.getDescription()); cmsg.setResourceUuid(msg.getResourceUuid()); cmsg.setAccountUuid(msg.getSession().getAccountUuid()); cmsg.setVolumeUuid(msg.getVolumeUuid()); bus.makeLocalServiceId(cmsg, VolumeSnapshotConstant.SERVICE_ID); bus.send( cmsg, new CloudBusCallBack(chain) { @Override public void run(MessageReply reply) { APICreateVolumeSnapshotEvent evt = new APICreateVolumeSnapshotEvent(msg.getId()); if (reply.isSuccess()) { CreateVolumeSnapshotReply creply = (CreateVolumeSnapshotReply) reply; evt.setInventory(creply.getInventory()); tagMgr.createTagsFromAPICreateMessage( msg, creply.getInventory().getUuid(), VolumeSnapshotVO.class.getSimpleName()); } else { evt.setErrorCode(reply.getError()); } bus.publish(evt); chain.next(); } }); } @Override public String getName() { return String.format("create-snapshot-for-volume-%s", self.getUuid()); } }); } private void handle(APIChangeVolumeStateMsg msg) { VolumeStateEvent sevt = VolumeStateEvent.valueOf(msg.getStateEvent()); if (sevt == VolumeStateEvent.enable) { self.setState(VolumeState.Enabled); } else { self.setState(VolumeState.Disabled); } self = dbf.updateAndRefresh(self); VolumeInventory inv = VolumeInventory.valueOf(self); APIChangeVolumeStateEvent evt = new APIChangeVolumeStateEvent(msg.getId()); evt.setInventory(inv); bus.publish(evt); } }
/** * 1. create a vm with 2 flat L3 networks 2. change the vm's default L3 network from one to another * * <p>confirm the ResetDefaultGatewayCmd sent to the backend */ public class TestMevocoMultipleNetwork1 { CLogger logger = Utils.getLogger(TestMevocoMultipleNetwork1.class); Deployer deployer; Api api; ComponentLoader loader; CloudBus bus; DatabaseFacade dbf; SessionInventory session; LocalStorageSimulatorConfig config; FlatNetworkServiceSimulatorConfig fconfig; KVMSimulatorConfig kconfig; PrimaryStorageOverProvisioningManager psRatioMgr; HostCapacityOverProvisioningManager hostRatioMgr; long totalSize = SizeUnit.GIGABYTE.toByte(100); @Before public void setUp() throws Exception { DBUtil.reDeployDB(); WebBeanConstructor con = new WebBeanConstructor(); deployer = new Deployer("deployerXml/mevoco/TestMevocoMultipleNetwork.xml", con); deployer.addSpringConfig("mevocoRelated.xml"); deployer.load(); loader = deployer.getComponentLoader(); bus = loader.getComponent(CloudBus.class); dbf = loader.getComponent(DatabaseFacade.class); config = loader.getComponent(LocalStorageSimulatorConfig.class); fconfig = loader.getComponent(FlatNetworkServiceSimulatorConfig.class); kconfig = loader.getComponent(KVMSimulatorConfig.class); psRatioMgr = loader.getComponent(PrimaryStorageOverProvisioningManager.class); hostRatioMgr = loader.getComponent(HostCapacityOverProvisioningManager.class); Capacity c = new Capacity(); c.total = totalSize; c.avail = totalSize; config.capacityMap.put("host1", c); deployer.build(); api = deployer.getApi(); session = api.loginAsAdmin(); } @Test public void test() throws ApiSenderException, InterruptedException { VmInstanceInventory vm = deployer.vms.get("TestVm"); final L3NetworkInventory l31 = deployer.l3Networks.get("TestL3Network1"); final L3NetworkInventory l32 = deployer.l3Networks.get("TestL3Network2"); VmNicInventory nic1 = CollectionUtils.find( vm.getVmNics(), new Function<VmNicInventory, VmNicInventory>() { @Override public VmNicInventory call(VmNicInventory arg) { return arg.getL3NetworkUuid().equals(l31.getUuid()) ? arg : null; } }); VmNicInventory nic2 = CollectionUtils.find( vm.getVmNics(), new Function<VmNicInventory, VmNicInventory>() { @Override public VmNicInventory call(VmNicInventory arg) { return arg.getL3NetworkUuid().equals(l32.getUuid()) ? arg : null; } }); VmInstanceInventory update = new VmInstanceInventory(); update.setUuid(vm.getUuid()); update.setDefaultL3NetworkUuid(l32.getUuid()); api.updateVm(update); TimeUnit.SECONDS.sleep(2); Assert.assertEquals(1, fconfig.resetDefaultGatewayCmds.size()); ResetDefaultGatewayCmd cmd = fconfig.resetDefaultGatewayCmds.get(0); Assert.assertEquals(nic1.getMac(), cmd.macOfGatewayToRemove); Assert.assertEquals(nic1.getGateway(), cmd.gatewayToRemove); Assert.assertEquals( new BridgeNameFinder().findByL3Uuid(l31.getUuid()), cmd.bridgeNameOfGatewayToRemove); Assert.assertEquals(nic2.getMac(), cmd.macOfGatewayToAdd); Assert.assertEquals(nic2.getGateway(), cmd.gatewayToAdd); Assert.assertEquals( new BridgeNameFinder().findByL3Uuid(l32.getUuid()), cmd.bridgeNameOfGatewayToAdd); } }
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE) public class VirtualRouterSyncPortForwardingRulesOnStartFlow implements Flow { private static CLogger logger = Utils.getLogger(VirtualRouterSyncPortForwardingRulesOnStartFlow.class); @Autowired private DatabaseFacade dbf; @Autowired private CloudBus bus; @Autowired private ErrorFacade errf; @Autowired private VirtualRouterManager vrMgr; @Transactional private List<PortForwardingRuleVO> findRulesForThisRouter( VirtualRouterVmInventory vr, Map<String, Object> data, boolean isNewCreated) { if (!isNewCreated) { String sql = "select rule from PortForwardingRuleVO rule, VirtualRouterPortForwardingRuleRefVO ref, VmNicVO nic, VmInstanceVO vm where vm.state = :vmState and nic.vmInstanceUuid = vm.uuid and rule.vmNicUuid = nic.uuid and rule.uuid = ref.uuid and ref.virtualRouterVmUuid = :vrUuid"; TypedQuery<PortForwardingRuleVO> q = dbf.getEntityManager().createQuery(sql, PortForwardingRuleVO.class); q.setParameter("vrUuid", vr.getUuid()); q.setParameter("vmState", VmInstanceState.Running); return q.getResultList(); } else { VmNicInventory publicNic = vr.getPublicNic(); VmNicInventory guestNic = vr.getGuestNic(); String sql = "select rule from PortForwardingRuleVO rule, VipVO vip, VmNicVO nic, VmInstanceVO vm where vm.uuid = nic.vmInstanceUuid and vm.state = :vmState and rule.vipUuid = vip.uuid and rule.vmNicUuid = nic.uuid and vip.l3NetworkUuid = :vipL3Uuid and nic.l3NetworkUuid = :guestL3Uuid"; TypedQuery<PortForwardingRuleVO> q = dbf.getEntityManager().createQuery(sql, PortForwardingRuleVO.class); q.setParameter("vipL3Uuid", publicNic.getL3NetworkUuid()); q.setParameter("guestL3Uuid", guestNic.getL3NetworkUuid()); q.setParameter("vmState", VmInstanceState.Running); List<PortForwardingRuleVO> rules = q.getResultList(); if (!rules.isEmpty()) { List<VirtualRouterPortForwardingRuleRefVO> refs = new ArrayList<VirtualRouterPortForwardingRuleRefVO>(); for (PortForwardingRuleVO rule : rules) { VirtualRouterPortForwardingRuleRefVO ref = new VirtualRouterPortForwardingRuleRefVO(); ref.setVirtualRouterVmUuid(vr.getUuid()); ref.setVipUuid(rule.getVipUuid()); ref.setUuid(rule.getUuid()); dbf.getEntityManager().persist(ref); refs.add(ref); } data.put(VirtualRouterSyncPortForwardingRulesOnStartFlow.class.getName(), refs); } return rules; } } @Transactional(readOnly = true) private Collection<PortForwardingRuleTO> calculateAllRules( Map<String, PortForwardingRuleVO> ruleMap, String vrUuid) { String sql = "select rule.uuid, nic.ip, vip.ip from PortForwardingRuleVO rule, VmNicVO nic, VipVO vip where rule.vmNicUuid = nic.uuid and rule.uuid in (:ruleUuids) and vip.uuid = rule.vipUuid"; TypedQuery<Tuple> q = dbf.getEntityManager().createQuery(sql, Tuple.class); q.setParameter("ruleUuids", ruleMap.keySet()); List<Tuple> privateIps = q.getResultList(); Map<String, PortForwardingRuleTO> tos = new HashMap<String, PortForwardingRuleTO>(); for (Tuple t : privateIps) { String ruleUuid = t.get(0, String.class); PortForwardingRuleTO to = new PortForwardingRuleTO(); to.setPrivateIp(t.get(1, String.class)); PortForwardingRuleVO ruleVO = ruleMap.get(ruleUuid); to.setAllowedCidr(ruleVO.getAllowedCidr()); to.setPrivatePortEnd(ruleVO.getPrivatePortEnd()); to.setPrivatePortStart(ruleVO.getPrivatePortStart()); to.setVipPortEnd(ruleVO.getVipPortEnd()); to.setSnatInboundTraffic( PortForwardingGlobalConfig.SNAT_INBOUND_TRAFFIC.value(Boolean.class)); to.setVipPortStart(ruleVO.getVipPortStart()); to.setVipIp(t.get(2, String.class)); to.setProtocolType(ruleVO.getProtocolType().toString()); tos.put(ruleUuid, to); } assert tos.size() == ruleMap.size(); sql = "select rule.uuid, vrnic.mac from PortForwardingRuleVO rule, VmNicVO vrnic, VmNicVO nic2, ApplianceVmVO vr where vr.uuid = vrnic.vmInstanceUuid and vrnic.l3NetworkUuid = nic2.l3NetworkUuid and nic2.uuid = rule.vmNicUuid and rule.uuid in (:ruleUuids) and vr.uuid = :vrUuid"; TypedQuery<Tuple> privateMacQuery = dbf.getEntityManager().createQuery(sql, Tuple.class); privateMacQuery.setParameter("ruleUuids", ruleMap.keySet()); privateMacQuery.setParameter("vrUuid", vrUuid); List<Tuple> privateMacs = privateMacQuery.getResultList(); for (Tuple t : privateMacs) { String ruleUuid = t.get(0, String.class); PortForwardingRuleTO to = tos.get(ruleUuid); to.setPrivateMac(t.get(1, String.class)); } return tos.values(); } @Override public void run(final FlowTrigger chain, Map data) { final VirtualRouterVmInventory vr = (VirtualRouterVmInventory) data.get(VirtualRouterConstant.Param.VR.toString()); VmNicInventory guestNic = vr.getGuestNic(); if (!vrMgr.isL3NetworkNeedingNetworkServiceByVirtualRouter( guestNic.getL3NetworkUuid(), PortForwardingConstant.PORTFORWARDING_NETWORK_SERVICE_TYPE)) { chain.next(); return; } boolean isNewCreated = data.containsKey(Param.IS_NEW_CREATED.toString()); List<PortForwardingRuleVO> ruleVOs = findRulesForThisRouter(vr, data, isNewCreated); if (ruleVOs.isEmpty()) { chain.next(); return; } Map<String, PortForwardingRuleVO> ruleMap = new HashMap<String, PortForwardingRuleVO>(ruleVOs.size()); for (PortForwardingRuleVO rvo : ruleVOs) { ruleMap.put(rvo.getUuid(), rvo); } Collection<PortForwardingRuleTO> tos = calculateAllRules(ruleMap, vr.getUuid()); List<PortForwardingRuleTO> toList = new ArrayList<PortForwardingRuleTO>(tos.size()); toList.addAll(tos); SyncPortForwardingRuleCmd cmd = new SyncPortForwardingRuleCmd(); cmd.setRules(toList); VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg(); msg.setCommand(cmd); msg.setPath(VirtualRouterConstant.VR_SYNC_PORT_FORWARDING); msg.setVmInstanceUuid(vr.getUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send( msg, new CloudBusCallBack(chain) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { chain.fail(reply.getError()); return; } VirtualRouterAsyncHttpCallReply re = reply.castReply(); SyncPortForwardingRuleRsp ret = re.toResponse(SyncPortForwardingRuleRsp.class); if (ret.isSuccess()) { String info = String.format( "successfully sync port forwarding rules served by virtual router[name: %s uuid: %s]", vr.getName(), vr.getUuid()); logger.debug(info); chain.next(); } else { String err = String.format( "failed to sync port forwarding rules served by virtual router[name: %s, uuid: %s], because %s", vr.getName(), vr.getUuid(), ret.getError()); logger.warn(err); chain.fail(errf.stringToOperationError(err)); } } }); } @Override public void rollback(FlowTrigger chain, Map data) { List<VirtualRouterPortForwardingRuleRefVO> refs = (List<VirtualRouterPortForwardingRuleRefVO>) data.get(VirtualRouterSyncPortForwardingRulesOnStartFlow.class.getName()); if (refs != null) { dbf.removeCollection(refs, VirtualRouterPortForwardingRuleRefVO.class); } chain.rollback(); } }
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE) public class VirtualRouterSyncDnsOnStartFlow extends NoRollbackFlow { private static final CLogger logger = Utils.getLogger(VirtualRouterSyncDnsOnStartFlow.class); @Autowired private CloudBus bus; @Autowired private VirtualRouterManager vrMgr; @Autowired private DatabaseFacade dbf; @Autowired private ErrorFacade errf; @Autowired private ApiTimeoutManager apiTimeoutManager; @Override public void run(final FlowTrigger chain, final Map data) { final VirtualRouterVmInventory vr = (VirtualRouterVmInventory) data.get(VirtualRouterConstant.Param.VR.toString()); List<String> nwServed = vr.getGuestL3Networks(); List<String> l3Uuids = vrMgr.selectL3NetworksNeedingSpecificNetworkService(nwServed, NetworkServiceType.DNS); if (l3Uuids.isEmpty()) { chain.next(); return; } if (VirtualRouterSystemTags.DEDICATED_ROLE_VR.hasTag(vr.getUuid()) && !VirtualRouterSystemTags.VR_DNS_ROLE.hasTag(vr.getUuid())) { chain.next(); return; } new VirtualRouterRoleManager().makeDnsRole(vr.getUuid()); SimpleQuery<L3NetworkDnsVO> query = dbf.createQuery(L3NetworkDnsVO.class); query.select(L3NetworkDnsVO_.dns); query.add(L3NetworkDnsVO_.l3NetworkUuid, Op.IN, l3Uuids); List<String> lst = query.listValue(); if (lst.isEmpty()) { chain.next(); return; } Set<String> dnsAddresses = new HashSet<String>(lst.size()); dnsAddresses.addAll(lst); final List<DnsInfo> dns = new ArrayList<DnsInfo>(dnsAddresses.size()); for (String d : dnsAddresses) { DnsInfo dinfo = new DnsInfo(); dinfo.setDnsAddress(d); dns.add(dinfo); } SetDnsCmd cmd = new SetDnsCmd(); cmd.setDns(dns); VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg(); msg.setVmInstanceUuid(vr.getUuid()); msg.setPath(VirtualRouterConstant.VR_SET_DNS_PATH); msg.setCommand(cmd); msg.setCommandTimeout(apiTimeoutManager.getTimeout(cmd.getClass(), "5m")); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send( msg, new CloudBusCallBack(chain) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { chain.fail(reply.getError()); return; } VirtualRouterAsyncHttpCallReply re = reply.castReply(); SetDnsRsp ret = re.toResponse(SetDnsRsp.class); if (ret.isSuccess()) { chain.next(); } else { String err = String.format( "virtual router[name: %s, uuid: %s] failed to configure dns%s, %s ", vr.getName(), vr.getUuid(), JSONObjectUtil.toJsonString(dns), ret.getError()); logger.warn(err); chain.fail(errf.stringToOperationError(err)); } } }); } }
public class TestReturnPrimaryStorage { CLogger logger = Utils.getLogger(TestReturnPrimaryStorage.class); Api api; ComponentLoader loader; DatabaseFacade dbf; CloudBus bus; @Before public void setUp() throws Exception { DBUtil.reDeployDB(); BeanConstructor con = new BeanConstructor(); /* This loads spring application context */ loader = con.addXml("PortalForUnitTest.xml") .addXml("Simulator.xml") .addXml("PrimaryStorageManager.xml") .addXml("ZoneManager.xml") .addXml("ClusterManager.xml") .addXml("HostManager.xml") .addXml("ConfigurationManager.xml") .addXml("AccountManager.xml") .build(); dbf = loader.getComponent(DatabaseFacade.class); bus = loader.getComponent(CloudBus.class); api = new Api(); api.startServer(); } @After public void tearDown() throws Exception { api.stopServer(); } @Test public void test() throws ApiSenderException, InterruptedException { long requiredSize = SizeUnit.GIGABYTE.toByte(10); SimulatorPrimaryStorageDetails sp = new SimulatorPrimaryStorageDetails(); sp.setTotalCapacity(SizeUnit.TERABYTE.toByte(10)); sp.setAvailableCapacity(sp.getTotalCapacity()); sp.setUrl("nfs://simulator/primary/"); PrimaryStorageInventory pinv = api.createSimulatoPrimaryStorage(1, sp).get(0); ZoneInventory zone = api.createZones(1).get(0); ClusterInventory cluster = api.createClusters(1, zone.getUuid()).get(0); HostInventory host = api.createHost(1, cluster.getUuid()).get(0); api.attachPrimaryStorage(cluster.getUuid(), pinv.getUuid()); AllocatePrimaryStorageMsg msg = new AllocatePrimaryStorageMsg(); msg.setRequiredHostUuid(host.getUuid()); msg.setSize(requiredSize); msg.setServiceId(bus.makeLocalServiceId(PrimaryStorageConstant.SERVICE_ID)); MessageReply reply = bus.call(msg); Assert.assertEquals(AllocatePrimaryStorageReply.class, reply.getClass()); AllocatePrimaryStorageReply ar = (AllocatePrimaryStorageReply) reply; Assert.assertEquals(pinv.getUuid(), ar.getPrimaryStorageInventory().getUuid()); ReturnPrimaryStorageCapacityMsg rmsg = new ReturnPrimaryStorageCapacityMsg(); rmsg.setDiskSize(requiredSize); rmsg.setPrimaryStorageUuid(pinv.getUuid()); rmsg.setServiceId(bus.makeLocalServiceId(PrimaryStorageConstant.SERVICE_ID)); bus.send(rmsg); Thread.sleep(2000); PrimaryStorageVO pvo = dbf.findByUuid(pinv.getUuid(), PrimaryStorageVO.class); Assert.assertEquals( pvo.getCapacity().getTotalCapacity(), pvo.getCapacity().getAvailableCapacity()); } }
/** * Created with IntelliJ IDEA. User: frank Time: 5:38 PM To change this template use File | Settings * | File Templates. */ @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE) public class ImageBase implements Image { private static final CLogger logger = Utils.getLogger(ImageBase.class); @Autowired protected CloudBus bus; @Autowired protected DatabaseFacade dbf; @Autowired private CascadeFacade casf; @Autowired private ErrorFacade errf; @Autowired private ImageDeletionPolicyManager deletionPolicyMgr; protected ImageVO self; ImageBase(ImageVO vo) { self = vo; } @Override public void handleMessage(Message msg) { try { if (msg instanceof APIMessage) { handleApiMessage((APIMessage) msg); } else { handleLocalMessage(msg); } } catch (Exception e) { bus.logExceptionWithMessageDump(msg, e); bus.replyErrorByMessageType(msg, e); } } protected ImageVO getSelf() { return self; } protected ImageInventory getSelfInventory() { return ImageInventory.valueOf(getSelf()); } private void handleLocalMessage(Message msg) { if (msg instanceof ImageDeletionMsg) { handle((ImageDeletionMsg) msg); } else if (msg instanceof ExpungeImageMsg) { handle((ExpungeImageMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } private void handle(final ExpungeImageMsg msg) { final ExpungeImageReply reply = new ExpungeImageReply(); final ImageBackupStorageRefVO ref = CollectionUtils.find( self.getBackupStorageRefs(), new Function<ImageBackupStorageRefVO, ImageBackupStorageRefVO>() { @Override public ImageBackupStorageRefVO call(ImageBackupStorageRefVO arg) { return arg.getBackupStorageUuid().equals(msg.getBackupStorageUuid()) ? arg : null; } }); if (ref == null) { logger.debug( String.format( "cannot find reference for the image[uuid:%s] on the backup storage[uuid:%s], assume it's been deleted", self.getUuid(), msg.getBackupStorageUuid())); bus.reply(msg, reply); return; } DeleteBitsOnBackupStorageMsg dmsg = new DeleteBitsOnBackupStorageMsg(); dmsg.setBackupStorageUuid(ref.getBackupStorageUuid()); dmsg.setInstallPath(ref.getInstallPath()); bus.makeTargetServiceIdByResourceUuid( dmsg, BackupStorageConstant.SERVICE_ID, dmsg.getBackupStorageUuid()); bus.send( dmsg, new CloudBusCallBack(msg) { @Override public void run(MessageReply r) { if (!r.isSuccess()) { // TODO logger.warn( String.format( "failed to delete image[uuid:%s, name:%s] from backup storage[uuid:%s] because %s, need to garbage collect it", self.getUuid(), self.getName(), r.getError(), ref.getBackupStorageUuid())); reply.setError(r.getError()); } else { returnBackupStorageCapacity(ref.getBackupStorageUuid(), self.getSize()); dbf.remove(ref); logger.debug( String.format( "successfully expunged the image[uuid: %s, name: %s] on the backup storage[uuid: %s]", self.getUuid(), self.getName(), ref.getBackupStorageUuid())); self = dbf.findByUuid(self.getUuid(), ImageVO.class); if (self.getBackupStorageRefs().isEmpty()) { logger.debug( String.format( "the image[uuid:%s, name:%s] has been expunged on all backup storage, remove it from database", self.getUuid(), self.getName())); dbf.remove(self); } } bus.reply(msg, reply); } }); } private void returnBackupStorageCapacity(final String bsUuid, final long size) { ReturnBackupStorageMsg msg = new ReturnBackupStorageMsg(); msg.setBackupStorageUuid(bsUuid); msg.setSize(size); bus.makeTargetServiceIdByResourceUuid(msg, BackupStorageConstant.SERVICE_ID, bsUuid); bus.send( msg, new CloudBusCallBack() { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { // TODO logger.warn( String.format( "failed to return capacity[%s] to the backup storage[uuid:%s]", size, bsUuid)); } } }); } private void handle(final ImageDeletionMsg msg) { final ImageDeletionReply reply = new ImageDeletionReply(); if (self.getBackupStorageRefs().isEmpty()) { // the image is not on any backup storage; mostly likely the image is not in the status of // Ready, for example // it's still downloading // in this case, we directly delete it from the database dbf.remove(self); bus.reply(msg, reply); return; } final ImageDeletionPolicy deletionPolicy = msg.getDeletionPolicy() == null ? deletionPolicyMgr.getDeletionPolicy(self.getUuid()) : ImageDeletionPolicy.valueOf(msg.getDeletionPolicy()); FlowChain chain = FlowChainBuilder.newSimpleFlowChain(); chain.setName(String.format("delete-image-%s", self.getUuid())); Collection<ImageBackupStorageRefVO> toDelete = msg.getBackupStorageUuids() == null ? self.getBackupStorageRefs() : CollectionUtils.transformToList( self.getBackupStorageRefs(), new Function<ImageBackupStorageRefVO, ImageBackupStorageRefVO>() { @Override public ImageBackupStorageRefVO call(ImageBackupStorageRefVO arg) { return msg.getBackupStorageUuids().contains(arg.getBackupStorageUuid()) ? arg : null; } }); for (final ImageBackupStorageRefVO ref : toDelete) { chain.then( new NoRollbackFlow() { String __name__ = String.format( "delete-image-%s-from-backup-storage-%s", self.getUuid(), ref.getBackupStorageUuid()); @Override public void run(final FlowTrigger trigger, Map data) { if (deletionPolicy == ImageDeletionPolicy.Direct) { DeleteBitsOnBackupStorageMsg dmsg = new DeleteBitsOnBackupStorageMsg(); dmsg.setBackupStorageUuid(ref.getBackupStorageUuid()); dmsg.setInstallPath(ref.getInstallPath()); bus.makeTargetServiceIdByResourceUuid( dmsg, BackupStorageConstant.SERVICE_ID, dmsg.getBackupStorageUuid()); bus.send( dmsg, new CloudBusCallBack(trigger) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { // TODO logger.warn( String.format( "failed to delete image[uuid:%s, name:%s] from backup storage[uuid:%s] because %s, need to garbage collect it", self.getUuid(), self.getName(), reply.getError(), ref.getBackupStorageUuid())); } else { returnBackupStorageCapacity(ref.getBackupStorageUuid(), self.getSize()); dbf.remove(ref); } trigger.next(); } }); } else if (deletionPolicy == ImageDeletionPolicy.DeleteReference) { dbf.remove(ref); logger.debug( String.format( "delete the image[uuid: %s, name:%s]'s reference of the backup storage[uuid:%s]", self.getUuid(), self.getName(), ref.getBackupStorageUuid())); trigger.next(); } else { ref.setStatus(ImageStatus.Deleted); dbf.update(ref); trigger.next(); } } }); } chain .done( new FlowDoneHandler(msg) { @Override public void handle(Map data) { self = dbf.reload(self); if (self.getBackupStorageRefs().isEmpty()) { dbf.remove(self); if (deletionPolicy == ImageDeletionPolicy.DeleteReference) { logger.debug( String.format( "successfully directly deleted the image[uuid:%s, name:%s] from the database," + " as the policy is DeleteReference, it's still on the physical backup storage", self.getUuid(), self.getName())); } else { logger.debug( String.format( "successfully directly deleted the image[uuid:%s, name:%s]", self.getUuid(), self.getName())); } } else { int deleteCount = 0; for (ImageBackupStorageRefVO ref : self.getBackupStorageRefs()) { if (ref.getStatus() == ImageStatus.Deleted) { deleteCount++; } } if (deleteCount == self.getBackupStorageRefs().size()) { self.setStatus(ImageStatus.Deleted); self = dbf.updateAndRefresh(self); logger.debug( String.format( "successfully deleted the image[uuid:%s, name:%s] with deletion policy[%s]", self.getUuid(), self.getName(), deletionPolicy)); } } bus.reply(msg, reply); } }) .error( new FlowErrorHandler(msg) { @Override public void handle(ErrorCode errCode, Map data) { reply.setError(errCode); bus.reply(msg, reply); } }) .start(); } private void handleApiMessage(APIMessage msg) { if (msg instanceof APIChangeImageStateMsg) { handle((APIChangeImageStateMsg) msg); } else if (msg instanceof APIExpungeImageMsg) { handle((APIExpungeImageMsg) msg); } else if (msg instanceof APIDeleteImageMsg) { handle((APIDeleteImageMsg) msg); } else if (msg instanceof APIUpdateImageMsg) { handle((APIUpdateImageMsg) msg); } else if (msg instanceof APIRecoverImageMsg) { handle((APIRecoverImageMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } private void handle(APIRecoverImageMsg msg) { List<String> toRecoverBsUuids; if (msg.getBackupStorageUuids() == null || msg.getBackupStorageUuids().isEmpty()) { toRecoverBsUuids = CollectionUtils.transformToList( self.getBackupStorageRefs(), new Function<String, ImageBackupStorageRefVO>() { @Override public String call(ImageBackupStorageRefVO arg) { return arg.getStatus() == ImageStatus.Deleted ? arg.getBackupStorageUuid() : null; } }); if (toRecoverBsUuids.isEmpty()) { throw new OperationFailureException( errf.stringToOperationError( String.format( "the image[uuid:%s, name:%s] is not deleted on any backup storage", self.getUuid(), self.getName()))); } } else { toRecoverBsUuids = new ArrayList<String>(); for (final String bsUuid : msg.getBackupStorageUuids()) { ImageBackupStorageRefVO ref = CollectionUtils.find( self.getBackupStorageRefs(), new Function<ImageBackupStorageRefVO, ImageBackupStorageRefVO>() { @Override public ImageBackupStorageRefVO call(ImageBackupStorageRefVO arg) { return bsUuid.equals(arg.getBackupStorageUuid()) ? arg : null; } }); if (ref == null) { throw new OperationFailureException( errf.stringToInvalidArgumentError( String.format( "the image[uuid:%s, name:%s] is not on the backup storage[uuid:%s]", self.getUuid(), self.getName(), bsUuid))); } if (ref.getStatus() != ImageStatus.Deleted) { throw new OperationFailureException( errf.stringToInvalidArgumentError( String.format( "the image[uuid:%s, name:%s]'s status[%s] is not Deleted on the backup storage[uuid:%s]", self.getUuid(), self.getName(), ref.getStatus(), bsUuid))); } toRecoverBsUuids.add(bsUuid); } } for (ImageBackupStorageRefVO ref : self.getBackupStorageRefs()) { if (toRecoverBsUuids.contains(ref.getBackupStorageUuid())) { ref.setStatus(ImageStatus.Ready); dbf.update(ref); } } self.setStatus(ImageStatus.Ready); self = dbf.updateAndRefresh(self); logger.debug( String.format( "successfully recovered the image[uuid:%s, name:%s] on the backup storage%s", self.getUuid(), self.getName(), toRecoverBsUuids)); APIRecoverImageEvent evt = new APIRecoverImageEvent(msg.getId()); evt.setInventory(getSelfInventory()); bus.publish(evt); } private void handle(final APIExpungeImageMsg msg) { List<String> bsUuids = new ArrayList<String>(); if (msg.getBackupStorageUuids() == null || msg.getBackupStorageUuids().isEmpty()) { bsUuids = CollectionUtils.transformToList( self.getBackupStorageRefs(), new Function<String, ImageBackupStorageRefVO>() { @Override public String call(ImageBackupStorageRefVO arg) { return ImageStatus.Deleted == arg.getStatus() ? arg.getBackupStorageUuid() : null; } }); if (bsUuids.isEmpty()) { throw new OperationFailureException( errf.stringToOperationError( String.format( "the image[uuid:%s, name:%s] is not deleted on any backup storage", self.getUuid(), self.getName()))); } } else { for (final String bsUuid : msg.getBackupStorageUuids()) { ImageBackupStorageRefVO ref = CollectionUtils.find( self.getBackupStorageRefs(), new Function<ImageBackupStorageRefVO, ImageBackupStorageRefVO>() { @Override public ImageBackupStorageRefVO call(ImageBackupStorageRefVO arg) { return arg.getBackupStorageUuid().equals(bsUuid) ? arg : null; } }); if (ref == null) { throw new OperationFailureException( errf.stringToInvalidArgumentError( String.format( "the image[uuid:%s, name:%s] is not on the backup storage[uuid:%s]", self.getUuid(), self.getName(), bsUuid))); } if (ref.getStatus() != ImageStatus.Deleted) { throw new OperationFailureException( errf.stringToInvalidArgumentError( String.format( "the image[uuid:%s, name:%s] is not deleted on the backup storage[uuid:%s]", self.getUuid(), self.getName(), bsUuid))); } bsUuids.add(bsUuid); } } List<ExpungeImageMsg> emsgs = CollectionUtils.transformToList( bsUuids, new Function<ExpungeImageMsg, String>() { @Override public ExpungeImageMsg call(String arg) { ExpungeImageMsg emsg = new ExpungeImageMsg(); emsg.setBackupStorageUuid(arg); emsg.setImageUuid(self.getUuid()); bus.makeTargetServiceIdByResourceUuid( emsg, ImageConstant.SERVICE_ID, self.getUuid()); return emsg; } }); final List<String> finalBsUuids = bsUuids; final APIExpungeImageEvent evt = new APIExpungeImageEvent(msg.getId()); bus.send( emsgs, new CloudBusListCallBack(msg) { @Override public void run(List<MessageReply> replies) { for (MessageReply r : replies) { if (!r.isSuccess()) { String bsUuid = finalBsUuids.get(replies.indexOf(r)); // TODO logger.warn( String.format( "failed to expunge the image[uuid:%s, name:%s] on the backup storage[uuid:%s]" + ", %s", self.getUuid(), self.getName(), bsUuid, r.getError())); } } bus.publish(evt); } }); } private void handle(APIUpdateImageMsg msg) { boolean update = false; if (msg.getName() != null) { self.setName(msg.getName()); update = true; } if (msg.getDescription() != null) { self.setDescription(msg.getDescription()); update = true; } if (msg.getSystem() != null) { self.setSystem(msg.getSystem()); update = true; } if (msg.getGuestOsType() != null) { self.setGuestOsType(msg.getGuestOsType()); update = true; } if (msg.getMediaType() != null) { self.setMediaType(ImageMediaType.valueOf(msg.getMediaType())); update = true; } if (msg.getFormat() != null) { self.setFormat(msg.getFormat()); update = true; } if (msg.getPlatform() != null) { self.setPlatform(ImagePlatform.valueOf(msg.getPlatform())); update = true; } if (update) { self = dbf.updateAndRefresh(self); } APIUpdateImageEvent evt = new APIUpdateImageEvent(msg.getId()); evt.setInventory(getSelfInventory()); bus.publish(evt); } private void handle(APIChangeImageStateMsg msg) { ImageStateEvent sevt = ImageStateEvent.valueOf(msg.getStateEvent()); if (sevt == ImageStateEvent.disable) { self.setState(ImageState.Disabled); } else { self.setState(ImageState.Enabled); } self = dbf.updateAndRefresh(self); APIChangeImageStateEvent evt = new APIChangeImageStateEvent(msg.getId()); evt.setInventory(ImageInventory.valueOf(self)); bus.publish(evt); } private void handle(APIDeleteImageMsg msg) { final APIDeleteImageEvent evt = new APIDeleteImageEvent(msg.getId()); final String issuer = ImageVO.class.getSimpleName(); ImageDeletionStruct struct = new ImageDeletionStruct(); struct.setImage(ImageInventory.valueOf(self)); struct.setBackupStorageUuids(msg.getBackupStorageUuids()); final List<ImageDeletionStruct> ctx = Arrays.asList(struct); FlowChain chain = FlowChainBuilder.newSimpleFlowChain(); chain.setName(String.format("delete-image-%s", msg.getUuid())); if (msg.getDeletionMode() == APIDeleteMessage.DeletionMode.Permissive) { chain .then( new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade( CascadeConstant.DELETION_CHECK_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }) .then( new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade( CascadeConstant.DELETION_DELETE_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); } else { chain.then( new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade( CascadeConstant.DELETION_FORCE_DELETE_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); } chain .done( new FlowDoneHandler(msg) { @Override public void handle(Map data) { casf.asyncCascadeFull( CascadeConstant.DELETION_CLEANUP_CODE, issuer, ctx, new NopeCompletion()); bus.publish(evt); } }) .error( new FlowErrorHandler(msg) { @Override public void handle(ErrorCode errCode, Map data) { evt.setErrorCode( errf.instantiateErrorCode(SysErrors.DELETE_RESOURCE_ERROR, errCode)); bus.publish(evt); } }) .start(); } }
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE) public abstract class BackupStorageBase extends AbstractBackupStorage { private static final CLogger logger = Utils.getLogger(BackupStorageBase.class); protected BackupStorageVO self; @Autowired protected CloudBus bus; @Autowired protected DatabaseFacade dbf; @Autowired protected GlobalConfigFacade gcf; @Autowired protected BackupStorageExtensionPointEmitter extpEmitter; @Autowired protected CascadeFacade casf; @Autowired protected ErrorFacade errf; @Autowired protected ThreadFacade thdf; @Autowired protected BackupStoragePingTracker tracker; @Autowired protected EventFacade evtf; @Autowired protected RESTFacade restf; protected abstract void handle(DownloadImageMsg msg); protected abstract void handle(DownloadVolumeMsg msg); protected abstract void handle(DeleteBitsOnBackupStorageMsg msg); protected abstract void handle(BackupStorageAskInstallPathMsg msg); protected abstract void handle(GetImageSizeOnBackupStorageMsg msg); protected abstract void handle(SyncImageSizeOnBackupStorageMsg msg); protected abstract void connectHook(boolean newAdd, Completion completion); protected abstract void pingHook(Completion completion); public BackupStorageBase(BackupStorageVO self) { this.self = self; } @Override public void deleteHook() {} @Override public void detachHook(Completion completion) { completion.success(); } @Override public void attachHook(String zoneUuid, Completion completion) { completion.success(); } @Override public void changeStateHook(BackupStorageStateEvent evt, BackupStorageState nextState) {} protected void exceptionIfImageSizeGreaterThanAvailableCapacity(String url) { if (CoreGlobalProperty.UNIT_TEST_ON) { return; } url = url.trim(); if (!url.startsWith("http") && !url.startsWith("https")) { return; } String len; try { HttpHeaders header = restf.getRESTTemplate().headForHeaders(url); len = header.getFirst("Content-Length"); } catch (Exception e) { logger.warn(String.format("cannot get image. The image url : %s.", url)); return; } if (len == null) { return; } long size = Long.valueOf(len); if (size > self.getAvailableCapacity()) { throw new OperationFailureException( errf.stringToOperationError( String.format( "the backup storage[uuid:%s, name:%s] has not enough capacity to download the image[%s]." + "Required size:%s, available size:%s", self.getUuid(), self.getName(), url, size, self.getAvailableCapacity()))); } } protected void refreshVO() { self = dbf.reload(self); } protected BackupStorageInventory getSelfInventory() { return BackupStorageInventory.valueOf(self); } protected void checkStatus(Message msg) { if (!statusChecker.isOperationAllowed(msg.getClass().getName(), self.getStatus().toString())) { throw new OperationFailureException( errf.stringToOperationError( String.format( "backup storage cannot proceed message[%s] because its status is %s", msg.getClass().getName(), self.getStatus()))); } } protected void checkState(Message msg) { if (!stateChecker.isOperationAllowed(msg.getClass().getName(), self.getState().toString())) { throw new OperationFailureException( errf.stringToOperationError( String.format( "backup storage cannot proceed message[%s] because its state is %s", msg.getClass().getName(), self.getState()))); } } @Override public void handleMessage(Message msg) { try { if (msg instanceof APIMessage) { handleApiMessage((APIMessage) msg); } else { handleLocalMessage(msg); } } catch (Exception e) { bus.logExceptionWithMessageDump(msg, e); bus.replyErrorByMessageType(msg, e); } } protected void handleLocalMessage(Message msg) throws URISyntaxException { if (msg instanceof DownloadImageMsg) { handleBase((DownloadImageMsg) msg); } else if (msg instanceof ScanBackupStorageMsg) { handle((ScanBackupStorageMsg) msg); } else if (msg instanceof BackupStorageDeletionMsg) { handle((BackupStorageDeletionMsg) msg); } else if (msg instanceof ChangeBackupStorageStatusMsg) { handle((ChangeBackupStorageStatusMsg) msg); } else if (msg instanceof ConnectBackupStorageMsg) { handle((ConnectBackupStorageMsg) msg); } else if (msg instanceof ReturnBackupStorageMsg) { handle((ReturnBackupStorageMsg) msg); } else if (msg instanceof DownloadVolumeMsg) { handleBase((DownloadVolumeMsg) msg); } else if (msg instanceof DeleteBitsOnBackupStorageMsg) { handleBase((DeleteBitsOnBackupStorageMsg) msg); } else if (msg instanceof PingBackupStorageMsg) { handle((PingBackupStorageMsg) msg); } else if (msg instanceof BackupStorageAskInstallPathMsg) { handle((BackupStorageAskInstallPathMsg) msg); } else if (msg instanceof SyncImageSizeOnBackupStorageMsg) { handle((SyncImageSizeOnBackupStorageMsg) msg); } else if (msg instanceof GetImageSizeOnBackupStorageMsg) { handle((GetImageSizeOnBackupStorageMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } private void handle(final PingBackupStorageMsg msg) { final PingBackupStorageReply reply = new PingBackupStorageReply(); pingHook( new Completion(msg) { private void reconnect() { ConnectBackupStorageMsg cmsg = new ConnectBackupStorageMsg(); cmsg.setBackupStorageUuid(self.getUuid()); cmsg.setNewAdd(false); bus.makeTargetServiceIdByResourceUuid( cmsg, BackupStorageConstant.SERVICE_ID, self.getUuid()); bus.send(cmsg); } @Override public void success() { if (self.getStatus() != BackupStorageStatus.Connected) { reconnect(); } bus.reply(msg, reply); } @Override public void fail(ErrorCode errorCode) { changeStatus(BackupStorageStatus.Disconnected); Boolean doReconnect = (Boolean) errorCode.getFromOpaque(Opaque.RECONNECT_AGENT.toString()); if (doReconnect != null && doReconnect) { reconnect(); } reply.setError(errorCode); bus.reply(msg, reply); } }); } private void handleBase(DownloadImageMsg msg) { checkState(msg); checkStatus(msg); exceptionIfImageSizeGreaterThanAvailableCapacity(msg.getImageInventory().getUrl()); handle(msg); } private void handleBase(DownloadVolumeMsg msg) { checkState(msg); checkStatus(msg); handle(msg); } private void handleBase(DeleteBitsOnBackupStorageMsg msg) { checkState(msg); checkStatus(msg); handle(msg); } @Transactional private void handle(ReturnBackupStorageMsg msg) { self = dbf.getEntityManager() .find(BackupStorageVO.class, self.getUuid(), LockModeType.PESSIMISTIC_WRITE); long availSize = self.getAvailableCapacity() + msg.getSize(); if (availSize > self.getTotalCapacity()) { availSize = self.getTotalCapacity(); } self.setAvailableCapacity(availSize); dbf.getEntityManager().merge(self); bus.reply(msg, new ReturnBackupStorageReply()); } private void handle(final ConnectBackupStorageMsg msg) { thdf.chainSubmit( new ChainTask(msg) { @Override public String getSyncSignature() { return String.format("connect-backup-storage-%s", self.getUuid()); } @Override public void run(final SyncTaskChain chain) { final ConnectBackupStorageReply reply = new ConnectBackupStorageReply(); changeStatus(BackupStorageStatus.Connecting); connectHook( msg.isNewAdd(), new Completion(msg, chain) { @Override public void success() { self = dbf.reload(self); changeStatus(BackupStorageStatus.Connected); tracker.track(self.getUuid()); bus.reply(msg, reply); chain.next(); } @Override public void fail(ErrorCode errorCode) { if (!msg.isNewAdd()) { changeStatus(BackupStorageStatus.Disconnected); } reply.setError(errorCode); bus.reply(msg, reply); chain.next(); } }); } @Override public String getName() { return getSyncSignature(); } }); } protected void changeStatus( final BackupStorageStatus status, final NoErrorCompletion completion) { thdf.syncSubmit( new SyncTask<Void>() { private String name = String.format("backupstorage-%s-change-status", self.getUuid()); @Override public String getSyncSignature() { return name; } @Override public int getSyncLevel() { return 1; } @Override public String getName() { return name; } @Override public Void call() throws Exception { if (status == self.getStatus()) { completion.done(); return null; } changeStatus(status); logger.debug( String.format( "backup storage[uuid:%s, name:%s] change status from %s to %s", self.getUuid(), self.getName(), self.getStatus(), status)); completion.done(); return null; } }); } private void handle(final ChangeBackupStorageStatusMsg msg) { changeStatus( BackupStorageStatus.valueOf(msg.getStatus()), new NoErrorCompletion(msg) { @Override public void done() { ChangeBackupStorageStatusReply reply = new ChangeBackupStorageStatusReply(); bus.reply(msg, reply); } }); } private void handle(BackupStorageDeletionMsg msg) { BackupStorageInventory inv = BackupStorageInventory.valueOf(self); extpEmitter.beforeDelete(inv); deleteHook(); extpEmitter.afterDelete(inv); BackupStorageDeletionReply reply = new BackupStorageDeletionReply(); tracker.untrackHook(self.getUuid()); bus.reply(msg, reply); } private void doScanImages() { try { List<ImageInventory> images = this.scanImages(); } catch (Exception e) { logger.warn( String.format( "Unhandled exception happened while scanning backup storage[uuid:%s]", self.getUuid()), e); } } private void handle(ScanBackupStorageMsg msg) { doScanImages(); } protected void handleApiMessage(APIMessage msg) { try { if (msg instanceof APIDeleteBackupStorageMsg) { handle((APIDeleteBackupStorageMsg) msg); } else if (msg instanceof APIChangeBackupStorageStateMsg) { handle((APIChangeBackupStorageStateMsg) msg); } else if (msg instanceof APIAttachBackupStorageToZoneMsg) { handle((APIAttachBackupStorageToZoneMsg) msg); } else if (msg instanceof APIDetachBackupStorageFromZoneMsg) { handle((APIDetachBackupStorageFromZoneMsg) msg); } else if (msg instanceof APIScanBackupStorageMsg) { handle((APIScanBackupStorageMsg) msg); } else if (msg instanceof APIUpdateBackupStorageMsg) { handle((APIUpdateBackupStorageMsg) msg); } else if (msg instanceof APIReconnectBackupStorageMsg) { handle((APIReconnectBackupStorageMsg) msg); } else { bus.dealWithUnknownMessage(msg); } } catch (Exception e) { bus.logExceptionWithMessageDump(msg, e); bus.replyErrorByMessageType(msg, e); } } private void handle(APIReconnectBackupStorageMsg msg) { final APIReconnectBackupStorageEvent evt = new APIReconnectBackupStorageEvent(msg.getId()); ConnectBackupStorageMsg cmsg = new ConnectBackupStorageMsg(); cmsg.setBackupStorageUuid(self.getUuid()); bus.makeTargetServiceIdByResourceUuid(cmsg, BackupStorageConstant.SERVICE_ID, self.getUuid()); bus.send( cmsg, new CloudBusCallBack(msg) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { evt.setErrorCode(reply.getError()); } else { self = dbf.reload(self); evt.setInventory(getSelfInventory()); } bus.publish(evt); } }); } protected BackupStorageVO updateBackupStorage(APIUpdateBackupStorageMsg msg) { boolean update = false; if (msg.getName() != null) { self.setName(msg.getName()); update = true; } if (msg.getDescription() != null) { self.setDescription(msg.getDescription()); update = true; } return update ? self : null; } private void handle(APIUpdateBackupStorageMsg msg) { BackupStorageVO vo = updateBackupStorage(msg); if (vo != null) { self = dbf.updateAndRefresh(vo); } APIUpdateBackupStorageEvent evt = new APIUpdateBackupStorageEvent(msg.getId()); evt.setInventory(getSelfInventory()); bus.publish(evt); } private void handle(APIScanBackupStorageMsg msg) { APIScanBackupStorageEvent evt = new APIScanBackupStorageEvent(msg.getId()); bus.publish(evt); doScanImages(); } protected void handle(final APIDetachBackupStorageFromZoneMsg msg) { final APIDetachBackupStorageFromZoneEvent evt = new APIDetachBackupStorageFromZoneEvent(msg.getId()); try { extpEmitter.preDetach(self, msg.getZoneUuid()); } catch (BackupStorageException e) { evt.setErrorCode(errf.instantiateErrorCode(BackupStorageErrors.DETACH_ERROR, e.getMessage())); bus.publish(evt); return; } extpEmitter.beforeDetach(self, msg.getZoneUuid()); detachHook( new Completion(msg) { @Transactional private BackupStorageVO updateDb(BackupStorageVO vo, String zoneUuid) { dbf.entityForTranscationCallback( TransactionalCallback.Operation.REMOVE, BackupStorageZoneRefVO.class); String sql = "delete from BackupStorageZoneRefVO bz where bz.zoneUuid = :zoneUuid and bz.backupStorageUuid = :bsUuid"; Query q = dbf.getEntityManager().createQuery(sql); q.setParameter("zoneUuid", zoneUuid); q.setParameter("bsUuid", vo.getUuid()); q.executeUpdate(); vo = dbf.getEntityManager().find(BackupStorageVO.class, vo.getUuid()); return vo; } @Override public void success() { self = updateDb(self, msg.getZoneUuid()); extpEmitter.afterDetach(self, msg.getZoneUuid()); evt.setInventory(getSelfInventory()); logger.debug( String.format( "successfully detached backup storage[uuid:%s] from zone[uuid:%s]", self.getUuid(), msg.getBackupStorageUuid())); bus.publish(evt); } @Override public void fail(ErrorCode errorCode) { logger.warn(errorCode.toString()); extpEmitter.failToDetach(self, msg.getZoneUuid()); evt.setErrorCode( errf.instantiateErrorCode(BackupStorageErrors.DETACH_ERROR, errorCode)); bus.publish(evt); } }); } protected void handle(final APIAttachBackupStorageToZoneMsg msg) { final APIAttachBackupStorageToZoneEvent evt = new APIAttachBackupStorageToZoneEvent(msg.getId()); final BackupStorageVO svo = dbf.findByUuid(msg.getBackupStorageUuid(), BackupStorageVO.class); String err = extpEmitter.preAttach(svo, msg.getZoneUuid()); if (err != null) { evt.setErrorCode(errf.instantiateErrorCode(BackupStorageErrors.ATTACH_ERROR, err)); bus.publish(evt); return; } extpEmitter.beforeAttach(svo, msg.getZoneUuid()); attachHook( msg.getZoneUuid(), new Completion(msg) { @Override public void success() { BackupStorageZoneRefVO rvo = new BackupStorageZoneRefVO(); rvo.setBackupStorageUuid(svo.getUuid()); rvo.setZoneUuid(msg.getZoneUuid()); dbf.persist(rvo); refreshVO(); extpEmitter.afterAttach(self, msg.getZoneUuid()); evt.setInventory(getSelfInventory()); logger.debug( String.format( "successfully attached backup storage[uuid:%s, name:%s]", self.getUuid(), self.getName())); bus.publish(evt); } @Override public void fail(ErrorCode errorCode) { logger.warn(errorCode.toString()); extpEmitter.failToAttach(svo, msg.getZoneUuid()); evt.setErrorCode( errf.instantiateErrorCode(BackupStorageErrors.ATTACH_ERROR, errorCode)); bus.publish(evt); } }); } protected void handle(APIChangeBackupStorageStateMsg msg) { APIChangeBackupStorageStateEvent evt = new APIChangeBackupStorageStateEvent(msg.getId()); BackupStorageState currState = self.getState(); BackupStorageStateEvent event = BackupStorageStateEvent.valueOf(msg.getStateEvent()); BackupStorageState nextState = AbstractBackupStorage.getNextState(currState, event); try { extpEmitter.preChange(self, event); } catch (BackupStorageException e) { evt.setErrorCode( errf.instantiateErrorCode(SysErrors.CHANGE_RESOURCE_STATE_ERROR, e.getMessage())); bus.publish(evt); return; } extpEmitter.beforeChange(self, event); changeStateHook(event, nextState); self.setState(nextState); self = dbf.updateAndRefresh(self); extpEmitter.afterChange(self, event, currState); evt.setInventory(getSelfInventory()); bus.publish(evt); } protected void handle(APIDeleteBackupStorageMsg msg) { final APIDeleteBackupStorageEvent evt = new APIDeleteBackupStorageEvent(msg.getId()); final String issuer = BackupStorageVO.class.getSimpleName(); final List<BackupStorageInventory> ctx = BackupStorageInventory.valueOf(Arrays.asList(self)); FlowChain chain = FlowChainBuilder.newSimpleFlowChain(); chain.setName(String.format("delete-backup-storage-%s", msg.getUuid())); if (msg.getDeletionMode() == APIDeleteMessage.DeletionMode.Permissive) { chain .then( new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade( CascadeConstant.DELETION_CHECK_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }) .then( new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade( CascadeConstant.DELETION_DELETE_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); } else { chain.then( new NoRollbackFlow() { @Override public void run(final FlowTrigger trigger, Map data) { casf.asyncCascade( CascadeConstant.DELETION_FORCE_DELETE_CODE, issuer, ctx, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); } chain .done( new FlowDoneHandler(msg) { @Override public void handle(Map data) { casf.asyncCascadeFull( CascadeConstant.DELETION_CLEANUP_CODE, issuer, ctx, new NopeCompletion()); bus.publish(evt); } }) .error( new FlowErrorHandler(msg) { @Override public void handle(ErrorCode errCode, Map data) { evt.setErrorCode( errf.instantiateErrorCode(SysErrors.DELETE_RESOURCE_ERROR, errCode)); bus.publish(evt); } }) .start(); } protected void updateCapacity(Long totalCapacity, Long availableCapacity) { if (totalCapacity != null && availableCapacity != null) { self.setTotalCapacity(totalCapacity); self.setAvailableCapacity(availableCapacity); dbf.update(self); } } protected void changeStatus(BackupStorageStatus status) { if (status == self.getStatus()) { return; } BackupStorageStatus oldStatus = self.getStatus(); self.setStatus(status); dbf.update(self); BackupStorageStatusChangedData d = new BackupStorageStatusChangedData(); d.setBackupStorageUuid(self.getUuid()); d.setNewStatus(status.toString()); d.setOldStatus(oldStatus.toString()); d.setInventory(BackupStorageInventory.valueOf(self)); evtf.fire(BackupStorageCanonicalEvents.BACKUP_STORAGE_STATUS_CHANGED, d); logger.debug( String.format("change backup storage[uuid:%s] status to %s", self.getUuid(), status)); } }