|
| 1 | +== ZFS Filesystem bindings for Ruby |
| 2 | + |
| 3 | +LibZfs Ruby is a C library interface to ZFS, Sun's Zettabyte File System, which |
| 4 | +made its debut in OpenSolaris. Actually, Solaris 10 stable release, Open |
| 5 | +Solaris and FreeBSD-8.0 provide stable implementations. |
| 6 | + |
| 7 | +There is also a community driven implementation for Mac OsX, but haven't tried |
| 8 | +to get this library running there yet. |
| 9 | + |
| 10 | +=== A Word of Caution |
| 11 | + |
| 12 | +At this moment, I'm trying to review and test this library into as many as |
| 13 | +possible different versions of Open Solaris. The library hasn't been updated |
| 14 | +since 2007 so, it's perfectly possible to find bugs and, what is worse, cause |
| 15 | +infamous <i>Segmentation faults</i>. |
| 16 | + |
| 17 | +=== Building |
| 18 | + |
| 19 | + rake compile |
| 20 | + |
| 21 | +=== Usage |
| 22 | + |
| 23 | +Previous version have some code intended to manage ZFS Storage Pools creation/deletion. |
| 24 | +However, getting that code working is not too high on the priority list; |
| 25 | +there are other interesting functionalities provided by the ZFS library which |
| 26 | +should be implemented before, like <code>zfs send/recv</code>, since it looks |
| 27 | +like those would be widely used if you compare with Zpool creation. |
| 28 | + |
| 29 | +The idea is to progressively provide a ruby interface for the most frequently used |
| 30 | +subcommands of the <code>zfs</code> and <code>zpool</code> command line utilities. |
| 31 | + |
| 32 | +==== ZFS Storage Pools. |
| 33 | + |
| 34 | +The library provides equivalents for the following <code>zpool</code> subcommands: |
| 35 | + |
| 36 | + zpool list |
| 37 | + zpool get property pool |
| 38 | + zpool set property=value pool |
| 39 | + zpool status pool |
| 40 | + |
| 41 | +Primary usage of the <code>Zpool</code> class might be iteration over the different |
| 42 | +storage pools defined on the system: |
| 43 | + |
| 44 | + [@zlib = LibZfs.new] |
| 45 | + Zpool.each [(@zlib)] do |zpool| |
| 46 | + # access to each zpool instance |
| 47 | + end |
| 48 | + |
| 49 | +One can, anyway, access directly to a given <code>Zpool</code> using its |
| 50 | +<code>name</code>, either as a String or a Ruby Symbol: |
| 51 | + |
| 52 | + [@zlib = LibZfs.new] |
| 53 | + # Use a String: |
| 54 | + @zpool = Zpool.new('pool_name' [, @zlib]) |
| 55 | + # Use a Symbol: |
| 56 | + @zpool = Zpool.new(:pool_name [, @zlib]) |
| 57 | + |
| 58 | +Then, for a given <code>Zpool</code> instance, we can access to any defined |
| 59 | +property using <code>@zpool.get('propname')</code> or set any property by |
| 60 | +using <code>@zpool.get('propname', 'propval')</code>. |
| 61 | + |
| 62 | +Of course, any attempt to set an invalid value for a property, or trying to |
| 63 | +set any value for a read-only property will result in an error. (See |
| 64 | +<code>LibZfs</code> error methods in order to get more info). |
| 65 | + |
| 66 | +Finally, <code>status</code> method will return the current <code>Zpool</code> |
| 67 | +instance status as any of the constants defined at |
| 68 | +<code>ZfsConsts::State::Pool</code>. |
| 69 | + |
| 70 | +==== ZFS Datasets |
| 71 | + |
| 72 | +The library provides equivalents for the following <code>zfs</code> subcommands: |
| 73 | + |
| 74 | + zfs list |
| 75 | + zfs get property dataset/name |
| 76 | + zfs set property=value dataset/name |
| 77 | + zfs destroy dataset/name |
| 78 | + zfs snapshot dataset/name@snap |
| 79 | + zfs rollback dataset/name@snap |
| 80 | + zfs mount dataset/name |
| 81 | + zfs unmount dataset/name |
| 82 | + zfs clone dataset/name@snap another/dataset |
| 83 | + zfs promote another/dataset |
| 84 | + zfs rename dataset/name another/name |
| 85 | + zfs share dataset/name |
| 86 | + zfs unshare dataset/name |
| 87 | + |
| 88 | +We can also iterate over <i>root</i> filesystems using <code>ZFS.each</code>: |
| 89 | + |
| 90 | + [@zlib = LibZfs.new] |
| 91 | + ZFS.each [(@zlib)] do |zfs| |
| 92 | + # access to each root filesystem zfs instance |
| 93 | + end |
| 94 | + |
| 95 | +We can say these <i>root</i> filesystems will be the equivalent for the system |
| 96 | +defined <code>Zpools</code>. Then, for these and any other dataset, we can use |
| 97 | +one of the different iteration methods: |
| 98 | + |
| 99 | + zfs.each_filesystem |
| 100 | + zfs.each_snapshot |
| 101 | + zfs.each_dependent |
| 102 | + |
| 103 | +While it's obvious the type of datasets <code>each_filesystem</code> and |
| 104 | +<code>each_snapshot</code> will iterate over, it's convenient to highlight that |
| 105 | +<code>each_dependent</code> will iterate not only over snapshots and children |
| 106 | +filesystems for the current <code>ZFS</code> instance, but also over |
| 107 | +<i>any associated clone</i>. |
| 108 | + |
| 109 | +For ZFS Datasets is also possible to access directly to any of them instantiating |
| 110 | +the ZFS class with the dataset name and type: |
| 111 | + |
| 112 | + [@zlib = LibZfs.new] |
| 113 | + # Use a String: |
| 114 | + @zfs = ZFS.new('dataset/name', ZfsConsts::Types::FILESYSTEM [, @zlib]) |
| 115 | + |
| 116 | +=== Run the test suite: |
| 117 | + |
| 118 | +In order to be able to run the test suite, need to create some predefined ZFS |
| 119 | +Datasets and Storage Pools: |
| 120 | + |
| 121 | + sudo mkdir /export/vdev |
| 122 | + sudo mkfile 128m /export/vdev/d1 |
| 123 | + sudo zpool create tpool /export/vdev/d1 |
| 124 | + sudo zfs create tpool/home |
| 125 | + sudo zfs create tpool/thome |
| 126 | + sudo zfs snapshot tpool/thome@snap |
| 127 | + sudo zfs clone tpool/thome@snap tpool/thomeclone |
| 128 | + sudo zfs set zfs_rb:sample=test tpool/thome |
| 129 | + sudo zfs create tpool/rollback |
| 130 | + |
| 131 | +Then, you need to run the tests as root with: |
| 132 | + |
| 133 | + sudo rake test |
| 134 | + |
| 135 | +or, you need to run it with a privileged user with all the required profiles, |
| 136 | +including: |
| 137 | + |
| 138 | + ZFS File System Management |
| 139 | + ZFS Storage Management |
| 140 | + File System Management |
| 141 | + SMB Management |
| 142 | + |
| 143 | +by running: |
| 144 | + |
| 145 | + pfexec rake test |
| 146 | + |
| 147 | +=== Tested Systems |
| 148 | + |
| 149 | +I've successfully built and tested the library on the following Open Solaris |
| 150 | +Versions: |
| 151 | + |
| 152 | +- Open Solaris 2009.06 (snv_111b) |
| 153 | +- Open Solaris 2010.02 Preview (snv_117) |
| 154 | +- Open Solaris Development 134 (snv_134) |
| 155 | + |
| 156 | +=== TODO: |
| 157 | + |
| 158 | +* Review arguments given to all the C library functions, perform the appropriated |
| 159 | + type checks, and raise <code>ArgumentError</code> when proceeds. |
| 160 | + |
| 161 | +* Validate Zpool/ZFS properties given to <code>@zfs.set</code>, |
| 162 | + <code>@zfs.get</code>, <code>@zpool.get</code>, <code>@zpool.set</code>. |
| 163 | + |
| 164 | +* Allow <code>@zfs.set</code> to use numerical values too. |
| 165 | + |
| 166 | +* Handle properties of type Integer from <code>@zfs.get_user_prop</code> |
| 167 | + |
| 168 | +* Define all the required library constants, and do not rely into libzfs values |
| 169 | + from ruby. The implementation should try to hide whatever can change on |
| 170 | + libzfs updates. |
| 171 | + |
| 172 | +* Define a set of custom error classes, and raise the appropriated one when |
| 173 | + required. LibZfs error integers shouldn't be available to the end user. |
| 174 | + |
| 175 | +* Implement the equivalents for the following zfs subcommands: |
| 176 | + |
| 177 | + zfs send |
| 178 | + zfs receive |
| 179 | + zfs release |
| 180 | + zfs hold |
| 181 | + |
| 182 | +* Some refactoring: my_zfs_dataset_exists, my_zfs_create and my_zfs_new share a |
| 183 | + lot of code which could be using the same C function. |
0 commit comments