JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Sun ZFS Storage 7000 System Administration Guide
search filter icon
search icon

Document Information

Preface

1.  Introduction

2.  Status

3.  Configuration

Configuration

Introduction

Initial

Initial Configuration

Prerequisites

Summary

BUI

Configuring Management Port

CLI

Performing Initial Configuration with the CLI

Network

Network Configuration

Devices

Datalinks

Interfaces

IP MultiPathing (IPMP)

Performance and Availability

Routing

Routing Entries

Routing Properties

BUI

Configuration

Addresses

Routing

CLI

Tasks

BUI

CLI

Infiniband Upgrade Procedures for Q3.2010

Storage

Introduction

Configure

Verification and Allocation

Profile Configuration

Import

Add

Unconfig

Scrub

Tasks

BUI

SAN

SAN

Terminology

Targets and Initiators

Target and Initiator Groups

BUI

CLI

Terms

SAN Terminology

FC

Fibre Channel

Target Configuration

Clustering Considerations

Initiator Configuration

Switch Considerations

Clustering Considerations

Performance Considerations

Troubleshooting

Queue Overruns

Link-level Issues

BUI

Changing modes of FC ports

Viewing discovered FC ports

Creating FC Initiator Groups

Associating a LUN with an FC initiator group

CLI

Changing modes of FC ports

Viewing discovered FC ports

Creating FC Initiator Groups

Associating a LUN with an FC initiator group

Scripting Aliases for Initiators and Initiator Groups

FCMPxIO

Configuring FC Client Multipathing

Configuring Solaris Initiators

Configuring Windows Initiators

Windows Tunables - Microsoft DSM Details

Configuring Linux Initiators

Configuring VMware ESX Initiators

Troubleshooting

See Also

iSCSI

Introduction

Target Configuration

Clustering Considerations

Initiator Configuration

Planning Client Configuration

Solaris iSCSI/iSER and MPxIO Considerations

Troubleshooting

Observing Performance

BUI

Creating an Analytics Worksheet

CLI

Adding an iSCSI target with an auto-generated IQN

Adding an iSCSI target with a specific IQN and RADIUS authentication

Adding an iSCSI initiator which uses CHAP authentication

Adding an iSCSI target group

Adding an iSCSI initiator group

SRP

Introduction

Target configuration

Clustering Considerations

Initiator configuration

Observing Performance

Multipathing Considerations

Linux with OFED SRP Initiator

OFED 1.5 Issues

VMWare 4.0

Path Selection Plugin (psp)

Storage Array Type Plugin (satp)

VMWare ESX 4.0 Issues

BUI

iSER Target Configuration

SRP Target Configuration

CLI

Users

Introduction

Roles

Authorizations

Properties

Users

Roles

BUI

CLI

Tasks

BUI

CLI

Generic

Preferences

Introduction

BUI

CLI

SSH Public Keys

Alerts

Introduction

Actions

Send Email

Send SNMP trap

Send Syslog Message

Resume/Suspend Dataset

Resume/Suspend Worksheet

Threshold Alerts

BUI

CLI

Tasks

BUI

Workflows

Introduction

Workflow execution context

Workflow parameters

Constrained parameters

Optional parameters

Error Handling

Input validation

Execution auditing

Execution reporting

Versioning

Appliance versioning

Workflow versioning

Workflows as alert actions

Alert action execution context

Auditing alert actions

Example: device type selection

BUI

CLI

Downloading workflows

Viewing workflows

Executing workflows

Cluster

Clustering

Features and Benefits

Drawbacks

Terminology

Subsystem Design

Cluster Interconnect I/O

Resource Management Concepts

Takeover and Failback

Configuration Changes in a Clustered Environment

Clustering Considerations for Storage

Clustering Considerations for Networking

Clustering Considerations for Infiniband

Redundant Path Scenarios

Preventing "Split-Brain" Conditions

Estimating and Reducing Takeover Impact

Setup Procedure

Node Cabling

JBOD Cabling

BUI

Unconfiguring Clustering

4.  Services

5.  Shares

6.  Analytics

7.  Application Integration

Glossary

Index

Workflows

Introduction

A workflow is a script that is uploaded to and managed by the appliance by itself. Workflows can be parameterized and executed in a first-class fashion from either the browser interface or the command line interface. Workflows may also be optionally executed as alert actions or at a designated time. As such, workflows allow for the appliance to extended in ways that capture specific policies and procedures, and can be used (for example) to formally encode best practices for a particular organization or application.

A workflow is embodied in a valid ECMAscript file, containing a single global variable, workflow. This is an Object that must contain at least three members:

Required member
Type
Description
name
String
Name of the workflow
description
String
Description of workflow
execute
Function
Function that executes the workflow

Here is the canonically trivial workflow:

var workflow = {
       name: 'Hello world',
       description: 'Bids a greeting to the world',
       execute: function () { return ('hello world!') }
};

Uploading this workflow will result in a new workflow named "Hello world"; executing the workflow will result in the output "hello world!"

Workflow execution context

Workflows execute asynchronously in the appliance shell, running (by default) as the user executing the workflow. As such, workflows have at their disposal the appliance scripting facility, and may interact with the appliance just as any other instance of the appliance shell. That is, workflows may execute commands, parse output, modify state, and so on. Here is a more complicated example that uses the run function to return the current CPU utilization:

var workflow = {
       name: 'CPU utilization',
       description: 'Displays the current CPU utilization',
       execute: function () {
               run('analytics datasets select name=cpu.utilization');
               cpu = run('csv 1').split('\n')[1].split(',');
               return ('At ' + cpu[0] + ', utilization is ' + cpu[1] + '%');
       }
};
Workflow parameters

Workflows that do not operate on input have limited scope; many workflows need to be parameterized to be useful. This is done by adding a parameters member to the global workflow object. The parameters member is in turn an object that is expected to have a member for each parameter. Each parameters member must have the following members:

Required Member
Type
Description
label
String
Label to adorn input of workflow parameter
type
String
Type of workflow parameter

The type member must be set to one of these types:

Type name
Description
Boolean
A boolean value
ChooseOne
One of a number of specified values
EmailAddress
An e-mail address
File
A file to be transferred to the appliance
Host
A valid host, as either a name or dotted decimal
HostName
A valid hostname
HostPort
A valid, available port
Integer
An integer
NetAddress
A network address
NodeName
A name of a network node
NonNegativeInteger
An integer that is greater than or equal to zero
Number
Any number -- including floating point
Password
A password
Permissions
POSIX permissions
Port
A port number
Size
A size
String
A string
StringList
A list of strings

Based on the specified types, an appropriate input form will be generated upon execution of the workflow. For example, here is a workflow that has two parameters, the name of a business unit (to be used as a project) and the name of a share (to be used as the share name):

var workflow = {
       name: 'New share',
       description: 'Creates a new share in a business unit',
       parameters: {
               name: {
                       label: 'Name of new share',
                       type: 'String'
               },
               unit: {
                       label: 'Business unit',
                       type: 'String'
               }
       },
       execute: function (params) {
               run('shares select ' + params.unit);
               run('filesystem ' + params.name);
               run('commit');
               return ('Created new share "' + params.name + '"');
       }
};

If you upload this workflow and execute it, you will be prompted with a dialog box to fill in the name of the share and the business unit. When the share has been created, a message will be generated indicating as much.

Constrained parameters

For some parameters, one does not wish to allow an arbitrary string, but wishes to rather limit input to one of a small number of alternatives. These parameters should be specified to be of type ChooseOne, and the object containing the parameter must have two additional members:

Required Member
Type
Description
options
Array
An array of strings that specifies the valid options
optionlabels
Array
An array of strings that specifies the labels associated with the options specified in options

Using the ChooseOne parameter type, we can enhance the previous example to limit the business unit to be one of a small number of predefined values:

var workflow = {
    name: 'Create share',
    description: 'Creates a new share in a business unit',
    parameters: {
        name: {
            label: 'Name of new share',
            type: 'String'
        },
        unit: {
            label: 'Business unit',
            type: 'ChooseOne',
            options: [ 'development', 'finance', 'qa', 'sales' ],
            optionlabels: [ 'Development', 'Finance',
                'Quality Assurance', 'Sales/Administrative' ],
        }
    },
    execute: function (params) {
        run('shares select ' + params.unit);
        run('filesystem ' + params.name);
        run('commit');
        return ('Created new share "' + params.name + '"');
    }
};

When this workflow is executed, the unit parameter will not be entered by hand -- it will be selected from the specified list of possible options.

Optional parameters

Some parameters may be considered optional in that the UI should not mandate that these parameters are set to any value to allow execution of the workflow. Such a parameter is denoted via the optional field of the parameters member:

Optional Member
Type
Description
optional
Boolean
If set to true, denotes that the parameter need not be set; the UI may allow the workflow to be executed without a value being specified for the parameter.

If a parameter is optional and is unset, its member in the parameters object passed to the execute function will be set to undefined.

Error Handling

If, in the course of executing a workflow, an error is encountered, an exception will be thrown. If the exception is not caught by the workflow itself (or if the workflow throws an exception that is not otherwise caught), the workflow will fail, and the information regarding the exception will be displayed to the user. To properly handle errors, exceptions should be caught and processed. For example, in the previous example, an attempt to create a share in a non-existent project results in an uncaught exception. This example could be modified to catch the offending error, and create the project in the case that it doesn't exist:

var workflow = {
    name: 'Create share',
    description: 'Creates a new share in a business unit',
    parameters: {
        name: {
            label: 'Name of new share',
            type: 'String'
        },
        unit: {
            label: 'Business unit',
            type: 'ChooseOne',
            options: [ 'development', 'finance', 'qa', 'sales' ],
            optionlabels: [ 'Development', 'Finance',
                'Quality Assurance', 'Sales/Administrative' ],
        }
    },
    execute: function (params) {
        try {
            run('shares select ' + params.unit);
        } catch (err) {
            if (err.code != EAKSH_ENTITY_BADSELECT)
                throw (err);

            /*
             * We haven't yet created a project that corresponds to
             * this business unit; create it now.
             */
            run('shares project ' + params.unit);
            run('commit');
            run('shares select ' + params.unit);
        }

        run('filesystem ' + params.name);
        run('commit');
        return ('Created new share "' + params.name + '"');
    }
};
Input validation

Workflows may optionally validate their input by adding a validate member that takes as a parameter an object that contains the workflow parameters as members. The validate function should return an object where each member is named with the parameter that failed validation, and each member's value is the validation failure message to be displayed to the user. To extend our example to give a crisp error if the user attempts to create an extant share:

var workflow = {
    name: 'Create share',
    description: 'Creates a new share in a business unit',
    parameters: {
        name: {
            label: 'Name of new share',
            type: 'String'
        },
        unit: {
            label: 'Business unit',
            type: 'ChooseOne',
            options: [ 'development', 'finance', 'qa', 'sales' ],
            optionlabels: [ 'Development', 'Finance',
                'Quality Assurance', 'Sales/Administrative' ],
        }
    },
    validate: function (params) {
        try {
            run('shares select ' + params.unit);
            run('select ' + params.name);
        } catch (err) {
            if (err.code == EAKSH_ENTITY_BADSELECT)
                return;
        }

        return ({ name: 'share already exists' });
    },
    execute: function (params) {
        try {
            run('shares select ' + params.unit);
        } catch (err) {
            if (err.code != EAKSH_ENTITY_BADSELECT)
                throw (err);

            /*
             * We haven't yet created a project that corresponds to
             * this business unit; create it now.
             */
            run('shares project ' + params.unit);
            set('mountpoint', '/export/' + params.unit);
            run('commit');
            run('shares select ' + params.unit);
        }

        run('filesystem ' + params.name);
        run('commit');
        return ('Created new share "' + params.name + '"');
    }
};
Execution auditing

Workflows may emit audit records by calling the audit function. The audit function's only argument is a string that is to be placed into the audit log.

Execution reporting

For complicated workflows that may require some time to execute, it can be useful to provide clear progress to the user executing the workflow. To allow the execution of a workflow to be reported in this way, the execute member should return an array of steps. Each array element must contain the following members:

Required Member
Type
Description
step
String
String that denotes the name of the execution step
execute
Function
Function that executes the step of the workflow

As with the execute function on the workflow as a whole, the execute member of each step takes as its argument an object that contains the parameters to the workflow. As an example, here is a workflow that creates a new project, share, and audit record over three steps:

var steps = [ {
    step: 'Checking for associated project',
    execute: function (params) {
        try {
            run('shares select ' + params.unit);
        } catch (err) {
            if (err.code != EAKSH_ENTITY_BADSELECT)
                throw (err);

            /*
             * We haven't yet created a project that corresponds to
             * this business unit; create it now.
             */
            run('shares project ' + params.unit);
            set('mountpoint', '/export/' + params.unit);
            run('commit');
            run('shares select ' + params.unit);
        }
    }
}, {
    step: 'Creating share',
    execute: function (params) {
        run('filesystem ' + params.name);
        run('commit');
    }
}, {
    step: 'Creating audit record',
    execute: function (params) {
        audit('created "' + params.name + '" in "' + params.unit);
    }
} ];

var workflow = {
    name: 'Create share',
    description: 'Creates a new share in a business unit',
    parameters: {
        name: {
            label: 'Name of new share',
            type: 'String'
        },
        unit: {
            label: 'Business unit',
            type: 'ChooseOne',
            options: [ 'development', 'finance', 'qa', 'sales' ],
            optionlabels: [ 'Development', 'Finance',
                'Quality Assurance', 'Sales/Administrative' ],
        }
    },
    validate: function (params) {
        try {
            run('shares select ' + params.unit);
            run('select ' + params.name);
        } catch (err) {
            if (err.code == EAKSH_ENTITY_BADSELECT)
                return;
        }

        return ({ name: 'share already exists' });
    },
    execute: function (params) { return (steps); }
};
Versioning

There are two aspects of versioning with respect to workflows: the first is the expression of the version of the appliance software that the workflow depends on, and the second is the expression of the version of the workflow itself. Versioning is expressed through two optional members to the workflow:

Optional Member
Type
Description
required
String
The minimum version of the appliance software required to run this workflow, including the minimum year, month, day, build and branch.
version
String
Version of this workflow, in dotted decimal (major.minor.micro) form.
Appliance versioning

To express a minimally required version of the appliance software, add the optional required field to your workflow. The appliance is versioned in terms of the year, month and day on which the software was built, followed by a build number and then a branch number, expressed as "year.month.day.build-branch". For example "2009.04.10,12-0" would be the twelfth build of the software originally build on April 10th, 2009. To get the version of the current appliance kit software, run the "configuration version get version" CLI command, or look at the "Version" field in the system view in the BUI. Here's an example of using the required field:

var workflow = {
    name: 'Configure FC',
    description: 'Configures fibre channel target groups',
        required: '2009.12.25,1-0',
        ...

If a workflow requires a version of software that is newer than the version loaded on the appliance, the attempt to upload the workflow will fail with a message explaining the mismatch.

Workflow versioning

In addition to specifying the required version of the appliance software, workflows themselves may be versioned with the version field. This string denotes the major, minor and micro numbers of the workflow version, and allows multiple versions of the same workflow to exist on the machine. When uploading a workflow, any compatible, older versions of the same workflow are deleted. A workflow is deemed to be compatible if it has the same major number, and a workflow is considered to be older if it has a lower version number. Therefore, uploading a workflow with a version of "2.1" will remove the same workflow with version "2.0" (or version "2.0.1") but not "1.2" or "0.1".

Workflows as alert actions

Workflows may be optionally executed as alert actions. To allow a workflow to be eligible as an alert action, its alert action must be set to true.

Alert action execution context

When executed as alert actions, workflows assume the identity of the user that created them. For this reason, any workflow that is to be eligible as an alert action must set setid to true. Alert actions have a single object parameter that has the following members:

Required Member
Type
Description
class
String
The class of the alert.
code
String
The code of the alert.
items
Object
An object describing the alert.
timestamp
Date
Time of alert.

The items member of the parameters object has the following members:

Required Member
Type
Description
url
String
The URL of the web page describing the alert
action
String
The action that should be taken by the user in response to the alert.
impact
String
The impact of the event that precipitated the alert.
description
String
A human-readable string describing the alert.
severity
String
The severity of the event that precipitated the alert.
Auditing alert actions

Workflows executing as alert actions may use the audit function to generate audit log entries. It is recommended that any relevant debugging information be generated to the audit log via the audit function. For example, here is a workflow that executes failover if in the clustered state -- but audits any failure to reboot:

var workflow = {
       name: 'Failover',
       description: 'Fail the node over to its clustered peer',
       alert: true,
       setid: true,
       execute: function (params) {
               /*
                * To failover, we first confirm that clustering is configured
                * and that we are in the clustered state.  We then reboot,
                * which will force our peer to takeover.  Note that we're
                * being very conservative by only rebooting if in the
                * AKCS_CLUSTERED state:  there are other states in which it
                * may well be valid to failback (e.g., we are in AKCS_OWNER,
                * and our peer is AKCS_STRIPPED), but those states may also
                * indicate aberrent operation, and we therefore refuse to
                * failback.  (Even in an active/passive clustered config, a
                * FAILBACK should always be performed to transition the
                * cluster peers from OWNER/STRIPPED to CLUSTERED/CLUSTERED.)
                */
               var uuid = params.uuid;
               var clustered = 'AKCS_CLUSTERED';

               audit('attempting failover in response to alert ' + uuid);

               try {
                       run('configuration cluster');
               } catch (err) {
                       audit('could not get clustered state; aborting');
                       return;
               }

               if ((state = get('state')) != clustered) {
                       audit('state is ' + state + '; aborting');
                       return;
               }

               if ((state = get('peer_state')) != clustered) {
                       audit('peer state is ' + state + '; aborting');
                       return;
               }

               run('cd /');
               run('confirm maintenance system reboot');
       }
};
Example: device type selection

Here is an example workflow that creates a worksheet based on a specified drive type:

var steps = [ {
    step: 'Checking for existing worksheet',
    execute: function (params) {
        /*
         * In this step, we're going to see if the worksheet that
         * we're going to create already exists.  If the worksheet
         * already exists, we blow it away if the user has indicated
         * that they desire this behavior.  Note that we store our
         * derived worksheet name with the parameters, even though
         * it is not a parameter per se; this is explicitly allowed,
         * and it allows us to build state in one step that is
         * processed in another without requiring additional global
         * variables.
         */
        params.worksheet = 'Drilling down on ' + params.type + ' disks';

        try {
            run('analytics worksheets select name="' +
                params.worksheet + '"');

            if (params.overwrite) {
                run('confirm destroy');
                return;
            }
                
            throw ('Worksheet called "' + params.worksheet +
                '" already exists!');
        } catch (err) {
            if (err.code != EAKSH_ENTITY_BADSELECT)
                throw (err);
        }
    }
}, {
    step: 'Finding disks of specified type',
    execute: function (params) {
        /*
         * In this step, we will iterate over all chassis, and for
         * each chassis iterates over all disks in the chassis,
         * looking for disks that match the specified type.
         */
        var chassis, name, disks;
        var i, j;

        run('cd /');
        run('maintenance hardware');

        chassis = list();
        params.disks = [];

        for (i = 0; i < chassis.length; i++) {
            run('select ' + chassis[i]);

            name = get('name');
            run('select disk');
            disks = list();

            for (j = 0; j < disks.length; j++) {
                run('select ' + disks[j]);

                if (get('use') == params.type) {
                    params.disks.push(name + '/' +
                        get('label'));
                }

                run('cd ..');
            }

            run('cd ../..');
        }

        if (params.disks.length === 0)
            throw ('No ' + params.type + ' disks found');
        run('cd /');
    }
}, {
    step: 'Creating worksheet',
    execute: function (params) {
        /*
         * In this step, we're ready to actually create the worksheet
         * itself:  we have the disks of the specified type and
         * we know that we can create the worksheet.  Note that we
         * create several datasets:  first, I/O bytes broken down
         * by disk, with each disk of the specified type highlighted
         * as a drilldown.  Then, we create a separate dataset for
         * each disk of the specified type.  Finally, note that we
         * aren't saving the datasets -- we'll let the user do that
         * from the created worksheet if they so desire.  (It would
         * be straightforward to add a boolean parameter to this
         * workflow that allows that last behavior to be optionally
         * changed.)
         */
        var disks = [], i;

        run('analytics worksheets');
        run('create "' + params.worksheet + '"');
        run('select name="' + params.worksheet + '"');
        run('dataset');
        run('set name=io.bytes[disk]');

        for (i = 0; i < params.disks.length; i++)
            disks.push('"' + params.disks[i] + '"');

        run('set drilldowns=' + disks.join(','));
        run('commit');

        for (i = 0; i < params.disks.length; i++) {
            run('dataset');
            run('set name="io.bytes[disk=' +
                params.disks[i] + ']"');
            run('commit');
        }
    }
} ];

var workflow = {
    name: 'Disk drilldown',
    description: 'Creates a worksheet that drills down on system, ' +
        'cache, or log devices',
    parameters: {
        type: {
            label: 'Create a new worksheet drilling down on',
            type: 'ChooseOne',
            options: [ 'cache', 'log', 'system' ],
            optionlabels: [ 'Cache', 'Log', 'System' ]
        },
        overwrite: {
            label: 'Overwrite the worksheet if it exists',
            type: 'Boolean'
        }
    },
    execute: function (params) { return (steps); }
};

BUI

Workflows are uploaded to the appliance by clicking on the plus icon, and they are executed by clicking on the row specifying the workflow.

CLI

Workflows are manipulated in the maintenance workflows section of the CLI.

Downloading workflows

Workflows are downloaded to the appliance via the download command, which is similar to the mechanism used for software updates:

dory:maintenance workflows> download
dory:maintenance workflows download (uncommitted)> get
                          url = (unset)
                         user = (unset)
                     password = (unset)

You must set the "url" property to be a valid URL for the workflow. This may be either local to your network or over the internet. The URL can be either HTTP (beginning with "http://") or FTP (beginning with "ftp://"). If user authentication is required, it may be a part of the URL (e.g. "ftp://myusername:mypasswd@myserver/export/foo"), or you may leave the username and password out of the URL and instead set the user and password properties.

dory:maintenance workflows download (uncommitted)> set url=
   ftp://foo/example1.akwf
                          url = ftp://foo/example1.akwf
dory:maintenance workflows download (uncommitted)> set user=bmc
                         user = bmc
dory:maintenance workflows download (uncommitted)> set password
Enter password: 
                     password = ********
dory:maintenance workflows download (uncommitted)> commit
Transferred 138 of 138 (100%) ... done
Viewing workflows

To list workflows, use the list command from the maintenance workflows context:

dory:maintenance workflows> list
WORKFLOW     NAME                 OWNER      SETID ORIGIN              
workflow-000 Hello world          root       false <local>             

To select a workflow, use the select command:

dory:maintenance workflows> select workflow-000 
dory:maintenance workflow-000>

To get a workflow's properties, use the get command from within the context of the selected workflow:

dory:maintenance workflow-000> get
                         name = Hello world
                  description = Bids a greeting to the world
                        owner = root
                       origin = <local>
                        setid = false
                         alert = false
               scheduled = false
Executing workflows

To execute a workflow, use the execute command from within the context of the selected workflow. If the workflow takes no parameters, it will simply execute:

dory:maintenance workflow-000> execute 
hello world!

If the workflow takes parameters, the context will become a captive context in which parameters must be specified:

dory:maintenance workflow-000> execute 
dory:maintenance workflow-000 execute (uncommitted)> get
                         type = (unset)
                    overwrite = (unset)

Any attempt to commit the execution of the workflow without first setting the requisite parameters will result in an explicit failure:

dory:maintenance workflow-000 execute (uncommitted)> commit
error: cannot execute workflow without setting property "type"

To execute the workflow, set the specified parameters, and then use the commit command:

dory:maintenance workflow-000 execute (uncommitted)> set type=system 
                         type = system
dory:maintenance workflow-000 execute (uncommitted)> set overwrite=true
                    overwrite = true
dory:maintenance workflow-000 execute (uncommitted)> commit

If the workflow has specified steps, those steps will be displayed via the CLI, e.g.:

dory:maintenance workflow-000 execute (uncommitted)> commit
Checking for existing worksheet ... done
Finding disks of specified type ... done
Creating worksheet ... done