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

Overview

Introduction

Platforms

Expansion Storage

Protocols

Key Features

Data Services

Availability

Browser User Interface (BUI)

Command Line Interface (CLI)

User Interface

Browser User Interface (BUI)

Command Line Interface (CLI)

Browsers

Supported Browsers

Tier 1

Tier 2

Unsupported Browsers

Main Window

Overview

Masthead

Navigation

Alerts

Session Annotation

Title Bar

Side Panels and Menu Titles

Main Window Side Panels and Menu Titles

Add Projects

Move Shares

Object Name

Non-Standard BUI Control Primer

Permissions

Editing Share Properties

Viewing List Item Controls

Modal Dialogs

Icons

General Usage

Status

Basic Usage

Networking

Dashboard Thresholds

Analytics

Identity Mapping

Miscellaneous Icons

CLI

CLI Introduction

Logging Into the CLI

Contexts

CLI Contexts

Root Context

Child Contexts

Dynamic Child Contexts

Returning to a Previous Context

Navigating to a Parent Context

Contexts and Tab-Completion

Executing Context-Specific Commands

Uncommitted Contexts

Properties

CLI Properties

Getting Properties

Getting a Single Property Value

Tab Completion

Setting Properties

Committing a Set Property Value

Setting a Property Value with an Implied Commit

Setting a Property to a List of Values

Setting a Property to a Value Containing Special Characters

Immutable Properties

Scripting

Batching Commands

Scripting

The Script Environment

Interacting with the System

The Run Function

The Get Function

The List Function

The Children Function

Generating Output

Dealing with Errors

Automating Access

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

Using Scheduled Workflows

Using the CLI

Coding the Schedule

Example: device type selection

BUI

CLI

Downloading workflows

Viewing workflows

Executing workflows

2.  Status

3.  Configuration

4.  Services

5.  Shares

6.  Analytics

7.  Application Integration

Glossary

Index

Scripting

Batching Commands

The simplest scripting mechanism is to batch appliance shell commands. For example, to automatically take a snapshot called "newsnap" in the project "myproj" and the filesystem "myfs", put the following commands in a file:

shares
select myproj
select myfs
snapshots snapshot newsnap

Then ssh onto the appliance, redirecting standard input to be the file:

% ssh root@dory < myfile.txt

In many shells, you can abbreviate this by using a "here file", where input up to a token is sent to standard input. Following is the above example in terms of a here file:

% '''ssh root@dory << EOF
shares
select myproj
select myfs
snapshots snapshot newsnap
EOF'''

This mechanism is sufficient for the simplest kind of automation, and may be sufficient if wrapped in programmatic logic in a higher-level shell scripting language on a client, but it generally leaves much to be desired.

Scripting

While batching commands is sufficient for the simplest of operations, it can be tedious to wrap in programmatic logic. For example, if you want to get information on the space usage for every share, you must have many different invocations of the CLI, wrapped in a higher level language on the client that parsed the output of specific commands. This results in slow, brittle automation infrastructure. To allow for faster and most robust automation, the appliance has a rich scripting environment based on ECMAScript 3. An ECMAScript tutorial is beyond the scope of this document, but it is a dynamically typed language with a C-like syntax that allows for:

The Script Environment

In the CLI, enter the script environment using the script command:

dory:> script
("." to run)> 

As the script environment prompt, you can input your script, finally entering "." alone on a line to execute it:

dory:> script
("." to run)> for (i = 10; i > 0; i--)
("." to run)>    printf("%d... ", i);
("." to run)> printf("Blastoff!\n");
("." to run)> .
10... 9... 8... 7... 6... 5... 4... 3... 2... 1... Blastoff!

If your script is a single line, you can simply provide it as an argument to the script command, making for an easy way to explore scripting:

dory:> script print("It is now " + new Date())
It is now Tue Oct 14 2009 05:33:01 GMT+0000 (UTC)

