コード例 #1
0
ファイル: VolumeBase.java プロジェクト: xujun10110/zstack
  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);
          }
        });
  }
コード例 #2
0
ファイル: VolumeBase.java プロジェクト: xujun10110/zstack
  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);
          }
        });
  }
コード例 #3
0
ファイル: VolumeBase.java プロジェクト: xujun10110/zstack
  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);
          }
        });
  }
コード例 #4
0
ファイル: ImageBase.java プロジェクト: rechen/zstack
  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);
          }
        });
  }
コード例 #5
0
 @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);
   }
 }
  @Override
  public void rollback(FlowRollback trigger, Map data) {
    Long size = (Long) data.get(LocalStorageAllocateCapacityForAttachingVolumeFlow.class);
    if (size != null) {
      PrimaryStorageInventory pri =
          (PrimaryStorageInventory)
              data.get(
                  VmInstanceConstant.Params.DestPrimaryStorageInventoryForAttachingVolume
                      .toString());
      ReturnPrimaryStorageCapacityMsg rmsg = new ReturnPrimaryStorageCapacityMsg();
      rmsg.setPrimaryStorageUuid(pri.getUuid());
      rmsg.setDiskSize(size);
      bus.makeTargetServiceIdByResourceUuid(rmsg, PrimaryStorageConstant.SERVICE_ID, pri.getUuid());
      bus.send(rmsg);
    }

    trigger.rollback();
  }
コード例 #7
0
ファイル: ImageBase.java プロジェクト: rechen/zstack
 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));
           }
         }
       });
 }
コード例 #8
0
  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);
          }
        });
  }
コード例 #9
0
 @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));
     }
   }
 }
コード例 #10
0
ファイル: VolumeBase.java プロジェクト: xujun10110/zstack
  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);
          }
        });
  }
コード例 #11
0
  @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));
            }
          }
        });
  }
コード例 #12
0
ファイル: VolumeBase.java プロジェクト: xujun10110/zstack
  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();
    }
  }
コード例 #13
0
ファイル: VmCascadeExtension.java プロジェクト: no2key/zstack
  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();
            }
          });
    }
  }
  @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));
            }
          }
        });
  }