/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.networkcontroller.impl.mds;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.IntRange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.model.FCEndpoint;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.networkcontroller.SSHDialog;
import com.emc.storageos.networkcontroller.SSHPrompt;
import com.emc.storageos.networkcontroller.SSHSession;
import com.emc.storageos.networkcontroller.exceptions.NetworkDeviceControllerException;
import com.emc.storageos.networkcontroller.impl.NetworkDeviceController;
import com.google.common.collect.Sets;
/**
* This file contains all the SSH dialogs to/from the MDS (or Nexus) Cisco switches.
*
* @author Watson
* Generally, methods are named similar to the command(s) they execute.
* For example, showZoneset() issues the command "show zoneset..."
*
* The command strings, and regular expression matching patterns, are externalized to a file
* called networksystem-mds-dialog-properties. In this way should a problem arise in the field,
* it is possible to patch the regular expressions thereby implementing a work-around by simply
* modifying /os/storageos/conf/networksystem-mds-dialog-properties.
*
* Also, for debugging purposes, it is possible to turn on debugging such that every command sent and
* all data received from the device is logged in the controllersvc.log by including the following in your
* controllersvc-log4j.properties file (also in /os/storageos/conf) and restarting:
* log4j.logger.com.emc.storageos.networkcontroller=DEBUG
* (Note this output can be very verbose.)
*
*/
public class MDSDialog extends SSHDialog {
private boolean inConfigMode = false;
private boolean inSession = false;
private SSHPrompt lastPrompt = null;
private static final Logger _log = LoggerFactory.getLogger(MDSDialog.class);
private final String wwnRegex = "([0-9A-Fa-f][0-9A-Fa-f]:){7}[0-9A-Fa-f][0-9A-Fa-f]";
private final static Integer sessionLockRetryMax = 5;
private final static String IVR_ZONENAME_PREFIX = "IVRZ_";
private final static String EXCEPTION_REGEX_KEY = "MDSDialog.exception.regex";
public MDSDialog(SSHSession session, Integer defaultTimeout) {
super(session, defaultTimeout);
}
/**
* This initializes a new session, gathering the prompts, and setting the terminal length.
*
* @throws NetworkDeviceControllerException
*/
public void initialize() throws NetworkDeviceControllerException {
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
SSHPrompt got = waitFor(prompts, defaultTimeout, buf, true);
String[] lines = buf.toString().split("[\n\r]+");
String lastLine = lines[lines.length - 1];
String[] groups = new String[2];
if (match(lastLine, new String[] { MDSDialogProperties.getString("MDSDialog.initalize.match") + got.getRegex() }, groups) == 0) { // \\s*([-_A-Za-z0-9]+)
devname = groups[0];
}
sendWaitFor(MDSDialogProperties.getString("MDSDialog.initialize.termlength.cmd"), 5000, prompts, buf); // terminal length 0\n
_log.info(buf.toString());
}
/**
* Returns the device type and software version
*
* @return [0] device type, [1] software version
*/
public String[] showVersion() throws NetworkDeviceControllerException {
String[] returnVal = new String[2];
SSHPrompt[] prompts = { SSHPrompt.MDS_POUND, SSHPrompt.MDS_GREATER_THAN };
StringBuilder buf = new StringBuilder();
SSHPrompt prompt = sendWaitFor(MDSDialogProperties.getString("MDSDialog.showVersion.cmd"), // show version\n
10000, prompts, buf);
String[] lines = getLines(buf);
String[] regex = {
MDSDialogProperties.getString("MDSDialog.showVersion.version.match"), // .*system:\\s+version +(\\S+).*
MDSDialogProperties.getString("MDSDialog.showVersion.MDS.match"), // .*[Cc][Ii][Ss][Cc][Oo]\\s+(MDS\\s+\\S+).*
MDSDialogProperties.getString("MDSDialog.showVersion.Nexus.match") // *[Cc][Ii][Ss][Cc][Oo]\\s+(Nexus\\S+).*
};
String[] groups = new String[2];
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0: // software version number
returnVal[1] = groups[0];
break;
case 1: // hardware type
returnVal[0] = groups[0]; // MDS
break;
case 2:
returnVal[0] = groups[0]; // Nexus
break;
}
}
return returnVal;
}
/**
* Returns the system uptime.
*
* @return systme uptime
* @throws NetworkDeviceControllerException
*/
public String showSystemUptime() throws NetworkDeviceControllerException {
SSHPrompt[] prompts = { SSHPrompt.MDS_POUND, SSHPrompt.MDS_GREATER_THAN };
StringBuilder buf = new StringBuilder();
String systemUptime = null;
String[] regex = {
MDSDialogProperties.getString("MDSDialog.showSystem.systemUptime.match") // System uptime:\\s+(.*)
};
SSHPrompt prompt = sendWaitFor(MDSDialogProperties.getString("MDSDialog.showSystem.systemUptime.cmd"), // show system uptime\n
10000, prompts, buf);
String[] lines = getLines(buf);
String[] groups = new String[1];
for (String line : lines) {
if (match(line, regex, groups) == 0) {
systemUptime = groups[0];
break;
}
}
return systemUptime;
}
/**
* Generates a set of FCPortConnection entries for the specified vsan id (or all
* Vsans if vsanId is null).
*
* @param vsanId used to qualify command to one vsan
* @return list of FCPortConnections
*/
public List<FCEndpoint> showFcnsDatabase(Integer vsanId) throws NetworkDeviceControllerException {
Map<Integer, String> vsanToWwns = getVsanWwns(vsanId);
List<FCEndpoint> connections = new ArrayList<FCEndpoint>();
SSHPrompt[] prompts = { SSHPrompt.MDS_POUND, SSHPrompt.MDS_GREATER_THAN };
StringBuilder buf = new StringBuilder();
String cmd = MDSDialogProperties.getString("MDSDialog.showFcnsDatabase.cmd"); // show fcns database detail
if (vsanId != null) {
cmd = cmd + MDSDialogProperties.getString("MDSDialog.showFcnsDatabase.vsan.cmd") + vsanId.toString() + "\n"; // \ vsan
}
else {
cmd = cmd + "\n"; //$NON-NLS-1$
}
SSHPrompt prompt = sendWaitFor(cmd, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
String[] regex = {
// "VSAN:(\\d+)\\w+FCID:(.*)",
MDSDialogProperties.getString("MDSDialog.showFcnsDatabase.VSAN.match"), // VSAN:(\\d+)\\s+FCID:(0x[0-9a-fA-F:]+)\\s*
MDSDialogProperties.getString("MDSDialog.showFcnsDatabase.portwwn.match"), // port-wwn[^:]+:([0-9a-fA-F:]+).*
MDSDialogProperties.getString("MDSDialog.showFcnsDatabase.nodewwn.match"), // node-wwn[^:]+:([0-9a-fA-F:]+).*
MDSDialogProperties.getString("MDSDialog.showFcnsDatabase.fabricportwwn.match"), // fabric-port-wwn[^:]+:([0-9a-fA-F:]+).*
MDSDialogProperties.getString("MDSDialog.showFcnsDatabase.ConnectedInterface.match"), // Connected Interface[^:]+:(fc\\S+)
MDSDialogProperties.getString("MDSDialog.showFcnsDatabase.SwitchName.match"), // Switch Name[^:]+:(.*)
MDSDialogProperties.getString("MDSDialog.showFcnsDatabase.deviceAlias.match") // \\s*\\[(\\S+)\\]\\s*:q
};
String[] groups = new String[10];
FCEndpoint conn = null;
for (String line : lines) {
int index = match(line, regex, groups, Pattern.CASE_INSENSITIVE);
switch (index) {
case 0:
conn = new FCEndpoint();
conn.setFabricId(groups[0]); // vsan
conn.setFcid(groups[1]); // fcid
String fabricWwn = vsanToWwns.get(new Integer(groups[0]));
if (fabricWwn != null) {
conn.setFabricWwn(fabricWwn);
}
connections.add(conn);
break;
case 1:
conn.setRemotePortName(groups[0]); // remote wwpn
break;
case 2:
conn.setRemoteNodeName(groups[0]); // remote wwnn
break;
case 3:
conn.setSwitchPortName(groups[0]); // local wwpn
break;
case 4:
conn.setSwitchInterface(groups[0]); // switch interface
break;
case 5:
conn.setSwitchName(groups[0]); // switch name
break;
case 6:
conn.setRemotePortAlias(groups[0]); // pwwn alias
}
}
return connections;
}
/**
* Issues the "show interface" command and collects in information into a list of
* interfaces. For now only parses fiber channel interfaces starting with "fc",
* e.g. fc1/1, fc2/20, ...
* This method is not currently used.
*
* @return List<Interface>
*/
public List<Interface> showInterface() throws NetworkDeviceControllerException {
List<Interface> interfaces = new ArrayList<Interface>();
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
SSHPrompt prompt = sendWaitFor(MDSDialogProperties.getString("MDSDialog.showInterface.cmd"), // show interface\n
60000, prompts, buf);
String[] lines = getLines(buf);
String[] regex = {
MDSDialogProperties.getString("MDSDialog.showInterface.interfacename.match"), // (fc\\d+/\\d+) is (\\S+).*
MDSDialogProperties.getString("MDSDialog.showInterface.Portdescription.match"), // \\s+Port description is (.*)
MDSDialogProperties.getString("MDSDialog.showInterface.PortWWN.match"), // \\s+Port WWN is ([0-9a-fA-F:]+)\\s*
MDSDialogProperties.getString("MDSDialog.showInterface.PortmodeFCID.match"), // \\s+Port mode is (\\w*), FCID is
// (0x\\p{XDigit}+)\\s*
MDSDialogProperties.getString("MDSDialog.showInterface.Portvsan.match"), // \\s+Port vsan is (\\d+)\\s*
MDSDialogProperties.getString("MDSDialog.showInterface.Portmode.match"), // \\s+Port mode is (\\w*)\\s*
};
String[] groups = new String[10];
Interface intf = null;
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
intf = new Interface(groups[0]); // save name
intf.setStatus(groups[1]);
interfaces.add(intf);
break;
case 1:
intf.setDescription(groups[0]);
break;
case 2:
intf.setWwpn(groups[0]);
break;
case 3:
intf.setMode(groups[0]);
intf.setFcid(groups[1]);
break;
case 4:
intf.setVsan(groups[0]);
break;
case 5:
intf.setMode(groups[0]);
break;
}
}
return interfaces;
}
/**
* Shows the FLOGI database, which are the local logins to this switch.
* This method is not currently used.
*
* @throws NetworkDeviceControllerException
*/
public void showFlogiDatabase() throws NetworkDeviceControllerException {
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
SSHPrompt prompt = sendWaitFor(MDSDialogProperties.getString("MDSDialog.showFlogiDatabase.cmd"), 60000, prompts, buf); // show flogi
// database\n
String[] lines = getLines(buf);
boolean sawHdr = false;
String[] regex = {
MDSDialogProperties.getString("MDSDialog.showFlogiDatabase.INTERFACEVSANFCID.match"), // INTERFACE\\s+VSAN\\s+FCID\\s+PORT
// NAME\\s+NODE NAME\\s*
MDSDialogProperties.getString("MDSDialog.showFlogiDatabase.interfacename.match"), // (fc\\S+)\\s+(\\d+)\\s+(\\S+)\\s+([0-9a-fA-F:]+)\\s+([0-9a-fA-F:]+)\\s*
MDSDialogProperties.getString("MDSDialog.showFlogiDatabase.Totalflogi.match") // Total number of flogi.*
};
String[] groups = new String[10];
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
sawHdr = true;
break;
case 1:
_log.info(groups[0] + " " + groups[1] + " " + groups[2] + " " + groups[3] + " " + groups[4]);
break;
case 2:
sawHdr = false;
break;
}
}
}
/**
* Returns a map from Vsan ID to the fabric WWN as determined by the principal switch.
* Note this value is not immutable; if a new principal switch is elected, then the mapping
* will change.
*
* @param vsanId If non null, only returns result for specificed Vsan. If null, all Vsans.
* @return Map keyed by Vsan ID to WWN of Fabric
* @throws NetworkDeviceControllerException
*/
public Map<Integer, String> getVsanWwns(Integer vsanId) throws NetworkDeviceControllerException {
Map<Integer, String> vsanToWwns = new HashMap<Integer, String>();
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
String cmd = MDSDialogProperties.getString("MDSDialog.getVsanWwns.showfcdomain.cmd"); // show fcdomain
if (vsanId != null) {
cmd = cmd + MDSDialogProperties.getString("MDSDialog.getVsanWwns.vsan.cmd") // \ vsan
+ vsanId.toString() + "\n";
} else {
cmd = cmd + "\n";
}
sendWaitFor(cmd, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
String[] regex = {
MDSDialogProperties.getString("MDSDialog.getVsanWwns.VSAN.match"), // \\s*VSAN\\s+(\\d+).*
MDSDialogProperties.getString("MDSDialog.getVsanWwns.Runningfabricname.match") // .*Running fabric name:\\s+(
+ wwnRegex + MDSDialogProperties.getString("MDSDialog.getVsanWwns.Runningfabricname2.match") // ).*
};
String[] groups = new String[10];
Integer vsan = null;
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0: // "\\s*VSAN\\s+(\\d+).*"
vsan = new Integer(groups[0]);
break;
case 1: // ".*Running fabric name:\\s+(" + wwnRegex + ").*"
String wwn = groups[0];
if (vsan != null) {
vsanToWwns.put(vsan, wwn);
vsan = null;
} else if (vsanId != null) { // "show fcdomain vsan 3180" has different format output
vsanToWwns.put(vsanId, wwn);
}
}
}
return vsanToWwns;
}
/**
* Collect the active Zoneset, and its Zones, members for a specified Vsan ID.
*
* @param vsanId -- Integer vsanId
* @return active zoneset for given vsanId
*/
public Zoneset showActiveZoneset(Integer vsanId) throws NetworkDeviceControllerException {
List<Zoneset> zonesets = showZoneset(vsanId, true, null, false, false);
return zonesets.isEmpty() ? null : zonesets.get(0);
}
/**
* Collect the Zonesets, and their Zones, members for a specified Vsan ID.
*
* @param vsanId -- Integer vsanId
* @param activeZonesetOnly - only return active zoneset. Otherwise, return all zonesets
* @param zoneName - only returns zone with given zoneName. Return all zones, if not specified.
* @param excludeMembers - true, do not include member with zone. Include members, if not specified.
* @param excludeAliases - true, do not include aliases with zone. Include aliases, if not specified.
* @return List<Zoneset> zonesets within that fabric. If zoneName is specified, and there is a match, then only one zone is returned.
*/
public List<Zoneset> showZoneset(Integer vsanId, boolean activeZonesetOnly, String zoneName, boolean excludeMembers,
boolean excludeAliases) throws NetworkDeviceControllerException {
List<Zoneset> zonesets = new ArrayList<Zoneset>();
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
String zonesetCommand = MDSDialogProperties.getString("MDSDialog.showZoneset.cmd");
sendWaitFor(zonesetCommand // show zoneset vsan
+ vsanId.toString() + "\n", defaultTimeout, prompts, buf);
if (buf.toString().indexOf(MDSDialogProperties.getString("MDSDialog.showZoneset.not.configured")) >= 0) {
throw NetworkDeviceControllerException.exceptions.fabricNotFoundInNetwork(vsanId.toString(), "");
}
String[] lines = getLines(buf);
Zoneset zoneset = null;
Zone zone = null;
ZoneMember member = null;
String[] regex = {
MDSDialogProperties.getString("MDSDialog.showZoneset.zonesetname.match"), // \\s*zoneset name ([-\\w]+) vsan (\\d+).*
MDSDialogProperties.getString("MDSDialog.showZoneset.zonename.match"), // \\s*zone name ([-\\w]+) vsan (\\d+).*
MDSDialogProperties.getString("MDSDialog.showZoneset.pwwn.match"), // \\s*pwwn ([0-9a-fA-F:]+)\\s*(\\[\\S+\\])?\\s*(\\w*)
// ex: pwwn 11:11:12:12:13:13:14:14 [alias] init|target
MDSDialogProperties.getString("MDSDialog.showZoneset.deviceAlias.match") // \\s*device-alias \\s*(\\S+)\\s*
};
String[] groups = new String[10];
Map<String, String> aliasDatabase = showDeviceAliasDatabase();
String filterCriteria = null;
if (!StringUtils.isEmpty(zoneName) && zoneName.startsWith(NetworkDeviceController.ZONESET_QUERY_FILTER)) {
filterCriteria = zoneName.substring(NetworkDeviceController.ZONESET_QUERY_FILTER.length());
}
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
zoneset = new Zoneset(groups[0]);
if (!vsanId.toString().equals(groups[1])) {
String message = "VSAN " + vsanId.toString() + " not the expected VSAN " + groups[1];
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedDeviceState(message);
}
zonesets.add(zoneset);
break;
case 1:
// if zoneName is not specified, we want all zones in zoneset.
// Or, if it zoneName is specified, then only return zone matched the name.
// Or, if there was a filter specified, check the name for that. Otherwise, ignore it.
if (StringUtils.isEmpty(zoneName) || StringUtils.equals(groups[0], zoneName)
|| (!StringUtils.isEmpty(filterCriteria) && groups[0].contains(filterCriteria))) {
zone = new Zone(groups[0]);
zoneset.getZones().add(zone);
} else {
zone = null; //
}
break;
case 2:
case 3:
// if zone is to be ignored, or members are excluded, break out
if (zone == null || excludeMembers) {
break;
}
member = new ZoneMember(ZoneMember.ConnectivityMemberType.WWPN);
zone.getMembers().add(member);
if (excludeAliases) {
_log.info("Excluding aliases while getting zone members");
}
if (index == 2) {
member.setAddress(groups[0]); // set wwn id
// matched "pwwn <wwnid> [alias]" regex, thus
// set alias field as well
if (!excludeAliases && groups.length >= 2 && groups[1] != null) {
member.setAlias(groups[1].replace("[", "").replace("]", ""));
}
} else if (index == 3) {
// matched "device-alias <alias>
if (!excludeAliases) {
member.setAlias(groups[0]); // set alias
member.setAliasType(true); // indicate member type of alias
}
String pwwn = getDeviceAliasPwwn(groups[0], aliasDatabase);
if (!StringUtils.isEmpty(pwwn)) {
member.setAddress(pwwn);
}
}
break;
}
}
if (zonesets.isEmpty()) {
return zonesets;
}
// Now find the active zoneset
sendWaitFor(MDSDialogProperties.getString("MDSDialog.showZoneset.showzonesetactivevsan.cmd") // show zoneset active vsan
+ vsanId.toString() + "\n", defaultTimeout, prompts, buf);
lines = getLines(buf);
String[] regex2 = {
MDSDialogProperties.getString("MDSDialog.showZoneset.zonesetname2.match"), // \\s*zoneset name ([-\\w]+) vsan (\\d+).*
MDSDialogProperties.getString("MDSDialog.showZoneset.zonename2.match") // \\s*zone name ([-\\w]+) vsan (\\d+).*
};
Zoneset activeZoneset = null;
for (String line : lines) {
int index = match(line, regex2, groups);
switch (index) {
case 0: // found the active one
String activeName = groups[0];
for (Zoneset zs : zonesets) {
if (zs.getName().equals(activeName)) {
activeZoneset = zs;
zs.setActive(true);
} else {
zs.setActive(false);
}
}
break;
case 1:
if (zoneset != null) { // if there is an active zoneset
for (Zone zo : activeZoneset.getZones()) {
if (zo.getName().equals(groups[0])) {
zo.setActive(true);
}
}
}
}
}
// if only want active zone set, return only active one if found
if (activeZonesetOnly) {
zonesets.clear();
if (activeZoneset != null) {
zonesets.add(activeZoneset);
}
}
return zonesets;
}
/**
* Collect the Zonesets, and their Zones, members for a specified Vsan ID.
*
* @param vsanId -- Integer vsanId
* @return a list of Zones
*/
public List<Zone> showFabricZones(Integer vsanId) throws NetworkDeviceControllerException {
List<Zone> zones = new ArrayList<Zone>();
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
sendWaitFor(MDSDialogProperties.getString("MDSDialog.showFabricZones.cmd")
+ vsanId.toString() + "\n", defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
Zone zone = null;
String[] regex = {
MDSDialogProperties.getString("MDSDialog.showZoneset.zonename.match"),
MDSDialogProperties.getString("MDSDialog.showZoneset.pwwn.match"),
MDSDialogProperties.getString("MDSDialog.showZoneset.deviceAlias.match")
};
Map<String, String> aliasDatabase = showDeviceAliasDatabase();
String[] groups = new String[10];
for (String line : lines) {
ZoneMember member = null;
int index = match(line, regex, groups);
switch (index) {
case 0:
if (!vsanId.toString().equals(groups[1])) {
String message = "VSAN " + vsanId.toString() + " not the expected VSAN " + groups[1];
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedDeviceState(message);
}
zone = new Zone(groups[0]);
zones.add(zone);
break;
case 1:
case 2:
member = new ZoneMember(ZoneMember.ConnectivityMemberType.WWPN);
zone.getMembers().add(member);
if (index == 1) {
member.setAddress(groups[0]);
// matched "pwwn <wwnid> [alias]" regex, thus
// set alias field as well
if (groups.length >= 2 && groups[1] != null) {
member.setAlias(groups[1].replace("[", "").replace("]", ""));
}
} else if (index == 2) {
// match "device-alas <alias>" regex
member.setAlias(groups[0]); // device alias
member.setAliasType(true);// indicate member is an alias type
String pwwn = getDeviceAliasPwwn(groups[0], aliasDatabase);
if (!StringUtils.isEmpty(pwwn)) {
member.setAddress(pwwn);
}
}
break;
}
}
return zones;
}
/**
* Get corresponded pwwn for the given device alias
*
* @param deviceAlias
* @param aliasDatabase - device alias database. If null, get it from switch
* @return pwwn
*/
public String getDeviceAliasPwwn(String deviceAlias, Map<String, String> aliasDatabase) {
Map<String, String> myAliasDatabase = aliasDatabase;
if (myAliasDatabase == null) {
myAliasDatabase = showDeviceAliasDatabase();
}
return StringUtils.isEmpty(deviceAlias) ? null : myAliasDatabase.get(deviceAlias);
}
/**
* Query device aliases via "show device-alias database" cli
*
* @return
* @throws NetworkDeviceControllerException
*/
public Map<String, String> showDeviceAliasDatabase() throws NetworkDeviceControllerException {
return showDeviceAliasDatabase(false);
}
/**
* Query device aliases via "show device-alias database" cli, and include pending change if <code>includePending</code> is specified
*
* @param includePending true to include pending change
* @return
* @throws NetworkDeviceControllerException
*/
public Map<String, String> showDeviceAliasDatabase(boolean includePending) throws NetworkDeviceControllerException {
String[] regex = {
MDSDialogProperties.getString("MDSDialog.deviceAliasName.match") // device-alias name \\s(\\S+)\\s*pwwn \\s*(\\S+)\\s*
};
Map<String, String> deviceAliasMap = new HashMap<String, String>();
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
sendWaitFor(MDSDialogProperties.getString("MDSDialog.showDeviceAlias.cmd"), defaultTimeout, prompts, buf); // show device-alias
// database\n
// get pending database as well
if (includePending) {
StringBuilder buf2 = new StringBuilder();
sendWaitFor(MDSDialogProperties.getString("MDSDialog.showDeviceAlias.pending.cmd"), defaultTimeout, prompts, buf2); // show
// device-alias
// pending\n
buf.append(buf2.toString());
}
String[] groups = new String[10];
String[] lines = getLines(buf);
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
// Save the device alias
String deviceAlias = groups[0];
String pwwn = groups[1];
if (deviceAlias != null) {
deviceAliasMap.put(deviceAlias, pwwn);
}
deviceAlias = null;
break;
}
}
return deviceAliasMap;
}
/**
* Returns a map of vsan id to Vsan object using "show vsans" and
* calling show zonesets and show zones.
*
* @param includeZonesets If true, the Vsan structures include zonesets and their descendents.
* @return a Map of Vsan ID to Vsan structure
*/
public Map<Integer, Vsan> showVsan(boolean includeZonesets) throws NetworkDeviceControllerException {
Map<Integer, Vsan> vsans = new HashMap<Integer, Vsan>();
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
sendWaitFor(MDSDialogProperties.getString("MDSDialog.showVsan.cmd"), defaultTimeout, prompts, buf); // show vsan\n
String[] lines = getLines(buf);
Vsan vsan = null;
Integer vsanId = null;
String[] regex = {
MDSDialogProperties.getString("MDSDialog.showVsan.vsan.match"), // vsan\\s+(\\d+).*
MDSDialogProperties.getString("MDSDialog.showVsan.namestate.match") // \\s+name:\\s*(\\w+|\\w[\\w\\s]*\\w)\\s+state:(\\w+).*
};
String[] groups = new String[10];
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
// Save the vsan id.
vsanId = new Integer(groups[0]);
break;
case 1:
String vsanName = groups[0];
vsan = new Vsan(vsanId.toString(), vsanName);
vsans.put(vsanId, vsan);
if (includeZonesets) {
List<Zoneset> zonesets = showZoneset(vsanId, false, null, false, false);
for (Zoneset zs : zonesets) {
if (zs.getActive()) {
vsan.setActiveZoneset(zs);
} else {
vsan.getInactiveZonesets().add(zs);
}
}
}
vsanId = null;
break;
}
}
return vsans;
}
/**
* Put in terminal config mode.
*/
public void config() throws NetworkDeviceControllerException {
if (inConfigMode == true) {
return;
}
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG };
StringBuilder buf = new StringBuilder();
lastPrompt = sendWaitFor(MDSDialogProperties.getString("MDSDialog.config.configterminal.cmd"), defaultTimeout, prompts, buf); // config
// terminal\n
if (lastPrompt != SSHPrompt.MDS_CONFIG) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG.toString());
}
inConfigMode = true;
}
/**
* Put in terminal device alias database mode
*/
public void deviceAliasConfig() throws NetworkDeviceControllerException {
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG_DEVICE_ALIAS };
StringBuilder buf = new StringBuilder();
lastPrompt = sendWaitFor(MDSDialogProperties.getString("MDSDialog.config.deviceAlias.cmd"), defaultTimeout, prompts, buf); // config
// terminal\n
if (lastPrompt != SSHPrompt.MDS_CONFIG_DEVICE_ALIAS) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG_DEVICE_ALIAS.toString());
}
}
/**
* commit device alias configuration
*
* @throws NetworkDeviceControllerException
*/
public void deviceAliasCommit() throws NetworkDeviceControllerException {
if (lastPrompt != SSHPrompt.MDS_CONFIG_DEVICE_ALIAS) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG_DEVICE_ALIAS.toString());
}
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG };
StringBuilder buf = new StringBuilder();
String payload = MDSDialogProperties.getString("MDSDialog.config.deviceAlias.commit.cmd"); // device-alias commit
boolean retryNeeded = true;
for (int retryCount = 0; retryCount < sessionLockRetryMax && retryNeeded; retryCount++) {
retryNeeded = false;
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
String waitReason = "";
for (String line : lines) {
// retry again if device alias database is locked or busy
if (line.indexOf(MDSDialogProperties.getString("MDSDialog.deviceAlias.busy")) >= 0 ||
line.indexOf(MDSDialogProperties.getString("MDSDialog.deviceAlias.locked")) >= 0) {
retryNeeded = true;
waitReason = line;
break;
}
}
// if retry needed, sleep for a bit (defaultTimeout), and retry again
if (retryNeeded) {
if (retryCount + 1 >= sessionLockRetryMax) {
// exceed retry, throw exception
_log.error("Devias alias database is busy or locked, gave up after " + sessionLockRetryMax + " retries!");
throw NetworkDeviceControllerException.exceptions.deviceAliasDatabaseLockedOrBusy(retryCount + 1);
} else {
_log.info("Lock/Busy msg: " + waitReason);
_log.info("Devias alias database is busy or locked, will retry after " + defaultTimeout / 1000 + " seconds...");
try {
Thread.sleep(defaultTimeout);
} catch (InterruptedException ex) {
_log.warn(ex.getLocalizedMessage());
}
}
}
}
}
/**
* abort device alias configuration
*
* @throws NetworkDeviceControllerException
*/
public void deviceAliasAbort() throws NetworkDeviceControllerException {
if (lastPrompt != SSHPrompt.MDS_CONFIG_DEVICE_ALIAS && lastPrompt != SSHPrompt.MDS_CONFIG) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG.toString());
}
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG };
StringBuilder buf = new StringBuilder();
String payload = MDSDialogProperties.getString("MDSDialog.config.deviceAlias.abort.cmd"); // device-alias abort
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
}
/**
* Configure a device alias
*
* @param alias
* @param pwwn wwn maps to given alias
* @param remove delete alias if true, other create the alias
* @throws NetworkDeviceControllerException
*/
public void deviceAliasName(String alias, String pwwn, boolean remove) throws NetworkDeviceControllerException {
if (lastPrompt != SSHPrompt.MDS_CONFIG_DEVICE_ALIAS) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG_DEVICE_ALIAS.toString());
}
String invalidCommand = MDSDialogProperties.getString("MDSDialog.invalidCommand");
String illegalName = MDSDialogProperties.getString("MDSDialog.deviceAlias.illegal.name");
String notPresent = MDSDialogProperties.getString("MDSDialog.not.present");
String alreadyPresent = MDSDialogProperties.getString("MDSDialog.already.present");
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG_DEVICE_ALIAS };
StringBuilder buf = new StringBuilder();
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.config.deviceAliasName.cmd"), alias, pwwn);
if (remove) {
payload = MDSDialogProperties.getString("MDSDialog.zoneNameVsan.no.cmd") + " " + payload;
}
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
for (String line : lines) {
// throw exception only when trying to get into config mode, but not found
if (line.indexOf(invalidCommand) >= 0 ||
((!remove && line.indexOf(illegalName) >= 0) ||
line.indexOf(notPresent) >= 0 ||
line.indexOf(alreadyPresent) >= 0)) {
throw new NetworkDeviceControllerException(line + ": " + alias);
}
}
}
/**
* Rename the current alias to new alias
*
* @param currentAlias
* @param newAlias
* @throws NetworkDeviceControllerException
*/
public void deviceAliasRename(String currentAlias, String newAlias) throws NetworkDeviceControllerException {
if (lastPrompt != SSHPrompt.MDS_CONFIG_DEVICE_ALIAS) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG_DEVICE_ALIAS.toString());
}
String invalidCommand = MDSDialogProperties.getString("MDSDialog.invalidCommand");
String illegalName = MDSDialogProperties.getString("MDSDialog.deviceAlias.illegal.name");
String notPresent = MDSDialogProperties.getString("MDSDialog.not.present");
String alreadyPresent = MDSDialogProperties.getString("MDSDialog.already.present");
String alreadyInUse = MDSDialogProperties.getString("MDSDialog.already.in.use");
String notExists = MDSDialogProperties.getString("MDSDialog.not.existing");
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG_DEVICE_ALIAS };
StringBuilder buf = new StringBuilder();
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.config.deviceAliasRename.cmd"), currentAlias,
newAlias);
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
for (String line : lines) {
// throw exception only when trying to get into config mode, but not found
if (line.indexOf(invalidCommand) >= 0 ||
line.indexOf(illegalName) >= 0 ||
line.indexOf(notPresent) >= 0 ||
line.indexOf(alreadyInUse) >= 0 ||
line.indexOf(notExists) >= 0 ||
line.indexOf(alreadyPresent) >= 0) {
throw new NetworkDeviceControllerException(line + " - " + "Failed to rename alias: " + currentAlias + " / " + newAlias);
}
}
}
/**
* End config mode.
*/
public void endConfig() throws NetworkDeviceControllerException {
if (inConfigMode == false) {
return;
}
SSHPrompt[] prompts = { SSHPrompt.MDS_POUND, SSHPrompt.MDS_GREATER_THAN };
StringBuilder buf = new StringBuilder();
lastPrompt = sendWaitFor(MDSDialogProperties.getString("MDSDialog.endConfig.end.cmd"), defaultTimeout, prompts, buf); // end\n
inConfigMode = false;
}
/**
* Exits from an inner config mode to config mode.
*/
public void exitToConfig() throws NetworkDeviceControllerException {
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG };
StringBuilder buf = new StringBuilder();
lastPrompt = sendWaitFor(MDSDialogProperties.getString("MDSDialog.exitToConfig.exit.cmd"), defaultTimeout, prompts, buf); // exit\n
}
// /**
// * Returns a boolean indicating if enhanced zoning is enabled.
// * @param vsanId
// * @return
// * @throws NetworkControllerException
// */
// public boolean isEnhancedZoningEnabled(Integer vsanId) throws NetworkControllerException {
// assert(inConfigMode == false);
// SSHPrompt[] prompts = { SSHPrompt.MDS_POUND };
// StringBuilder buf = new StringBuilder();
// String payload = MessageFormat.format("show zone status vsan {0}\n", vsanId.toString());
// lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
// String[] lines = getLines(buf);
// String[] regex = {
// "\\s*mode:\\s+(\\w+).*"
// };
// String[] groups = new String[10];
// boolean enhanced = false;
// for (String line : lines) {
// int index = match(line, regex, groups);
// switch(index) {
// case 0:
// if (groups[0].equals("enhanced")) {
// enhanced = true;
// }
// }
// }
// return enhanced;
// }
/**
* Returns a boolean indicating if enhanced zoning is enabled.
* Also logs a message if enhanced zoning is not enabled.
*
* @param vsanId
* @return
* @throws NetworkDeviceControllerException
*/
public boolean isSessionInProgress(Integer vsanId) throws NetworkDeviceControllerException {
if (inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceInConfigMode();
}
SSHPrompt[] prompts = { SSHPrompt.MDS_POUND };
StringBuilder buf = new StringBuilder();
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.isSessionInProgress.showzonestatus.cmd"),
vsanId.toString()); // show zone status vsan {0}\n
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
String[] regex = {
MDSDialogProperties.getString("MDSDialog.isSessionInProgress.session.match"), // \\s*session:\\s+(\\w+).*
MDSDialogProperties.getString("MDSDialog.isSessionInProgress.mode.match") // \\s*mode:\\s+(\\w+).*
};
String[] groups = new String[10];
boolean session = false;
boolean enhanced = false;
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
if (false == groups[0].equals(MDSDialogProperties.getString("MDSDialog.isSessionInProgress.none"))) { // none
session = true;
}
case 1:
if (groups[0].equals(MDSDialogProperties.getString("MDSDialog.isSessionInProgress.enhanced"))) { // enhanced
enhanced = true;
}
}
}
if (!enhanced) {
_log.warn("Enhanced zoning not enabled: " + vsanId);
}
return session;
}
/**
* Scans the lines looking for evidence that an Enhanced zone session was created.
*
* @param lines String[]
* @param retryCount indicates how many retries have already been tried
* @return true if a retry is needed because the lock is busy
*
*/
private boolean checkForZoneSession(String[] lines, Integer retryCount, boolean forIvr)
throws NetworkDeviceControllerException {
String busyKey = "MDSDialog.checkForEnhancedZoneSession.busy";
String createdKey = "MDSDialog.checkForEnhancedZoneSession.created";
String pendingKey = "MDSDialog.checkForEnhancedZoneSession.pending";
if (forIvr) {
busyKey = "MDSDialog.ivr.checkForEnhancedZoneSession.busy";
createdKey = "MDSDialog.ivr.checkForEnhancedZoneSession.created";
pendingKey = "MDSDialog.ivr.checkForEnhancedZoneSession.pending";
}
for (String s : lines) {
_log.debug("line : {}", s);
if (s.startsWith(MDSDialogProperties.getString(createdKey))) { // Enhanced zone session has been created
inSession = true;
return false;
}
if (s.startsWith(MDSDialogProperties.getString(busyKey))) { // Lock is currently busy
if ((retryCount + 1) < sessionLockRetryMax) {
_log.info("Zone session lock is busy, will retry after " + defaultTimeout / 1000 + " seconds...");
try {
Thread.sleep(defaultTimeout);
} catch (InterruptedException ex) {
_log.warn(ex.getLocalizedMessage());
}
return true;
}
_log.error("Zone session lock is busy, gave up after " + sessionLockRetryMax + " retries!");
throw NetworkDeviceControllerException.exceptions.zoneSessionLocked(retryCount + 1);
}
if (s.contains(MDSDialogProperties.getString(pendingKey))) {
if ((retryCount + 1) < sessionLockRetryMax) {
_log.info("There is a pending session, will retry after " + defaultTimeout / 1000 + " seconds...");
try {
Thread.sleep(defaultTimeout);
} catch (InterruptedException ex) {
_log.warn(ex.getLocalizedMessage());
}
return true;
}
_log.error("There is a pending session still, gave up after " + sessionLockRetryMax + " retries!");
throw NetworkDeviceControllerException.exceptions.timeoutWaitingOnPendingActions();
}
}
return false;
}
/**
* Scans the lines looking for evidence that an Enhanced zone session was created.
*
* @param lines String[]
* @param retryCount indicates how many retries have already been tried
* @return true if a retry is needed because the lock is busy
*/
private boolean checkForEnhancedZoneSession(String[] lines, Integer retryCount)
throws NetworkDeviceControllerException {
return checkForZoneSession(lines, retryCount, false);
}
/**
* Scans the lines looking for evidence that ivr zone in session
*
* @param lines String[]
* @param retryCount indicates how many retries have already been tried
* @return true if a retry is needed because the lock is busy
*/
private boolean checkForIvrZoneSession(String[] lines, Integer retryCount)
throws NetworkDeviceControllerException {
return checkForZoneSession(lines, retryCount, true);
}
/**
* zone name {zoneName} vsan {vsanId}
* no zone name {zoneName} vsan {vsanId}
*
* @param zoneName
* @param vsanId
* @param no -- makes no version of command
* @throws NetworkDeviceControllerException
*/
public void zoneNameVsan(String zoneName, Integer vsanId, boolean no) throws NetworkDeviceControllerException {
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (lastPrompt != SSHPrompt.MDS_CONFIG) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG.toString());
}
String noString = no ? MDSDialogProperties.getString("MDSDialog.zoneNameVsan.no.cmd") : ""; // no
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG_ZONE, SSHPrompt.MDS_CONFIG };
SSHPrompt[] noPrompts = { SSHPrompt.MDS_CONFIG };
StringBuilder buf = new StringBuilder();
boolean retryNeeded = true;
for (int retryCount = 0; retryCount < sessionLockRetryMax && retryNeeded; retryCount++) {
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.zoneNameVsan.cmd"), zoneName, vsanId.toString(),
noString); // {2}zone name {0} vsan {1}\n
lastPrompt = sendWaitFor(payload, defaultTimeout, (no ? noPrompts : prompts), buf);
String[] lines = getLines(buf);
retryNeeded = checkForEnhancedZoneSession(lines, retryCount);
}
if ((no == false) && (lastPrompt != SSHPrompt.MDS_CONFIG_ZONE)) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG_ZONE.toString());
}
}
/**
* member pwwn {pwwn}
*
* @param pwwn
* @throws NetworkDeviceControllerException
*/
public void zoneMemberPwwn(String pwwn) throws NetworkDeviceControllerException {
zoneMemberPwwn(pwwn, false); // add zone
}
/**
* member pwwn {pwwn}
*
* @param pwwn
* @param remove - delete member pwwn from zone
* @throws NetworkDeviceControllerException
*/
public void zoneMemberPwwn(String pwwn, boolean remove) throws NetworkDeviceControllerException {
zoneAddRemoveMember(pwwn, false, remove);
}
/**
* member alias {alias}
*
* @param alias
* @throws NetworkDeviceControllerException
*/
public void zoneMemberAlias(String alias) throws NetworkDeviceControllerException {
zoneAddRemoveMember(alias, true, false);
}
/**
* member alias {alias}
*
* @param alias
* @param remove delete member alias from zone
* @throws NetworkDeviceControllerException
*/
public void zoneMemberAlias(String alias, boolean remove) throws NetworkDeviceControllerException {
zoneAddRemoveMember(alias, true, remove);
}
/**
* Add zone "member device-alias {alias}" if useAlias is set to true, other
* uses "member pwwn {pwwn}"
*
* @param address
* @param useAlias
* @throws NetworkDeviceControllerException
*/
private void zoneAddRemoveMember(String address, boolean useAlias, boolean remove) throws NetworkDeviceControllerException {
String mdsCommand = "";
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (lastPrompt != SSHPrompt.MDS_CONFIG_ZONE) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG_ZONE.toString());
}
if (useAlias) { // add memeber via device-alias
mdsCommand = MDSDialogProperties.getString("MDSDialog.zoneMemberAlias.cmd");
} else { // add member via pwwn
if (!address.matches(wwnRegex)) {
String message = "port wwn " + address + " is not formatted correctly";
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedDeviceState(message);
}
mdsCommand = MDSDialogProperties.getString("MDSDialog.zoneMemberPwwn.cmd");
}
if (remove) {
mdsCommand = MDSDialogProperties.getString("MDSDialog.zonesetActivate.no.cmd") + " " + mdsCommand;
}
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG_ZONE };
StringBuilder buf = new StringBuilder();
boolean retryNeeded = true;
for (int retryCount = 0; retryCount < sessionLockRetryMax && retryNeeded; retryCount++) {
String payload = MessageFormat.format(mdsCommand, address); // =member pwwn {0}\n
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
for (String line : lines) {
// add mode - throw exception if alias is not found
if (!remove) {
if (line.indexOf(MDSDialogProperties.getString("MDSDialog.not.present")) >= 0) {
throw new NetworkDeviceControllerException(line + ": " + address);
}
}
}
retryNeeded = checkForEnhancedZoneSession(lines, retryCount);
}
}
/**
* (no) zoneset name {zonesetName} vsan {vsanId}
*
* @param zonesetName
* @param vsanId
* @param no - true for removing zoneset, false otherwise
* @throws NetworkDeviceControllerException
*/
public void zonesetNameVsan(String zonesetName, Integer vsanId, boolean no) throws NetworkDeviceControllerException {
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (lastPrompt != SSHPrompt.MDS_CONFIG) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG.toString());
}
String noString = no ? MDSDialogProperties.getString("MDSDialog.zonesetNameVsan.no.cmd") : ""; // no
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG_ZONESET, SSHPrompt.MDS_CONFIG };
StringBuilder buf = new StringBuilder();
boolean retryNeeded = true;
for (int retryCount = 0; retryCount < sessionLockRetryMax && retryNeeded; retryCount++) {
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.zonesetNameVsan.cmd"), zonesetName,
vsanId.toString(), noString); // zoneset name {0} vsan {1}\n
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
retryNeeded = checkForEnhancedZoneSession(lines, retryCount);
}
if (no == false && lastPrompt != SSHPrompt.MDS_CONFIG_ZONESET) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG_ZONESET.toString());
}
}
/**
* Makes a zoneset member.
* member {zoneName}
*
* @param zoneName
* @throws NetworkDeviceControllerException
*/
public void zonesetMember(String zoneName, boolean no) throws NetworkDeviceControllerException {
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (lastPrompt != SSHPrompt.MDS_CONFIG_ZONESET) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG_ZONESET.toString());
}
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG_ZONESET };
String noString = no ? MDSDialogProperties.getString("MDSDialog.zonesetMember.no.cmd") : ""; // no
StringBuilder buf = new StringBuilder();
boolean retryNeeded = true;
for (int retryCount = 0; retryCount < sessionLockRetryMax && retryNeeded; retryCount++) {
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.zonesetMember.member.cmd"), zoneName, noString); // member
// {0}\n
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
retryNeeded = checkForEnhancedZoneSession(lines, retryCount);
}
}
/**
* zoneset activate name {zonesetName} vsan {vsanId}
* no zoneset activate name {zonesetName} vsan {vsanId}
*
* @param zonesetName
* @param vsanId
* @param no (boolean) if true, issues "no" form of this command
* @throws NetworkDeviceControllerException
*/
public void zonesetActivate(String zonesetName, Integer vsanId, boolean no) throws NetworkDeviceControllerException {
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (lastPrompt != SSHPrompt.MDS_CONFIG) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG.toString());
}
String noString = no ? MDSDialogProperties.getString("MDSDialog.zonesetActivate.no.cmd") : ""; // no
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG, SSHPrompt.MDS_CONTINUE_QUERY };
StringBuilder buf = new StringBuilder();
boolean retryNeeded = true;
for (int retryCount = 0; retryCount < sessionLockRetryMax && retryNeeded; retryCount++) {
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.zonesetActivate.cmd"), zonesetName,
vsanId.toString(), noString); // {2}zoneset activate name {0} vsan {1}\n
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
// error, throw exception. Otherwise check for enhance zone session
if (buf.toString().indexOf(MDSDialogProperties.getString("MDSDialog.zonesetActivate.no.zone.members")) >= 0) {
throw new NetworkDeviceControllerException("Activate zoneset/vsan: " + zonesetName + "/" + vsanId
+ " failed. One or more zone do not have members");
} else {
// check for user input
if (lastPrompt == SSHPrompt.MDS_CONTINUE_QUERY) {
payload = MDSDialogProperties.getString("MDSDialog.zonesetActivate.continue.y.cmd"); // y\n
SSHPrompt[] prompts2 = { SSHPrompt.MDS_CONFIG };
buf = new StringBuilder();
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts2, buf);
}
String[] lines = getLines(buf);
retryNeeded = checkForEnhancedZoneSession(lines, retryCount);
}
}
}
/**
* zone commit vsan {vsanId}
* (commits the session)
*
* @param vsanId
* @throws NetworkDeviceControllerException
*/
public void zoneCommit(Integer vsanId) throws NetworkDeviceControllerException {
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (lastPrompt != SSHPrompt.MDS_CONFIG) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG.toString());
}
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG };
StringBuilder buf = new StringBuilder();
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.zoneCommit.zonecommitvsan.cmd"), vsanId.toString()); // zone
// commit
// vsan
// {0}\n
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
inSession = false;
}
/**
* no zone commit vsan {vsanId}
* (aborts the session commit)
*
* @param vsanId
* @throws NetworkDeviceControllerException
*/
public void noZoneCommit(Integer vsanId) throws NetworkDeviceControllerException {
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (lastPrompt != SSHPrompt.MDS_CONFIG) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG.toString());
}
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG };
StringBuilder buf = new StringBuilder();
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.noZoneCommit.nozonecommitvsan.cmd"),
vsanId.toString()); // no zone commit vsan {0}\n
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
inSession = false;
}
/**
* Waits for a zone commit to complete. Checks for in-progress and failed status.
*
* @param vsanId
* @throws NetworkDeviceControllerException
*/
public void waitForZoneCommit(Integer vsanId) throws NetworkDeviceControllerException {
_log.info(MessageFormat.format("Host: {0}, Port: {1} - BEGIN waitForZoneCommit",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
SSHPrompt[] prompts = { SSHPrompt.MDS_POUND, SSHPrompt.MDS_CONFIG };
StringBuilder buf = new StringBuilder();
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.waitForZoneCommit.showzonestatusvsan.cmd"),
vsanId.toString()); // show zone status vsan {0}\n
String[] regex = {
MDSDialogProperties.getString("MDSDialog.waitForZoneCommit.inprogress.match"), // ^Status:\\s+Commit in progress.*
MDSDialogProperties.getString("MDSDialog.waitForZoneCommit.complete.match"), // ^Status:\\s+Commit complete.*
MDSDialogProperties.getString("MDSDialog.waitForZoneCommit.failed.match") // ^Status:\\s+Operation failed.*
};
String[] groups = new String[2];
/*
* compute retry attempts based on the configured timeout.
* will retry in every SLEEP_TIME_PER_RETRY until exceeded the timeout value
* Add one more attempt to ensure timeout value is reached
*/
int retryAttempts = defaultTimeout / MDSDialogProperties.SLEEP_TIME_PER_RETRY + 1;
boolean completed = false;
for (int retrys = 0; !completed && retrys < retryAttempts; retrys++) {
try {
Thread.sleep(MDSDialogProperties.SLEEP_TIME_PER_RETRY);
} catch (InterruptedException ex) {
_log.warn(ex.getLocalizedMessage());
}
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
completed = false;
break;
case 1:
completed = true;
break;
case 2:
throw new NetworkDeviceControllerException("Zone Commit failed: " + line);
}
}
}
_log.info(MessageFormat.format("Host: {0}, Port: {1} - END waitForZoneCommit",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
}
/**
* Does a local copy running-config to startup-config.
*
* @throws NetworkDeviceControllerException
*/
public void copyRunningConfigToStartup() throws NetworkDeviceControllerException {
_log.info(MessageFormat.format("Host: {0}, Port: {1} - BEGIN copyRunningConfigToStartup",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (lastPrompt != SSHPrompt.MDS_CONFIG) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG.toString());
}
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG };
StringBuilder buf = new StringBuilder();
String payload = MDSDialogProperties.getString("MDSDialog.copyRunningConfigToStartup.cmd"); // copy running-config startup-config\n
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
_log.info(MessageFormat.format("Host: {0}, Port: {1} - END copyRunningConfigToStartup",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
}
/**
* Creates a clone of the zoneset.
* cmd : zoneset clone <existing_zoneset_name> <zoneset_clone_name> vsan <vsan id>
*
* @throws NetworkDeviceControllerException
*/
public void zonesetClone(Integer vsanId, String zonesetToClone) throws NetworkDeviceControllerException {
_log.info(MessageFormat.format("Host: {0}, Port: {1} - BEGIN zonesetClone",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (lastPrompt != SSHPrompt.MDS_CONFIG) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG.toString());
}
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG };
String errorString = MDSDialogProperties.getString("MDSDialog.zonesetClone.invalidname.cmd");
StringBuilder buf = new StringBuilder();
String newZoneset = generateZonesetCloneName(zonesetToClone);
List<String> zonesetClonesToDelete = findZonesetClonesToDelete(vsanId);
_log.info("Creating new zoneset clone : " + newZoneset );
boolean retryNeeded = false;
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.zonesetClone.cmd"), zonesetToClone, newZoneset, vsanId); //zoneset clone {0} {1} vsan {2}\n
for (int retryCount = 0; retryCount < sessionLockRetryMax && retryNeeded; retryCount++) {
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
for(String line : lines ) {
if (line.indexOf(errorString) >= 0) {
_log.info("Zoneset clone operation failed");
throw NetworkDeviceControllerException.exceptions.zonesetCloneFailed(newZoneset, line);
}
}
retryNeeded = checkForEnhancedZoneSession(lines, retryCount);
}
//Delete older clones
for (String zonesetClone : zonesetClonesToDelete) {
_log.info(String.format("Removing zoneset (clone) %s", zonesetClone));
zonesetNameVsan(zonesetClone, vsanId, true);
}
_log.info(MessageFormat.format("Host: {0}, Port: {1} - END zonesetClone",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
}
/**
* This routine looks for any zoneset clones that contain the same date-stamp and add them to the list
* of clones to be deleted.
* Only one zoneset clone per zoneset per vsan per day is maintained on the switch
*
* @param vsanId
*
*/
private List<String> findZonesetClonesToDelete(Integer vsanId) {
List<String> zonesetClonesToDelete = new ArrayList<String>();
List<Zoneset> zonesets = showZoneset(vsanId, false, null, false, false);
Calendar cal = Calendar.getInstance();
DateFormat dateFormat = new SimpleDateFormat("MMddyy");
String dateStr = dateFormat.format(cal.getTime());
for (Zoneset zoneset : zonesets) {
if (zoneset.getName().contains(dateStr) && zoneset.getName().contains("ViPR")) {
_log.info(String.format("Identified zoneset (clone) %s to be removed", zoneset.getName()));
zonesetClonesToDelete.add(zoneset.getName());
}
}
return zonesetClonesToDelete;
}
/**
* Generate a unique name for the zoneset clone.
* The format of the zoneset clone name is "ViPR-<existing_zone>-MMddyy-HHmmss"
* MMddyy and HHmmss refer to the date and the time-stamp that will help identify when the clone was taken.
*
* @param zonesetToClone
* @return
*/
private String generateZonesetCloneName(String zonesetToClone) {
//Sleep for one second to make sure that the new zoneset clone name doesn't clash with something existing
//if there were multiple operations all happening at the same time
try {
Thread.sleep(1000); // sleep one second
} catch (InterruptedException ex) {
_log.warn(ex.getLocalizedMessage());
}
//get current date time with Calendar()
Calendar cal = Calendar.getInstance();
DateFormat dateFormat = new SimpleDateFormat("MMddyy-HHmmss");
String dateString = dateFormat.format(cal.getTime());
String longName = MDSDialogProperties.getString("MDSDialog.zonesetCloneLongName.cmd");
//NOTE: This is a hook placed to assist QE in triggering a zoneset clone failure on demand.
if (!longName.contains("!MDSDialog.zonesetCloneLongName.cmd!")) {
return longName;
}
return "ViPR-" + zonesetToClone + "-" + dateString;
}
/**
* Does a fabric wide copy running-configuration to startup-configuration.
* If for some reason this fails, then tries a local copy running-config startup-configuration as a fallback.
*
* @throws NetworkDeviceControllerException
*/
public void copyRunningConfigToStartupFabric() throws NetworkDeviceControllerException {
_log.info(MessageFormat.format("Host: {0}, Port: {1} - BEGIN copyRunningConfigToStartupFabric",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (lastPrompt != SSHPrompt.MDS_CONFIG) {
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(),
SSHPrompt.MDS_CONFIG.toString());
}
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG, SSHPrompt.MDS_CONTINUE_QUERY };
StringBuilder buf = new StringBuilder();
String payload = MDSDialogProperties.getString("MDSDialog.copyRunningConfigToStartupFabric.cmd"); // copy running-config
// startup-config fabric\n
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
if (lastPrompt == SSHPrompt.MDS_CONTINUE_QUERY) {
payload = MDSDialogProperties.getString("MDSDialog.copyRunningConfigToStartupFabric.y.cmd"); // y\n
SSHPrompt[] prompts2 = { SSHPrompt.MDS_CONFIG };
buf = new StringBuilder();
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts2, buf);
String[] lines = getLines(buf);
String[] regex = {
MDSDialogProperties.getString("MDSDialog.copyRunningConfigToStartupFabric.100Percent.match"), // .*100%.*
};
String[] groups = new String[2];
boolean done = false;
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0: // .*100%.*
done = true;
break;
}
}
if (!done) {
_log.error("Copy running-config to startup-config fabric did not complete... trying non-fabric version");
copyRunningConfigToStartup();
}
}
_log.info(MessageFormat.format("Host: {0}, Port: {1} - END copyRunningConfigToStartupFabric",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
}
public boolean isInConfigMode() {
return inConfigMode;
}
public boolean isInSession() {
return inSession;
}
public SSHPrompt getLastPrompt() {
return lastPrompt;
}
/**
* Check if auto routing is enabled for the device. It is enabled if ivr, its distributing mode, and
* auto topology are enabled
*
* @return
*/
public boolean isIvrEnabled() throws NetworkDeviceControllerException {
boolean ivrEnabled = false;
boolean ivrDistributeEnabled = false;
;
boolean ivrVsanTopologyActive = false;
SSHPrompt[] prompts = { SSHPrompt.MDS_POUND, SSHPrompt.MDS_CONFIG, SSHPrompt.MDS_CONFIG_IVR_ZONE, SSHPrompt.MDS_CONFIG_IVR_ZONESET };
StringBuilder buf = new StringBuilder();
sendWaitFor(MDSDialogProperties.getString("MDSDialog.ivr.show.cmd"), 10000, prompts, buf); // show ivr\n
String[] lines = getLines(buf);
for (String line : lines) {
if (line.indexOf(MDSDialogProperties.getString("MDSDialog.ivr.enabled")) >= 0) {
ivrEnabled = true;
} else if (line.indexOf(MDSDialogProperties.getString("MDSDialog.ivr.distribute.enabled")) >= 0) {
ivrDistributeEnabled = true;
} else if (line.indexOf(MDSDialogProperties.getString("MDSDialog.ivr.auto.topology.enabled")) >= 0) {
ivrVsanTopologyActive = true;
}
if (ivrEnabled && ivrVsanTopologyActive && ivrDistributeEnabled) {
break;
}
}
return ivrEnabled && ivrVsanTopologyActive && ivrDistributeEnabled;
}
/**
* ivr zoneset name {zonesetName}
*
* @param zonesetName
* @param activate make zoneset active
* @param isRemove remove zoneset
* @throws NetworkDeviceControllerException
*/
public void ivrZoneName(String zoneName, boolean isRemove) throws NetworkDeviceControllerException {
ivrZoneName(false, zoneName, false, isRemove);
}
/**
* Create/remove an ivr zoneset
*
* @param zonesetName
* @param isActivate
* @param isRemove
* @throws NetworkDeviceControllerException
*/
public void ivrZonesetName(String zonesetName, boolean isActivate, boolean isRemove) throws NetworkDeviceControllerException {
ivrZoneName(true, zonesetName, isActivate, isRemove);
}
/**
* Configure ivr zone or zone set depended on isZoneset flag.
*
* @param isZoneset indicate to config ivr zoneset, otherwise ivr zone
* @param zoneName
* @param isActivate make zoneset active
* @param isRemove remove zoneset
* @throws NetworkDeviceControllerException
*/
private void ivrZoneName(boolean isZoneset, String zoneName, boolean isActivate, boolean isRemove)
throws NetworkDeviceControllerException {
_log.info(MessageFormat.format("Host: {0}, Port: {1} - BEGIN Configure {2}: {3} - Remove {4}",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort(), isZoneset ? "zoneset" : "zone",
zoneName, isRemove }));
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
SSHPrompt[] promptsToCheck = { SSHPrompt.MDS_CONFIG, SSHPrompt.MDS_CONFIG_IVR_ZONE, SSHPrompt.MDS_CONFIG_IVR_ZONESET };
if (!Arrays.asList(promptsToCheck).contains(lastPrompt)) {
String message = Arrays.asList(promptsToCheck).toString();
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(), message);
}
// cannot be activate and remove at the same time
if (isActivate && isRemove) {
String message = "cannot be activate and remove at the same time";
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedDeviceState(message);
}
String ivrZoneNameResourceKey = "MDSDialog.ivr.zoneName.cmd";
if (isZoneset) {
// only zoneset can be activate
ivrZoneNameResourceKey = isActivate ? "MDSDialog.ivr.zonesetName.activate.cmd" : "MDSDialog.ivr.zonesetName.cmd";
}
SSHPrompt[] prompts = { isZoneset ? SSHPrompt.MDS_CONFIG_IVR_ZONESET : SSHPrompt.MDS_CONFIG_IVR_ZONE, SSHPrompt.MDS_CONFIG };
String noString = isRemove ? MDSDialogProperties.getString("MDSDialog.zoneNameVsan.no.cmd") : ""; // no
StringBuilder buf = new StringBuilder();
String payload = MessageFormat.format(noString + MDSDialogProperties.getString(ivrZoneNameResourceKey), zoneName);
boolean retryNeeded = true;
boolean error = false;
String errorMessage = MDSDialogProperties.getString("MDSDialog.ivr.waitForZoneset.activate.error.atLeast2Members");
for (int retryCount = 0; retryCount < sessionLockRetryMax && retryNeeded; retryCount++) {
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
retryNeeded = checkForIvrZoneSession(lines, retryCount);
if (isActivate && isZoneset) {
for (String line : lines) {
error = line.indexOf(errorMessage) >= 0;
if (error) {
break;
}
}
}
}
// verify for appropriate prompt
if (isZoneset) {
SSHPrompt[] morePromptsToCheck = { SSHPrompt.MDS_CONFIG_IVR_ZONESET, SSHPrompt.MDS_CONFIG };
if (!Arrays.asList(morePromptsToCheck).contains(lastPrompt)) {
String message = Arrays.asList(morePromptsToCheck).toString();
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(), message);
}
} else {
SSHPrompt[] morePromptsToCheck = { SSHPrompt.MDS_CONFIG_IVR_ZONE, SSHPrompt.MDS_CONFIG };
if (!Arrays.asList(morePromptsToCheck).contains(lastPrompt)) {
String message = Arrays.asList(morePromptsToCheck).toString();
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(), message);
}
}
if (error) {
throw new NetworkDeviceControllerException(errorMessage + ": " + zoneName);
}
_log.info(MessageFormat.format("Host: {0}, Port: {1} - END Configure {2}: {3} - Remove {4}",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort(), isZoneset ? "zoneset" : "zone",
zoneName, isRemove }));
}
/**
* Create an ivr zoneset, or activate an existing ivr zoneset
*
* @param zonesetName
* @param activate
* @throws NetworkDeviceControllerException
*/
public void ivrZonesetName(String zonesetName, boolean activate) throws NetworkDeviceControllerException {
ivrZoneName(true, zonesetName, activate, false);
}
/**
* member pwwn {pwwn} vsan {vsanId}
*
* @param pwwn
* @param vsanId
* @throws NetworkDeviceControllerException
*/
public void ivrZoneMember(String pwwn, Integer vsanId, boolean isRemove) throws NetworkDeviceControllerException {
_log.info(MessageFormat.format("Host: {0}, Port: {1} - BEGIN Add or remove ivrZoneMember: pwwn {2} vsan {3} - Remove {4}",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort(), pwwn, vsanId, isRemove }));
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG_IVR_ZONE };
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (!Arrays.asList(prompts).contains(lastPrompt)) {
String message = Arrays.asList(prompts).toString();
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(), message);
}
if (!pwwn.matches(wwnRegex)) {
String message = "port wwn " + pwwn + " is not formatted correctly";
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedDeviceState(message);
}
if (!isIvrVsan(vsanId)) {
String message = "VSAN " + vsanId.toString() + " is not an IVR VSAN.";
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedDeviceState(message);
}
String noString = isRemove ? MDSDialogProperties.getString("MDSDialog.zoneNameVsan.no.cmd") : ""; // no
StringBuilder buf = new StringBuilder();
String payload = MessageFormat.format(noString + MDSDialogProperties.getString("MDSDialog.ivr.zoneMember.cmd"), pwwn,
vsanId.toString()); // =member pwwn {0} vsan {0}\n
boolean retryNeeded = true;
for (int retryCount = 0; retryCount < sessionLockRetryMax && retryNeeded; retryCount++) {
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
retryNeeded = checkForEnhancedZoneSession(lines, retryCount);
}
_log.info(MessageFormat.format("Host: {0}, Port: {1} - END - Add or remove ivrZoneMember: pwwn {2} vsan {3} - Remove {4}",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort(), pwwn, vsanId, isRemove }));
}
/**
* member {ivrZoneName}
*
* @param pwwn
* @param vsanId
* @throws NetworkDeviceControllerException
*/
public void ivrZonesetMember(String ivrZonename, boolean isRemove) throws NetworkDeviceControllerException {
_log.info(MessageFormat.format("Host: {0}, Port: {1} - Add or remove ivrZonesetMember: {2} - Remove {3}",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort(), ivrZonename, isRemove }));
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG_IVR_ZONESET };
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (!Arrays.asList(prompts).contains(lastPrompt)) {
String message = Arrays.asList(prompts).toString();
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(), message);
}
String noString = isRemove ? MDSDialogProperties.getString("MDSDialog.zoneNameVsan.no.cmd") : ""; // no
StringBuilder buf = new StringBuilder();
String payload = MessageFormat.format(noString + MDSDialogProperties.getString("MDSDialog.ivr.zonesetMember.cmd"), ivrZonename); // =member
// {zonename}
boolean retryNeeded = true;
for (int retryCount = 0; retryCount < sessionLockRetryMax && retryNeeded; retryCount++) {
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
for (String line : lines) {
// throw exception only when trying to get into config mode, but not found
if (line.indexOf(MDSDialogProperties.getString("MDSDialog.ivr.zone.not.found")) >= 0 && !isRemove) {
throw new NetworkDeviceControllerException(line + ": " + ivrZonename);
}
}
retryNeeded = checkForEnhancedZoneSession(lines, retryCount);
}
}
/**
* Commit ivr changes
*
* @throws NetworkDeviceControllerException
*/
public void ivrCommit() throws NetworkDeviceControllerException {
_log.info(MessageFormat.format("Host: {0}, Port: {1} - BEGIN ivrCommit",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG, SSHPrompt.MDS_CONFIG_IVR_ZONE, SSHPrompt.MDS_CONFIG_IVR_ZONESET };
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (!Arrays.asList(prompts).contains(lastPrompt)) {
String message = Arrays.asList(prompts).toString();
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(), message);
}
StringBuilder buf = new StringBuilder();
String payload = MDSDialogProperties.getString("MDSDialog.ivr.commit.cmd"); // zone commit vsan {0}\n
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
inSession = false;
_log.info(MessageFormat.format("Host: {0}, Port: {1} - END ivrCommit",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
}
/**
* Wait for activation finish processing
*
* @throws NetworkDeviceControllerException
*/
public void waitForIvrZonesetActivate() throws NetworkDeviceControllerException {
_log.info(MessageFormat.format("Host: {0}, Port: {1} - BEGIN waitForIvrZonesetActivate",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
_log.info("Waiting for ivr zoneset to activate");
SSHPrompt[] prompts = { SSHPrompt.MDS_POUND, SSHPrompt.MDS_GREATER_THAN, SSHPrompt.MDS_CONFIG, SSHPrompt.MDS_CONFIG_IVR_ZONE,
SSHPrompt.MDS_CONFIG_IVR_ZONESET };
StringBuilder buf = new StringBuilder();
String payload = MDSDialogProperties.getString("MDSDialog.ivr.show.zoneset.status.cmd"); // show zone status vsan {0}\n
String[] regex = {
MDSDialogProperties.getString("MDSDialog.ivr.waitForZoneset.activate.inprogress.match"), // ^State:\\s+activating*
MDSDialogProperties.getString("MDSDialog.ivr.waitForZoneset.activate.success.match"), // ^State:\\s+activation success*
};
String[] groups = new String[2];
boolean completed = false;
for (int i = 0; i < defaultTimeout && completed == false; i += 1000) {
try {
Thread.sleep(1000); // sleep one second
} catch (InterruptedException ex) {
_log.warn(ex.getLocalizedMessage());
}
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
completed = false;
break;
case 1:
completed = true;
break;
case 2:
throw new NetworkDeviceControllerException("ivr zoneset activate Commit failed: " + line);
}
if (completed) {
break;
}
}
}
_log.info(MessageFormat.format("Host: {0}, Port: {1} -DONE waitForIvrZonesetActivate",
new Object[] { getSession().getSession().getHost(), getSession().getSession().getPort() }));
}
/**
* Abort ivr changes
*
* @throws NetworkDeviceControllerException
*/
public void ivrAbort() throws NetworkDeviceControllerException {
SSHPrompt[] prompts = { SSHPrompt.MDS_CONFIG, SSHPrompt.MDS_CONFIG_IVR_ZONE, SSHPrompt.MDS_CONFIG_IVR_ZONESET };
if (!inConfigMode) {
throw NetworkDeviceControllerException.exceptions.mdsDeviceNotInConfigMode();
}
if (!Arrays.asList(prompts).contains(lastPrompt)) {
String message = Arrays.asList(prompts).toString();
throw NetworkDeviceControllerException.exceptions.mdsUnexpectedLastPrompt(lastPrompt.toString(), message);
}
StringBuilder buf = new StringBuilder();
String payload = MDSDialogProperties.getString("MDSDialog.ivr.abort.cmd"); // zone commit vsan {0}\n
lastPrompt = sendWaitFor(payload, defaultTimeout, prompts, buf);
inSession = false;
}
/**
* Collect the active ivr zoneset, and its zones, members
*
* @return a ivr zoneset
*/
public IvrZoneset showActiveIvrZoneset() throws NetworkDeviceControllerException {
List<IvrZoneset> zonesets = showIvrZonesets(true);
return zonesets.isEmpty() ? null : zonesets.get(0);
}
/**
* Collect the active ivr zoneset, and its zones, members
*
* @return a ivr zoneset
*/
public List<IvrZoneset> showIvrZonesets(boolean active) throws NetworkDeviceControllerException {
List<IvrZoneset> zonesets = new ArrayList<IvrZoneset>();
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN, SSHPrompt.MDS_CONFIG, SSHPrompt.MDS_CONFIG_IVR_ZONE,
SSHPrompt.MDS_CONFIG_IVR_ZONESET };
StringBuilder buf = new StringBuilder();
String cmdKey = active ? "MDSDialog.ivr.show.zoneset.active.cmd" : "MDSDialog.ivr.show.zoneset.cmd";
sendWaitFor(MDSDialogProperties.getString(cmdKey), defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
String[] regex = {
MDSDialogProperties.getString("MDSDialog.ivr.showZoneset.zoneset.name.match"),
MDSDialogProperties.getString("MDSDialog.ivr.showZoneset.zone.name.match"),
MDSDialogProperties.getString("MDSDialog.ivr.showZoneset.zone.member.match")
};
IvrZoneset zoneset = null;
IvrZone zone = null;
IvrZoneMember member = null;
String[] groups = new String[10];
for (String line : lines) {
line = line.replace('*', ' '); // remove un-need * char
int index = match(line, regex, groups);
switch (index) {
case 0:
zoneset = new IvrZoneset(groups[0]);
zonesets.add(zoneset);
zoneset.setActive(active);
break;
case 1:
zone = new IvrZone(groups[0]);
zone.setActive(active);
zoneset.getZones().add(zone);
break;
case 2:
member = new IvrZoneMember(groups[0] + groups[2], Integer.valueOf(groups[3]));
zone.getMembers().add(member);
break;
}
}
return zonesets;
}
/**
* Get ivr vsan topology of the switch
*
* @return
* @throws NetworkDeviceControllerException
*/
public List<IvrVsanConfiguration> showIvrVsanTopology() throws NetworkDeviceControllerException {
List<IvrVsanConfiguration> ivrVsans = new ArrayList<IvrVsanConfiguration>();
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN, SSHPrompt.MDS_CONFIG, SSHPrompt.MDS_CONFIG_IVR_ZONE,
SSHPrompt.MDS_CONFIG_IVR_ZONESET };
StringBuilder buf = new StringBuilder();
sendWaitFor(MDSDialogProperties.getString("MDSDialog.ivr.vsan.topology.cmd"), defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
String[] regex = {
MDSDialogProperties.getString("MDSDialog.ivr.showTopology.wwn.match")
};
String[] groups = new String[10];
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
IvrVsanConfiguration ivrVsan = new IvrVsanConfiguration();
ivrVsan.setSwitchWwn(groups[0] + groups[2]);
// local switch is indicated by present of * character
ivrVsan.setLocalSwitch("*".equalsIgnoreCase(groups[3]));
try {
// get the first vsan in the line
int vsanId = Integer.valueOf(groups[4]);
// if there is vsan present in the line, split the line
// and get all ivr vsans via StringSplit
if (vsanId > 0) {
String vsansText = line.substring(line.indexOf(groups[4], line.indexOf(ivrVsan.getSwitchWwn())
+ ivrVsan.getSwitchWwn().length()));
String[] vsans = vsansText.split(",");
for (String vsan : vsans) {
// get vsan range
if (vsan.indexOf('-') > 0) {
String[] range = vsan.split("-");
ivrVsan.getVsansRanges().add(
new IntRange(Integer.valueOf(range[0].trim()), Integer.valueOf(range[1].trim())));
} else {
ivrVsan.getVsans().add(Integer.valueOf(vsan.trim()));
}
}
}
} catch (Exception e) {
// not ivr vsan
}
ivrVsans.add(ivrVsan);
break;
}
}
return ivrVsans;
}
/**
* Get switch 's wwn
*
* @return
* @throws NetworkDeviceControllerException
*/
public String showSwitchWwn() throws NetworkDeviceControllerException {
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN, SSHPrompt.MDS_CONFIG, SSHPrompt.MDS_CONFIG_IVR_ZONE,
SSHPrompt.MDS_CONFIG_IVR_ZONESET };
StringBuilder buf = new StringBuilder();
sendWaitFor(MDSDialogProperties.getString("MDSDialog.show.wwn.switch.cmd"), defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
String[] regex = {
MDSDialogProperties.getString("MDSDialog.show.wwn.switch.match"),
};
String switchWwn = null;
String[] groups = new String[10];
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
switchWwn = groups[0];
break;
}
if (switchWwn != null) {
break;
}
}
return switchWwn;
}
/**
* Get switch ivr zones
*
* @return
* @throws NetworkDeviceControllerException
*/
public List<IvrZone> showIvrZones(boolean active) throws NetworkDeviceControllerException {
List<IvrZone> zones = new ArrayList<IvrZone>();
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
String cmdKey = active ? "MDSDialog.ivr.show.zone.active.cmd" : "MDSDialog.ivr.show.zone.cmd";
sendWaitFor(MDSDialogProperties.getString(cmdKey), defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
IvrZone zone = null;
IvrZoneMember member = null;
String[] regex = {
MDSDialogProperties.getString("MDSDialog.ivr.showZoneset.zone.name.match"),
MDSDialogProperties.getString("MDSDialog.ivr.showZoneset.zone.member.match")
};
String[] groups = new String[10];
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
zone = new IvrZone(groups[0]);
zones.add(zone);
break;
case 1:
member = new IvrZoneMember(groups[0], Integer.valueOf(groups[3]));
zone.getMembers().add(member);
break;
}
}
return zones;
}
/**
* Collect the active ivr zone
*
* @return a ivr zoneset
*/
public List<IvrZone> showActiveIvrZone() throws NetworkDeviceControllerException {
return showIvrZones(true);
}
/**
* Check if given vsan is an ivr vsan
*
* @param vsanId
* @return
* @throws NetworkDeviceControllerException
*/
private boolean isIvrVsan(int vsanId) throws NetworkDeviceControllerException {
List<IvrVsanConfiguration> ivrVsansList = showIvrVsanTopology();
for (IvrVsanConfiguration ivrVsans : ivrVsansList) {
if (ivrVsans.isIvrVsan(vsanId)) {
return true;
}
}
return false;
}
/**
* Return map vsan 's peer devices' ip address
*
* @return a Map of Vsan ID to set of peer devices ( identify by ip address )
*/
public Map<Integer, Set<String>> showTopology() throws NetworkDeviceControllerException {
Map<Integer, Set<String>> peerDevicesMap = new HashMap<Integer, Set<String>>();
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
sendWaitFor(MDSDialogProperties.getString("MDSDialog.show.topology.cmd"), 10000, prompts, buf); // show topology\n
String[] lines = getLines(buf);
Integer vsanId = null;
String[] regex = {
MDSDialogProperties.getString("MDSDialog.show.topology.vsan.match"), // FC Topology for VSAN\\s+(\\d+).*
MDSDialogProperties.getString("MDSDialog.show.topology.peer.ip.match") // .*\\s+(([0-9]{1,3}\\.){3})([0-9]{1,3}).*
};
String[] groups = new String[10];
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
// Save the vsan id.
vsanId = new Integer(groups[0]);
break;
case 1:
Set<String> peerDevicesIpAddr = peerDevicesMap.get(vsanId);
if (peerDevicesIpAddr == null) {
peerDevicesIpAddr = Sets.newHashSet();
peerDevicesMap.put(vsanId, peerDevicesIpAddr);
}
String peerDevice = groups[0] + groups[2];
peerDevicesIpAddr.add(peerDevice);
break;
}
}
return peerDevicesMap;
}
/**
* Get list of zone names where the given pwwn belongs to
*
* @param pwwn
* @param vsanId
* @param activeOnly only list names of active zones
* @return
* @throws NetworkDeviceControllerException
*/
public Set<String> showZoneNamesForPwwn(String pwwn, Integer vsanId, boolean activeOnly) throws NetworkDeviceControllerException {
Set<String> zoneNames = Sets.newHashSet();
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
String cmdKey = activeOnly ? "MDSDialog.showZone.pwwn.active.cmd" : "MDSDialog.showZone.pwwn.cmd";
String payload = MessageFormat.format(MDSDialogProperties.getString(cmdKey), pwwn, vsanId.toString());
sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
String[] regex = {
// regex expression is \\s*zone\\s+([-\\w]+)
MDSDialogProperties.getString("MDSDialog.zoneName.match"),
};
String[] groups = new String[10];
for (String line : lines) {
int index = match(line, regex, groups);
switch (index) {
case 0:
zoneNames.add(groups[0]);
break;
}
}
return zoneNames;
}
/**
* Get Zone and its members for given zone name
*
* @param zoneName zone name
* @return
* @throws NetworkDeviceControllerException
*/
public Zone showZone(String zoneName) throws NetworkDeviceControllerException {
return showZone(zoneName, null, true);
}
/**
* Get list of zones for given zone names
*
* @param zoneNames
* @param excludeAliases
* @return
*/
public List<Zone> showZones(Collection<String> zoneNames, boolean excludeAliases) {
List<Zone> zones = new ArrayList<Zone>();
Zone zone = null;
if (zoneNames != null && !zoneNames.isEmpty()) {
Map<String, String> aliasDatabase = showDeviceAliasDatabase();
for (String zoneName : zoneNames) {
//it's ivr zone
if (zoneName.startsWith(IVR_ZONENAME_PREFIX)) {
zone = showIvrZone(zoneName.substring(IVR_ZONENAME_PREFIX.length()));
} else {
zone = showZone(zoneName, aliasDatabase, excludeAliases);
}
zones.add(zone);
}
}
return zones;
}
/**
* Get Zone and its members for given ivr zone name.
*
* @param zoneName
* @return zone
* @throws NetworkDeviceControllerException
*/
private Zone showIvrZone(String zoneName) {
Zone zone = new Zone(zoneName);
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.ivr.show.zoneName.cmd"), zoneName);
sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
ZoneMember member = null;
String[] regex = {
MDSDialogProperties.getString("MDSDialog.ivr.showZoneset.zone.member.match")
};
String[] groups = new String[10];
for (String line : lines) {
int index = match(line, regex, groups);
member = new ZoneMember(ZoneMember.ConnectivityMemberType.WWPN);
switch (index) {
case 0:
member.setAddress(groups[0]);
zone.getMembers().add(member);
break;
}
}
return zone;
}
/**
* Get Zone and its members for given zone name. Besure to resolve device alias if present.
*
* @param zoneName
* @param aliasDatabase
* @param excludeAliases
* @return
* @throws NetworkDeviceControllerException
*/
private Zone showZone(String zoneName, Map<String, String> aliasDatabase, boolean excludeAliases)
throws NetworkDeviceControllerException {
Zone zone = new Zone(zoneName);
SSHPrompt[] prompts = { SSHPrompt.POUND, SSHPrompt.GREATER_THAN };
StringBuilder buf = new StringBuilder();
String payload = MessageFormat.format(MDSDialogProperties.getString("MDSDialog.showZone.name.cmd"), zoneName);
sendWaitFor(payload, defaultTimeout, prompts, buf);
String[] lines = getLines(buf);
ZoneMember member = null;
String[] regex = {
MDSDialogProperties.getString("MDSDialog.showZoneset.pwwn.match"), // \\s*pwwn ([0-9a-fA-F:]+)\\s*(\\[\\S+\\])?
MDSDialogProperties.getString("MDSDialog.showZoneset.deviceAlias.match") // \\s*device-alias \\s*(\\S+)\\s*
};
String[] groups = new String[10];
Map<String, String> myAliasDatabase = aliasDatabase == null ? showDeviceAliasDatabase() : aliasDatabase;
if (excludeAliases) {
_log.info("Excluding aliases while getting zone members");
}
for (String line : lines) {
int index = match(line, regex, groups);
member = new ZoneMember(ZoneMember.ConnectivityMemberType.WWPN);
switch (index) {
case 0:
member.setAddress(groups[0]); // set wwn id
// matched "pwwn <wwnid> [alias]" regex, thus
// set alias field as well
if (!excludeAliases && groups.length >= 2 && groups[1] != null) {
member.setAlias(groups[1].replace("[", "").replace("]", ""));
}
zone.getMembers().add(member);
break;
case 1:
// matched "device-alias <alias>
if (!excludeAliases) {
member.setAlias(groups[0]); // set alias
member.setAliasType(true); // indicate member type of alias
}
String pwwn = getDeviceAliasPwwn(groups[0], myAliasDatabase);
if (!StringUtils.isEmpty(pwwn)) {
member.setAddress(pwwn);
}
zone.getMembers().add(member);
break;
}
}
return zone;
}
/**
* Populate routedEndpoints based on ivr zone information.
*
* @param routedEndpoints a IN/OUT parameters which is a map of fabricWwn to endpoint set
*/
public void populateConnectionByIvrZone(Map<String, Set<String>> routedEndpoints) {
List<IvrZone> ivrZones = this.showIvrZones(false);
for (IvrZone ivrZone : ivrZones) {
for (IvrZoneMember zoneMember : ivrZone.getMembers()) {
Integer vsanId = zoneMember.getVsanId();
Map<Integer, String> idWwnMap = getVsanWwns(vsanId);
String fabricWwn = idWwnMap.get(vsanId);
if (NullColumnValueGetter.isNullValue(fabricWwn)) {
continue;
}
Set<String> netRoutedEndpoints = routedEndpoints.get(fabricWwn.toUpperCase());
if (netRoutedEndpoints == null) {
netRoutedEndpoints = new HashSet<String>();
routedEndpoints.put(fabricWwn.toUpperCase(), netRoutedEndpoints);
}
Set<String> connectedPwwns = this.getOtherMemberPwwn(ivrZone.getMembers(), zoneMember.getPwwn());
netRoutedEndpoints.addAll(connectedPwwns);
}
}
}
/**
* Get pwwns from ivr zone members excludes specific one.
*
* @param ivrZoneMember
* @param pwwn which should be excluded
* @return otherPwwns pwwn set except spcific pwwn
*/
private Set<String> getOtherMemberPwwn(List<IvrZoneMember> ivrZoneMembers, String pwwn) {
Set<String> otherPwwns = new HashSet<String>();
for (IvrZoneMember member : ivrZoneMembers) {
if (!member.getPwwn().equals(pwwn)) {
otherPwwns.add(member.getPwwn());
}
}
return otherPwwns;
}
/**
* {@inheritDoc}
*/
@Override
protected String getResponseExceptionRegex() {
return MDSDialogProperties.getString(EXCEPTION_REGEX_KEY);
}
}