Visualizing IBM SAN Volume Controller FlashCopy Mappings

Dan Rumney

January 22, 2009


Table of Contents

SVC FlashCopy Mappings
The DOT Language
SVC Command Line Scripting
Script Analysis
Lines 1-18
Lines 19-26
Lines 27-30
Lines 31-46
Lines 48-55
Lines 56-58
Using the script
Interactive session
Batch session
Possible Improvements
A. Graph generating script
B. Valid colours in the DOT language

Abstract

With the introduction of Multiple-Target FlashCopy® and Cascaded FlashCopy to IBM® System StorageSAN Volume Controller (SVC) , it can become difficult to keep track of which Virtual Disks are mapped to which, and how FlashCopy Mappings (FCM) depend upon one another. While submitting svcinfocommands or using the SVC Console can provide this information in a textual format, there are times when a diagram provides all the information you need in an easy to understand format.

This paper outlines a method for generating diagrams that link VDisks and FlashCopy Mappings. It also serves as a worked example of automation on the SVC Command Line. This paper assumes familiarity with SVC and the FlashCopy functionality.

SVC FlashCopy Mappings

When SVC was introduced in 2003 it included a number of Copy Services: FlashCopy and Remote Copy. FlashCopy is a Point-In-Time Copy Service, whereby the contents of a Source Virtual Disk (Source) is copied to a Target Virtual Disk (Target), such that the Target is an exact copy of the Source, at that point in time. The relationship between a Source and a Target is called a FlashCopy Mapping (FCM). The original implementation was such that a Source could only ever have one active Target. In addition to this, a Target of one FCM could not be the Source of another FCM. A number of FCMs can be gathered together into a FlashCopy Consistency Group (FCG) and managed as a single entity, to ensure that all Target VDisks in the FCG represent the exact same point in time.

With the release of SVC 4.2.1, new types of FlashCopy arrangements can be created. A single VDisk can act as the Source to multiple Targets. In addition to this, a VDisk which is acting as the Target of one FCM can also act as the Source of a different FCM. For more details on Copy Services in SVC, see the Redbook SVC 4.2.1 Advanced Copy Services [SG24-7574-00] .

In a complex environment, the interactions between FCMs and VDisks can get quite involved. Dependencies between FCMs stem from internal data structures within the cluster rather than the logical connections between VDisks. All of these dependencies can be discovered by submitting the appropriate svcinfo commands, but the information is presented in a purely textual way; this provides no insight into the interaction between cluster objects. Example 1, “Sample output from SVC commands, viewing FCM interactions” shows how this output looks.

Example 1. Sample output from SVC commands, viewing FCM interactions

IBM_2145:cluster_name:admin>svcinfo lsfcmap -delim :
id:name:source_vdisk_id:source_vdisk_name:target_vdisk_id:target_vdisk_name:
group_id:group_name:status:progress:copy_rate:clean_progress:incremental
0:fcmap0:1039:vdisk1039:1040:vdisk1040:::idle_or_copied:100:93:100:on
1:fcmap1:1041:vdisk1041:1042:vdisk1042:::idle_or_copied:100:30:100:off
2:fcmap2:1043:vdisk1043:1044:vdisk1044:::idle_or_copied:100:88:100:on
3:fcmap3:1045:vdisk1045:1046:vdisk1046:::idle_or_copied:100:36:100:off
4:fcmap4:1046:vdisk1046:1047:vdisk1047:::idle_or_copied:100:96:100:on
IBM_2145:cluster_name:admin>
IBM_2145:cluster_name:admin>svcinfo lsfcmapdependentmaps -delim : 2
fc_id:fc_name
1:fcmap1
3:fcmap3

The output from the svcinfo command does not lend itself to a swift overview of the cluster state. We look to the DOT language to generate a graphical representation of this information.

The DOT Language

The DOT Language is a language used to describe directed and undirected graphs. Once written, the DOT can then be processed by an appropriate program, to render the graph on screen.

