Scripting with the Sun ZFS Storage 7000 Appliance
Posted
by Geoff Ongley
on Oracle Blogs
See other posts from Oracle Blogs
or by Geoff Ongley
Published on Tue, 07 Dec 2010 01:28:00 +1000
Indexed on
2010/12/06
16:58 UTC
Read the original article
Hit count: 574
Sun ZFS Storage 7000 Appl
|Sun Storage 7000 scriptin
- Repetitive tasks
- Tasks which work on (or obtain information about) a large number of shares or users
- Tasks which are triggered by an alert threshold (workflows)
- Tasks where you want a only very basic input, but a consistent output (workflows)
For example, I can declare a variable and use it straight away in the middle of my code, for example:
projects=list();
Which makes projects an array of values that are returned from the list(); function (which is usable in most contexts). With this kind of variable, I can do things like:
projects.length (this property on array tells you how many objects are in it, good for for loops etc). Alternatively, I could say:
projects=3;
and now projects is just a simple number.
var myVariable=0;
fishy10:> script("." to run)> run("cd /");("." to run)> run ("shares");("." to run)> var projects;("." to run)> projects=list();("." to run)> printf("Number of projects is: %d\n",projects.length);("." to run)> projects=152;("." to run)> printf("Value of the projects variable as an integer is now: %d\n",projects);("." to run)> .Number of projects is: 7Value of the projects variable as an integer is now: 152
fishy10:> script("." to run)> run("cd /");("." to run)> run ("shares");("." to run)> var projects;("." to run)> projects=list();("." to run)> printf("var projects is of type %s\n",typeof(projects));("." to run)> projects=152;("." to run)> printf("var projects is of type %s\n",typeof(projects));("." to run)> .var projects is of type objectvar projects is of type number
var myArray = new Array();
fishy10:> script("." to run)> testArray = new Array();("." to run)> testArray[0]="This";("." to run)> testArray[1]="is";("." to run)> testArray[2]="just";("." to run)> testArray[3]="a";("." to run)> testArray[4]="test";("." to run)> for (i=0; i < testArray.length; i++)("." to run)> {("." to run)> printf("Array element %d is %s\n",i,testArray[i]);("." to run)> }("." to run)> .Array element 0 is ThisArray element 1 is isArray element 2 is justArray element 3 is aArray element 4 is test
for (variable; test-case; modifier for variable){}
var i=0;var MAX_ITERATIONS=10;
for (i=0; i < MAX_ITERATIONS; i++){// some work to do}
fishy10:> script("." to run)> var i=0;("." to run)> var MAX_ITERATIONS=10;("." to run)> for (i=0; i < MAX_ITERATIONS; i++)("." to run)> {("." to run)> printf("The number is %d\n",i);("." to run)> }("." to run)> .The number is 0The number is 1The number is 2The number is 3The number is 4The number is 5The number is 6The number is 7The number is 8The number is 9
fishy10:> script("." to run)> var isTen=false;("." to run)> var counter=0;("." to run)> while(isTen==false)("." to run)> {("." to run)> if (counter==10)("." to run)> {("." to run)> isTen=true;("." to run)> }("." to run)> printf("Counter is %d\n",counter);("." to run)> counter++;("." to run)> }("." to run)> printf("Loop has ended and Counter is %d\n",counter);("." to run)> .Counter is 0Counter is 1Counter is 2Counter is 3Counter is 4Counter is 5Counter is 6Counter is 7Counter is 8Counter is 9Counter is 10Loop has ended and Counter is 11
fishy10:> script("." to run)> var isTen=false;("." to run)> var counter=0;("." to run)> while(isTen==false)("." to run)> {("." to run)> if (counter==10)("." to run)> {("." to run)> isTen=true;("." to run)> break;("." to run)> }("." to run)> printf("Counter is %d\n",counter);("." to run)> counter++;("." to run)> }("." to run)> printf("Loop has ended and Counter is %d\n", counter);("." to run)> .Counter is 0Counter is 1Counter is 2Counter is 3Counter is 4Counter is 5Counter is 6Counter is 7Counter is 8Counter is 9Loop has ended and Counter is 10
var myVariable=get('property');
var users=list();
for(k=0; k < users.length; k++){user=users[k];run('select ' + user);var username=get('name');var usage=get('usage');var quota=get('quota');...
set('property','value'); // where value is a string, if it was a number, you don't need quotes
For example, we could set the quota on a share as follows (first observing the initial value):
fishy10:shares default/test-geoff> script("." to run)> var currentQuota=get('quota');("." to run)> printf("Current Quota is: %s\n",currentQuota);("." to run)> set('quota','30G');("." to run)> run('commit');("." to run)> currentQuota=get('quota');("." to run)> printf("Current Quota is: %s\n",currentQuota);("." to run)> .Current Quota is: 0Current Quota is: 32212254720
var myVar=list();
fishy10:shares another-project> script("." to run)> var shares=list();("." to run)> for (i=0; i < shares.length; i++)("." to run)> {("." to run)> run('select ' + shares[i]);("." to run)> var mountpoint=get('mountpoint');("." to run)> printf("Share %s discovered, has mountpoint %s\n",shares[i],mountpoint);("." to run)> run('done');("." to run)> }("." to run)> .Share and-another discovered, has mountpoint /export/another-project/and-anotherShare another-share discovered, has mountpoint /export/another-project/another-shareShare bob discovered, has mountpoint /export/another-projectShare more-shares-for-all discovered, has mountpoint /export/another-project/more-shares-for-allShare yep discovered, has mountpoint /export/another-project/yep
function functionName(variable1,variable2,...,variableN){}
function getShares(proj){run('select ' + proj);shares=list();printf("Project: %s\n", proj);for(j=0; j < shares.length; j++){printf("Discovered share: %s\n",shares[i]);}run('done'); // exit selected project}
//
/*
*/
fishy10:> script("." to run)> // This is a test comment("." to run)> printf("doing some work...\n");("." to run)> /* This is a multi-line("." to run)> comment which I will span across("." to run)> three lines in total */("." to run)> printf("doing some more work...\n");("." to run)> .doing some work...doing some more work...
try{// do some work}catch(err) // Catch any error that could occur{// do something here under the error condition}
function getShareQuota(shar) // Get quota for each user of this share{run('select ' + shar);printf(" SHARE: %s\n", shar);try{run('users');printf(" %20s %11s %11s %3s\n","Username","Usage(G)","Quota(G)","Quota(%)");printf(" %20s %11s %11s %4s\n","--------","--------","--------","----");users=list();for(k=0; k < users.length; k++){user=users[k];getUserQuota(user);}run('done'); // exit user context}catch(err){printf(" SKIPPING %s - This is NOT a NFS or CIFs share, not looking for users\n", shar);}run('done'); // done with this share}
- Create scripts on a remote system and run them over ssh
- Create scripts, wrapping them in workflow code, so they are stored on the appliance and can be triggered under certain circumstances (like a threshold being reached)
[geoff@lightning ~] ssh-keygen -t rsa -b 1024Generating public/private rsa key pair.Enter file in which to save the key (/export/home/geoff/.ssh/id_rsa): /export/home/geoff/.ssh/nas_key_rsaEnter passphrase (empty for no passphrase):Enter same passphrase again:Your identification has been saved in /export/home/geoff/.ssh/nas_key_rsa.Your public key has been saved in /export/home/geoff/.ssh/nas_key_rsa.pub.The key fingerprint is:7f:3d:53:f0:2a:5e:8b:2d:94:2a:55:77:66:5c:9b:14 geoff@lightning
[geoff@lightning ~] cat .ssh/nas_key_rsa.pubssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvYfK3RIaAYmMHBOvyhKM41NaSmcgUMC3igPN5gUKJQvSnYmjuWG6CBr1CkF5UcDji7v19jG3qAD5lAMFn+L0CxgRr8TNaAU+hA4/tpAGkjm+dKYSyJgEdMIURweyyfUFXoerweR8AWW5xlovGKEWZTAfvJX9Zqvh8oMQ5UJLUUc= geoff@lightning
AAAAB3NzaC1yc2EAAAABIwAAAIEAvYfK3RIaAYmMHBOvyhKM41NaSmcgUMC3igPN5gUKJQvSnYmjuWG6CBr1CkF5UcDji7v19jG3qAD5lAMFn+L0CxgRr8TNaAU+hA4/tpAGkjm+dKYSyJgEdMIURweyyfUFXoerweR8AWW5xlovGKEWZTAfvJX9Zqvh8oMQ5UJLUUc=
[geoff@lightning ~] ssh [email protected]Password:Last login: Mon Dec 6 17:13:28 2010 from 192.168.0.2fishy10:> configuration usersfishy10:configuration users> select rootfishy10:configuration users root> preferencesfishy10:configuration users root preferences> keys
configuration users select root preferences keysfishy10:>
fishy10:configuration users root preferences keys> createfishy10:configuration users root preferences key (uncommitted)> set type=RSA
fishy10:configuration users root preferences key (uncommitted)> set key="AAAAB3NzaC1yc2EAAAABIwAAAIEAvYfK3RIaAYmMHBOvyhKM41NaSmcgUMC3igPN5gUKJQvSnYmjuWG6CBr1CkF5UcDji7v19jG3qAD5lAMFn+L0CxgRr8TNaAU+hA4/tpAGkjm+dKYSyJgEdMIURweyyfUFXoerweR8AWW5xlovGKEWZTAfvJX9Zqvh8oMQ5UJLUUc="
fishy10:configuration users root preferences key (uncommitted)> set comment="LightningRSAKey"
fishy10:configuration users root preferences key (uncommitted)> commit
fishy10:configuration users root preferences keys> lsKeys:NAME MODIFIED TYPE COMMENTkey-000 2010-10-25 20:56:42 RSA cycloneRSAKeykey-001 2010-12-6 17:44:53 RSA LightningRSAKey
[geoff@lightning ~] cat test.ecma3script// This is a test script, By Geoff Ongley 2010.printf("Testing script remotely over ssh\n");.
[geoff@lightning ~] ssh -i .ssh/nas_key_rsa root@fishy10 < test.ecma3Pseudo-terminal will not be allocated because stdin is not a terminal.Testing script remotely over ssh
script/************************************** Quick and Dirty Quota Check script ** Written By Geoff Ongley ** 25 October 2010 **************************************/function getUserQuota(usr){run('select ' + usr);var username=get('name');var usage=get('usage');var quota=get('quota');var usage_g=usage / 1073741824; // convert bytes to gigabytesvar quota_g=quota / 1073741824; // as abovevar quota_percent=0if (quota > 0){quota_percent=(usage / quota)*(100/1);}printf(" %20s %8.2f %8.2f %d%%\n",username,usage_g,quota_g,quota_percent);run('done'); // done with this selected user}function getShareQuota(shar){//printf("DEBUG: selecting share %s\n", shar);run('select ' + shar);printf(" SHARE: %s\n", shar);try{run('users');printf(" %20s %11s %11s %3s\n","Username","Usage(G)","Quota(G)","Quota(%)");printf(" %20s %11s %11s %4s\n","--------","--------","--------","--------");users=list();for(k=0; k < users.length; k++){user=users[k];getUserQuota(user);}run('done'); // exit user context}catch(err){printf(" SKIPPING %s - This is NOT a NFS or CIFs share, not looking for users\n", shar);}run('done'); // done with this share}function getShares(proj){//printf("DEBUG: selecting project %s\n",proj);run('select ' + proj);shares=list();printf("Project: %s\n", proj);for(j=0; j < shares.length; j++){share=shares[j];getShareQuota(share);}run('done'); // exit selected project}function getProjects(){run('cd /');run('shares');projects=list();for (i=0; i < projects.length; i++){var project=projects[i];getShares(project);}run('done'); // exit context for all projects}getProjects();.
[geoff@lightning ~/FISHWORKS_SCRIPTS] ssh -i ~/.ssh/nas_key_rsa root@fishy10 < get_quota_utilisation.ecma3
Pseudo-terminal will not be allocated because stdin is not a terminal.Project: another-projectSHARE: and-anotherUsername Usage(G) Quota(G) Quota(%)-------- -------- -------- --------nobody 0.00 0.00 0%geoffro 0.05 0.00 0%Billy 0.10 0.00 0%root 0.00 0.00 0%testing-user 0.05 0.00 0%SHARE: another-shareUsername Usage(G) Quota(G) Quota(%)-------- -------- -------- --------root 0.00 0.00 0%nobody 0.00 0.00 0%geoffro 0.05 0.49 9%testing-user 0.05 0.02 249%Billy 0.10 0.29 33%SHARE: bobUsername Usage(G) Quota(G) Quota(%)-------- -------- -------- --------nobody 0.00 0.00 0%root 0.00 0.00 0%SHARE: more-shares-for-allUsername Usage(G) Quota(G) Quota(%)-------- -------- -------- --------Billy 0.10 0.00 0%testing-user 0.05 0.00 0%nobody 0.00 0.00 0%root 0.00 0.00 0%geoffro 0.05 0.00 0%SHARE: yepUsername Usage(G) Quota(G) Quota(%)-------- -------- -------- --------root 0.00 0.00 0%nobody 0.00 0.00 0%Billy 0.10 0.01 999%testing-user 0.05 0.49 9%geoffro 0.05 0.00 0%Project: defaultSHARE: Test-LUNSKIPPING Test-LUN - This is NOT a NFS or CIFs share, not looking for usersSHARE: test-geoffUsername Usage(G) Quota(G) Quota(%)-------- -------- -------- --------geoffro 0.05 0.00 0%root 3.18 10.00 31%uucp 0.00 0.00 0%nobody 0.59 0.49 119%^CKilled by signal 2.
name: A name for this workflowdescription: A Description for the workflowparameters: A set of input parameters (useful when you need user input to execute the workflow)execute: The code, the script itself to execute, which will be function (parameters)
parameters:variableParam1:{
execute: ....};
However, it appears (at least in my experience to date) that the workflow object may only be happy with one function in the execute parameter - either that or I'm doing something wrong. As far as I can tell, after execute: you should only have a basic one function context like so:var workflow = {name: 'Get User Quotas',description: 'Displays Quota Utilisation for each user on each share',execute: function(){// (basic script goes here, minus the "script" at the beginning, and "." at the end)}};
execute: function()
{}
var workflow = {name: 'Get User Quotas',description: 'Displays Quota Utilisation for each user on each share',execute: function () {run('cd /');run('shares');projects=list();for (i=0; i < projects.length; i++){run('select ' + projects[i]);shares=list('filesystem');printf("Project: %s\n", projects[i]);for(j=0; j < shares.length; j++){run('select ' +shares[j]);try{run('users');printf(" SHARE: %s\n", shares[j]);printf(" %20s %11s %11s %3s\n","Username","Usage(G)","Quota(G)","Quota(%)");printf(" %20s %11s %11s %4s\n","--------","--------","--------","-------");users=list();for(k=0; k < users.length; k++){run('select ' + users[k]);username=get('name');usage=get('usage');quota=get('quota');usage_g=usage / 1073741824; // convert bytes to gigabytesquota_g=quota / 1073741824; // as abovequota_percent=0if (quota > 0){quota_percent=(usage / quota)*(100/1);}printf(" %20s %8.2f %8.2f %d%%\n",username,usage_g,quota_g,quota_percent);run('done');}run('done'); // exit user context}catch(err){// printf(" %s is a LUN, Not looking for users\n", shares[j]);}run('done'); // exit selected share context}run('done'); // exit project context}}};
© Oracle Blogs or respective owner