Example #1
0
/**
 * GroupInfo class holds data for heartbeat group, that is in some ways like normal service, but it
 * can contain other services.
 */
public final class GroupInfo extends ServiceInfo {
  /** Logger. */
  private static final Logger LOG = LoggerFactory.getLogger(GroupInfo.class);
  /** Creates new GroupInfo object. */
  GroupInfo(final ResourceAgent ra, final Browser browser) {
    super(ConfigData.PM_GROUP_NAME, ra, browser);
  }

  /** Applies the the whole group if for example an order has changed. */
  void applyWhole(
      final Host dcHost,
      final boolean createGroup,
      final List<String> newOrder,
      final boolean testOnly) {
    final String[] params = getParametersFromXML();
    if (!testOnly) {
      Tools.invokeAndWait(
          new Runnable() {
            @Override
            public void run() {
              final MyButton ab = getApplyButton();
              if (ab != null) {
                ab.setEnabled(false);
              }
            }
          });
    }
    getInfoPanel();
    waitForInfoPanel();

    final Map<String, String> groupMetaArgs = new LinkedHashMap<String, String>();
    for (String param : params) {
      if (GUI_ID.equals(param) || PCMK_ID.equals(param)) {
        continue;
      }
      String value = getComboBoxValue(param);
      if (value == null) {
        value = "";
      }
      if (value.equals(getParamDefault(param))) {
        continue;
      }
      if (!"".equals(value)) {
        if (CRMXML.GROUP_ORDERED_META_ATTR.equals(param)) {
          groupMetaArgs.put("ordered", value);
        } else {
          groupMetaArgs.put(param, value);
        }
      }
    }
    final Map<String, Map<String, String>> pacemakerResAttrs =
        new HashMap<String, Map<String, String>>();
    final Map<String, Map<String, String>> pacemakerResArgs =
        new HashMap<String, Map<String, String>>();
    final Map<String, Map<String, String>> pacemakerMetaArgs =
        new HashMap<String, Map<String, String>>();
    final Map<String, String> instanceAttrId = new HashMap<String, String>();
    final Map<String, Map<String, String>> nvpairIdsHash =
        new HashMap<String, Map<String, String>>();
    final Map<String, Map<String, Map<String, String>>> pacemakerOps =
        new HashMap<String, Map<String, Map<String, String>>>();
    final Map<String, String> operationsId = new HashMap<String, String>();
    final Map<String, String> metaAttrsRefId = new HashMap<String, String>();
    final Map<String, String> operationsRefId = new HashMap<String, String>();
    final Map<String, Boolean> stonith = new HashMap<String, Boolean>();

    final ClusterStatus cs = getBrowser().getClusterStatus();
    for (final String resId : newOrder) {
      final ServiceInfo gsi = getBrowser().getServiceInfoFromCRMId(resId);
      if (gsi == null) {
        continue;
      }
      Tools.invokeAndWait(
          new Runnable() {
            @Override
            public void run() {
              gsi.getInfoPanel();
            }
          });
    }
    Tools.waitForSwing();
    for (final String resId : newOrder) {
      final ServiceInfo gsi = getBrowser().getServiceInfoFromCRMId(resId);
      if (gsi == null) {
        continue;
      }
      pacemakerResAttrs.put(resId, gsi.getPacemakerResAttrs(testOnly));
      pacemakerResArgs.put(resId, gsi.getPacemakerResArgs());
      pacemakerMetaArgs.put(resId, gsi.getPacemakerMetaArgs());
      instanceAttrId.put(resId, cs.getResourceInstanceAttrId(resId));
      nvpairIdsHash.put(resId, cs.getParametersNvpairsIds(resId));
      pacemakerOps.put(resId, gsi.getOperations(resId));
      operationsId.put(resId, cs.getOperationsId(resId));
      metaAttrsRefId.put(resId, gsi.getMetaAttrsRefId());
      operationsRefId.put(resId, gsi.getOperationsRefId());
      stonith.put(resId, gsi.getResourceAgent().isStonith());
    }
    final CloneInfo ci = getCloneInfo();
    String cloneId = null;
    boolean master = false;
    final Map<String, String> cloneMetaArgs = new LinkedHashMap<String, String>();
    String cloneMetaAttrsRefIds = null;
    if (createGroup && ci != null) {
      cloneId = ci.getHeartbeatId(testOnly);
      final String[] cloneParams = ci.getParametersFromXML();
      master = ci.getService().isMaster();
      cloneMetaAttrsRefIds = ci.getMetaAttrsRefId();
      for (String param : cloneParams) {
        if (GUI_ID.equals(param) || PCMK_ID.equals(param)) {
          continue;
        }
        final String value = ci.getComboBoxValue(param);
        if (value.equals(ci.getParamDefault(param))) {
          continue;
        }
        if (!GUI_ID.equals(param) && !"".equals(value)) {
          cloneMetaArgs.put(param, value);
        }
      }
    }
    CRM.replaceGroup(
        createGroup,
        dcHost,
        cloneId,
        master,
        cloneMetaArgs,
        cloneMetaAttrsRefIds,
        newOrder,
        groupMetaArgs,
        getHeartbeatId(testOnly),
        pacemakerResAttrs,
        pacemakerResArgs,
        pacemakerMetaArgs,
        instanceAttrId,
        nvpairIdsHash,
        pacemakerOps,
        operationsId,
        metaAttrsRefId,
        getMetaAttrsRefId(),
        operationsRefId,
        stonith,
        testOnly);
    if (!testOnly) {
      storeComboBoxValues(params);
      getBrowser().reload(getNode(), false);
    }
    getBrowser().getCRMGraph().repaint();
  }

  /** Applies the changes to the group parameters. */
  @Override
  void apply(final Host dcHost, final boolean testOnly) {
    if (!testOnly) {
      Tools.invokeAndWait(
          new Runnable() {
            @Override
            public void run() {
              getApplyButton().setEnabled(false);
              getRevertButton().setEnabled(false);
            }
          });
    }
    getInfoPanel();
    waitForInfoPanel();
    final String[] params = getParametersFromXML();
    if (!testOnly) {
      Tools.invokeLater(
          new Runnable() {
            @Override
            public void run() {
              getApplyButton().setToolTipText("");
              final Widget idField = getWidget(GUI_ID, null);
              idField.setEnabled(false);
            }
          });

      /* add myself to the hash with service name and id as
       * keys */
      getBrowser().removeFromServiceInfoHash(this);
      final String oldHeartbeatId = getHeartbeatId(testOnly);
      if (oldHeartbeatId != null) {
        getBrowser().mHeartbeatIdToServiceLock();
        getBrowser().getHeartbeatIdToServiceInfo().remove(oldHeartbeatId);
        getBrowser().mHeartbeatIdToServiceUnlock();
      }
      if (getService().isNew()) {
        final String id = getComboBoxValue(GUI_ID);
        getService().setIdAndCrmId(id);
        if (getTypeRadioGroup() != null) {
          getTypeRadioGroup().setEnabled(false);
        }
      }
      getBrowser().addNameToServiceInfoHash(this);
      getBrowser().addToHeartbeatIdList(this);
    }

    /*
        MSG_ADD_GRP group
                param_id1 param_name1 param_value1
                param_id2 param_name2 param_value2
                ...
                param_idn param_namen param_valuen
    */
    final String heartbeatId = getHeartbeatId(testOnly);
    if (getService().isNew()) {
      final Set<ServiceInfo> parents = getBrowser().getCRMGraph().getParents(this);
      final List<Map<String, String>> colAttrsList = new ArrayList<Map<String, String>>();
      final List<Map<String, String>> ordAttrsList = new ArrayList<Map<String, String>>();
      final List<String> parentIds = new ArrayList<String>();
      for (final ServiceInfo parentInfo : parents) {
        final String parentId = parentInfo.getService().getHeartbeatId();
        parentIds.add(parentId);
        final Map<String, String> colAttrs = new LinkedHashMap<String, String>();
        final Map<String, String> ordAttrs = new LinkedHashMap<String, String>();
        colAttrs.put(CRMXML.SCORE_STRING, CRMXML.INFINITY_STRING);
        ordAttrs.put(CRMXML.SCORE_STRING, CRMXML.INFINITY_STRING);
        if (getService().isMaster()) {
          colAttrs.put("with-rsc-role", "Master");
          ordAttrs.put("first-action", "promote");
          ordAttrs.put("then-action", "start");
        }
        colAttrsList.add(colAttrs);
        ordAttrsList.add(ordAttrs);
      }
      CRM.setOrderAndColocation(
          dcHost,
          heartbeatId,
          parentIds.toArray(new String[parentIds.size()]),
          colAttrsList,
          ordAttrsList,
          testOnly);
      @SuppressWarnings("unchecked")
      final Enumeration<DefaultMutableTreeNode> e = getNode().children();
      final List<String> newOrder = new ArrayList<String>();
      while (e.hasMoreElements()) {
        final DefaultMutableTreeNode n = e.nextElement();
        final ServiceInfo child = (ServiceInfo) n.getUserObject();
        newOrder.add(child.getHeartbeatId(testOnly));
      }
      applyWhole(dcHost, true, newOrder, testOnly);
      if (!testOnly) {
        setApplyButtons(null, params);
      }
      getBrowser().getCRMGraph().repaint();
      return;
    } else {
      final Map<String, String> groupMetaArgs = new LinkedHashMap<String, String>();
      for (String param : params) {
        if (GUI_ID.equals(param) || PCMK_ID.equals(param)) {
          continue;
        }
        final String value = getComboBoxValue(param);
        if (value.equals(getParamDefault(param))) {
          continue;
        }
        if (!"".equals(value)) {
          if (CRMXML.GROUP_ORDERED_META_ATTR.equals(param)) {
            groupMetaArgs.put("ordered", value);
          } else {
            groupMetaArgs.put(param, value);
          }
        }
      }
      CRM.setParameters(
          dcHost,
          "-R",
          null, /* crm id */
          null, /* TODO: clone id */
          false, /* master */
          null, /* cloneMetaArgs, */
          groupMetaArgs,
          heartbeatId, /* group id */
          null, /* pacemakerResAttrs, */
          null, /* pacemakerResArgs, */
          null, /* pacemakerMetaArgs, */
          null, /* cs.getResourceInstanceAttrId(heartbeatId), */
          null, /* cs.getParametersNvpairsIds(heartbeatId), */
          null, /* getOperations(heartbeatId), */
          null, /* cs.getOperationsId(heartbeatId), */
          null, /* getMetaAttrsRefId(), */
          null, /* cloneMetaAttrsRefIds, */
          getMetaAttrsRefId(),
          null, /* getOperationsRefId(), */
          false, /* stonith */
          testOnly);
    }
    final CloneInfo ci = getCloneInfo();
    if (ci == null) {
      setLocations(heartbeatId, dcHost, testOnly);
    } else {
      ci.setLocations(heartbeatId, dcHost, testOnly);
    }
    if (!testOnly) {
      storeComboBoxValues(params);
      getBrowser().reload(getNode(), false);
    }
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {
        final ServiceInfo gsi = getBrowser().getServiceInfoFromCRMId(hbId);

        if (gsi != null
            && gsi.checkResourceFieldsCorrect(null, gsi.getParametersFromXML(), false, false, true)
            && gsi.checkResourceFieldsChanged(
                null, gsi.getParametersFromXML(), false, false, true)) {
          gsi.apply(dcHost, testOnly);
        }
      }
    }
    if (!testOnly) {
      setApplyButtons(null, params);
    }
    getBrowser().getCRMGraph().repaint();
  }

  /** Returns the list of services that can be added to the group. */
  List<ResourceAgent> getAddGroupServiceList(final String cl) {
    return getBrowser().getCRMXML().getServices(cl);
  }

  /**
   * Adds service to this group. Adds it in the submenu in the menu tree and initializes it.
   *
   * @param newServiceInfo service info object of the new service
   */
  void addGroupServicePanel(final ServiceInfo newServiceInfo, final boolean reloadNode) {
    final DefaultMutableTreeNode gn = getNode();
    if (gn == null) {
      return;
    }
    newServiceInfo
        .getService()
        .setResourceClass(newServiceInfo.getResourceAgent().getResourceClass());
    newServiceInfo.setGroupInfo(this);
    getBrowser().addNameToServiceInfoHash(newServiceInfo);
    getBrowser().addToHeartbeatIdList(newServiceInfo);
    final DefaultMutableTreeNode newServiceNode = new DefaultMutableTreeNode(newServiceInfo);
    newServiceInfo.setNode(newServiceNode);
    Tools.invokeLater(
        !Tools.CHECK_SWING_THREAD,
        new Runnable() {
          @Override
          public void run() {
            gn.add(newServiceNode);
            if (reloadNode) {
              getBrowser().reloadAndWait(gn, false);
              getBrowser().reloadAndWait(newServiceNode, true);
            }
          }
        });
  }

  /** Adds service to this group and creates new service info object. */
  ServiceInfo addGroupServicePanel(final ResourceAgent newRA, final boolean reloadNode) {
    ServiceInfo newServiceInfo;

    final String name = newRA.getName();
    if (newRA.isFilesystem()) {
      newServiceInfo = new FilesystemInfo(name, newRA, getBrowser());
    } else if (newRA.isLinbitDrbd()) {
      newServiceInfo = new LinbitDrbdInfo(name, newRA, getBrowser());
    } else if (newRA.isDrbddisk()) {
      newServiceInfo = new DrbddiskInfo(name, newRA, getBrowser());
    } else if (newRA.isIPaddr()) {
      newServiceInfo = new IPaddrInfo(name, newRA, getBrowser());
    } else if (newRA.isVirtualDomain()) {
      newServiceInfo = new VirtualDomainInfo(name, newRA, getBrowser());
    } else if (newRA.isGroup()) {
      LOG.appError("addGroupServicePanel: no groups in group allowed");
      return null;
    } else {
      newServiceInfo = new ServiceInfo(name, newRA, getBrowser());
    }
    addGroupServicePanel(newServiceInfo, reloadNode);
    return newServiceInfo;
  }

  /**
   * Returns on which node this group is running, meaning on which node all the services are
   * running. Null if they running on different nodes or not at all.
   */
  @Override
  List<String> getRunningOnNodes(final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    final List<String> allNodes = new ArrayList<String>();
    if (resources != null) {
      for (final String hbId : resources) {
        final List<String> ns = cs.getRunningOnNodes(hbId, testOnly);
        if (ns != null) {
          for (final String n : ns) {
            if (!allNodes.contains(n)) {
              allNodes.add(n);
            }
          }
        }
      }
    }
    return allNodes;
  }

  /** Returns node name of the host where this service is running. */
  @Override
  List<String> getMasterOnNodes(final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    final List<String> allNodes = new ArrayList<String>();
    if (resources != null) {
      for (final String hbId : resources) {
        final List<String> ns = cs.getMasterOnNodes(hbId, testOnly);
        if (ns != null) {
          for (final String n : ns) {
            if (!allNodes.contains(n)) {
              allNodes.add(n);
            }
          }
        }
      }
    }
    return allNodes;
  }

  /** Starts all resources in the group. */
  @Override
  void startResource(final Host dcHost, final boolean testOnly) {
    if (!testOnly) {
      setUpdated(true);
    }
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {
        CRM.startResource(dcHost, hbId, testOnly);
      }
    }
  }

  /** Stops all resources in the group. */
  @Override
  void stopResource(final Host dcHost, final boolean testOnly) {
    if (!testOnly) {
      setUpdated(true);
    }
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {
        CRM.stopResource(dcHost, hbId, testOnly);
      }
    }
  }

  /** Cleans up all resources in the group. */
  @Override
  void cleanupResource(final Host dcHost, final boolean testOnly) {
    if (!testOnly) {
      setUpdated(true);
    }
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {

        final ServiceInfo gsi = getBrowser().getServiceInfoFromCRMId(hbId);
        if (gsi != null) {
          gsi.cleanupResource(dcHost, testOnly);
        }
      }
    }
  }

  /** Sets whether the group services are managed. */
  @Override
  void setManaged(final boolean isManaged, final Host dcHost, final boolean testOnly) {
    if (!testOnly) {
      setUpdated(true);
    }
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {
        CRM.setManaged(dcHost, hbId, isManaged, testOnly);
      }
    }
  }

  /** Returns items for the group popup. */
  @Override
  public List<UpdatableItem> createPopup() {
    final boolean testOnly = false;
    final GroupInfo thisGroupInfo = this;
    /* add group service */
    final MyMenu addGroupServiceMenuItem =
        new MyMenu(
            Tools.getString("ClusterBrowser.Hb.AddGroupService"),
            new AccessMode(ConfigData.AccessType.ADMIN, false),
            new AccessMode(ConfigData.AccessType.OP, false)) {
          private static final long serialVersionUID = 1L;
          private final Lock mUpdateLock = new ReentrantLock();

          @Override
          public String enablePredicate() {
            if (getBrowser().clStatusFailed()) {
              return ClusterBrowser.UNKNOWN_CLUSTER_STATUS_STRING;
            } else {
              return null;
            }
          }

          @Override
          public void update() {
            final Thread t =
                new Thread(
                    new Runnable() {
                      @Override
                      public void run() {
                        if (mUpdateLock.tryLock()) {
                          try {
                            updateThread();
                          } finally {
                            mUpdateLock.unlock();
                          }
                        }
                      }
                    });
            t.start();
          }

          private void updateThread() {
            Tools.invokeLater(
                new Runnable() {
                  @Override
                  public void run() {
                    setEnabled(false);
                  }
                });
            Tools.invokeAndWait(
                new Runnable() {
                  @Override
                  public void run() {
                    removeAll();
                  }
                });
            final List<JDialog> popups = new ArrayList<JDialog>();
            for (final String cl : ClusterBrowser.HB_CLASSES) {
              final MyMenu classItem =
                  new MyMenu(
                      ClusterBrowser.HB_CLASS_MENU.get(cl),
                      new AccessMode(ConfigData.AccessType.ADMIN, false),
                      new AccessMode(ConfigData.AccessType.OP, false));
              MyListModel<MyMenuItem> dlm = new MyListModel<MyMenuItem>();
              for (final ResourceAgent ra : getAddGroupServiceList(cl)) {
                final MyMenuItem mmi =
                    new MyMenuItem(
                        ra.getMenuName(),
                        null,
                        null,
                        new AccessMode(ConfigData.AccessType.ADMIN, false),
                        new AccessMode(ConfigData.AccessType.OP, false)) {
                      private static final long serialVersionUID = 1L;

                      @Override
                      public void action() {
                        final CloneInfo ci = getCloneInfo();
                        if (ci != null) {
                          ci.hidePopup();
                        }
                        hidePopup();
                        for (final JDialog otherP : popups) {
                          otherP.dispose();
                        }
                        if (ra.isLinbitDrbd() && !getBrowser().linbitDrbdConfirmDialog()) {
                          return;
                        }
                        addGroupServicePanel(ra, true);
                        repaint();
                      }
                    };
                dlm.addElement(mmi);
              }
              final boolean ret =
                  Tools.getScrollingMenu(
                      ClusterBrowser.HB_CLASS_MENU.get(cl),
                      null, /* options */
                      classItem,
                      dlm,
                      new MyList<MyMenuItem>(dlm, getBackground()),
                      thisGroupInfo,
                      popups,
                      null);
              if (!ret) {
                classItem.setEnabled(false);
              }
              Tools.invokeLater(
                  new Runnable() {
                    @Override
                    public void run() {
                      add(classItem);
                    }
                  });
            }
            Tools.waitForSwing();
            super.update();
          }
        };
    final List<UpdatableItem> items = new ArrayList<UpdatableItem>();
    items.add((UpdatableItem) addGroupServiceMenuItem);
    for (final UpdatableItem item : super.createPopup()) {
      items.add(item);
    }

    /* group services */
    if (!Tools.getConfigData().isSlow()) {
      final ClusterStatus cs = getBrowser().getClusterStatus();
      final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
      if (resources != null) {
        for (final String hbId : resources) {
          final ServiceInfo gsi = getBrowser().getServiceInfoFromCRMId(hbId);
          if (gsi == null) {
            continue;
          }
          final MyMenu groupServicesMenu =
              new MyMenu(
                  gsi.toString(),
                  new AccessMode(ConfigData.AccessType.RO, false),
                  new AccessMode(ConfigData.AccessType.RO, false)) {
                private static final long serialVersionUID = 1L;
                private final Lock mUpdateLock = new ReentrantLock();

                @Override
                public String enablePredicate() {
                  return null;
                }

                @Override
                public void update() {
                  final Thread t =
                      new Thread(
                          new Runnable() {
                            @Override
                            public void run() {
                              if (mUpdateLock.tryLock()) {
                                try {
                                  updateThread();
                                } finally {
                                  mUpdateLock.unlock();
                                }
                              }
                            }
                          });
                  t.start();
                }

                public void updateThread() {
                  Tools.invokeLater(
                      new Runnable() {
                        @Override
                        public void run() {
                          setEnabled(false);
                        }
                      });
                  Tools.invokeAndWait(
                      new Runnable() {
                        @Override
                        public void run() {
                          removeAll();
                        }
                      });
                  final List<UpdatableItem> serviceMenus = new ArrayList<UpdatableItem>();
                  for (final UpdatableItem u : gsi.createPopup()) {
                    serviceMenus.add(u);
                    u.update();
                  }
                  Tools.invokeLater(
                      new Runnable() {
                        @Override
                        public void run() {
                          for (final UpdatableItem u : serviceMenus) {
                            add((JMenuItem) u);
                          }
                        }
                      });
                  super.update();
                }
              };
          items.add((UpdatableItem) groupServicesMenu);
        }
      }
    }
    return items;
  }

  /** Removes this group from the cib. */
  @Override
  public void removeMyself(final boolean testOnly) {
    if (getService().isNew()) {
      removeMyselfNoConfirm(getBrowser().getDCHost(), testOnly);
      getService().setNew(false);
      super.removeInfo();
      getService().doneRemoving();
      return;
    }
    String desc = Tools.getString("ClusterBrowser.confirmRemoveGroup.Description");

    final StringBuilder services = new StringBuilder();

    @SuppressWarnings("unchecked")
    final Enumeration<DefaultMutableTreeNode> e = getNode().children();
    try {
      while (e.hasMoreElements()) {
        final DefaultMutableTreeNode n = e.nextElement();
        final ServiceInfo child = (ServiceInfo) n.getUserObject();
        services.append(child.toString());
        if (e.hasMoreElements()) {
          services.append(", ");
        }
      }
    } catch (java.util.NoSuchElementException ele) {
      LOG.info("removeMyself: removing aborted");
      return;
    }

    desc = desc.replaceAll("@GROUP@", "'" + Matcher.quoteReplacement(toString()) + "'");
    desc = desc.replaceAll("@SERVICES@", Matcher.quoteReplacement(services.toString()));
    if (Tools.confirmDialog(
        Tools.getString("ClusterBrowser.confirmRemoveGroup.Title"),
        desc,
        Tools.getString("ClusterBrowser.confirmRemoveGroup.Yes"),
        Tools.getString("ClusterBrowser.confirmRemoveGroup.No"))) {
      if (!testOnly) {
        getService().setRemoved(true);
      }
      removeMyselfNoConfirm(getBrowser().getDCHost(), testOnly);
      super.removeInfo();
      getService().setNew(false);
    }
    getService().doneRemoving();
  }

  @Override
  public void removeInfo() {
    final DefaultMutableTreeNode node = getNode();
    if (node == null) {
      return;
    }
    @SuppressWarnings("unchecked")
    final Enumeration<DefaultMutableTreeNode> e = node.children();
    try {
      while (e.hasMoreElements()) {
        final DefaultMutableTreeNode n = e.nextElement();
        final ServiceInfo child = (ServiceInfo) n.getUserObject();
        child.removeInfo();
      }
    } catch (java.util.NoSuchElementException ele) {
      LOG.info("removeInfo: removing aborted");
      return;
    }
    super.removeInfo();
  }

  /** Remove all the services in the group and the group. */
  @Override
  public void removeMyselfNoConfirm(final Host dcHost, final boolean testOnly) {
    final List<ServiceInfo> children = new ArrayList<ServiceInfo>();
    if (!testOnly) {
      @SuppressWarnings("unchecked")
      final Enumeration<DefaultMutableTreeNode> e = getNode().children();
      try {
        while (e.hasMoreElements()) {
          final DefaultMutableTreeNode n = e.nextElement();
          final ServiceInfo child = (ServiceInfo) n.getUserObject();
          child.getService().setRemoved(true);
          children.add(child);
        }
      } catch (java.util.NoSuchElementException ele) {
        LOG.info("removeMyselfNoConfirm: removing aborted");
        return;
      }
    }
    if (getService().isNew()) {
      if (!testOnly) {
        getService().setNew(false);
        getBrowser().getCRMGraph().killRemovedVertices();
        getService().doneRemoving();
      }
    } else {
      String cloneId = null;
      boolean master = false;
      final CloneInfo ci = getCloneInfo();
      if (ci != null) {
        cloneId = ci.getHeartbeatId(testOnly);
        master = ci.getService().isMaster();
      }
      super.removeMyselfNoConfirm(dcHost, testOnly);
      for (final ServiceInfo child : children) {
        child.removeConstraints(dcHost, testOnly);
      }
      CRM.removeResource(
          dcHost, null, getHeartbeatId(testOnly), cloneId, /* clone id */ master, testOnly);
      for (final ServiceInfo child : children) {
        child.cleanupResource(dcHost, testOnly);
      }
    }
    if (!testOnly) {
      for (final ServiceInfo child : children) {
        getBrowser().mHeartbeatIdToServiceLock();
        getBrowser().getHeartbeatIdToServiceInfo().remove(child.getService().getHeartbeatId());
        getBrowser().mHeartbeatIdToServiceUnlock();
        getBrowser().removeFromServiceInfoHash(child);
        child.cleanup();
        child.getService().doneRemoving();
      }
    }
  }

  /** Removes the group, but not the services. */
  void removeMyselfNoConfirmFromChild(final Host dcHost, final boolean testOnly) {
    super.removeMyselfNoConfirm(dcHost, testOnly);
  }

  /** Returns tool tip for the group vertex. */
  @Override
  public String getToolTipText(final boolean testOnly) {
    final List<String> hostNames = getRunningOnNodes(testOnly);
    final StringBuilder sb = new StringBuilder(220);
    sb.append("<b>");
    sb.append(toString());
    if (hostNames == null || hostNames.isEmpty()) {
      sb.append(" not running");
    } else if (hostNames.size() == 1) {
      sb.append(" running on node: ");
    } else {
      sb.append(" running on nodes: ");
    }
    if (hostNames != null && !hostNames.isEmpty()) {
      sb.append(Tools.join(", ", hostNames.toArray(new String[hostNames.size()])));
    }
    sb.append("</b>");

    final DefaultMutableTreeNode node = getNode();
    if (node == null) {
      return sb.toString();
    }
    @SuppressWarnings("unchecked")
    final Enumeration<DefaultMutableTreeNode> e = node.children();
    try {
      while (e.hasMoreElements()) {
        final DefaultMutableTreeNode n = e.nextElement();
        final ServiceInfo child = (ServiceInfo) n.getUserObject();
        sb.append("\n&nbsp;&nbsp;&nbsp;");
        sb.append(child.getToolTipText(testOnly));
      }
    } catch (java.util.NoSuchElementException ele) {
      /* ignore */
    }

    return sb.toString();
  }

  /** Returns whether one of the services on one of the hosts failed. */
  @Override
  boolean isOneFailed(final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {
        final ServiceInfo gsi = getBrowser().getServiceInfoFromCRMId(hbId);
        if (gsi != null && gsi.isOneFailed(testOnly)) {
          return true;
        }
      }
    }
    return false;
  }

  /** Returns whether one of the services on one of the hosts failed. */
  @Override
  boolean isOneFailedCount(final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {
        final ServiceInfo gsi = getBrowser().getServiceInfoFromCRMId(hbId);
        if (gsi != null && gsi.isOneFailedCount(testOnly)) {
          return true;
        }
      }
    }
    return false;
  }

  /** Returns whether one of the services failed to start. */
  @Override
  public boolean isFailed(final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {
        final ServiceInfo si = getBrowser().getServiceInfoFromCRMId(hbId);
        if (si == null) {
          continue;
        }
        if (si.isFailed(testOnly)) {
          return true;
        }
      }
    }
    return false;
  }

  /** Returns subtexts that appears in the service vertex. */
  @Override
  public Subtext[] getSubtextsForGraph(final boolean testOnly) {
    final List<Subtext> texts = new ArrayList<Subtext>();
    Subtext prevSubtext = null;
    final Host dcHost = getBrowser().getDCHost();

    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String resId : resources) {
        final ServiceInfo si = getBrowser().getServiceInfoFromCRMId(resId);
        if (si == null) {
          continue;
        }
        final Subtext[] subtexts = si.getSubtextsForGraph(testOnly);
        Subtext sSubtext = null;
        if (subtexts == null || subtexts.length == 0) {
          continue;
        }
        sSubtext = subtexts[0];
        if (prevSubtext == null || !sSubtext.getSubtext().equals(prevSubtext.getSubtext())) {
          texts.add(new Subtext(sSubtext.getSubtext() + ":", sSubtext.getColor(), Color.BLACK));
          prevSubtext = sSubtext;
        }
        String unmanaged = "";
        if (!si.isManaged(testOnly)) {
          unmanaged = " / unmanaged";
        }
        String migrated = "";
        if (si.getMigratedTo(testOnly) != null || si.getMigratedFrom(testOnly) != null) {
          migrated = " / migrated";
        }
        final HbConnectionInfo[] hbcis = getBrowser().getCRMGraph().getHbConnections(si);
        String constraintLeft = "";
        String constraint = "";
        if (hbcis != null) {
          boolean scoreFirst = false;
          boolean scoreThen = false;
          boolean someConnection = false;
          for (final HbConnectionInfo hbci : hbcis) {
            if (hbci == null) {
              continue;
            }
            if (!someConnection && hbci.hasColocationOrOrder(si)) {
              someConnection = true;
            }
            if (!scoreFirst && !hbci.isOrdScoreNull(si, null)) {
              scoreFirst = true;
            }
            if (!scoreThen && !hbci.isOrdScoreNull(null, si)) {
              scoreThen = true;
            }
          }
          if (someConnection) {
            if (scoreFirst || scoreThen) {
              if (scoreFirst) {
                constraint = " \u2192"; /* -> */
              }
              if (scoreThen) {
                constraintLeft = "\u2192 "; /* -> */
              }
            } else {
              /* just colocation */
              constraint = " --"; /* -- */
            }
          }
        }
        texts.add(
            new Subtext(
                "   " + constraintLeft + si.toString() + unmanaged + migrated + constraint,
                sSubtext.getColor(),
                Color.BLACK));
        boolean skip = true;
        for (final Subtext st : subtexts) {
          if (skip) {
            skip = false;
            continue;
          }
          texts.add(new Subtext("   " + st.getSubtext(), st.getColor(), Color.BLACK));
        }
      }
    }
    return texts.toArray(new Subtext[texts.size()]);
  }

  /** Returns from which hosts the services or the whole group was migrated. */
  @Override
  public List<Host> getMigratedFrom(final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    List<Host> hosts = super.getMigratedFrom(testOnly);
    if (resources == null) {
      return null;
    } else {
      if (resources.isEmpty()) {
        return null;
      }
      for (final String hbId : resources) {
        final ServiceInfo si = getBrowser().getServiceInfoFromCRMId(hbId);
        if (si != null) {
          final List<Host> siHosts = si.getMigratedFrom(testOnly);
          if (siHosts != null) {
            if (hosts == null) {
              hosts = new ArrayList<Host>();
            }
            hosts.addAll(siHosts);
          }
        }
      }
    }
    return hosts;
  }

  /** Returns whether at least one service is unmaneged. */
  @Override
  public boolean isManaged(final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources == null) {
      return true;
    } else {
      if (resources.isEmpty()) {
        return true;
      }
      for (final String hbId : resources) {
        final ServiceInfo si = getBrowser().getServiceInfoFromCRMId(hbId);
        if (si != null && !si.isManaged(testOnly)) {
          return false;
        }
      }
    }
    return true;
  }

  /** Returns whether all of the services are started. */
  @Override
  boolean isStarted(final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {
        final ServiceInfo si = getBrowser().getServiceInfoFromCRMId(hbId);
        if (si != null && !si.isStarted(testOnly)) {
          return false;
        }
      }
    }
    return true;
  }

  /** Returns whether one of the services is stopped. */
  @Override
  public boolean isStopped(final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {
        final ServiceInfo si = getBrowser().getServiceInfoFromCRMId(hbId);
        if (si != null && si.isStopped(testOnly)) {
          return true;
        }
      }
    }
    return false;
  }

  /** Returns whether the group is stopped. */
  @Override
  boolean isGroupStopped(final boolean testOnly) {
    return super.isStopped(testOnly);
  }

  /** Returns true if at least one service in the group are running. */
  boolean isOneRunning(final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {
        final ServiceInfo si = getBrowser().getServiceInfoFromCRMId(hbId);
        if (si != null && si.isRunning(testOnly)) {
          return true;
        }
      }
    }
    return false;
  }

  /** Returns true if all services in the group are running. */
  @Override
  public boolean isRunning(final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(testOnly), testOnly);
    if (resources != null) {
      for (final String hbId : resources) {
        final ServiceInfo si = getBrowser().getServiceInfoFromCRMId(hbId);
        if (si != null && !si.isRunning(testOnly)) {
          return false;
        }
      }
    }
    return true;
  }

  /**
   * Returns whether the specified parameter or any of the parameters have changed. If group does
   * not have any services, its changes cannot by applied.
   */
  @Override
  public boolean checkResourceFieldsChanged(final String param, final String[] params) {
    return checkResourceFieldsChanged(param, params, false, false);
  }

  /**
   * Returns whether the specified parameter or any of the parameters have changed. If group does
   * not have any services, its changes cannot by applied.
   */
  boolean checkResourceFieldsChanged(
      final String param,
      final String[] params,
      final boolean fromServicesInfo,
      final boolean fromCloneInfo) {
    final DefaultMutableTreeNode gn = getNode();
    if (gn == null) {
      return false;
    }
    @SuppressWarnings("unchecked")
    final Enumeration<DefaultMutableTreeNode> se = gn.children();
    if (!se.hasMoreElements()) {
      return false;
    }
    boolean changed =
        super.checkResourceFieldsChanged(param, params, fromServicesInfo, fromCloneInfo, true);
    @SuppressWarnings("unchecked")
    final Enumeration<DefaultMutableTreeNode> e = gn.children();
    try {
      while (e.hasMoreElements()) {
        final DefaultMutableTreeNode n = e.nextElement();
        final ServiceInfo gsi = (ServiceInfo) n.getUserObject();
        if (gsi.checkResourceFieldsChanged(
            null, gsi.getParametersFromXML(), fromServicesInfo, fromCloneInfo, true)) {
          changed = true;
        }
      }
    } catch (java.util.NoSuchElementException ele) {
      return false;
    }
    return changed;
  }

  /**
   * Returns whether all the parameters are correct. If param is null, all paremeters will be
   * checked, otherwise only the param, but other parameters will be checked only in the cache. This
   * is good if only one value is changed and we don't want to check everything.
   */
  @Override
  public boolean checkResourceFieldsCorrect(final String param, final String[] params) {
    return checkResourceFieldsCorrect(param, params, false, false);
  }

  /**
   * Returns whether all the parameters are correct. If param is null, all paremeters will be
   * checked, otherwise only the param, but other parameters will be checked only in the cache. This
   * is good if only one value is changed and we don't want to check everything.
   */
  boolean checkResourceFieldsCorrect(
      final String param,
      final String[] params,
      final boolean fromServicesInfo,
      final boolean fromCloneInfo) {
    boolean cor =
        super.checkResourceFieldsCorrect(param, params, fromServicesInfo, fromCloneInfo, true);
    final DefaultMutableTreeNode gn = getNode();
    if (gn != null) {
      @SuppressWarnings("unchecked")
      final Enumeration<DefaultMutableTreeNode> e = gn.children();
      if (!e.hasMoreElements()) {
        return false;
      }
      try {
        while (e.hasMoreElements()) {
          final DefaultMutableTreeNode n = e.nextElement();
          final ServiceInfo gsi = (ServiceInfo) n.getUserObject();
          if (!gsi.checkResourceFieldsCorrect(
              null, gsi.getParametersFromXML(), fromServicesInfo, fromCloneInfo, true)) {
            cor = false;
          }
        }
      } catch (java.util.NoSuchElementException ele) {
        return false;
      }
    }
    return cor;
  }

  /** Update menus with positions and calles their update methods. */
  @Override
  void updateMenus(final Point2D pos) {
    super.updateMenus(pos);
    if (!Tools.getConfigData().isSlow()) {
      final ClusterStatus cs = getBrowser().getClusterStatus();
      final List<String> resources = cs.getGroupResources(getHeartbeatId(false), false);
      if (resources != null) {
        for (final String hbId : resources) {
          final ServiceInfo si = getBrowser().getServiceInfoFromCRMId(hbId);
          if (si != null) {
            si.updateMenus(pos);
          }
        }
      }
    }
  }

  /** Adds existing service menu item for every member of a group. */
  @Override
  protected void addExistingGroupServiceMenuItems(
      final ServiceInfo asi,
      final MyListModel<MyMenuItem> dlm,
      final Map<MyMenuItem, ButtonCallback> callbackHash,
      final MyList<MyMenuItem> list,
      final JCheckBox colocationCB,
      final JCheckBox orderCB,
      final List<JDialog> popups,
      final boolean testOnly) {
    final ClusterStatus cs = getBrowser().getClusterStatus();
    final List<String> resources = cs.getGroupResources(getHeartbeatId(false), false);
    if (resources != null) {
      for (final String hbId : resources) {
        final ServiceInfo si = getBrowser().getServiceInfoFromCRMId(hbId);
        if (si != null) {
          asi.addExistingServiceMenuItem(
              "         " + si.toString(),
              si,
              dlm,
              callbackHash,
              list,
              colocationCB,
              orderCB,
              popups,
              testOnly);
        }
      }
    }
  }

  /** Returns the icon for the category. */
  @Override
  public ImageIcon getCategoryIcon(final boolean testOnly) {
    if (getBrowser().allHostsDown() || !isOneRunning(testOnly)) {
      return ServiceInfo.SERVICE_STOPPED_ICON_SMALL;
    }
    return ServiceInfo.SERVICE_RUNNING_ICON_SMALL;
  }

  /** Revert all values. */
  @Override
  public void revert() {
    super.revert();
    @SuppressWarnings("unchecked")
    final Enumeration<DefaultMutableTreeNode> e = getNode().children();
    try {
      while (e.hasMoreElements()) {
        final DefaultMutableTreeNode n = e.nextElement();
        final ServiceInfo gsi = (ServiceInfo) n.getUserObject();
        if (gsi != null
            && gsi.checkResourceFieldsChanged(
                null, gsi.getParametersFromXML(), true, false, false)) {
          gsi.revert();
        }
      }
    } catch (java.util.NoSuchElementException ele) {
      /* do nothing */
    }
  }
}
Example #2
0
/**
 * This class is used to test the GUI.
 *
 * @author Rasto Levrinc
 */
final class PcmkTestA {
  /** Logger. */
  private static final Logger LOG = LoggerFactory.getLogger(PcmkTestA.class);

  /** Private constructor, cannot be instantiated. */
  private PcmkTestA() {
    /* Cannot be instantiated. */
  }

  static void start(final int count) {
    slowFactor = 0.5f;
    aborted = false;
    final int gx = 235;
    final int gy = 207;
    disableStonith();
    for (int i = count; i > 0; i--) {
      if (i % 5 == 0) {
        info("testA I: " + i);
      }
      checkTest("testA", 1);
      /* group with dummy resources */
      moveTo(gx, gy);
      sleep(1000);
      rightClick(); /* popup */
      sleep(1000);
      moveTo(Tools.getString("ClusterBrowser.Hb.AddGroup"));
      leftClick();
      sleep(3000);
      /* create dummy */
      moveTo(gx + 46, gy + 11);
      rightClick(); /* group popup */
      sleep(2000);
      moveTo(Tools.getString("ClusterBrowser.Hb.AddGroupService"));
      sleep(1000);
      moveTo("OCF Resource Agents");
      sleep(1000);
      typeDummy();
      sleep(300);
      setTimeouts(true);
      moveTo(Tools.getString("Browser.ApplyResource"));
      sleep(6000);
      leftClick();
      sleep(6000);
      checkTest("testA", 2);
      stopResource(gx, gy);
      sleep(6000);
      checkTest("testA", 3);

      /* copy/paste */
      moveTo(gx + 10, gy + 10);
      leftClick();
      robot.keyPress(KeyEvent.VK_CONTROL);
      press(KeyEvent.VK_C);
      press(KeyEvent.VK_V);
      robot.keyRelease(KeyEvent.VK_CONTROL);
      moveTo(gx + 10, gy + 90);
      leftClick();
      moveTo(Tools.getString("Browser.ApplyGroup"));
      sleep(4000);
      leftClick();
      checkTest("testA", 4);

      removeResource(gx, gy, CONFIRM_REMOVE);
      removeResource(gx, gy + 90, CONFIRM_REMOVE);
      resetTerminalAreas();
    }
    System.gc();
  }
}
Example #3
0
/**
 * This class is used to test the GUI.
 *
 * @author Rasto Levrinc
 */
final class PcmkTest3 {
  /** Logger. */
  private static final Logger LOG = LoggerFactory.getLogger(PcmkTest3.class);

  /** Private constructor, cannot be instantiated. */
  private PcmkTest3() {
    /* Cannot be instantiated. */
  }

  static void start(final int count) {
    slowFactor = 0.3f;
    aborted = false;
    disableStonith();
    final String testName = "test3";
    for (int i = count; i > 0; i--) {
      if (i % 5 == 0) {
        info(testName + " I: " + i);
      }
      checkTest(testName, 1);
      /* filesystem/drbd */
      moveTo(577, 205);
      rightClick(); /* popup */
      sleep(1000);
      moveTo(Tools.getString("ClusterBrowser.Hb.AddService"));
      sleep(1000);
      moveTo("Filesystem + Linbit:DRBD");
      leftClick(); /* choose fs */

      moveTo("block device", Widget.MComboBox.class); /* choose drbd */
      leftClick();
      sleep(2000);
      press(KeyEvent.VK_DOWN);
      sleep(200);
      press(KeyEvent.VK_DOWN);
      sleep(200);
      press(KeyEvent.VK_ENTER);

      moveTo("mount point", Widget.MComboBox.class);
      leftClick();
      sleep(2000);
      press(KeyEvent.VK_DOWN);
      sleep(200);
      press(KeyEvent.VK_DOWN);
      sleep(200);
      press(KeyEvent.VK_ENTER);

      moveTo("filesystem type", Widget.MComboBox.class);
      leftClick();
      sleep(2000);
      press(KeyEvent.VK_E);
      sleep(200);
      press(KeyEvent.VK_E);
      sleep(200);
      press(KeyEvent.VK_ENTER);

      moveTo(Tools.getString("Browser.ApplyResource"));
      leftClick();
      sleep(2000);
      checkTest(testName, 2);
      checkNumberOfVertices(testName, 4);
      stopEverything();
      checkTest(testName, 3);
      removeEverything();
      resetTerminalAreas();

      /* filesystem/drbd - with name */
      moveTo(577, 205);
      rightClick(); /* popup */
      sleep(1000);
      moveTo(Tools.getString("ClusterBrowser.Hb.AddService"));
      sleep(1000);
      moveTo("Filesystem + Linbit:DRBD");
      leftClick(); /* choose fs */

      checkTest(testName, 4);
      moveTo("Name", Widget.MTextField.class);
      leftClick();
      press(KeyEvent.VK_X);
      sleep(200);
      press(KeyEvent.VK_Y);
      sleep(200);

      moveTo("block device", Widget.MComboBox.class); /* choose drbd */
      leftClick();
      sleep(2000);
      press(KeyEvent.VK_DOWN);
      sleep(200);
      press(KeyEvent.VK_DOWN);
      sleep(200);
      press(KeyEvent.VK_ENTER);

      moveTo("mount point", Widget.MComboBox.class);
      leftClick();
      sleep(2000);
      press(KeyEvent.VK_DOWN);
      sleep(200);
      press(KeyEvent.VK_DOWN);
      sleep(200);
      press(KeyEvent.VK_ENTER);

      moveTo("filesystem type", Widget.MComboBox.class);
      leftClick();
      sleep(2000);
      press(KeyEvent.VK_E);
      sleep(200);
      press(KeyEvent.VK_E);
      sleep(200);
      press(KeyEvent.VK_ENTER);

      moveTo(Tools.getString("Browser.ApplyResource"));
      leftClick();
      sleep(2000);
      checkTest(testName, 5);
      checkNumberOfVertices(testName, 4);
      stopEverything();
      checkTest(testName, 6);
      removeEverything();
      resetTerminalAreas();
    }
    System.gc();
  }
}
Example #4
0
/**
 * An implementation of a dialog where connection to every host will be checked and established if
 * there isn't one.
 *
 * @author Rasto Levrinc
 * @version $Id$
 */
final class Connect extends DialogCluster {
  /** Logger. */
  private static final Logger LOG = LoggerFactory.getLogger(Connect.class);
  /** Serial version UID. */
  private static final long serialVersionUID = 1L;