A directed graph consists of nodes and edges. A node is a graphical shape which may or may not contain some text. The nodes are interconnected by lines, called edges. In a directed graph, the edges have arrows at one or both ends. Figure 1, “Sample directed graph” shows a sample directed graph. Ellipses a,b, c and d are all nodes.

Figure 1. Sample directed graph

Sample directed graph generated by a DOT parser

The DOT language is quite straightforward; for instance, the DOT required to generate Figure 1, “Sample directed graph” can be seen in Example 2, “DOT language for generating a directed graph”. The nodes are represented by the various letters. In each line in the example, you can see the 'arrow' notation which indicates a directed edge, joining two nodes.

Example 2. DOT language for generating a directed graph

digraph EXAMPLE
{
  a -> c;
  b -> c;
  c -> d;
  d -> a;
}

A DOT file only describes the graph. You must pass this file to a rendering program in order to generate a graphical representation. Once such program is dot, which is part of the Graphviz package. Once installed, the invocation shown in Example 3, “Invocation to generate graphic from DOT language (Windows)” will generate a GIF file rendering of the sample directed graph described in Example 2, “DOT language for generating a directed graph”.

Example 3. Invocation to generate graphic from DOT language (Windows)

dot -T gif -o sampleDigraph.gif -K dot -v sampleDiGraph.dot

The capabilities of the DOT language lend themselves directly to the challenge of visualizing FlashCopy Mapping and VDisk relationships. The challenge is to generate the DOT necessary to generate our required visualization. In order to do this, we can use SVC Command Line Scripting.

SVC Command Line Scripting

The SVC Command Line Interface is based on a restricted Bash Shell. This provides us with a double-edged opportunity. On one hand, the Bash Shell means that we have the opportunity to execute scripts while logged in to the SVC Command Line. On the other hand, the restricted aspect strongly limits what we can do and results in the need for some imaginative scripting.

The Bash Shell includes a number of 'built-in' commands that can be used, such as:

if
while
for
read
echo

The restrictions on the Shell mean that there is no access to scripting standards such as sed, awk and grep. In addition, IO cannot be redirected to files. However, command output can be redirected to other commands, via pipes.

Appendix A, Graph generating script contains the script that we'll be discussing for the remainder of this paper. This script creates a CLI function which, when executed, generates DOT language which describes the connections between a set of VDisks and FCMs. The CLI function has one parameter, which is the id of one of the cluster's VDisks. Given a VDisk ID, this command follows the procedure below.

  1. Search for any FCMs which have the provided VDisk as a Source or Target

  2. For any FCMs found, identify the counterpart VDisks and repeat step 1 for each of the new VDisks

  3. For all of the FCMs found, search for all dependant FCMs

  4. Generate the DOT language, describing the VDisk and FCM interactions

Example 4, “Sample output from script” shows example output from this function. When rendered by dot, the graphic shown in Figure 2, “Sample directed graph”

Example 4. Sample output from script

IBM_2145:cluster_name:admin>makeFCMapTree 1212
digraph F {
  1210 [style=filled,fillcolor=green]
  514 [shape=box,height=0.4,width=0.4,fillcolor=green,style=filled]
  1210 -> 514
  514 -> 1212
  515 [shape=box,height=0.4,width=0.4,fillcolor=green,style=filled]
  1210 -> 515
  515 -> 1213
  1212 [style=filled,fillcolor=green]
  1213 [style=filled,fillcolor=green]
  1211 [style=filled,fillcolor=green]
  512 [shape=box,height=0.4,width=0.4,fillcolor=green,style=filled]
  1211 -> 512
  512 -> 1209
  513 [shape=box,height=0.4,width=0.4,fillcolor=green,style=filled]
  1211 -> 513
  513 -> 1210
  1209 [style=filled,fillcolor=green]
}

The ellipses represent VDisks. The rectangles represent FlashCopy Mappings. The colours of the shapes represent the state of the FlashCopy Mappings and VDisks. In one glance, the interactions between VDisks and FlashCopy Mappings are clear and any issues are immediately obvious.

