Chapter 1 Oracle ZFS Storage Appliance Overview
Chapter 3 Initial Configuration
Chapter 4 Network Configuration
Chapter 5 Storage Configuration
Chapter 6 Storage Area Network Configuration
Chapter 8 Setting ZFSSA Preferences
Chapter 10 Cluster Configuration
Chapter 12 Shares, Projects, and Schema
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:
|
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+/)) ['', 'boot_time', '=', '2009-10-12', '07:02:17', '']
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.
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 ...
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]); try { printf("%-10s %s\n", svcs[i], get('<status>')); } catch (err) { } 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
The choices function returns an array of the valid property values for any property for which the set of values is known and enumerable. For example, the following script retrieves the list of all pools on the shares node using the choices function and then iterates all pools to list projects and shares along with the available space.
fmt = '%-40s %-15s %-15s\n'; printf(fmt, 'SHARE', 'USED', 'AVAILABLE'); run('cd /'); run('shares'); pools = choices('pool'); for (p = 0; p < pools.length; p++) { set('pool', pools[p]); 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]); share = pools[p] + ':' + projects[i] + '/' + shares[j]; printf(fmt, share, get('space_data'), get('space_available')); run('cd ..'); } run('cd ..'); } }
Here is the output of running the script:
SHARE USED AVAILABLE pond:projectA/fs1 31744 566196178944 pond:projectA/fs2 31744 566196178944 pond:projectB/lun1 21474836480 587670999040 puddle:deptA/share1 238475 467539219283 puddle:deptB/share1 129564 467539219283 puddle:deptB/share2 19283747 467539219283