NetApp.rb 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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: