Пример #1
0
  private FlowChain addBootstrapFlows(FlowChain chain, HypervisorType hvType) {
    for (Flow flow : createBootstrapFlows(hvType)) {
      chain.then(flow);
    }

    return chain;
  }
Пример #2
0
 private void prepareFirewallInfo(FlowChain chain) {
   SimpleQuery<ApplianceVmFirewallRuleVO> q = dbf.createQuery(ApplianceVmFirewallRuleVO.class);
   q.add(ApplianceVmFirewallRuleVO_.applianceVmUuid, Op.EQ, getSelf().getUuid());
   List<ApplianceVmFirewallRuleVO> vos = q.list();
   List<ApplianceVmFirewallRuleInventory> rules = ApplianceVmFirewallRuleInventory.valueOf(vos);
   chain.getData().put(ApplianceVmConstant.Params.applianceVmFirewallRules.toString(), rules);
 }
Пример #3
0
  @Override
  protected FlowChain getMigrateVmWorkFlowChain(VmInstanceInventory inv) {
    FlowChain chain = super.getMigrateVmWorkFlowChain(inv);
    chain.setName(String.format("migrate-appliancevm-%s", inv.getUuid()));
    prepareLifeCycleInfo(chain);
    prepareFirewallInfo(chain);

    List<Flow> subMigrateFlows = getPostMigrateFlows();
    if (subMigrateFlows != null) {
      for (Flow f : subMigrateFlows) {
        chain.then(f);
      }
    }

    boolean noRollbackOnFailure = ApplianceVmGlobalProperty.NO_ROLLBACK_ON_POST_FAILURE;
    chain.noRollback(noRollbackOnFailure);
    return chain;
  }
Пример #4
0
 private void prepareLifeCycleInfo(FlowChain chain) {
   ApplianceVmPostLifeCycleInfo info = new ApplianceVmPostLifeCycleInfo();
   ApplianceVmInventory ainv = ApplianceVmInventory.valueOf(getSelf());
   L3NetworkVO defaultRouteL3VO =
       dbf.findByUuid(ainv.getDefaultRouteL3NetworkUuid(), L3NetworkVO.class);
   info.setDefaultRouteL3Network(L3NetworkInventory.valueOf(defaultRouteL3VO));
   info.setManagementNic(ainv.getManagementNic());
   chain
       .getData()
       .put(ApplianceVmConstant.Params.applianceVmInfoForPostLifeCycle.toString(), info);
 }
Пример #5
0
  @Override
  protected FlowChain getStopVmWorkFlowChain(VmInstanceInventory inv) {
    FlowChain chain = super.getStopVmWorkFlowChain(inv);
    chain.setName(String.format("stop-appliancevm-%s", inv.getUuid()));
    chain.insert(
        new Flow() {
          String __name__ = "change-appliancevm-status-to-disconnected";
          ApplianceVmStatus originStatus = getSelf().getStatus();

          @Override
          public void run(FlowTrigger trigger, Map data) {
            getSelf().setStatus(ApplianceVmStatus.Disconnected);
            self = dbf.updateAndRefresh(self);
            trigger.next();
          }

          @Override
          public void rollback(FlowTrigger trigger, Map data) {
            self = dbf.reload(self);
            getSelf().setStatus(originStatus);
            self = dbf.updateAndRefresh(self);
            trigger.rollback();
          }
        });

    prepareLifeCycleInfo(chain);
    prepareFirewallInfo(chain);

    List<Flow> subStopFlows = getPostStopFlows();
    if (subStopFlows != null) {
      for (Flow f : subStopFlows) {
        chain.then(f);
      }
    }

    boolean noRollbackOnFailure = ApplianceVmGlobalProperty.NO_ROLLBACK_ON_POST_FAILURE;
    chain.noRollback(noRollbackOnFailure);
    return chain;
  }
Пример #6
0
  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();
  }
Пример #7
0
  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();
  }
Пример #8
0
  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();
  }
Пример #9
0
  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();
  }
Пример #10
0
  private void releaseNetworkServices(
      final VmInstanceSpec spec,
      NetworkServiceExtensionPosition position,
      final NoErrorCompletion completion) {
    if (!spec.getVmInventory().getType().equals(VmInstanceConstant.USER_VM_TYPE)) {
      completion.done();
      return;
    }

    if (nsExts.isEmpty()) {
      completion.done();
      return;
    }

    // we run into this situation when VM nics are all detached and the
    // VM is being rebooted
    if (spec.getDestNics().isEmpty()) {
      completion.done();
      return;
    }

    List<String> nsTypes = spec.getRequiredNetworkServiceTypes();

    FlowChain schain =
        FlowChainBuilder.newSimpleFlowChain()
            .setName(
                String.format(
                    "release-network-services-from-vm-%s", spec.getVmInventory().getUuid()));
    schain.allowEmptyFlow();

    for (final NetworkServiceExtensionPoint ns : nsExts) {
      if (position != null && ns.getNetworkServiceExtensionPosition() != position) {
        continue;
      }

      if (!nsTypes.contains(ns.getNetworkServiceType().toString())) {
        continue;
      }

      NoRollbackFlow flow =
          new NoRollbackFlow() {
            String __name__ =
                String.format("release-network-service-%s", ns.getNetworkServiceType());

            @Override
            public void run(final FlowTrigger chain, Map data) {
              logger.debug(
                  String.format(
                      "NetworkServiceExtensionPoint[%s] is asking back ends to release network service[%s] if needed",
                      ns.getClass().getName(), ns.getNetworkServiceType()));
              ns.releaseNetworkService(
                  spec,
                  data,
                  new NoErrorCompletion() {
                    @Override
                    public void done() {
                      chain.next();
                    }
                  });
            }
          };

      schain.then(flow);
    }

    schain
        .done(
            new FlowDoneHandler(completion) {
              @Override
              public void handle(Map data) {
                logger.debug(
                    String.format(
                        "successfully released network services for vm[uuid:%s,  name:%s]",
                        spec.getVmInventory().getUuid(), spec.getVmInventory().getName()));
                completion.done();
              }
            })
        .start();
  }
Пример #11
0
  private void applyEip(
      final VirtualRouterVmInventory vr, final EipStruct struct, final Completion completion) {
    FlowChain chain = FlowChainBuilder.newSimpleFlowChain();
    chain.setName(String.format("apply-eip-%s-vr-%s", struct.getEip().getUuid(), vr.getUuid()));
    chain
        .then(
            new Flow() {
              @Override
              public void run(final FlowTrigger trigger, Map data) {
                asf.openFirewall(
                    vr.getUuid(),
                    struct.getVip().getL3NetworkUuid(),
                    getFirewallRules(struct),
                    new Completion(trigger) {
                      @Override
                      public void success() {
                        trigger.next();
                      }

                      @Override
                      public void fail(ErrorCode errorCode) {
                        trigger.fail(errorCode);
                      }
                    });
              }

              @Override
              public void rollback(final FlowRollback trigger, Map data) {
                asf.removeFirewall(
                    vr.getUuid(),
                    struct.getVip().getL3NetworkUuid(),
                    getFirewallRules(struct),
                    new Completion(trigger) {
                      @Override
                      public void success() {
                        trigger.rollback();
                      }

                      @Override
                      public void fail(ErrorCode errorCode) {
                        logger.warn(
                            String.format(
                                "failed to remove firewall rules on virtual router[uuid:%s, l3Network uuid:%s], %s",
                                vr.getUuid(), struct.getVip().getL3NetworkUuid(), errorCode));
                        trigger.rollback();
                      }
                    });
              }
            })
        .then(
            new NoRollbackFlow() {
              @Override
              public void run(final FlowTrigger trigger, Map data) {
                EipTO to = new EipTO();
                String priMac =
                    CollectionUtils.find(
                        vr.getVmNics(),
                        new Function<String, VmNicInventory>() {
                          @Override
                          public String call(VmNicInventory arg) {
                            if (arg.getL3NetworkUuid().equals(struct.getNic().getL3NetworkUuid())) {
                              return arg.getMac();
                            }
                            return null;
                          }
                        });
                to.setPrivateMac(priMac);
                to.setVipIp(struct.getVip().getIp());
                to.setGuestIp(struct.getNic().getIp());
                to.setSnatInboundTraffic(struct.isSnatInboundTraffic());

                VirtualRouterCommands.CreateEipCmd cmd = new VirtualRouterCommands.CreateEipCmd();
                cmd.setEip(to);
                VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg();
                msg.setCheckStatus(true);
                msg.setPath(VirtualRouterConstant.VR_CREATE_EIP);
                msg.setCommand(cmd);
                msg.setVmInstanceUuid(vr.getUuid());
                bus.makeTargetServiceIdByResourceUuid(
                    msg, VmInstanceConstant.SERVICE_ID, vr.getUuid());
                bus.send(
                    msg,
                    new CloudBusCallBack(completion) {
                      @Override
                      public void run(MessageReply reply) {
                        if (!reply.isSuccess()) {
                          trigger.fail(reply.getError());
                          return;
                        }

                        VirtualRouterAsyncHttpCallReply re = reply.castReply();
                        CreateEipRsp ret = re.toResponse(CreateEipRsp.class);
                        if (ret.isSuccess()) {
                          trigger.next();
                        } else {
                          trigger.fail(
                              errf.stringToOperationError(
                                  String.format(
                                      "failed to create eip[uuid:%s, name:%s, ip:%s] for vm nic[uuid:%s] on virtual router[uuid:%s], %s",
                                      struct.getEip().getUuid(),
                                      struct.getEip().getName(),
                                      struct.getVip().getIp(),
                                      struct.getNic().getUuid(),
                                      vr.getUuid(),
                                      ret.getError())));
                        }
                      }
                    });
              }
            })
        .done(
            new FlowDoneHandler(completion) {
              @Override
              public void handle(Map data) {
                String info =
                    String.format(
                        "successfully created eip[uuid:%s, name:%s, ip:%s] for vm nic[uuid:%s] on virtual router[uuid:%s]",
                        struct.getEip().getUuid(),
                        struct.getEip().getName(),
                        struct.getVip().getIp(),
                        struct.getNic().getUuid(),
                        vr.getUuid());
                new VirtualRouterRoleManager().makeEipRole(vr.getUuid());
                logger.debug(info);
                completion.success();
              }
            })
        .error(
            new FlowErrorHandler(completion) {
              @Override
              public void handle(ErrorCode errCode, Map data) {
                completion.fail(errCode);
              }
            })
        .start();
  }
Пример #12
0
  @Override
  public void revokeEip(final EipStruct struct, final Completion completion) {
    SimpleQuery<VirtualRouterEipRefVO> q = dbf.createQuery(VirtualRouterEipRefVO.class);
    q.add(VirtualRouterEipRefVO_.eipUuid, SimpleQuery.Op.EQ, struct.getEip().getUuid());
    final VirtualRouterEipRefVO ref = q.find();
    if (ref == null) {
      // vr may have been deleted
      completion.success();
      return;
    }

    VirtualRouterVmVO vrvo = dbf.findByUuid(ref.getVirtualRouterVmUuid(), VirtualRouterVmVO.class);
    if (vrvo.getState() != VmInstanceState.Running) {
      // rule will be synced when vr state changes to Running
      completion.success();
      return;
    }

    final VirtualRouterVmInventory vr = VirtualRouterVmInventory.valueOf(vrvo);

    // TODO: how to cleanup on failure
    final FlowChain chain = FlowChainBuilder.newSimpleFlowChain();
    chain.setName(String.format("revoke-eip-%s-vr-%s", struct.getEip().getUuid(), vr.getUuid()));
    chain
        .then(
            new NoRollbackFlow() {
              @Override
              public void run(final FlowTrigger trigger, Map data) {
                VirtualRouterCommands.RemoveEipCmd cmd = new VirtualRouterCommands.RemoveEipCmd();
                EipTO to = new EipTO();
                String priMac =
                    CollectionUtils.find(
                        vr.getVmNics(),
                        new Function<String, VmNicInventory>() {
                          @Override
                          public String call(VmNicInventory arg) {
                            if (arg.getL3NetworkUuid().equals(struct.getNic().getL3NetworkUuid())) {
                              return arg.getMac();
                            }
                            return null;
                          }
                        });

                to.setPrivateMac(priMac);
                to.setSnatInboundTraffic(struct.isSnatInboundTraffic());
                to.setVipIp(struct.getVip().getIp());
                to.setGuestIp(struct.getNic().getIp());
                cmd.setEip(to);

                VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg();
                msg.setVmInstanceUuid(vr.getUuid());
                msg.setCommand(cmd);
                msg.setCheckStatus(true);
                msg.setPath(VirtualRouterConstant.VR_REMOVE_EIP);
                bus.makeTargetServiceIdByResourceUuid(
                    msg, VmInstanceConstant.SERVICE_ID, vr.getUuid());
                bus.send(
                    msg,
                    new CloudBusCallBack(trigger) {
                      @Override
                      public void run(MessageReply reply) {
                        if (!reply.isSuccess()) {
                          trigger.setError(reply.getError());
                        } else {
                          VirtualRouterAsyncHttpCallReply re = reply.castReply();
                          RemoveEipRsp ret = re.toResponse(RemoveEipRsp.class);
                          if (!ret.isSuccess()) {
                            String err =
                                String.format(
                                    "failed to remove eip[uuid:%s, name:%s, ip:%s] for vm nic[uuid:%s] on virtual router[uuid:%s], %s",
                                    struct.getEip().getUuid(),
                                    struct.getEip().getName(),
                                    struct.getVip().getIp(),
                                    struct.getNic().getUuid(),
                                    vr.getUuid(),
                                    ret.getError());
                            trigger.setError(errf.stringToOperationError(err));
                          }
                        }

                        trigger.next();
                      }
                    });
              }
            })
        .then(
            new NoRollbackFlow() {
              @Override
              public void run(final FlowTrigger trigger, Map data) {
                asf.removeFirewall(
                    vr.getUuid(),
                    struct.getVip().getL3NetworkUuid(),
                    getFirewallRules(struct),
                    new Completion() {
                      @Override
                      public void success() {
                        trigger.next();
                      }

                      @Override
                      public void fail(ErrorCode errorCode) {
                        logger.warn(
                            String.format(
                                "failed to remove firewall rules on virtual router[uuid:%s, l3Network uuid:%s], %s",
                                vr.getUuid(), struct.getVip().getL3NetworkUuid(), errorCode));
                        trigger.next();
                      }
                    });
              }
            })
        .done(
            new FlowDoneHandler(completion) {
              @Override
              public void handle(Map data) {
                String info =
                    String.format(
                        "successfully removed eip[uuid:%s, name:%s, ip:%s] for vm nic[uuid:%s] on virtual router[uuid:%s]",
                        struct.getEip().getUuid(),
                        struct.getEip().getName(),
                        struct.getVip().getIp(),
                        struct.getNic().getUuid(),
                        vr.getUuid());
                logger.debug(info);
                dbf.remove(ref);
                completion.success();
              }
            })
        .error(
            new FlowErrorHandler(completion) {
              @Override
              public void handle(ErrorCode errCode, Map data) {
                completion.fail(errCode);
              }
            })
        .start();
  }
Пример #13
0
  protected void handle(APIDeletePrimaryStorageMsg msg) {
    final APIDeletePrimaryStorageEvent evt = new APIDeletePrimaryStorageEvent(msg.getId());
    final String issuer = PrimaryStorageVO.class.getSimpleName();
    final List<PrimaryStorageInventory> ctx = PrimaryStorageInventory.valueOf(Arrays.asList(self));
    FlowChain chain = FlowChainBuilder.newSimpleFlowChain();
    chain.setName(String.format("delete-primary-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);

                PrimaryStorageDeletedData d = new PrimaryStorageDeletedData();
                d.setPrimaryStorageUuid(self.getUuid());
                d.setInventory(PrimaryStorageInventory.valueOf(self));
                evtf.fire(PrimaryStorageCanonicalEvent.PRIMARY_STORAGE_DELETED_PATH, d);
              }
            })
        .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();
  }
Пример #14
0
  private void handle(final APISyncPrimaryStorageCapacityMsg msg) {
    final APISyncPrimaryStorageCapacityEvent evt =
        new APISyncPrimaryStorageCapacityEvent(msg.getId());

    FlowChain chain = FlowChainBuilder.newShareFlowChain();
    chain.setName(String.format("sync-capacity-of-primary-storage-%s", self.getUuid()));
    chain
        .then(
            new ShareFlow() {
              Long volumeUsage;
              Long snapshotUsage;
              Long totalPhysicalSize;
              Long availablePhysicalSize;

              @Override
              public void setup() {
                flow(
                    new NoRollbackFlow() {
                      String __name__ = "sync-capacity-used-by-volumes";

                      @Override
                      public void run(final FlowTrigger trigger, Map data) {
                        VolumeReportPrimaryStorageCapacityUsageMsg msg =
                            new VolumeReportPrimaryStorageCapacityUsageMsg();
                        msg.setPrimaryStorageUuid(self.getUuid());
                        bus.makeLocalServiceId(msg, VolumeConstant.SERVICE_ID);
                        bus.send(
                            msg,
                            new CloudBusCallBack(trigger) {
                              @Override
                              public void run(MessageReply reply) {
                                if (!reply.isSuccess()) {
                                  trigger.fail(reply.getError());
                                  return;
                                }

                                VolumeReportPrimaryStorageCapacityUsageReply r = reply.castReply();
                                volumeUsage = r.getUsedCapacity();
                                volumeUsage =
                                    ratioMgr.calculateByRatio(self.getUuid(), volumeUsage);
                                trigger.next();
                              }
                            });
                      }
                    });

                flow(
                    new NoRollbackFlow() {
                      String __name__ = "sync-capacity-used-by-volume-snapshots";

                      @Override
                      public void run(final FlowTrigger trigger, Map data) {
                        VolumeSnapshotReportPrimaryStorageCapacityUsageMsg msg =
                            new VolumeSnapshotReportPrimaryStorageCapacityUsageMsg();
                        msg.setPrimaryStorageUuid(self.getUuid());
                        bus.makeLocalServiceId(msg, VolumeSnapshotConstant.SERVICE_ID);
                        bus.send(
                            msg,
                            new CloudBusCallBack(trigger) {
                              @Override
                              public void run(MessageReply reply) {
                                if (!reply.isSuccess()) {
                                  trigger.fail(reply.getError());
                                  return;
                                }

                                // note: snapshot size is physical size,
                                // don't calculate over-provisioning here
                                VolumeSnapshotReportPrimaryStorageCapacityUsageReply r =
                                    reply.castReply();
                                snapshotUsage = r.getUsedSize();
                                trigger.next();
                              }
                            });
                      }
                    });

                flow(
                    new NoRollbackFlow() {
                      String __name__ = "sync-physical-capacity";

                      @Override
                      public void run(final FlowTrigger trigger, Map data) {
                        syncPhysicalCapacity(
                            new ReturnValueCompletion<PhysicalCapacityUsage>(trigger) {
                              @Override
                              public void success(PhysicalCapacityUsage returnValue) {
                                totalPhysicalSize = returnValue.totalPhysicalSize;
                                availablePhysicalSize = returnValue.availablePhysicalSize;
                                availablePhysicalSize =
                                    availablePhysicalSize < 0 ? 0 : availablePhysicalSize;
                                trigger.next();
                              }

                              @Override
                              public void fail(ErrorCode errorCode) {
                                trigger.fail(errorCode);
                              }
                            });
                      }
                    });

                done(
                    new FlowDoneHandler(msg) {
                      @Override
                      public void handle(Map data) {
                        writeToDb();
                        self = dbf.reload(self);
                        evt.setInventory(getSelfInventory());
                        bus.publish(evt);
                      }

                      private void writeToDb() {
                        PrimaryStorageCapacityUpdater updater =
                            new PrimaryStorageCapacityUpdater(self.getUuid());
                        updater.run(
                            new PrimaryStorageCapacityUpdaterRunnable() {
                              @Override
                              public PrimaryStorageCapacityVO call(PrimaryStorageCapacityVO cap) {
                                long avail = cap.getTotalCapacity() - volumeUsage - snapshotUsage;
                                cap.setAvailableCapacity(avail);
                                cap.setAvailablePhysicalCapacity(availablePhysicalSize);
                                cap.setTotalPhysicalCapacity(totalPhysicalSize);
                                return cap;
                              }
                            });
                      }
                    });

                error(
                    new FlowErrorHandler(msg) {
                      @Override
                      public void handle(ErrorCode errCode, Map data) {
                        evt.setErrorCode(errCode);
                        bus.publish(evt);
                      }
                    });
              }
            })
        .start();
  }
Пример #15
0
  @Override
  protected void startVmFromNewCreate(
      final StartNewCreatedVmInstanceMsg msg, final SyncTaskChain taskChain) {
    boolean callNext = true;
    try {
      refreshVO();
      ErrorCode allowed = validateOperationByState(msg, self.getState(), null);
      if (allowed != null) {
        bus.replyErrorByMessageType(msg, allowed);
        return;
      }
      ErrorCode preCreated = extEmitter.preStartNewCreatedVm(msg.getVmInstanceInventory());
      if (preCreated != null) {
        bus.replyErrorByMessageType(msg, preCreated);
        return;
      }

      StartNewCreatedApplianceVmMsg smsg = (StartNewCreatedApplianceVmMsg) msg;
      ApplianceVmSpec aspec = smsg.getApplianceVmSpec();

      final VmInstanceSpec spec = new VmInstanceSpec();
      spec.setVmInventory(msg.getVmInstanceInventory());
      if (msg.getL3NetworkUuids() != null && !msg.getL3NetworkUuids().isEmpty()) {
        SimpleQuery<L3NetworkVO> nwquery = dbf.createQuery(L3NetworkVO.class);
        nwquery.add(L3NetworkVO_.uuid, SimpleQuery.Op.IN, msg.getL3NetworkUuids());
        List<L3NetworkVO> vos = nwquery.list();
        List<L3NetworkInventory> nws = L3NetworkInventory.valueOf(vos);
        spec.setL3Networks(nws);
      } else {
        spec.setL3Networks(new ArrayList<L3NetworkInventory>(0));
      }

      if (msg.getDataDiskOfferingUuids() != null && !msg.getDataDiskOfferingUuids().isEmpty()) {
        SimpleQuery<DiskOfferingVO> dquery = dbf.createQuery(DiskOfferingVO.class);
        dquery.add(DiskOfferingVO_.uuid, SimpleQuery.Op.IN, msg.getDataDiskOfferingUuids());
        List<DiskOfferingVO> vos = dquery.list();

        // allow create multiple data volume from the same disk offering
        List<DiskOfferingInventory> disks = new ArrayList<DiskOfferingInventory>();
        for (final String duuid : msg.getDataDiskOfferingUuids()) {
          DiskOfferingVO dvo =
              CollectionUtils.find(
                  vos,
                  new Function<DiskOfferingVO, DiskOfferingVO>() {
                    @Override
                    public DiskOfferingVO call(DiskOfferingVO arg) {
                      if (duuid.equals(arg.getUuid())) {
                        return arg;
                      }
                      return null;
                    }
                  });
          disks.add(DiskOfferingInventory.valueOf(dvo));
        }
        spec.setDataDiskOfferings(disks);
      } else {
        spec.setDataDiskOfferings(new ArrayList<DiskOfferingInventory>(0));
      }

      ImageVO imvo = dbf.findByUuid(spec.getVmInventory().getImageUuid(), ImageVO.class);
      spec.getImageSpec().setInventory(ImageInventory.valueOf(imvo));

      spec.putExtensionData(ApplianceVmConstant.Params.applianceVmSpec.toString(), aspec);
      spec.setCurrentVmOperation(VmInstanceConstant.VmOperation.NewCreate);
      spec.putExtensionData(
          ApplianceVmConstant.Params.applianceVmSubType.toString(), getSelf().getApplianceVmType());

      changeVmStateInDb(VmInstanceStateEvent.starting);

      extEmitter.beforeStartNewCreatedVm(VmInstanceInventory.valueOf(self));
      FlowChain chain = apvmf.getCreateApplianceVmWorkFlowBuilder().build();
      chain.setName(String.format("create-appliancevm-%s", msg.getVmInstanceUuid()));
      chain.getData().put(VmInstanceConstant.Params.VmInstanceSpec.toString(), spec);
      chain
          .getData()
          .put(
              ApplianceVmConstant.Params.applianceVmFirewallRules.toString(),
              aspec.getFirewallRules());

      addBootstrapFlows(
          chain, VolumeFormat.getMasterHypervisorTypeByVolumeFormat(imvo.getFormat()));

      List<Flow> subCreateFlows = getPostCreateFlows();
      if (subCreateFlows != null) {
        for (Flow f : subCreateFlows) {
          chain.then(f);
        }
      }

      chain.then(
          new NoRollbackFlow() {
            String __name__ = "change-appliancevm-status-to-connected";

            @Override
            public void run(FlowTrigger trigger, Map data) {
              // must reload here, otherwise it will override changes created by previous flows
              self = dbf.reload(self);
              getSelf().setStatus(ApplianceVmStatus.Connected);
              dbf.update(self);
              trigger.next();
            }
          });

      boolean noRollbackOnFailure = ApplianceVmGlobalProperty.NO_ROLLBACK_ON_POST_FAILURE;
      chain.noRollback(noRollbackOnFailure);
      chain
          .done(
              new FlowDoneHandler(msg, taskChain) {
                @Override
                public void handle(Map data) {
                  VmInstanceSpec spec =
                      (VmInstanceSpec)
                          data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
                  self = dbf.reload(self);
                  self.setLastHostUuid(spec.getDestHost().getUuid());
                  self.setHostUuid(spec.getDestHost().getUuid());
                  self.setClusterUuid(spec.getDestHost().getClusterUuid());
                  self.setZoneUuid(spec.getDestHost().getZoneUuid());
                  self.setHypervisorType(spec.getDestHost().getHypervisorType());
                  self.setRootVolumeUuid(spec.getDestRootVolume().getUuid());
                  changeVmStateInDb(VmInstanceStateEvent.running);
                  logger.debug(
                      String.format(
                          "appliance vm[uuid:%s, name: %s, type:%s] is running ..",
                          self.getUuid(), self.getName(), getSelf().getApplianceVmType()));
                  VmInstanceInventory inv = VmInstanceInventory.valueOf(self);
                  extEmitter.afterStartNewCreatedVm(inv);
                  StartNewCreatedVmInstanceReply reply = new StartNewCreatedVmInstanceReply();
                  reply.setVmInventory(inv);
                  bus.reply(msg, reply);
                  taskChain.next();
                }
              })
          .error(
              new FlowErrorHandler(msg, taskChain) {
                @Override
                public void handle(ErrorCode errCode, Map data) {
                  extEmitter.failedToStartNewCreatedVm(VmInstanceInventory.valueOf(self), errCode);
                  dbf.remove(self);
                  StartNewCreatedVmInstanceReply reply = new StartNewCreatedVmInstanceReply();
                  reply.setError(errCode);
                  reply.setSuccess(false);
                  bus.reply(msg, reply);
                  taskChain.next();
                }
              })
          .start();

      callNext = false;
    } finally {
      if (callNext) {
        taskChain.next();
      }
    }
  }
Пример #16
0
  private void handle(final APISyncPrimaryStorageCapacityMsg msg) {
    final APISyncPrimaryStorageCapacityEvent evt =
        new APISyncPrimaryStorageCapacityEvent(msg.getId());

    FlowChain chain = FlowChainBuilder.newShareFlowChain();
    chain.setName(String.format("sync-capacity-of-primary-storage-%s", self.getUuid()));
    chain
        .then(
            new ShareFlow() {
              Long volumeUsage;
              Long snapshotUsage;
              Long totalPhysicalSize;
              Long availablePhysicalSize;

              @Override
              public void setup() {
                flow(
                    new NoRollbackFlow() {
                      String __name__ = "sync-capacity-used-by-volumes";

                      @Override
                      public void run(final FlowTrigger trigger, Map data) {
                        VolumeReportPrimaryStorageCapacityUsageMsg msg =
                            new VolumeReportPrimaryStorageCapacityUsageMsg();
                        msg.setPrimaryStorageUuid(self.getUuid());
                        bus.makeLocalServiceId(msg, VolumeConstant.SERVICE_ID);
                        bus.send(
                            msg,
                            new CloudBusCallBack(trigger) {
                              @Override
                              public void run(MessageReply reply) {
                                if (!reply.isSuccess()) {
                                  trigger.fail(reply.getError());
                                  return;
                                }

                                VolumeReportPrimaryStorageCapacityUsageReply r = reply.castReply();
                                volumeUsage = r.getUsedCapacity();
                                trigger.next();
                              }
                            });
                      }
                    });

                flow(
                    new NoRollbackFlow() {
                      String __name__ = "sync-capacity-used-by-volume-snapshots";

                      @Override
                      public void run(final FlowTrigger trigger, Map data) {
                        VolumeSnapshotReportPrimaryStorageCapacityUsageMsg msg =
                            new VolumeSnapshotReportPrimaryStorageCapacityUsageMsg();
                        msg.setPrimaryStorageUuid(self.getUuid());
                        bus.makeLocalServiceId(msg, VolumeSnapshotConstant.SERVICE_ID);
                        bus.send(
                            msg,
                            new CloudBusCallBack(trigger) {
                              @Override
                              public void run(MessageReply reply) {
                                if (!reply.isSuccess()) {
                                  trigger.fail(reply.getError());
                                  return;
                                }

                                VolumeSnapshotReportPrimaryStorageCapacityUsageReply r =
                                    reply.castReply();
                                snapshotUsage = r.getUsedSize();
                                trigger.next();
                              }
                            });
                      }
                    });

                flow(
                    new NoRollbackFlow() {
                      String __name__ = "sync-physical-capacity";

                      @Override
                      public void run(final FlowTrigger trigger, Map data) {
                        syncPhysicalCapacity(
                            new ReturnValueCompletion<PhysicalCapacityUsage>(trigger) {
                              @Override
                              public void success(PhysicalCapacityUsage returnValue) {
                                totalPhysicalSize = returnValue.totalPhysicalSize;
                                availablePhysicalSize = returnValue.availablePhysicalSize;
                                availablePhysicalSize =
                                    availablePhysicalSize < 0 ? 0 : availablePhysicalSize;
                                trigger.next();
                              }

                              @Override
                              public void fail(ErrorCode errorCode) {
                                trigger.fail(errorCode);
                              }
                            });
                      }
                    });

                done(
                    new FlowDoneHandler(msg) {
                      @Override
                      public void handle(Map data) {
                        writeToDb();
                        self = dbf.reload(self);
                        evt.setInventory(getSelfInventory());
                        bus.publish(evt);
                      }

                      @Transactional
                      private void writeToDb() {
                        PrimaryStorageCapacityVO vo =
                            dbf.getEntityManager()
                                .find(
                                    PrimaryStorageCapacityVO.class,
                                    self.getUuid(),
                                    LockModeType.PESSIMISTIC_WRITE);

                        long avail = vo.getTotalCapacity() - volumeUsage - snapshotUsage;
                        avail = avail < 0 ? 0 : avail;
                        vo.setAvailableCapacity(avail);
                        vo.setAvailablePhysicalCapacity(availablePhysicalSize);
                        vo.setTotalPhysicalCapacity(totalPhysicalSize);
                        dbf.getEntityManager().merge(vo);
                      }
                    });

                error(
                    new FlowErrorHandler(msg) {
                      @Override
                      public void handle(ErrorCode errCode, Map data) {
                        evt.setErrorCode(errCode);
                        bus.publish(evt);
                      }
                    });
              }
            })
        .start();
  }