Interacting with the System

Of course, scripts are of little utility unless they can interact with the system at large. There are several built-in functions that allow your scripts to interact with the system:

Function
Description
get
Gets the value of the specified property. Note that this function returns the value in native form, e.g. dates are returned as Date objects.
list
Returns an array of tokens corresponding to the dynamic children of the current context.
run
Runs the specified command in the shell, returning any output as a string. Note that if the output contains multiple lines, the returned string will contain embedded newlines.
props
Returns an array of the property names for the current node.
set
Takes two string arguments, setting the specified property to the specified value.
The Run Function

The simplest way for scripts to interact with the larger system is to use the "run" function: it takes a command to run, and returns the output of that command as a string. For example:

dory:> configuration version script dump(run('get boot_time'))
'                     boot_time = 2009-10-12 07:02:17\n'

The built-in dump function dumps the argument out, without expanding any embedded newlines. ECMAScript's string handling facilities can be used to take apart output. For example, splitting the above based on whitespace:

dory:> configuration version script dump(run('get boot_time').split(/\s+/))
[&#39;', 'boot_time', '=', '2009-10-12', '07:02:17', &#39;']
The Get Function

The run function is sufficiently powerful that it may be tempting to rely exclusively on parsing output to get information about the system -- but this has the decided disadvantage that it leaves scripts parsing human-readable output that may or may not change in the future. To more robustly gather information about the system, use the built-in "get" function. In the case of the boot_time property, this will return not the string but rather the ECMAScript Date object, allowing the property value to be manipulated programmatically. For example, you might want to use the boot_time property in conjunction with the current time to determine the time since boot:

script
       run('configuration version');
       now = new Date();
       uptime = (now.valueOf() - get('boot_time').valueOf()) / 1000; 
       printf('up %d day%s, %d hour%s, %d minute%s, %d second%s\n',
           d = uptime / 86400, d < 1 || d >= 2 ? 's' : '',
           h = (uptime / 3600) % 24, h < 1 || h >= 2 ? 's': '',
           m = (uptime / 60) % 60, m < 1 || m >= 2 ? 's': '',
           s = uptime % 60, s < 1 || s >= 2 ? 's': '');

Assuming the above is saved as a "uptime.aksh", you could run it this way:

% ssh root@dory < uptime.aksh
Pseudo-terminal will not be allocated because stdin is not a terminal.
Password: 
up 2 days, 10 hours, 47 minutes, 48 seconds

The message about pseudo-terminal allocation is due to the ssh client; the issue that this message refers to can be dealt with by specifying the "-T" option to ssh.

The List Function

In a context with dynamic children, it can be very useful to iterate over those children programmatically. This can be done by using the list function, which returns an array of dynamic children. For example, following is a script that iterates over every share in every project, printing out the amount of space consumed and space available:

script
       run('shares');
       projects = list();

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

               for (j = 0; j < shares.length; j++) {
                       run('select ' + shares[j]);
                       printf("%s/%s %1.64g %1.64g\n", projects[i], shares[j],
                           get('space_data'), get('space_available'));
                       run('cd ..');
               }

               run('cd ..');
       }

Here's the output of running the script, assuming it were saved to a file named "space.aksh":

% ssh root@koi < space.aksh
Password: 
admin/accounts 18432 266617007104
admin/exports 18432 266617007104
admin/primary 18432 266617007104
admin/traffic 18432 266617007104
admin/workflow 18432 266617007104
aleventhal/hw_eng 18432 266617007104
bcantrill/analytx 1073964032 266617007104
bgregg/dashbd 18432 266617007104
bgregg/filesys01 26112 107374156288
bpijewski/access_ctrl 18432 266617007104
...

If one would rather a "pretty printed" (though more difficult to handle programmatically) variant of this, one could directly parse the output of the get command:

script
       run('shares');
       projects = list();

       printf('%-40s %-10s %-10s\n', 'SHARE', 'USED', 'AVAILABLE');

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

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

                       share = projects[i] + '/' + shares[j];
                       used = run('get space_data').split(/\s+/)[3];
                       avail = run('get space_available').split(/\s+/)[3];

                       printf('%-40s %-10s %-10s\n', share, used, avail);
                       run('cd ..');
               }

               run('cd ..');
       }

And here's some of the output of running this new script, assuming it were named "prettyspace.aksh":

% ssh root@koi < prettyspace.aksh
Password:
SHARE                                    USED       AVAILABLE 
admin/accounts                           18K        248G      
admin/exports                            18K        248G      
admin/primary                            18K        248G      
admin/traffic                            18K        248G      
admin/workflow                           18K        248G      
aleventhal/hw_eng                        18K        248G      
bcantrill/analytx                        1.00G      248G      
bgregg/dashbd                            18K        248G       
bgregg/filesys01                         25.5K      100G      
bpijewski/access_ctrl                    18K        248G      
...
The Children Function

Even in a context with static children, it can be useful to iterate over those children programmatically. This can be done by using the children function, which returns an array of static children. For example, here's a script that iterates over every service, printing out the status of the service:

configuration services
script
       var svcs = children();
       for (var i = 0; i < svcs.length; ++i) {
               run(svcs[i]);
               if (props().length !== 0)
                       printf("%-10s %s\n", svcs[i], get('<status>'));
               run("done");
       }
.

Here's the output of running the script, assuming it were saved to a file named "svcinfo.aksh":

% ssh root@koi < space.aksh
Password: 
cifs       disabled
dns        online
ftp        disabled
http       disabled
identity   online
idmap      online
ipmp       online
iscsi      online
ldap       disabled
ndmp       online
nfs        online
nis        online
ntp        online
scrk       online
sftp       disabled
smtp       online
snmp       disabled
ssh        online
tags       online
vscan      disabled

Generating Output

Reporting state on the system requires generating output. Scripts have several built-in functions made available to them to generate output:

Function
Description
dump
Dumps the specified argument to the terminal, without expanding embedded newlines. Objects will be displayed in a JSON-like format. Useful for debugging.
print
Prints the specified object as a string, followed by a newline. If the object does not have a toString method, it will be printed opaquely.
printf
Like C's printf(3C), prints the specified arguments according to the specified formatting string.

Dealing with Errors

When an error is generated, an exception is thrown. The exception is generally an object that contains the following members:

Exceptions can be caught and handled, or they may be thrown out of the script environment. If a script environment has an uncaught exception, the CLI will display the details. For example:

dory:> script run('not a cmd')
error: uncaught error exception (code EAKSH_BADCMD) in script: invalid command
       "not a cmd" (encountered while attempting to run command "not a cmd")

You could see more details about the exception by catching it and dumping it out:

dory:> script try { run('not a cmd') } catch (err) { dump(err); }
{
   toString: <function>,
   code: 10004,
   message: 'invalid command "not a cmd" (encountered while attempting to
                      run command "not a cmd")'
}

This also allows you to have rich error handling, for example:

#!/usr/bin/ksh -p

ssh -T root@dory <<EOF
script
       try {
               run('shares select default select $1');
       } catch (err) {
               if (err.code == EAKSH_ENTITY_BADSELECT) {
                       printf('error: "$1" is not a share in the ' +
                           'default project\n');
                       exit(1);
               }

               throw (err);
       }

       printf('"default/$1": compression is %s\n', get('compression'));
       exit(0);
EOF

If this script is named "share.ksh" and run with an invalid share name, a rich error message will be generated:

% ksh ./share.ksh bogus
error: "bogus" is not a share in the default project

Automating Access

Whether using batched commands or scripting (or some combination), automated infrastructure requires automated access to the appliance. This should be done by creating users, giving them necessary authorizations, and uploading SSH keys.