  /** Prepares a new <code>Connect</code> object. */
  Connect(final WizardDialog previousDialog, final Cluster cluster) {
    super(previousDialog, cluster);
  }

  /** Returns the next dialog which is ClusterDrbdConf. */
  @Override
  public WizardDialog nextDialog() {
    return new CommStack(getPreviousDialog(), getCluster());
  }

  /** Returns cluster dialog title. */
  @Override
  protected String getClusterDialogTitle() {
    return Tools.getString("Dialog.Cluster.Connect.Title");
  }

  /** Returns description. */
  @Override
  protected String getDescription() {
    return Tools.getString("Dialog.Cluster.Connect.Description");
  }

  /** Checks hosts, if they are connected and if not reconnects them. */
  protected void checkHosts() {
    final StringBuilder text = new StringBuilder();
    boolean pending = false;
    boolean oneFailed = false;
    for (final Host host : getCluster().getHosts()) {
      String status;
      if (host.getSSH().isConnectionFailed()) {
        status = "failed.";
        oneFailed = true;
      } else if (host.isConnected()) {
        status = "connected.";
      } else {
        pending = true;
        status = "connecting...";
      }
      text.append(host.getName() + " " + status + "\n");
    }
    LOG.debug("checkHosts: pending: " + pending + ", one failed: " + oneFailed);
    if (pending) {
      answerPaneSetText(text.toString());
    } else if (oneFailed) {
      printErrorAndRetry(text.toString());
    } else {
      answerPaneSetText(text.toString());
      try {
        Thread.sleep(1000);
      } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
      }

      Tools.invokeLater(
          new Runnable() {
            @Override
            public void run() {
              buttonClass(nextButton()).pressButton();
            }
          });
    }
  }

  /** Connects all cluster hosts. */
  protected void connectHosts() {
    getCluster().connect(getDialogPanel(), true, 1);
    for (final Host host : getCluster().getHosts()) {
      host.waitOnLoading();
    }
    checkHosts();
  }

  /** Inits the dialog and connects the hosts. */
  @Override
  protected void initDialog() {
    super.initDialog();
    enableComponentsLater(new JComponent[] {buttonClass(nextButton())});
  }

  /** Inits dialog after it becomes visible. */
  @Override
  protected void initDialogAfterVisible() {
    final Thread t =
        new Thread(
            new Runnable() {
              @Override
              public void run() {
                connectHosts();
              }
            });
    t.start();
  }

  /** Returns the connect hosts dialog content. */
  @Override
  protected JComponent getInputPane() {
    final JPanel pane = new JPanel(new SpringLayout());
    final StringBuilder text = new StringBuilder();
    for (final Host host : getCluster().getHosts()) {
      text.append(host.getName());
      text.append(" connecting...\n");
    }
    pane.add(getAnswerPane(text.toString()));

    SpringUtilities.makeCompactGrid(
        pane, 1, 1, // rows, cols
        1, 1, // initX, initY
        1, 1); // xPad, yPad
    return pane;
  }

  /** Enable skip button. */
  @Override
  protected boolean skipButtonEnabled() {
    return true;
  }
}
Example #5
0
/**
 * This class is used to test the GUI.
 *
 * @author Rasto Levrinc
 */
final class DrbdTest5 {
  /** Logger. */
  private static final Logger LOG = LoggerFactory.getLogger(DrbdTest5.class);

  /** Private constructor, cannot be instantiated. */
  private DrbdTest5() {
    /* Cannot be instantiated. */
  }

  static void start(final Cluster cluster, final int blockDevY) {
    /* Two bds. */
    slowFactor = 0.6f;
    aborted = false;
    /* multi */
    LOG.info("start: create pvs");
    moveTo(334, blockDevY);
    leftClick();

    moveTo(534, getY());
    controlLeftClick();

    moveTo(334, blockDevY + 40);
    controlLeftClick();

    moveTo(534, blockDevY + 40);
    controlLeftClick();

    createPV(334, blockDevY);
    LOG.info("start: create vgs");
    createVGMulti(blockDevY);
    sleepNoFactor(5000);
    LOG.info("start: create lvs");
    moveToGraph("VG vg00");
    sleepNoFactor(5000);
    createLVMulti();
    LOG.info("start: remove lvs");
    moveTo(334, blockDevY);
    leftClick();
    moveTo(534, blockDevY);
    controlLeftClick();
    lvRemoveMulti();
    LOG.info("start: remove vgs");
    sleepNoFactor(5000);
    moveToGraph("VG vg00");
    leftClick();
    moveTo(534, getY());
    controlLeftClick();
    rightClick();
    sleep(1000);
    moveTo("Remove selected VGs");
    leftClick();
    sleep(1000);
    moveTo("Remove VG"); /* button */
    leftClick();
    LOG.info("start: remove pvs");
    moveTo(334, blockDevY);
    leftClick();
    moveTo(534, blockDevY);
    controlLeftClick();
    moveTo(334, blockDevY + 40);
    controlLeftClick();
    moveTo(534, blockDevY + 40);
    controlLeftClick();
    rightClick();
    sleep(3000);
    moveTo("Remove selected PVs");
    sleep(2000);
    leftClick();

    moveTo(430, 90);
    leftClick(); // reset selection

    /* single */
    for (int i = 0; i < 2; i++) {
      LOG.info("start: create pv 1 " + i);
      createPV(334, blockDevY);
      LOG.info("start: create pv 2 " + i);
      createPV(534, blockDevY);
      LOG.info("start: create vg " + i);
      createVG(cluster, blockDevY);
      sleepNoFactor(10000);
      LOG.info("start: create lv" + i);
      moveToGraph("VG vg0" + i);
      createLV(cluster);
      LOG.info("start: resize lv" + i);
      moveToGraph("vg0" + i + "/lvol0");
      resizeLV(cluster);
    }
    int offset = 0;
    for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
        moveToGraph("vg0" + i + "/lvol0");
        LOG.info("start: remove lv " + i + " " + j);
        lvRemove();
        sleepNoFactor(10000);
      }
      LOG.info("start: remove vg " + i);
      moveToGraph("VG vg0" + i);
      vgRemove(cluster);
      sleepNoFactor(10000);
      pvRemove(334, blockDevY + offset);
      pvRemove(534, blockDevY + offset);
      offset += 40;
    }
  }
}
Example #6
0
/** This class holds info about Virtual Disks. */
public final class VMSDiskInfo extends VMSHardwareInfo {
  /** Logger. */
  private static final Logger LOG = LoggerFactory.getLogger(VMSDiskInfo.class);
  /** Source file combo box, so that it can be disabled, depending on type. */
  private final Map<String, Widget> sourceFileWi = new HashMap<String, Widget>();
  /** Source block combo box, so that it can be disabled, depending on type. */
  private final Map<String, Widget> sourceDeviceWi = new HashMap<String, Widget>();

  private final Map<String, Widget> sourceNameWi = new HashMap<String, Widget>();
  private final Map<String, Widget> sourceProtocolWi = new HashMap<String, Widget>();
  private final Map<String, Widget> sourceHostNameWi = new HashMap<String, Widget>();
  private final Map<String, Widget> sourceHostPortWi = new HashMap<String, Widget>();
  private final Map<String, Widget> authUsernameWi = new HashMap<String, Widget>();
  private final Map<String, Widget> authSecretTypeWi = new HashMap<String, Widget>();
  private final Map<String, Widget> authSecretUuidWi = new HashMap<String, Widget>();

  /** Target device combo box, that needs to be reloaded if target type has changed. */
  private final Map<String, Widget> targetDeviceWi = new HashMap<String, Widget>();
  /** Driver name combo box. */
  private final Map<String, Widget> driverNameWi = new HashMap<String, Widget>();
  /** Driver type combo box. */
  private final Map<String, Widget> driverTypeWi = new HashMap<String, Widget>();
  /** Driver cache combo box. */
  private final Map<String, Widget> driverCacheWi = new HashMap<String, Widget>();
  /** Readonly combo box. */
  private final Map<String, Widget> readonlyWi = new HashMap<String, Widget>();
  /** Previous target device value. */
  private String prevTargetBusType = null;
  /** Previous target bus type (disk type) value. */
  private String previousTargetBusType = null;
  /** Parameters. */
  private static final String[] PARAMETERS = {
    DiskData.TYPE,
    DiskData.TARGET_BUS_TYPE,
    DiskData.TARGET_DEVICE,
    DiskData.SOURCE_FILE,
    DiskData.SOURCE_DEVICE,
    DiskData.SOURCE_PROTOCOL,
    DiskData.SOURCE_NAME,
    DiskData.SOURCE_HOST_NAME,
    DiskData.SOURCE_HOST_PORT,
    DiskData.AUTH_USERNAME,
    DiskData.AUTH_SECRET_TYPE,
    DiskData.AUTH_SECRET_UUID,
    DiskData.DRIVER_NAME,
    DiskData.DRIVER_TYPE,
    DiskData.DRIVER_CACHE,
    DiskData.READONLY,
    DiskData.SHAREABLE
  };
  /** Block parameters. */
  private static final String[] BLOCK_PARAMETERS = {
    DiskData.TYPE,
    DiskData.TARGET_BUS_TYPE,
    DiskData.TARGET_DEVICE,
    DiskData.SOURCE_DEVICE,
    DiskData.DRIVER_NAME,
    DiskData.DRIVER_TYPE,
    DiskData.DRIVER_CACHE,
    DiskData.READONLY,
    DiskData.SHAREABLE
  };
  /** File parameters. */
  private static final String[] FILE_PARAMETERS = {
    DiskData.TYPE,
    DiskData.TARGET_DEVICE,
    DiskData.SOURCE_FILE,
    DiskData.TARGET_BUS_TYPE,
    DiskData.DRIVER_NAME,
    DiskData.DRIVER_TYPE,
    DiskData.DRIVER_CACHE,
    DiskData.READONLY,
    DiskData.SHAREABLE
  };

  /** Network parameters. */
  private static final String[] NETWORK_PARAMETERS = {
    DiskData.TYPE,
    DiskData.TARGET_BUS_TYPE,
    DiskData.TARGET_DEVICE,
    DiskData.SOURCE_PROTOCOL,
    DiskData.SOURCE_NAME,
    DiskData.SOURCE_HOST_NAME,
    DiskData.SOURCE_HOST_PORT,
    DiskData.AUTH_USERNAME,
    DiskData.AUTH_SECRET_TYPE,
    DiskData.AUTH_SECRET_UUID,
    DiskData.DRIVER_NAME,
    DiskData.DRIVER_TYPE,
    DiskData.DRIVER_CACHE,
    DiskData.READONLY,
    DiskData.SHAREABLE
  };
  /** Whether the parameter is enabled only in advanced mode. */
  private static final Set<String> IS_ENABLED_ONLY_IN_ADVANCED =
      new HashSet<String>(
          Arrays.asList(
              new String[] {
                DiskData.TARGET_DEVICE,
                DiskData.DRIVER_NAME,
                DiskData.DRIVER_TYPE,
                DiskData.DRIVER_CACHE
              }));
  /** Whether the parameter is required. */
  private static final Set<String> IS_REQUIRED =
      new HashSet<String>(Arrays.asList(new String[] {DiskData.TYPE}));

