/** * 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 "); 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 */ } } }
/** * 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(); } }
/** * 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(); } }
/** * 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; } }
/** * 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; } } }
/** 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; } }