NetApp.rb 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. data/lib/netapp.rb +692 -0
  2. metadata +48 -0
@@ -0,0 +1,692 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # NetApp.rb:
4
+ # * Ruby library for NetApp filer administration via NetApp NMSDK
5
+ # * https://github.com/azet/NetApp.rb
6
+ #
7
+ # LICENSE:
8
+ # MIT License (http://opensource.org/licenses/MIT)
9
+ #
10
+ # AUTHORS:
11
+ # Aaron <azet@azet.org> Zauner
12
+ #
13
+
14
+ # Include NetApp Manageability SDK for Ruby (change name if neccessary)
15
+ $: << File.expand_path(File.dirname(__FILE__) + "/../lib/NMSDK-Ruby")
16
+ require 'NaServer'
17
+
18
+ #
19
+ # "Style is what gives value and currency to thoughts." -- Schopenhauer
20
+ #
21
+
22
+ # connect to filer, assign object
23
+ class Filer
24
+ def initialize(filer, username, password, secure=true, type=filer)
25
+ @@filer = NaServer.new(filer, 1, 17) # specifies API version (1.17)
26
+ if secure
27
+ # connect via SSL/TLS
28
+ @@filer.set_transport_type("HTTPS")
29
+ raise 'insecure connection!' unless @@filer.use_https
30
+ @@filer.set_admin_user(username, password)
31
+ else
32
+ # non-encrypted connection
33
+ @@filer.set_admin_user(username, password)
34
+ end
35
+
36
+ # TODO: implement NaServer::set_server_type for NetApp DFM/Filer
37
+ # TODO: implement different login styles (usr,pwd - cert - ...)
38
+ # see also - NaServer::set_style
39
+ end
40
+ def self.is_secure?
41
+ https = @@filer.use_https
42
+ return true if https
43
+ end
44
+ def self.is_clustered?
45
+ sys_version = @@filer.invoke("system-get-version")
46
+ raise sys_version.results_reason \
47
+ if sys_version.results_status == 'failed'
48
+ return sys_version.child_get_string("version") =~ /Cluster-Mode/ ? true : false
49
+ end
50
+ def self.is_ha?
51
+ cf_status = @@filer.invoke("cf-status")
52
+ return false if cf_status.results_status == 'failed' \
53
+ and cf_status.results_reason == 'monitor not initialiazed'
54
+ raise cf_status.results_reason if cf_status.results_status == 'failed'
55
+ return result = cf_status.child_get_string("is-enabled")
56
+ end
57
+ def self.set_vfiler(vfilername)
58
+ return true if @@filer.set_vfiler(vfilername)
59
+ end
60
+ def self.info
61
+ system_info = @@filer.invoke("system-get-info")
62
+ raise system_info.results_reason \
63
+ if system_info.results_status == 'failed'
64
+ result = {}
65
+ system_info.child_get("system-info").children_get.each do |key|
66
+ result = {
67
+ systemid: key.child_get_string("system-id"),
68
+ systemname: key.child_get_string("system-name"),
69
+ systemmodel: key.child_get_string("system-model"),
70
+ systemmachinetype: key.child_get_string("system-machine-type"),
71
+ systemrev: key.child_get_string("system-revision"),
72
+ systemserialno: key.child_get_string("system-serial-number"),
73
+ vendorid: key.child_get_string("vendor-id"),
74
+ prodtype: key.child_get_string("prod-type"),
75
+ partnersystemid: key.child_get_string("partner-system-id"),
76
+ partnersystemname: key.child_get_string("partner-system-name"),
77
+ partnersystemserialno: key.child_get_string("partner-system-serial-number"),
78
+ backplanepartno: key.child_get_string("backplane-part-number"),
79
+ backplanerev: key.child_get_string("backplane-revision"),
80
+ processorsno: key.child_get_string("number-of-processors"),
81
+ memorysize: key.child_get_string("memory-size"),
82
+ cpuserialno: key.child_get_string("cpu-serial-number"),
83
+ cpurev: key.child_get_string("cpu-revision"),
84
+ cputype: key.child_get_string("cpu-processor-type"),
85
+ cpuid: key.child_get_string("cpu-processor-id"),
86
+ cpupartno: key.child_get_string("cpu-part-number"),
87
+ cpumicrocodeversion: key.child_get_string("cpu-microcode-version"),
88
+ cpufirmwarerel: key.child_get_string("cpu-firmware-release"),
89
+ cpuciobrevid: key.child_get_string("cpu-ciob-revision-id"),
90
+ supportsraidarray: key.child_get_string("supports-raid-array"),
91
+ controlleraddress: key.child_get_string("controller-address"),
92
+ boardtype: key.child_get_string("board-type"),
93
+ boardspeed: key.child_get_string("board-speed")
94
+ }
95
+ end
96
+ return result
97
+ end
98
+ end
99
+
100
+ # function definitions to interface with NetApp filers
101
+ class Aggregate < Filer
102
+ def self.create(aggr, diskcount, raidtype="raid_dp")
103
+ aggr_create = @@filer.invoke("aggr-create",
104
+ "aggregate", aggr,
105
+ "disk-count", diskcount,
106
+ "raid-type", raidtype)
107
+ raise aggr_create.results_reason \
108
+ if aggr_create.results_status == 'failed'
109
+ return true
110
+ end
111
+ def self.purge(aggr)
112
+ aggr_destroy = @@filer.invoke("aggr-destroy",
113
+ "aggregate", aggr)
114
+ raise aggr_destroy.results_reason \
115
+ if aggr_destroy.results_status == 'failed'
116
+ return true
117
+ end
118
+ def self.add(aggr)
119
+ # implement me!
120
+ return false
121
+ end
122
+ def self.online(aggr)
123
+ aggr_online = @@filer.invoke("aggr-online",
124
+ "aggregate", aggr)
125
+ raise aggr_online.results_reason \
126
+ if aggr_online.results_status == 'failed'
127
+ return true
128
+ end
129
+ def self.offline(aggr)
130
+ aggr_offline = @@filer.invoke("aggr-offline",
131
+ "aggregate", aggr)
132
+ raise aggr_offline.results_reason \
133
+ if aggr_offline.results_status == 'failed'
134
+ return true
135
+ end
136
+ def self.rename(aggr, newname)
137
+ aggr_rename = @@filer.invoke("aggr-rename",
138
+ "aggregate", aggr,
139
+ "new-aggregate-name", newname)
140
+ raise aggr_rename.results_reason \
141
+ if aggr_rename.results_status == 'failed'
142
+ return true
143
+ end
144
+ def self.list
145
+ aggr_list_info = @@filer.invoke("aggr-list-info")
146
+ raise aggr_list_info.results_reason \
147
+ if aggr_list_info.results_status == 'failed'
148
+ result = []
149
+ aggr_list_info.child_get("aggregates").children_get.each do |key|
150
+ result << key.child_get_string("name")
151
+ end
152
+ return result
153
+ end
154
+ def self.info(aggr, verbose=true)
155
+ aggr_list_info = @@filer.invoke("aggr-list-info",
156
+ "aggregate", aggr,
157
+ "verbose", verbose)
158
+ raise aggr_list_info.results_reason \
159
+ if aggr_list_info.results_status == 'failed'
160
+ result = {}
161
+ aggr_list_info.child_get("aggregates").children_get.each do |key|
162
+ volumes = []
163
+ key.child_get("volumes").children_get.each { |vol|
164
+ volumes << vol.child_get_string("name")
165
+ }
166
+ plexes = {}
167
+ key.child_get("plexes").children_get.each { |plx|
168
+ plexes[name: plx.child_get_string("name")] = {
169
+ isonline: plx.child_get_string("is-online"),
170
+ isresyncing: plx.child_get_string("is-resyncing"),
171
+ resyncpercentage: plx.child_get_string("resyncing-percentage")
172
+ }
173
+ }
174
+ result = {
175
+ name: key.child_get_string("name"),
176
+ uuid: key.child_get_string("uuid"),
177
+ state: key.child_get_string("state"),
178
+ type: key.child_get_string("type"),
179
+ haslocalroot: key.child_get_string("has-local-root"),
180
+ haspartnerroot: key.child_get_string("has-partner-root"),
181
+ checksumstatus: key.child_get_string("checksum-status"),
182
+ isinconsistent: key.child_get_string("is-inconsistent"),
183
+ sizetotal: key.child_get_string("size-total"),
184
+ sizeused: key.child_get_string("size-used"),
185
+ sizeavail: key.child_get_string("size-available"),
186
+ sizepercentage: key.child_get_string("size-percentage-used"),
187
+ filestotal: key.child_get_string("files-total"),
188
+ filesused: key.child_get_string("files-used"),
189
+ isnaplock: key.child_get_string("is-snaplock"),
190
+ snaplocktype: key.child_get_string("snaplock-type"),
191
+ mirrorstatus: key.child_get_string("mirror-status"),
192
+ raidsize: key.child_get_string("raid-size"),
193
+ raidstatus: key.child_get_string("raid-status"),
194
+ diskcount: key.child_get_string("disk-count"),
195
+ volumecount: key.child_get_string("volume-count"),
196
+ volstripeddvcount: key.child_get_string("volume-count-striped-dv"),
197
+ volstripedmdvcount: key.child_get_string("volume-count-striped-mdv"),
198
+ volumes: volumes,
199
+ plexcount: key.child_get_string("plex-count"),
200
+ plexes: plexes
201
+ }
202
+ end
203
+ return result
204
+ end
205
+ end
206
+
207
+ class Volume < Filer
208
+ def self.create(aggr, volname, size)
209
+ vol_create = @@filer.invoke("volume-create",
210
+ "containing-aggr-name", aggr,
211
+ "volume", volname,
212
+ "size", size)
213
+ raise vol_create.results_reason \
214
+ if vol_create.results_status == 'failed'
215
+ return true
216
+ end
217
+ def self.purge(volname)
218
+ vol_destroy = @@filer.invoke("volume-destroy",
219
+ "name", volname)
220
+ raise vol_destroy.results_reason \
221
+ if vol_destroy.results_status == 'failed'
222
+ return true
223
+ end
224
+ def self.add(volname)
225
+ # implement me!
226
+ return false
227
+ end
228
+ def self.online(volname)
229
+ vol_online = @@filer.invoke("volume-online",
230
+ "name", volname)
231
+ raise vol_online.results_reason \
232
+ if vol_online.results_status == 'failed'
233
+ return true
234
+ end
235
+ def self.offline(volname)
236
+ vol_offline = @@filer.invoke("volume-offline",
237
+ "name", volname)
238
+ raise vol_offline.results_reason \
239
+ if vol_offline.results_status == 'failed'
240
+ return true
241
+ end
242
+ def self.container(volname)
243
+ vol_container = @@filer.invoke("volume-container",
244
+ "volume", volname)
245
+ raise vol_container.results_reason \
246
+ if vol_container.results_status == 'failed'
247
+ return result = vol_container.child_get_string("containing-aggregate")
248
+ end
249
+ def self.rename(volname, newname)
250
+ vol_rename = @@filer.invoke("volume-rename",
251
+ "volume", volname,
252
+ "new-volume-name", newname)
253
+ raise vol_rename.results_reason \
254
+ if vol_rename.results_status == 'failed'
255
+ return true
256
+ end
257
+ def self.list
258
+ vol_list_info = @@filer.invoke("volume-list-info")
259
+ raise vol_list_info.results_reason \
260
+ if vol_list_info.results_status == 'failed'
261
+ result = []
262
+ vol_list_info.child_get("volumes").children_get.each do |key|
263
+ result << key.child_get_string("name")
264
+ end
265
+ return result
266
+ end
267
+ def self.info(volname, verbose=true)
268
+ vol_list_info = @@filer.invoke("volume-list-info",
269
+ "volume", volname,
270
+ "verbose", verbose)
271
+ raise vol_list_info.results_reason \
272
+ if vol_list_info.results_status == 'failed'
273
+ result = {}
274
+ vol_list_info.child_get("volumes").children_get.each do |key|
275
+ plexes = {}
276
+ key.child_get("plexes").children_get.each { |plx|
277
+ plexes[name: plx.child_get_string("name")] = {
278
+ isonline: plx.child_get_string("is-online"),
279
+ isresyncing: plx.child_get_string("is-resyncing"),
280
+ resyncpercentage: plx.child_get_string("resyncing-percentage")
281
+ }
282
+ }
283
+ result = {
284
+ name: key.child_get_string("name"),
285
+ uuid: key.child_get_string("uuid"),
286
+ type: key.child_get_string("type"),
287
+ containingaggr: key.child_get_string("containing-aggregate"),
288
+ sizetotal: key.child_get_string("size-total"),
289
+ sizeused: key.child_get_string("size-used"),
290
+ sizeavail: key.child_get_string("size-available"),
291
+ percentageused: key.child_get_string("percentage-used"),
292
+ filestotal: key.child_get_string("files-total"),
293
+ filesused: key.child_get_string("files-used"),
294
+ cloneparent: key.child_get_string("clone-parent"),
295
+ clonechildren: key.child_get_string("clone-children"),
296
+ ischecksumenabled: key.child_get_string("is-checksum-enabled"),
297
+ checksumstyle: key.child_get_string("checksum-style"),
298
+ compression: key.child_get_string("compression"),
299
+ isinconsistent: key.child_get_string("is-inconsistent"),
300
+ isinvalid: key.child_get_string("is-invalid"),
301
+ isunrecoverable: key.child_get_string("is-unrecoverable"),
302
+ iswraparound: key.child_get_string("is-wraparound"),
303
+ issnaplock: key.child_get_string("is-snaplock"),
304
+ expirydate: key.child_get_string("expiry-date"),
305
+ mirrorstatus: key.child_get_string("mirror-status"),
306
+ raidsize: key.child_get_string("raid-size"),
307
+ raidstatus: key.child_get_string("raid-status"),
308
+ owningvfiler: key.child_get_string("owning-vfiler"),
309
+ quotainit: key.child_get_string("quota-init"),
310
+ remotelocation: key.child_get_string("remote-location"),
311
+ reserve: key.child_get_string("reserve"),
312
+ reserverequired: key.child_get_string("reserve-required"),
313
+ reserveused: key.child_get_string("reserve-used"),
314
+ reservedusedact: key.child_get_string("reserve-used-actual"),
315
+ snaplocktype: key.child_get_string("snaplock-type"),
316
+ snapshotblkreserved: key.child_get_string("snapshot-blocks-reserved"),
317
+ snapshotperreserved: key.child_get_string("snapshot-percent-reserved"),
318
+ spacereserveenabled: key.child_get_string("space-reserve-enabled"),
319
+ spacereserve: key.child_get_string("space-reserve"),
320
+ diskcount: key.child_get_string("disk-count"),
321
+ plexcount: key.child_get_string("plex-count"),
322
+ plexes: plexes
323
+ # add SIS and snaplock data
324
+ }
325
+ end
326
+ return result
327
+ end
328
+ def self.size(volname)
329
+ vol_size = @@filer.invoke("volume-size",
330
+ "volume", volname)
331
+ raise vol_size.results_reason \
332
+ if vol_size.results_status == 'failed'
333
+ return result = vol_size.child_get_string("volume-size")
334
+ end
335
+ def self.resize(volname, newsize)
336
+ vol_resize = @@filer.invoke("volume-size",
337
+ "volume", volname,
338
+ "new-size", newsize)
339
+ raise vol_resize.results_reason \
340
+ if vol_resize.results_status == 'failed'
341
+ return true
342
+ end
343
+ # TODO:
344
+ # implement volume-move-*
345
+ end
346
+
347
+ class Snapshot < Filer
348
+ def self.create(name, volname)
349
+ snapshot_create = @@filer.invoke("snapshot-create",
350
+ "snapshot", name,
351
+ "volume", volname)
352
+ raise snapshot_create.results_reason \
353
+ if snapshot_create.results_status == 'failed'
354
+ return true
355
+ end
356
+ def self.purge(name, volname)
357
+ snapshot_delete = @@filer.invoke("snapshot-delete",
358
+ "snapshot", name,
359
+ "volume", volname)
360
+ raise snapshot_delete.results_reason \
361
+ if snapshot_delete.results_status == 'failed'
362
+ return true
363
+ end
364
+ def self.rename(volume, name, newname)
365
+ snapshot_rename = @@filer.invoke("snapshot-rename",
366
+ "volume", volname,
367
+ "current-name", name,
368
+ "new-name", newname)
369
+ raise snapshot_rename.results_reason \
370
+ if snapshot_rename.results_status == 'failed'
371
+ return true
372
+ end
373
+ def self.delta(snap1, snap2, volname)
374
+ snapshot_delta = @@filer.invoke("snapshot-delta-info",
375
+ "volume", volname,
376
+ "snapshot1", snap1,
377
+ "snapshot2", snap2)
378
+ raise snapshot_delta.results_reason \
379
+ if snapshot_delta.results_status == 'failed'
380
+ result = {}
381
+ return result = {
382
+ consumedsize: snapshot_delta.child_get_string("consumed-size"),
383
+ elapsedtime: snapshot_delta.child_get_string("elapsed-time")
384
+ }
385
+ end
386
+ def self.delta_to_volume(snap, volname)
387
+ snapshot_delta = @@filer.invoke("snapshot-delta-info",
388
+ "volume", volname,
389
+ "snapshot1", snap)
390
+ raise snapshot_delta.results_reason \
391
+ if snapshot_delta.results_status == 'failed'
392
+ result = {}
393
+ return result = {
394
+ consumedsize: snapshot_delta.child_get_string("consumed-size"),
395
+ elapsedtime: snapshot_delta.child_get_string("elapsed-time")
396
+ }
397
+ end
398
+ def self.reserve(volname)
399
+ snapshot_reserve = @@filer.invoke("snapshot-get-reserve",
400
+ "volume", volname)
401
+ raise snapshot_reserve.results_reason \
402
+ if snapshot_reserve.results_status == 'failed'
403
+ result = {}
404
+ return result = {
405
+ blocksreserved: snapshot_reserve.child_get_string("blocks-reserved"),
406
+ percentreserved: snapshot_reserve.child_get_string("percent-reserved")
407
+ }
408
+ end
409
+ def self.schedule(volname)
410
+ snapshot_schedule = @@filer.invoke("snapshot-get-schedule",
411
+ "volume", volname)
412
+ raise snapshot_schedule.results_reason \
413
+ if snapshot_schedule.results_status == 'failed'
414
+ result = {}
415
+ return result = {
416
+ days: snapshot_schedule.child_get_string("days"),
417
+ hours: snapshot_schedule.child_get_string("hours"),
418
+ minutes: snapshot_schedule.child_get_string("minutes"),
419
+ weeks: snapshot_schedule.child_get_string("weeks"),
420
+ whichhours: snapshot_schedule.child_get_string("which-hours"),
421
+ whichminutes: snapshot_schedule.child_get_string("which-minutes")
422
+ }
423
+ end
424
+ def self.info(volname)
425
+ snapshot_info = @@filer.invoke("snapshot-list-info",
426
+ "volume", volname)
427
+ raise snapshot_info.results_reason \
428
+ if snapshot_info.results_status == 'failed'
429
+ result = {}
430
+ snapshot_info.child_get("snapshots").children_get.each do |key|
431
+ result = {
432
+ name: key.child_get_string("name"),
433
+ accesstime: key.child_get_string("access-time"),
434
+ busy: key.child_get_string("busy"),
435
+ containslunclones: key.child_get_string("contains-lun-clones"),
436
+ cumpercentageblockstotal: key.child_get_string("cumulative-percentage-of-total-blocks"),
437
+ cumpercentageblocksused: key.child_get_string("cumulative-percentage-of-used-blocks"),
438
+ cumtotal: key.child_get_string("cumulative-total"),
439
+ dependency: key.child_get_string("dependency"),
440
+ percentageblockstotal: key.child_get_string("percentage-of-total-blocks"),
441
+ percentageblocksused: key.child_get_string("percentage-of-used-blocks"),
442
+ total: key.child_get_string("total")
443
+ }
444
+ end
445
+ return result
446
+ end
447
+ end
448
+
449
+ class Qtree < Filer
450
+ def self.create(qtreename, volname)
451
+ qtree_create = @@filer.invoke("qtree-create",
452
+ "qtree", qtreename,
453
+ "volume", volname)
454
+ raise qtree_create.results_reason \
455
+ if qtree_create.results_status == 'failed'
456
+ return true
457
+ end
458
+ def self.purge(qtreename)
459
+ qtree_delete = @@filer.invoke("qtree-delete",
460
+ "qtree", qtreename)
461
+ raise qtree_delete.results_reason \
462
+ if qtree_delete.results_status == 'failed'
463
+ return true
464
+ end
465
+ def self.list
466
+ qtree_list = @@filer.invoke("qtree-list")
467
+ raise qtree_list.results_reason \
468
+ if qtree_list.results_status == 'failed'
469
+ result = {}
470
+ qtree_list.child_get("qtrees").children_get.each do |key|
471
+ result[qtree: key.child_get_string("qtree")] = {
472
+ volume: key.child_get_string("volume")
473
+ }
474
+ end
475
+ return result
476
+ end
477
+ def self.info(volname)
478
+ qtree_list = @@filer.invoke("qtree-list",
479
+ "volume", volname)
480
+ raise qtree_list.results_reason \
481
+ if qtree_list.results_status == 'failed'
482
+ result = {}
483
+ qtree_list.child_get("qtrees").children_get.each do |key|
484
+ result[id: key.child_get_string("id")] = {
485
+ qtree: key.child_get_string("qtree"),
486
+ volume: key.child_get_string("volume"),
487
+ status: key.child_get_string("status"),
488
+ oplocks: key.child_get_string("oplocks"),
489
+ owningvfiler: key.child_get_string("owning-vfiler"),
490
+ securitystyle: key.child_get_string("security-style")
491
+ }
492
+ end
493
+ return result
494
+ end
495
+ end
496
+
497
+ class Quota < Filer
498
+ def self.create(qtreename="", volname, path, quotasize, type)
499
+ quota_create = @@filer.invoke("quota-add-entry",
500
+ "qtree", qtreename,
501
+ "volume", volname,
502
+ "quota-target", path,
503
+ "soft-disk-limit", quotasize,
504
+ "quota-type", type)
505
+ raise quota_create.results_reason \
506
+ if quota_create.results_status == 'failed'
507
+ return true
508
+ end
509
+ def self.purge(qtreename="", volname, path, type)
510
+ quota_delete = @@filer.invoke("quota-delete-entry",
511
+ "qtree", qtreename,
512
+ "volume", volname,
513
+ "quota-target", path,
514
+ "quota-type", type)
515
+ raise quota_delete.results_reason \
516
+ if quota_delete.results_status == 'failed'
517
+ return true
518
+ end
519
+ def self.on(volname)
520
+ quota_on = @@filer.invoke("quota-on",
521
+ "volume", volname)
522
+ raise quota_on.results_reason \
523
+ if quota_on.results_status == 'failed'
524
+ return true
525
+ end
526
+ def self.off(volname)
527
+ quota_off = @@filer.invoke("quota-off",
528
+ "volume", volname)
529
+ raise quota_off.results_reason \
530
+ if quota_off.results_status == 'failed'
531
+ return true
532
+ end
533
+ def self.get_entry(qtreename, volname, path, type)
534
+ quota_get_entry = @@filer.invoke("quota-get-entry",
535
+ "qtree", qtreename,
536
+ "volume", volname,
537
+ "quota-target", path,
538
+ "quota-type", type)
539
+ raise quota_get_entry.results_reason \
540
+ if quota_get_entry.results_status == 'failed'
541
+ return true
542
+ end
543
+ def self.list
544
+ quota_list_entries = @@filer.invoke("quota-list-entries")
545
+ raise quota_list_entries.results_reason \
546
+ if quota_list_entries.results_status == 'failed'
547
+ result = {}
548
+ quota_list_entries.child_get("quota-entries").children_get.each do |key|
549
+ result[qtree: key.child_get_string("qtree")] = {
550
+ line: key.child_get_string("line"),
551
+ volume: key.child_get_string("volume"),
552
+ quotaerror: key.child_get_string("quota-error"),
553
+ quotatarget: key.child_get_string("quota-target"),
554
+ quotatype: key.child_get_string("quota-type")
555
+ }
556
+ end
557
+ end
558
+ def self.status(volname)
559
+ quota_status = @@filer.invoke("quota-status",
560
+ "volume", volname)
561
+ raise quota_status.results_reason \
562
+ if quota_status.results_status == 'failed'
563
+ return result = quota_status.child_get_string("status")
564
+ end
565
+ # TODO: no longer supported in NMSDK API as it seems
566
+ #def self.user(userid, username, usertype)
567
+ # quota_user = @@filer.invoke("quota-user",
568
+ # "quota-user-id", userid,
569
+ # "quota-user-name", username,
570
+ # "quota-user-type", usertype)
571
+ # if quota_user.results_status == 'failed'
572
+ # raise quota_user.results_reason
573
+ # end
574
+ #end
575
+ end
576
+
577
+ class NFS < Filer
578
+ def self.on
579
+ nfs_on = @@filer.invoke("nfs-enable")
580
+ raise nfs_on.results_reason \
581
+ if nfs_on.results_status == 'failed'
582
+ return true
583
+ end
584
+ def self.off
585
+ nfs_off = @@filer.invoke("nfs-disable")
586
+ raise nfs_off.results_reason \
587
+ if nfs_off.results_status == 'failed'
588
+ return true
589
+ end
590
+ def self.add_export(pathname, type, anon=false, nosuid=false, allhosts=false, exports)
591
+ #
592
+ # - type = read-only || read-write || root
593
+ # - exports = string (hostname, IP, subnet [CIDR])
594
+
595
+ raise "unkown argument in type" unless type == "read-only" or \
596
+ type == "read-write" or \
597
+ type == "root"
598
+ raise "empty pathname" if pathname.empty?
599
+
600
+ nfs_exports_rule_info = NaElement.new("exports-rule-info")
601
+ nfs_exports_rule_info.child_add_string("anon", anon) if anon
602
+ nfs_exports_rule_info.child_add_string("nosuid", nosuid) if nosuid
603
+ nfs_exports_rule_info.child_add_string("pathname", pathname)
604
+
605
+ nfs_exports = NaElement.new(type)
606
+ nfs_exports_host = NaElement.new("exports-hostname-info")
607
+ nfs_exports_host.child_add_string("all-hosts", true) if allhosts == true
608
+ nfs_exports_host.child_add_string("name", exports) if exports
609
+
610
+ nfs_exports.child_add(nfs_exports_host)
611
+ nfs_exports_rule_info.child_add(nfs_exports)
612
+
613
+ nfs_rules = NaElement.new("rules")
614
+ nfs_rules.child_add(nfs_exports_rule_info)
615
+
616
+ nfs_exports_invoke = NaElement.new("nfs-exportfs-append-rules")
617
+ nfs_exports_invoke.child_add(nfs_rules)
618
+ nfs_exports_invoke.child_add_string("verbose", true)
619
+
620
+ nfs_add_export = @@filer.invoke_elem(nfs_exports_invoke)
621
+ raise nfs_add_export.results_reason \
622
+ if nfs_add_export.results_status == 'failed'
623
+ return true
624
+ end
625
+ def self.del_export(pathname)
626
+ nfs_exports_path_del = NaElement.new("pathname-info")
627
+ nfs_exports_path_del.child_add_string("name", pathname)
628
+
629
+ nfs_pathnames = NaElement.new("pathnames")
630
+ nfs_pathnames.child_add(nfs_exports_path_del)
631
+
632
+ nfs_exports_invoke = NaElement.new("nfs-exportfs-delete-rules")
633
+ nfs_exports_invoke.child_add(nfs_pathnames)
634
+ nfs_exports_invoke.child_add_string("verbose", true)
635
+
636
+ nfs_del_export = @@filer.invoke_elem(nfs_exports_invoke)
637
+ raise nfs_del_export.results_reason \
638
+ if nfs_del_export.results_status == 'failed'
639
+ return true
640
+ end
641
+ def self.status
642
+ nfs_status = @@filer.invoke("nfs-status")
643
+ raise nfs_status.results_reason \
644
+ if nfs_status.results_status == 'failed'
645
+ return result = {
646
+ isdrained: nfs_status.child_get_string("is-drained"),
647
+ isenabled: nfs_status.child_get_string("is-enabled")
648
+ }
649
+ end
650
+ end
651
+
652
+ class Vfiler < Filer
653
+ def self.create(name, ipaddr, storage)
654
+ vfiler_create = @@filer.invoke("vfiler-create",
655
+ "vfiler", name,
656
+ "ip-addresses", ipaddr,
657
+ "storage-units", storage)
658
+ raise vfiler_create.results_reason \
659
+ if vfiler_create.results_status == 'failed'
660
+ return true
661
+ end
662
+ def self.purge(name)
663
+ vfiler_delete = @@filer.invoke("vfiler-destroy",
664
+ "vfiler", name)
665
+ raise vfiler_delete.results_reason \
666
+ if vfiler_delete.results_status == 'failed'
667
+ return true
668
+ end
669
+ def self.add_storage(name, storage)
670
+ vfiler_add_stroage = @@filer.invoke("vfiler-add-storage",
671
+ "vfiler", name,
672
+ "storage-path", storage)
673
+ raise vfiler_add_stroage.results_reason \
674
+ if vfiler_add_stroage.results_status == 'failed'
675
+ return true
676
+ end
677
+ # vfiler-add-ipaddress, setup, start, stop, migrate, status, list
678
+ end
679
+
680
+ class Diag < Filer
681
+ def self.status
682
+ # "Overall system health (ok,ok-with-suppressed,degraded,
683
+ # unreachable) as determined by the diagnosis framework"
684
+ diag_status = @@filer.invoke("diagnosis-status-get")
685
+ raise diag_status.results_reason \
686
+ if diag_status.results_status == 'failed'
687
+ stat = diag_status.child_get("attributes").children_get
688
+ stat.each { |k| return k.child_get_string("status") }
689
+ end
690
+ end
691
+
692
+ #EOF
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: NetApp.rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Aaron Zauner
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-09-02 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Rubyesque library to interface with NetApp Filers (via NMSDK)
15
+ email: azet@azet.org
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/netapp.rb
21
+ homepage: https://github.com/Gregor-Mendel-Institute/NetApp.rb
22
+ licenses:
23
+ - MIT
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirements:
41
+ - Proprietary NMSDK as provided by NetApp
42
+ rubyforge_project:
43
+ rubygems_version: 1.8.23
44
+ signing_key:
45
+ specification_version: 3
46
+ summary: NetApp.rb
47
+ test_files: []
48
+ has_rdoc: