/**
 * 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());
  }
}
Esempio n. 2
0
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;
              }
            });
  }
}
Esempio n. 4
0
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);
  }
}
Esempio n. 6
0
/**
 * 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);
      }
    }
  }
}
Esempio n. 8
0
/**
 * 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);
  }
}
Esempio n. 10
0
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);
  }
}
Esempio n. 12
0
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());
  }
}
Esempio n. 13
0
/**
 * 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]);
  }
}
Esempio n. 14
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());
  }
}
Esempio n. 15
0
/**
 * 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());
  }
}
Esempio n. 16
0
/**
 * 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);
  }
}
Esempio n. 17
0
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);
  }
}
Esempio n. 18
0
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());
  }
}
Esempio n. 20
0
/** 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);
    }
  }
}
Esempio n. 21
0
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;
  }
}
Esempio n. 22
0
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());
  }
}
Esempio n. 24
0
/**
 * 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());
  }
}
Esempio n. 29
0
/**
 * 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();
  }
}
Esempio n. 30
0
@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));
  }
}