Figure 2. Sample directed graph

Sample FlashCopy graph

In the next section, we will go through this script line by line and explain what is being done. The techniques used in this script can be used in scripts of your own to perform whatever actions you require. If you prefer, you can skip to the section called “Using the script” to learn how to use the script.

Script Analysis

When the script in Appendix A, Graph generating script is executed, it creates a new function called makeFCMapTree in the active SVC CLI session. The script itself has no output. Once the function has been created, it is invoked by providing the function name and a VDisk ID. It generates output in the DOT language which can be captured and saved for later rendering. In this section, we analysis the script section by section and explain its function.

Lines 1-18

The first 18 lines are concerned with setting up variables for use during the main loop.

Lines 1-15.  The fifteen first lines simply start the function and set up some variables assigning colours to FCM and VDisk states. These can be changed to suit your needs, with the requirement that all 10 states are present and the colours that are selected are part of the DOT language. Appendix B, Valid colours in the DOT language shows the colours supported by DOT.

Line 16.  This line outputs the first line of DOT, which indicates that we'll be describing a directed graph. We call it F for FlashCopy, but the name is entirely arbitrary (within the constraints of the DOT language)

Line 17.  In this line, we create an array called $possSrcs. This array will be treated as a FIFO stack. It will contain a list of VDisks which are possibly acting as the Sources of an FCM. At this point in the execution, we add the VDisk ID that was provided as the sole parameter to the function. In subsequent passes through the main loop, new VDisk IDs may be added, as required.

Line 18.  Here, we create an empty array which will keep track of all VDisk IDs which have been processed. This is to ensure that the script processes each VDisk ID once and once only.

Lines 19-26

These lines start the main loop and gather information about the next VDisk ID in the $possSrcs stack.

Line 19.  This starts the main loop of this script. The loop will execute as long as there are VDisk IDs in $possSrcs. This loop ends on line 56.

Lines 20-21.  Lines 20-21 perform the pop operation of a stack, removing the first element from $possSrcs and assigning it to $currSrc.

Lines 22-26.  Lines 22-26 show a technique that will be repeated a number of times in this script. This technique is to run an svcinfo command and execute a series of commands based on each line of output from the svcinfo command.

The technique has the following form:

svcinfo xxxx | while read var1 var2 var3 rest; do
          some commands using $var1, $var2, etc
done

This technique will take each line of output from the svcinfo command and pass it to the read built-in command. The read command works in the following way:

read [ name ...]

The read command takes a line from STDIN and splits it into words separated according to the Internal Field Separator (IFS). By default, IFS is set to whitespace. The first word is assigned to the first name, the second to the second name and so on. Any leftover words are assigned to the final name with the intervening IFS included.

In the technique shown above, the variables $var1, $var2, etc can now be used by commands inside the while loop. The loop will repeat once per line of output from the svcinfo command. The variable $rest is needed to capture any remaining values at the end of the line of output.

The command svcinfo lsvdisk -nohdr -filtervalue id=$currSrc will generate zero or one line of output. (depending on whether the value in $currSrc is an actual VDisk ID).

Line 24.  This line acts to 'dereference' the VDisk status. The code $(eval echo \$$vStatus) will take the value stored in $vStatus and treat it as the name of a variable and try to find the value stored in that. For instance, if $vStatus is equal to 'preparing' then this line will look for the value found in $preparing and, in this case, return 'yellow'. In this way, we can assign colours to VDisk states.

Line 25.  This generates lines of DOT which define a node in the graph. In this instance a VDisk node is generated. The VDisk node is an ellipse, filled in a colour representing the VDisk's state.

Lines 27-30

These two lines generate an array of FCM Target VDisk IDs and mark the current VDisk ID (held in $currentSrc) as having been processed.

Lines 27-29.  Lines 27-29 create a new array that holds all of the FCMs which have the current VDisk (represented by $currSrc) as the Source VDisk. This array is called $newTgts. These three lines shows a method of generating an array directly from the output of an svcinfo command. In this particular instance, each line of svcinfo output generates 3 array elements:

$newTgts[L]

FlashCopy Mapping ID

$newTgts[L+1]

Target VDisk ID

$newTgts[L+2]

FlashCopy Mapping status

where L increases by one per line of svcinfo output.

Line 30.  Line 30 keeps track of the fact that we have now processed the VDisk ID(as an FCM Source... it may appear later as an FCM Target).

Lines 31-46

These lines process the FCMs that were placed into $newTgts and generate the appropriate DOT to represent them.

Line 31.  Lines 31 creates the loop to process $newTgts. It creates an index variable which is incremented by 3 for each pass (since 3 elements in an array represent one FC Mapping).

Lines 32-35.  Lines 32 to 34 simply collect the relevant array elements in to clearer variable names. Line 35 decodes the FC Mapping status into a colour, much like line 24.

Lines 36-39.  Lines 36-39 generate DOT language; lines 36 and 37 creates an FC Mapping node, which is a square filled with a colour that represents its state.

Lines 38 and 39 generate the edges that link the FC Mapping node with its Source and Target VDisks.

Lines 40-42.  Lines 40-42 look at the FCM Target and determine whether or not it has been processed as a Source. If it has not, it is added to our list of possible Sources: $possSrcs. The code in line 41 acts to place this new VDisk ID at the end of the stack.

Lines 43-45.  Lines 43-45 look to see if there are any dependencies between this FCM and other FCMs. If there are, a new edge is generated to indicate this.

Lines 48-55

Lines 48-55 perform a similar task to line 27 and the loop that follows it.

Line 48.  Line 48 generates an array of FCM Source VDisk IDs, which have $currentSrc as their Target. This array is called $newSrcs. Instead of generating any DOT in the loop, however, this loop simply adds the indicated VDisk IDs to the $possSrcs array, if they have not previously been processed.

Lines 56-58

All that remains at this point is to complete the loops, close out the DOT language with a curly bracket and the function is complete.

Using the script

There are two simple ways to use the script. It can be executed directly from an interactive CLI session, or it can be used as part of a batch session.

Interactive session

Adding the makeFCTreeMap function to an interactive session is very straightforward. Simply copy the full text of the script into the clipboard and then paste it into the terminal. Once the script has executed, the makeFCTreeMap function will be available to you for the remainder of that CLI session.

Once you've passed a VDisk ID to the function, you will need to copy the output from the CLI session and place it into a dot file for rendering.

Batch session

Adding the makeFCTreeMap function to a batch session depends on your SSH client. Here, we will discuss PuTTY for the Windows operating system and ssh for Linux or AIX®.

Whichever operating system you use, the output from the script will be returned to the STDOUT stream on your local system. You can redirect this output to a dot file, and then pass it to your rendering application.

Required script changes

When a script is submitted to the SVC Cluster in this way, STDIN is replaced by the contents of the script and executed as if it was typed in manually. Once the end of the file is reached, control returns to the local command line and not the SVC command line. Since the normal function of the makeFCTreeMap script is to create a new function in the CLI session (and nothing more), the following modifications are needed to generate output:

  • Delete lines 1 and 2

  • Delete line 58

  • Replace $1 in line 17 with the ID of the VDisk that you're interested in.

Once these changes have been made, the resulting script_file should be submitted to the cluster using one of the methods shown in the next subsections.

PuTTY

The plink command comes as part of the PuTTY application. Example 5, “Submitting script to an SVC cluster using plink” shows the command to use to submit a script to an SVC cluster.

Example 5. Submitting script to an SVC cluster using plink

plink -l admin -m script_file -i private_key_file cluster_name
              
script_file

The file containing the makeFCTreeMap script

private_key_file

An SSH private key which corresponds to a public key that has been uploaded to the SVC cluster in question

cluster_name

The IP address or DNS name


SSH

The ssh command comes with most (if not all) *nix operating systems. Example 6, “Submitting script to an SVC cluster using ssh” shows the invocation required to submit a script to an SVC cluster using ssh.

Example 6. Submitting script to an SVC cluster using ssh

ssh -i private_key_file -T admin@cluster_name < script_file
          
script_file

The file containing the makeFCTreeMap script

private_key_file

An SSH private key which corresponds to a public key that has been uploaded to the SVC cluster in question

cluster_name

The IP address or DNS name


Possible Improvements

The script in Appendix A, Graph generating script functions correctly for all possible VDisk IDs, including ones that are not present on the cluster. However, there are some interesting changes that could be made to enhance the script. These are offered as suggestions and are left to the reader to implement:

Possible improvements to script

Handle Multiple VDisk IDs

The current version of the makeFCTreeMap only accepts a single VDisk ID. It would be a fairly simple task to change the script to allow the function to accept any number of VDisk IDs. It would be important to check for duplicate VDisk IDs appearing in the $possSrcs stack.

Handle FlashCopy Mapping IDs

Expanding this script to support FCM IDs instead of VDisk IDs is the straightforward task of taking the FCM ID, determining the Source VDisk's ID and placing this into the $possSrcs stack and then proceeding as before. The challenge lies in making the one script support VDisk IDs and FCM IDs.

Handle FlashCopy Consistency Group IDs

Handling FlashCopy Consistency Groups is the natural combination of handling multiple VDisk IDs and handling FlashCopy Mappings, since an FCG is simply a group of FCMs. The following code will turn an FCG id into an array of FCM ids: fcmIDs=(`svcinfo lsfcmap -nohdr -filtervalue group_id=0 | while read fcmid rest; do echo $fcmid; done`)

A. Graph generating script

The script below has been formatted so that it will fit onto the page. As a result, line continuation operators have been used on lines 22, 27, 28, 36 and 48.

makeFCMapTree ()
{
  # Define the colouring for FC Mapping and VDisk states
  idle_or_copied=green
  preparing=yellow
  prepared=green
  copying=green
  stopped=red
  suspended=red
  stopping=yellow
  online=green
  offline=red
  degraded=yellow

  # Start the directed graph
  echo "digraph F {";
  possSrcs=($1);
  processed=();
  while [ ${#possSrcs[@]} -gt 0 ]; do
    currSrc=${possSrcs[0]};
    possSrcs=(${possSrcs[@]:1});
    svcinfo lsvdisk -nohdr -filtervalue id=$currSrc | while read id name \
iogId iogName vStatus junk; do
      vdkColour=$(eval echo \$$vStatus);
      echo "$currSrc [style=filled,fillcolor=$vdkColour]";
    done
    newTgts=(`svcinfo lsfcmap -nohdr -filtervalue source_vdisk_id=$currSrc \
-delim :| while IFS=: read id n srcId srcName tgtId tgtName gId gName \
status junk; do echo "$id $tgtId $status"; done`);
    processed[$currSrc]=y;
    for ((i=0; i<${#newTgts[@]};i=$(($i + 3)))); do
      fcm=${newTgts[$i]};
      tgt=${newTgts[$(($i + 1))]};
      status=${newTgts[$(($i + 2))]};
      colour=$(eval echo \$$status);
      echo "fc$fcm [label=\"$fcm\"shape=box,height=0.4,width=0.4,\
fillcolor=$colour,style=filled]";
      echo "$currSrc -> fc$fcm";
      echo "fc$fcm -> $tgt";
      if [ "${processed[$tgt]}" != "y" ]; then
      possSrcs=(${possSrcs[@]} $tgt);
      fi;
      svcinfo lsfcmapdependentmaps -nohdr $fcm | while read fcId fcName; do
        echo "$fcm -> $fcId [style=dotted]"
      done
    done;

    newSrcs=(`svcinfo lsfcmap -nohdr -filtervalue target_vdisk_id=$currSrc| \
while read id name srcId junk; do echo "$srcId "; done`);
    for src in ${newSrcs[@]};
    do
      if [ "${processed[$src]}" != "y" ]; then
      possSrcs=(${possSrcs[@]} $src);
      fi;
    done;
  done;
  echo "}";
}

B. Valid colours in the DOT language

The following are acceptable colours in the DOT language: This list can also be found at Graphviz Color Names

alicebluegray18grey74orange1
antiquewhitegray19grey75orange2
antiquewhite1gray20grey76orange3
antiquewhite2gray21grey77orange4
antiquewhite3gray22grey78orangered
antiquewhite4gray23grey79orangered1
aquamarinegray24grey80orangered2
aquamarine1gray25grey81orangered3
aquamarine2gray26grey82orangered4
aquamarine3gray27grey83orchid
aquamarine4gray28grey84orchid1
azuregray29grey85orchid2
azure1gray30grey86orchid3
azure2gray31grey87orchid4
azure3gray32grey88palegoldenrod
azure4gray33grey89palegreen
beigegray34grey90palegreen1
bisquegray35grey91palegreen2
bisque1gray36grey92palegreen3
bisque2gray37grey93palegreen4
bisque3gray38grey94paleturquoise
bisque4gray39grey95paleturquoise1
blackgray40grey96paleturquoise2
blanchedalmondgray41grey97paleturquoise3
bluegray42grey98paleturquoise4
blue1gray43grey99palevioletred
blue2gray44grey100palevioletred1
blue3gray45honeydewpalevioletred2
blue4gray46honeydew1palevioletred3
bluevioletgray47honeydew2palevioletred4
browngray48honeydew3papayawhip
brown1gray49honeydew4peachpuff
brown2gray50hotpinkpeachpuff1
brown3gray51hotpink1peachpuff2
brown4gray52hotpink2peachpuff3
burlywoodgray53hotpink3peachpuff4
burlywood1gray54hotpink4peru
burlywood2gray55indianredpink
burlywood3gray56indianred1pink1
burlywood4gray57indianred2pink2
cadetbluegray58indianred3pink3
cadetblue1gray59indianred4pink4
cadetblue2gray60indigoplum
cadetblue3gray61ivoryplum1
cadetblue4gray62ivory1plum2
chartreusegray63ivory2plum3
chartreuse1gray64ivory3plum4
chartreuse2gray65ivory4powderblue
chartreuse3gray66khakipurple
chartreuse4gray67khaki1purple1
chocolategray68khaki2purple2
chocolate1gray69khaki3purple3
chocolate2gray70khaki4purple4
chocolate3gray71lavenderred
chocolate4gray72lavenderblushred1
coralgray73lavenderblush1red2
coral1gray74lavenderblush2red3
coral2gray75lavenderblush3red4
coral3gray76lavenderblush4rosybrown
coral4gray77lawngreenrosybrown1
cornflowerbluegray78lemonchiffonrosybrown2
cornsilkgray79lemonchiffon1rosybrown3
cornsilk1gray80lemonchiffon2rosybrown4
cornsilk2gray81lemonchiffon3royalblue
cornsilk3gray82lemonchiffon4royalblue1
cornsilk4gray83lightblueroyalblue2
crimsongray84lightblue1royalblue3
cyangray85lightblue2royalblue4
cyan1gray86lightblue3saddlebrown
cyan2gray87lightblue4salmon
cyan3gray88lightcoralsalmon1
cyan4gray89lightcyansalmon2
darkgoldenrodgray90lightcyan1salmon3
darkgoldenrod1gray91lightcyan2salmon4
darkgoldenrod2gray92lightcyan3sandybrown
darkgoldenrod3gray93lightcyan4seagreen
darkgoldenrod4gray94lightgoldenrodseagreen1
darkgreengray95lightgoldenrod1seagreen2
darkkhakigray96lightgoldenrod2seagreen3
darkolivegreengray97lightgoldenrod3seagreen4
darkolivegreen1gray98lightgoldenrod4seashell
darkolivegreen2gray99lightgoldenrodyellowseashell1
darkolivegreen3gray100lightgrayseashell2
darkolivegreen4greenlightgreyseashell3
darkorangegreen1lightpinkseashell4
darkorange1green2lightpink1sienna
darkorange2green3lightpink2sienna1
darkorange3green4lightpink3sienna2
darkorange4greenyellowlightpink4sienna3
darkorchidgreylightsalmonsienna4
darkorchid1grey0lightsalmon1skyblue
darkorchid2grey1lightsalmon2skyblue1
darkorchid3grey2lightsalmon3skyblue2
darkorchid4grey3lightsalmon4skyblue3
darksalmongrey4lightseagreenskyblue4
darkseagreengrey5lightskyblueslateblue
darkseagreen1grey6lightskyblue1slateblue1
darkseagreen2grey7lightskyblue2slateblue2
darkseagreen3grey8lightskyblue3slateblue3
darkseagreen4grey9lightskyblue4slateblue4
darkslatebluegrey10lightslateblueslategray
darkslategraygrey11lightslategrayslategray1
darkslategray1grey12lightslategreyslategray2
darkslategray2grey13lightsteelblueslategray3
darkslategray3grey14lightsteelblue1slategray4
darkslategray4grey15lightsteelblue2slategrey
darkslategreygrey16lightsteelblue3snow
darkturquoisegrey17lightsteelblue4snow1
darkvioletgrey18lightyellowsnow2
deeppinkgrey19lightyellow1snow3
deeppink1grey20lightyellow2snow4
deeppink2grey21lightyellow3springgreen
deeppink3grey22lightyellow4springgreen1
deeppink4grey23limegreenspringgreen2
deepskybluegrey24linenspringgreen3
deepskyblue1grey25magentaspringgreen4
deepskyblue2grey26magenta1steelblue
deepskyblue3grey27magenta2steelblue1
deepskyblue4grey28magenta3steelblue2
dimgraygrey29magenta4steelblue3
dimgreygrey30maroonsteelblue4
dodgerbluegrey31maroon1tan
dodgerblue1grey32maroon2tan1
dodgerblue2grey33maroon3tan2
dodgerblue3grey34maroon4tan3
dodgerblue4grey35mediumaquamarinetan4
firebrickgrey36mediumbluethistle
firebrick1grey37mediumorchidthistle1
firebrick2grey38mediumorchid1thistle2
firebrick3grey39mediumorchid2thistle3
firebrick4grey40mediumorchid3thistle4
floralwhitegrey41mediumorchid4tomato
forestgreengrey42mediumpurpletomato1
gainsborogrey43mediumpurple1tomato2
ghostwhitegrey44mediumpurple2tomato3
goldgrey45mediumpurple3tomato4
gold1grey46mediumpurple4transparent
gold2grey47mediumseagreenturquoise
gold3grey48mediumslateblueturquoise1
gold4grey49mediumspringgreenturquoise2
goldenrodgrey50mediumturquoiseturquoise3
goldenrod1grey51mediumvioletredturquoise4
goldenrod2grey52midnightblueviolet
goldenrod3grey53mintcreamvioletred
goldenrod4grey54mistyrosevioletred1
graygrey55mistyrose1violetred2
gray0grey56mistyrose2violetred3
gray1grey57mistyrose3violetred4
gray2grey58mistyrose4wheat
gray3grey59moccasinwheat1
gray4grey60navajowhitewheat2
gray5grey61navajowhite1wheat3
gray6grey62navajowhite2wheat4
gray7grey63navajowhite3white
gray8grey64navajowhite4whitesmoke
gray9grey65navyyellow
gray10grey66navyblueyellow1
gray11grey67oldlaceyellow2
gray12grey68olivedrabyellow3
gray13grey69olivedrab1yellow4
gray14grey70olivedrab2yellowgreen
gray15grey71olivedrab3 
gray16grey72olivedrab4 
gray17grey73orange