  static {
    IS_REQUIRED.add(DiskData.SOURCE_PROTOCOL);
    IS_REQUIRED.add(DiskData.SOURCE_NAME);
    IS_REQUIRED.add(DiskData.SOURCE_HOST_NAME);
    IS_REQUIRED.add(DiskData.SOURCE_HOST_PORT);
    IS_REQUIRED.add(DiskData.AUTH_USERNAME);
  }
  /** Field type. */
  private static final Map<String, Widget.Type> FIELD_TYPES = new HashMap<String, Widget.Type>();
  /** Target devices depending on the target type. */
  private static final Map<String, String[]> TARGET_DEVICES_MAP = new HashMap<String, String[]>();

  static {
    FIELD_TYPES.put(DiskData.TYPE, Widget.Type.RADIOGROUP);
    FIELD_TYPES.put(DiskData.SOURCE_FILE, Widget.Type.COMBOBOX);
    FIELD_TYPES.put(DiskData.READONLY, Widget.Type.CHECKBOX);
    FIELD_TYPES.put(DiskData.SHAREABLE, Widget.Type.CHECKBOX);
    FIELD_TYPES.put(DiskData.TARGET_DEVICE, Widget.Type.COMBOBOX);
  }
  /** Short name. */
  private static final Map<String, String> SHORTNAME_MAP = new HashMap<String, String>();

  static {
    SHORTNAME_MAP.put(DiskData.TYPE, Tools.getString("VMSDiskInfo.Param.Type"));
    SHORTNAME_MAP.put(DiskData.TARGET_DEVICE, Tools.getString("VMSDiskInfo.Param.TargetDevice"));
    SHORTNAME_MAP.put(DiskData.SOURCE_FILE, Tools.getString("VMSDiskInfo.Param.SourceFile"));
    SHORTNAME_MAP.put(DiskData.SOURCE_DEVICE, Tools.getString("VMSDiskInfo.Param.SourceDevice"));

    SHORTNAME_MAP.put(
        DiskData.SOURCE_PROTOCOL, Tools.getString("VMSDiskInfo.Param.SourceProtocol"));
    SHORTNAME_MAP.put(DiskData.SOURCE_NAME, Tools.getString("VMSDiskInfo.Param.SourceName"));
    SHORTNAME_MAP.put(
        DiskData.SOURCE_HOST_NAME, Tools.getString("VMSDiskInfo.Param.SourceHostName"));
    SHORTNAME_MAP.put(
        DiskData.SOURCE_HOST_PORT, Tools.getString("VMSDiskInfo.Param.SourceHostPort"));

    SHORTNAME_MAP.put(DiskData.AUTH_USERNAME, Tools.getString("VMSDiskInfo.Param.AuthUsername"));
    SHORTNAME_MAP.put(
        DiskData.AUTH_SECRET_TYPE, Tools.getString("VMSDiskInfo.Param.AuthSecretType"));
    SHORTNAME_MAP.put(
        DiskData.AUTH_SECRET_UUID, Tools.getString("VMSDiskInfo.Param.AuthSecretUuid"));

    SHORTNAME_MAP.put(DiskData.TARGET_BUS_TYPE, Tools.getString("VMSDiskInfo.Param.TargetBusType"));
    SHORTNAME_MAP.put(DiskData.DRIVER_NAME, Tools.getString("VMSDiskInfo.Param.DriverName"));
    SHORTNAME_MAP.put(DiskData.DRIVER_TYPE, Tools.getString("VMSDiskInfo.Param.DriverType"));
    SHORTNAME_MAP.put(DiskData.DRIVER_CACHE, Tools.getString("VMSDiskInfo.Param.DriverCache"));
    SHORTNAME_MAP.put(DiskData.READONLY, Tools.getString("VMSDiskInfo.Param.Readonly"));
    SHORTNAME_MAP.put(DiskData.SHAREABLE, Tools.getString("VMSDiskInfo.Param.Shareable"));
  }
  /** Tool tips. */
  private static final Map<String, String> TOOLTIP_MAP = new HashMap<String, String>();

  static {
    TOOLTIP_MAP.put(
        DiskData.SOURCE_HOST_NAME, Tools.getString("VMSDiskInfo.Param.SourceHostName.ToolTip"));
    TOOLTIP_MAP.put(
        DiskData.SOURCE_HOST_PORT, Tools.getString("VMSDiskInfo.Param.SourceHostPort.ToolTip"));
  }

  /** Sections. */
  private static final Map<String, String> SECTION_MAP = new HashMap<String, String>();

  private static final String SECTION_DISK_OPTIONS =
      Tools.getString("VMSDiskInfo.Section.DiskOptions");
  private static final String SECTION_SOURCE = Tools.getString("VMSDiskInfo.Section.Source");
  private static final String SECTION_AUTHENTICATION =
      Tools.getString("VMSDiskInfo.Section.Authentication");

  static {
    SECTION_MAP.put(DiskData.TYPE, SECTION_SOURCE);
    SECTION_MAP.put(DiskData.SOURCE_FILE, SECTION_SOURCE);
    SECTION_MAP.put(DiskData.SOURCE_DEVICE, SECTION_SOURCE);
    SECTION_MAP.put(DiskData.SOURCE_PROTOCOL, SECTION_SOURCE);
    SECTION_MAP.put(DiskData.SOURCE_NAME, SECTION_SOURCE);
    SECTION_MAP.put(DiskData.SOURCE_HOST_NAME, SECTION_SOURCE);
    SECTION_MAP.put(DiskData.SOURCE_HOST_PORT, SECTION_SOURCE);

    SECTION_MAP.put(DiskData.AUTH_USERNAME, SECTION_AUTHENTICATION);
    SECTION_MAP.put(DiskData.AUTH_SECRET_TYPE, SECTION_AUTHENTICATION);
    SECTION_MAP.put(DiskData.AUTH_SECRET_UUID, SECTION_AUTHENTICATION);
  }

  /** Preferred values. */
  private static final Map<String, String> PREFERRED_MAP = new HashMap<String, String>();
  /** Defaults. */
  private static final Map<String, String> DEFAULTS_MAP = new HashMap<String, String>();
  /** Possible values. */
  private static final Map<String, Object[]> POSSIBLE_VALUES = new HashMap<String, Object[]>();
  /** Default location for libvirt images. */
  public static final String LIBVIRT_IMAGE_LOCATION = "/var/lib/libvirt/images/";
  /**
   * A map from target bus and type as it is saved to the string representation that appears in the
   * menus.
   */
  private static final Map<String, String> TARGET_BUS_TYPES = new HashMap<String, String>();
  /** Disk types. */
  private static final String FILE_TYPE = "file";

  private static final String BLOCK_TYPE = "block";
  private static final String NETWORK_TYPE = "network";

  /** Drivers. */
  private static final String DRIVER_NAME_DEFUALT = null;

  private static final String DRIVER_NAME_FILE = "file";
  private static final String DRIVER_NAME_QEMU = "qemu";
  private static final String DRIVER_NAME_PHY = "phy";

  static {
    POSSIBLE_VALUES.put(
        DiskData.TYPE,
        new StringInfo[] {
          new StringInfo("Image file", FILE_TYPE, null),
          new StringInfo("Disk/block device", BLOCK_TYPE, null),
          new StringInfo("Network", NETWORK_TYPE, null)
        });
    POSSIBLE_VALUES.put(
        DiskData.TARGET_BUS_TYPE,
        new StringInfo[] {
          new StringInfo("IDE Disk", "ide/disk", null),
          new StringInfo("IDE CDROM", "ide/cdrom", null),
          new StringInfo("Floppy Disk", "fdc/floppy", null),
          new StringInfo("SCSI Disk", "scsi/disk", null),
          new StringInfo("USB Disk", "usb/disk", null),
          new StringInfo("Virtio Disk", "virtio/disk", null)
        });
    POSSIBLE_VALUES.put(
        DiskData.DRIVER_NAME,
        new String[] {DRIVER_NAME_DEFUALT, DRIVER_NAME_FILE, DRIVER_NAME_QEMU, DRIVER_NAME_PHY});
    POSSIBLE_VALUES.put(DiskData.DRIVER_TYPE, new String[] {null, "raw"});
    POSSIBLE_VALUES.put(
        DiskData.DRIVER_CACHE,
        new String[] {
          null, "default", "none", "writethrough", "writeback", "directsync", "unsafe"
        });

    POSSIBLE_VALUES.put(
        DiskData.SOURCE_PROTOCOL,
        new String[] {null, "rbd", "nbd", "iscsi", "sheepdog", "gluster"});

    POSSIBLE_VALUES.put(
        DiskData.SOURCE_NAME,
        new String[] {"", "poolname/imagename", "poolname/imagename:rbd_cache=1"});
    POSSIBLE_VALUES.put(DiskData.AUTH_SECRET_TYPE, new String[] {"", "ceph", "iscsi"});
    for (final StringInfo tbt : (StringInfo[]) POSSIBLE_VALUES.get(DiskData.TARGET_BUS_TYPE)) {
      TARGET_BUS_TYPES.put(tbt.getInternalValue(), tbt.toString());
    }
    DEFAULTS_MAP.put(DiskData.READONLY, "False");
    DEFAULTS_MAP.put(DiskData.SHAREABLE, "False");
    PREFERRED_MAP.put(DiskData.DRIVER_NAME, "file");
    TARGET_DEVICES_MAP.put("ide/disk", new String[] {"hda", "hdb", "hdd"});
    TARGET_DEVICES_MAP.put("ide/cdrom", new String[] {"hdc"});
    TARGET_DEVICES_MAP.put("fdc/floppy", new String[] {"fda", "fdb", "fdc", "fdd"});
    TARGET_DEVICES_MAP.put("scsi/disk", new String[] {"sda", "sdb", "sdc", "sdd"});
    TARGET_DEVICES_MAP.put("usb/disk", new String[] {"sda", "sdb", "sdc", "sdd"});
    TARGET_DEVICES_MAP.put("virtio/disk", new String[] {"vda", "vdb", "vdc", "vdd", "vde"});
  }
  /** Default source port if none is specified (and it is needed). */
  public static final String DEFAULT_SOURCE_HOST_PORT = "6789";

  private final List<Map<String, Widget>> checkFieldList = new ArrayList<Map<String, Widget>>();

  /** Table panel. */
  private JComponent tablePanel = null;

  /** Creates the VMSDiskInfo object. */
  VMSDiskInfo(
      final String name, final Browser browser, final VMSVirtualDomainInfo vmsVirtualDomainInfo) {
    super(name, browser, vmsVirtualDomainInfo);

    checkFieldList.add(sourceNameWi);
    checkFieldList.add(sourceProtocolWi);
    checkFieldList.add(sourceHostNameWi);
    checkFieldList.add(sourceHostPortWi);
    checkFieldList.add(authUsernameWi);
    checkFieldList.add(authSecretTypeWi);
    checkFieldList.add(authSecretUuidWi);
  }

  /** Adds disk table with only this disk to the main panel. */
  @Override
  protected void addHardwareTable(final JPanel mainPanel) {
    tablePanel =
        getTablePanel(
            "Disk", VMSVirtualDomainInfo.DISK_TABLE, getNewBtn(getVMSVirtualDomainInfo()));
    if (getResource().isNew()) {
      Tools.invokeLater(
          !Tools.CHECK_SWING_THREAD,
          new Runnable() {
            @Override
            public void run() {
              tablePanel.setVisible(false);
            }
          });
    }
    mainPanel.add(tablePanel);
  }

  /** Returns service icon in the menu. */
  @Override
  public ImageIcon getMenuIcon(final boolean testOnly) {
    return BlockDevInfo.HARDDISK_ICON;
  }

  /** Returns long description of the specified parameter. */
  @Override
  protected String getParamLongDesc(final String param) {
    return getParamShortDesc(param);
  }

  /** Returns short description of the specified parameter. */
  @Override
  protected String getParamShortDesc(final String param) {
    final String name = SHORTNAME_MAP.get(param);
    if (name == null) {
      return param;
    }
    return name;
  }

  /** Returns preferred value for specified parameter. */
  @Override
  protected String getParamPreferred(final String param) {
    final String domainType =
        getVMSVirtualDomainInfo().getWidget(VMSXML.VM_PARAM_DOMAIN_TYPE, null).getStringValue();
    if (DiskData.DRIVER_NAME.equals(param)
        && VMSVirtualDomainInfo.DOMAIN_TYPE_KVM.equals(domainType)) {
      return DRIVER_NAME_QEMU;
    }
    return PREFERRED_MAP.get(param);
  }

  /** Returns default value for specified parameter. */
  @Override
  protected String getParamDefault(final String param) {
    return DEFAULTS_MAP.get(param);
  }

  /** Returns parameters. */
  @Override
  public String[] getParametersFromXML() {
    return PARAMETERS.clone();
  }

  /** Returns real parameters. */
  @Override
  public String[] getRealParametersFromXML() {
    if (BLOCK_TYPE.equals(getComboBoxValue(DiskData.TYPE))) {
      return BLOCK_PARAMETERS.clone();
    } else if (FILE_TYPE.equals(getComboBoxValue(DiskData.TYPE))) {
      return FILE_PARAMETERS.clone();
    } else {
      return NETWORK_PARAMETERS.clone();
    }
  }

  /** Returns possible choices for drop down lists. */
  @Override
  protected Object[] getParamPossibleChoices(final String param) {
    if (DiskData.SOURCE_FILE.equals(param)) {
      final Set<String> sourceFileDirs = new TreeSet<String>();
      sourceFileDirs.add(LIBVIRT_IMAGE_LOCATION);
      for (final Host h : getVMSVirtualDomainInfo().getDefinedOnHosts()) {
        final VMSXML vmsxml = getBrowser().getVMSXML(h);
        if (vmsxml != null) {
          sourceFileDirs.addAll(vmsxml.getsourceFileDirs());
        }
      }
      return sourceFileDirs.toArray(new String[sourceFileDirs.size()]);
    } else if (DiskData.SOURCE_DEVICE.equals(param)) {
      for (final Host h : getVMSVirtualDomainInfo().getDefinedOnHosts()) {
        final VMSXML vmsxml = getBrowser().getVMSXML(h);
        final List<String> bds = new ArrayList<String>();
        bds.add(null);
        if (vmsxml != null) {
          for (final BlockDevInfo bdi : h.getBrowser().getBlockDevInfos()) {
            if (bdi.getBlockDevice().isDrbd()) {
              bds.add(bdi.getDrbdVolumeInfo().getDeviceByRes());
            } else {
              bds.add(bdi.getName());
            }
          }
          return bds.toArray(new String[bds.size()]);
        }
      }
    }
    return POSSIBLE_VALUES.get(param);
  }

  /** Returns section to which the specified parameter belongs. */
  @Override
  protected String getSection(final String param) {
    final String section = SECTION_MAP.get(param);
    if (section == null) {
      return SECTION_DISK_OPTIONS;
    } else {
      return section;
    }
  }

  /** Returns true if the specified parameter is required. */
  @Override
  protected boolean isRequired(final String param) {
    final String type = getComboBoxValue(DiskData.TYPE);
    if ((DiskData.SOURCE_FILE.equals(param) && FILE_TYPE.equals(type))
        || (DiskData.SOURCE_DEVICE.equals(param) && BLOCK_TYPE.equals(type))) {
      if ("ide/cdrom".equals(getComboBoxValue(DiskData.TARGET_BUS_TYPE))
          || "fdc/floppy".equals(getComboBoxValue(DiskData.TARGET_BUS_TYPE))) {
        return false;
      } else {
        return true;
      }
    }
    return IS_REQUIRED.contains(param);
  }

  /** Returns true if the specified parameter is integer. */
  @Override
  protected boolean isInteger(final String param) {
    return false;
  }

  /** Returns true if the specified parameter is label. */
  @Override
  protected boolean isLabel(final String param) {
    return false;
  }

  /** Returns true if the specified parameter is of time type. */
  @Override
  protected boolean isTimeType(final String param) {
    return false;
  }

  /** Returns whether parameter is checkbox. */
  @Override
  protected boolean isCheckBox(final String param) {
    return false;
  }

  /** Returns the type of the parameter. */
  @Override
  protected String getParamType(final String param) {
    return "undef"; // TODO:
  }

  /** Returns type of the field. */
  @Override
  protected Widget.Type getFieldType(final String param) {
    return FIELD_TYPES.get(param);
  }

  /** Returns device parameters. */
  @Override
  protected Map<String, String> getHWParameters(final boolean allParams) {
    Tools.invokeAndWait(
        new Runnable() {
          @Override
          public void run() {
            getInfoPanel();
          }
        });
    final String[] params = getRealParametersFromXML();
    final Map<String, String> parameters = new LinkedHashMap<String, String>();
    for (final String param : params) {
      final String value = getComboBoxValue(param);
      if (DiskData.TYPE.equals(param)) {
        parameters.put(param, value);
      } else if (DiskData.TARGET_BUS_TYPE.equals(param)) {
        if (value == null) {
          parameters.put(DiskData.TARGET_BUS, null);
          parameters.put(DiskData.TARGET_TYPE, null);
        } else {
          final String[] values = value.split("/");
          if (values.length == 2) {
            parameters.put(DiskData.TARGET_BUS, values[0]);
            parameters.put(DiskData.TARGET_TYPE, values[1]);
          } else {
            LOG.appWarning("getHWParameters: cannot parse: " + param + " = " + value);
          }
        }
      } else if (allParams) {
        if (Tools.areEqual(getParamDefault(param), value)) {
          parameters.put(param, null);
        } else {
          parameters.put(param, value);
        }
      } else if (!Tools.areEqual(getParamSaved(param), value)
          || DiskData.SOURCE_FILE.equals(param)
          || DiskData.SOURCE_DEVICE.equals(param)
          || DiskData.SOURCE_PROTOCOL.equals(param)
          || DiskData.SOURCE_NAME.equals(param)
          || DiskData.SOURCE_HOST_NAME.equals(param)
          || DiskData.SOURCE_HOST_PORT.equals(param)
          || DiskData.AUTH_USERNAME.equals(param)
          || DiskData.AUTH_SECRET_TYPE.equals(param)
          || DiskData.AUTH_SECRET_UUID.equals(param)) {
        if (Tools.areEqual(getParamDefault(param), value)) {
          parameters.put(param, null);
        } else {
          parameters.put(param, value);
        }
      }
    }
    parameters.put(DiskData.SAVED_TARGET_DEVICE, getName());
    setName(getParamSaved(DiskData.TARGET_DEVICE));
    return parameters;
  }

  /** Fix ports. Make the number of ports delimited with "," to match the host names. */
  private static void fixSourceHostParams(final Map<String, String> params) {
    final String names = params.get(DiskData.SOURCE_HOST_NAME);
    String ports = params.get(DiskData.SOURCE_HOST_PORT);
    if (names == null) {
      params.put(DiskData.SOURCE_HOST_PORT, null);
      return;
    }
    if ("".equals(names)) {
      params.put(DiskData.SOURCE_HOST_PORT, "");
      return;
    }

    if (ports == null || "".equals(ports)) {
      ports = DEFAULT_SOURCE_HOST_PORT;
    }

    final String[] namesA = names.trim().split("\\s*,\\s*");
    final String[] portsA = ports.trim().split("\\s*,\\s*");

    final String lastPort = portsA[portsA.length - 1];

    final String fixedNames = Tools.join(", ", namesA);
    String fixedPorts;
    if (namesA.length == portsA.length) {
      fixedPorts = Tools.join(", ", portsA);
    } else if (portsA.length < namesA.length) {
      /* add ports */
      fixedPorts = Tools.join(", ", portsA);
      for (int i = 0; i < namesA.length - portsA.length; i++) {
        fixedPorts += ", " + lastPort;
      }
    } else {
      /* remove ports */
      fixedPorts = Tools.join(", ", portsA, namesA.length);
    }
    params.put(DiskData.SOURCE_HOST_NAME, fixedNames);
    params.put(DiskData.SOURCE_HOST_PORT, fixedPorts);
  }

  /** Applies the changes. */
  @Override
  void apply(final boolean testOnly) {
    if (testOnly) {
      return;
    }
    Tools.invokeAndWait(
        new Runnable() {
          @Override
          public void run() {
            getApplyButton().setEnabled(false);
            getRevertButton().setEnabled(false);
            getInfoPanel();
          }
        });
    waitForInfoPanel();
    final Map<String, String> parameters = getHWParameters(getResource().isNew());
    final String[] params = getRealParametersFromXML();
    for (final Host h : getVMSVirtualDomainInfo().getDefinedOnHosts()) {
      final VMSXML vmsxml = getBrowser().getVMSXML(h);
      if (vmsxml != null) {
        final String domainName = getVMSVirtualDomainInfo().getDomainName();
        final Node domainNode = vmsxml.getDomainNode(domainName);
        /* fix host ports */

        fixSourceHostParams(parameters);
        final String fixedNames = parameters.get(DiskData.SOURCE_HOST_NAME);
        final String fixedPorts = parameters.get(DiskData.SOURCE_HOST_PORT);

        for (final String p : sourceHostNameWi.keySet()) {
          sourceHostNameWi.get(p).setValueAndWait(fixedNames);
        }
        for (final String p : sourceHostPortWi.keySet()) {
          sourceHostPortWi.get(p).setValueAndWait(fixedPorts);
        }
        modifyXML(vmsxml, domainNode, domainName, parameters);
        final String virshOptions = getVMSVirtualDomainInfo().getVirshOptions();
        vmsxml.saveAndDefine(domainNode, domainName, virshOptions);
      }
    }
    getResource().setNew(false);
    getBrowser().reload(getNode(), false);
    getBrowser().periodicalVMSUpdate(getVMSVirtualDomainInfo().getDefinedOnHosts());
    Tools.invokeLater(
        new Runnable() {
          @Override
          public void run() {
            tablePanel.setVisible(true);
          }
        });
    if (!testOnly) {
      storeComboBoxValues(params);
    }
    checkResourceFieldsChanged(null, params);
  }

  /** Modify device xml. */
  @Override
  protected void modifyXML(
      final VMSXML vmsxml,
      final Node node,
      final String domainName,
      final Map<String, String> params) {
    if (vmsxml != null) {
      vmsxml.modifyDiskXML(node, domainName, params);
    }
  }

  /** Returns data for the table. */
  @Override
  protected Object[][] getTableData(final String tableName) {
    if (VMSVirtualDomainInfo.HEADER_TABLE.equals(tableName)) {
      return getVMSVirtualDomainInfo().getMainTableData();
    } else if (VMSVirtualDomainInfo.DISK_TABLE.equals(tableName)) {
      if (getResource().isNew()) {
        return new Object[][] {};
      }
      return new Object[][] {
        getVMSVirtualDomainInfo()
            .getDiskDataRow(getName(), null, getVMSVirtualDomainInfo().getDisks(), true)
      };
    }
    return new Object[][] {};
  }

  /** Returns whether this parameter is advanced. */
  @Override
  protected boolean isAdvanced(final String param) {
    return false;
  }

  /** Returns access type of this parameter. */
  @Override
  protected ConfigData.AccessType getAccessType(final String param) {
    return ConfigData.AccessType.ADMIN;
  }
  /** Returns true if the value of the parameter is ok. */
  @Override
  protected boolean checkParam(final String param, final String newValue) {
    if (DiskData.TYPE.equals(param)) {
      Tools.invokeLater(
          !Tools.CHECK_SWING_THREAD,
          new Runnable() {
            @Override
            public void run() {
              final boolean file = FILE_TYPE.equals(newValue);
              final boolean block = BLOCK_TYPE.equals(newValue);
              final boolean network = NETWORK_TYPE.equals(newValue);
              for (final String p : sourceFileWi.keySet()) {
                sourceFileWi.get(p).setVisible(file);
              }
              for (final String p : sourceDeviceWi.keySet()) {
                sourceDeviceWi.get(p).setVisible(block);
              }
              for (final Map<String, Widget> w : checkFieldList) {
                for (String p : w.keySet()) {
                  w.get(p).setVisible(network);
                }
              }
            }
          });
      checkOneParam(DiskData.SOURCE_FILE);
      checkOneParam(DiskData.SOURCE_DEVICE);
    } else if (DiskData.TARGET_BUS_TYPE.equals(param)) {
      final Set<String> devices = new LinkedHashSet<String>();
      devices.add(null);
      if (newValue != null) {
        final String[] targetDevices = TARGET_DEVICES_MAP.get(newValue);
        if (targetDevices != null) {
          for (final String dev : targetDevices) {
            if (!getVMSVirtualDomainInfo().isDevice(dev)) {
              devices.add(dev);
            }
          }
        }
      }
      final String saved = getParamSaved(DiskData.TARGET_DEVICE);
      String selected = null;
      devices.add(saved);
      if (saved == null || getResource().isNew()) {
        if (devices.size() > 1) {
          selected = devices.toArray(new String[devices.size()])[1];
        }
      } else {
        selected = saved;
      }
      if (prevTargetBusType == null || !prevTargetBusType.equals(newValue)) {
        final String sel = selected;
        for (final String p : targetDeviceWi.keySet()) {
          targetDeviceWi.get(p).reloadComboBox(sel, devices.toArray(new String[devices.size()]));
        }
        prevTargetBusType = newValue;
      }
      final String tbs = getComboBoxValue(DiskData.TARGET_BUS_TYPE);
      if (getParamSaved(DiskData.DRIVER_NAME) == null && !tbs.equals(previousTargetBusType)) {
        if ("ide/cdrom".equals(newValue)) {
          for (final String p : readonlyWi.keySet()) {
            readonlyWi.get(p).setValue("True");
          }
          for (final String p : driverTypeWi.keySet()) {
            if (getResource().isNew()) {
              driverTypeWi.get(p).setValue("raw");
            } else {
              if (driverTypeWi.get(p).getValue() != null) {
                driverTypeWi.get(p).setValue(null);
              }
            }
          }
        } else if ("virtio/disk".equals(newValue)) {
          for (final String p : driverTypeWi.keySet()) {
            driverTypeWi.get(p).setValue("raw");
          }
          for (final String p : driverCacheWi.keySet()) {
            driverCacheWi.get(p).setValue("none");
          }
        } else {
          for (final String p : readonlyWi.keySet()) {
            readonlyWi.get(p).setValue("False");
            driverTypeWi.get(p).setValue("raw");
          }
        }
      }
      previousTargetBusType = tbs;
      checkOneParam(DiskData.SOURCE_FILE);
      checkOneParam(DiskData.SOURCE_DEVICE);
    }
    if (isRequired(param) && (newValue == null || "".equals(newValue))) {
      return false;
    }
    return true;
  }

  /** Whether the parameter should be enabled. */
  @Override
  protected String isEnabled(final String param) {
    return null;
  }

  /** Whether the parameter should be enabled only in advanced mode. */
  @Override
  protected boolean isEnabledOnlyInAdvancedMode(final String param) {
    return IS_ENABLED_ONLY_IN_ADVANCED.contains(param);
  }

  /** Updates parameters. */
  @Override
  void updateParameters() {
    final Map<String, DiskData> disks = getVMSVirtualDomainInfo().getDisks();
    if (disks != null) {
      final DiskData diskData = disks.get(getName());
      if (diskData != null) {
        for (final String param : getParametersFromXML()) {
          final String oldValue = getParamSaved(param);
          String value = getParamSaved(param);
          final Widget wi = getWidget(param, null);
          for (final Host h : getVMSVirtualDomainInfo().getDefinedOnHosts()) {
            final VMSXML vmsxml = getBrowser().getVMSXML(h);
            if (vmsxml != null) {
              final String savedValue = diskData.getValue(param);
              if (savedValue != null) {
                value = savedValue;
              }
            }
          }
          if (!Tools.areEqual(value, oldValue)) {
            getResource().setValue(param, value);
            if (wi != null) {
              /* only if it is not changed by user. */
              wi.setValue(value);
            }
          }
        }
      }
    }
    updateTable(VMSVirtualDomainInfo.HEADER_TABLE);
    updateTable(VMSVirtualDomainInfo.DISK_TABLE);
    // checkResourceFieldsChanged(null, getParametersFromXML());
    setApplyButtons(null, getRealParametersFromXML());
  }

  /** Returns combo box for parameter. */
  @Override
  protected Widget createWidget(final String param, final String prefix, final int width) {
    String prefixS;
    if (prefix == null) {
      prefixS = "";
    } else {
      prefixS = prefix;
    }
    if (DiskData.SOURCE_FILE.equals(param)) {
      final String sourceFile = getParamSaved(DiskData.SOURCE_FILE);
      final String regexp = ".*[^/]$";
      final MyButton fileChooserBtn = new MyButton("Browse...");
      fileChooserBtn.miniButton();
      final Widget paramWi =
          WidgetFactory.createInstance(
              getFieldType(param),
              sourceFile,
              getParamPossibleChoices(param),
              regexp,
              width,
              Widget.NO_ABBRV,
              new AccessMode(getAccessType(param), false), /* only adv. mode */
              fileChooserBtn);
      paramWi.setAlwaysEditable(true);
      sourceFileWi.put(prefixS, paramWi);
      if (Tools.isWindows()) {
        /* does not work on windows and I tried, ultimately because
           FilePane.usesShellFolder(fc) in BasicFileChooserUI returns
           true and it is not possible to descent into a directory.
           TODO: It may work in the future.
        */
        paramWi.setTFButtonEnabled(false);
      }
      fileChooserBtn.addActionListener(
          new ActionListener() {
            @Override
            public void actionPerformed(final ActionEvent e) {
              final Thread t =
                  new Thread(
                      new Runnable() {
                        @Override
                        public void run() {
                          String file;
                          final String oldFile = paramWi.getStringValue();
                          if (oldFile == null || "".equals(oldFile)) {
                            file = LIBVIRT_IMAGE_LOCATION;
                          } else {
                            file = oldFile;
                          }
                          startFileChooser(paramWi, file, FILECHOOSER_FILE_ONLY);
                        }
                      });
              t.start();
            }
          });
      widgetAdd(param, prefix, paramWi);
      return paramWi;
    } else {
      final Widget paramWi = super.createWidget(param, prefix, width);
      if (DiskData.TYPE.equals(param) || DiskData.TARGET_BUS_TYPE.equals(param)) {
        paramWi.setAlwaysEditable(false);
      } else if (DiskData.SOURCE_DEVICE.equals(param)) {
        paramWi.setAlwaysEditable(true);
        sourceDeviceWi.put(prefixS, paramWi);
      } else if (DiskData.SOURCE_NAME.equals(param)) {
        sourceNameWi.put(prefixS, paramWi);
      } else if (DiskData.SOURCE_PROTOCOL.equals(param)) {
        sourceProtocolWi.put(prefixS, paramWi);
      } else if (DiskData.SOURCE_HOST_NAME.equals(param)) {
        sourceHostNameWi.put(prefixS, paramWi);
      } else if (DiskData.SOURCE_HOST_PORT.equals(param)) {
        sourceHostPortWi.put(prefixS, paramWi);
      } else if (DiskData.AUTH_USERNAME.equals(param)) {
        authUsernameWi.put(prefixS, paramWi);
      } else if (DiskData.AUTH_SECRET_TYPE.equals(param)) {
        authSecretTypeWi.put(prefixS, paramWi);
      } else if (DiskData.AUTH_SECRET_UUID.equals(param)) {
        authSecretUuidWi.put(prefixS, paramWi);
      } else if (DiskData.TARGET_DEVICE.equals(param)) {
        paramWi.setAlwaysEditable(true);
        targetDeviceWi.put(prefixS, paramWi);
      } else if (DiskData.DRIVER_NAME.equals(param)) {
        driverNameWi.put(prefixS, paramWi);
      } else if (DiskData.DRIVER_TYPE.equals(param)) {
        driverTypeWi.put(prefixS, paramWi);
      } else if (DiskData.DRIVER_CACHE.equals(param)) {
        driverCacheWi.put(prefixS, paramWi);
      } else if (DiskData.READONLY.equals(param)) {
        readonlyWi.put(prefixS, paramWi);
      }
      return paramWi;
    }
  }

  /** Removes this disk without confirmation dialog. */
  @Override
  protected void removeMyselfNoConfirm(final boolean testOnly) {
    final String virshOptions = getVMSVirtualDomainInfo().getVirshOptions();
    for (final Host h : getVMSVirtualDomainInfo().getDefinedOnHosts()) {
      final VMSXML vmsxml = getBrowser().getVMSXML(h);
      if (vmsxml != null) {
        final Map<String, String> parameters = new HashMap<String, String>();
        parameters.put(DiskData.SAVED_TARGET_DEVICE, getName());
        vmsxml.removeDiskXML(getVMSVirtualDomainInfo().getDomainName(), parameters, virshOptions);
      }
    }
    getBrowser().periodicalVMSUpdate(getVMSVirtualDomainInfo().getDefinedOnHosts());
    removeNode();
  }

  /** Returns string representation. */
  @Override
  public String toString() {
    final StringBuilder s = new StringBuilder(30);
    final String name = getName();
    if (name == null) {
      return "new disk...";
    }
    s.append(name);
    s.append(" (");
    final String saved = getParamSaved(DiskData.TARGET_BUS_TYPE);
    if (saved == null) {
      s.append("new...");
    } else if (TARGET_BUS_TYPES.containsKey(saved)) {
      s.append(TARGET_BUS_TYPES.get(saved));
    } else {
      s.append(saved);
    }
    s.append(')');
    return s.toString();
  }

  /** Returns whether this item is removeable (null), or string why it isn't. */
  @Override
  protected String isRemoveable() {
    return null;
  }

  /** Returns "add new" button. */
  static MyButton getNewBtn(final VMSVirtualDomainInfo vdi) {
    final MyButton newBtn = new MyButton("Add Disk");
    newBtn.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(final ActionEvent e) {
            final Thread t =
                new Thread(
                    new Runnable() {
                      @Override
                      public void run() {
                        vdi.addDiskPanel();
                      }
                    });
            t.start();
          }
        });
    return newBtn;
  }

  /** Returns the regexp of the parameter. */
  @Override
  protected String getParamRegexp(final String param) {
    if (FILE_TYPE.equals(getComboBoxValue(DiskData.TYPE)) && DiskData.SOURCE_FILE.equals(param)) {
      return ".*[^/]$";
    }
    return super.getParamRegexp(param);
  }

  /** Additional tool tip. */
  @Override
  protected String additionalToolTip(final String param) {
    final String tt = TOOLTIP_MAP.get(param);
    if (tt == null) {
      return "";
    }
    return tt;
  }
}