haveapi-fs 0.1.0

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 (89) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -0
  3. data/CHANGELOG +2 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +338 -0
  7. data/Rakefile +1 -0
  8. data/assets/css/bootstrap.min.css +6 -0
  9. data/assets/css/local.css +11 -0
  10. data/bin/haveapi-fs +5 -0
  11. data/haveapi-fs.gemspec +30 -0
  12. data/lib/core_ext/string.rb +9 -0
  13. data/lib/haveapi/fs/auth/base.rb +56 -0
  14. data/lib/haveapi/fs/auth/basic.rb +29 -0
  15. data/lib/haveapi/fs/auth/noauth.rb +9 -0
  16. data/lib/haveapi/fs/auth/token.rb +39 -0
  17. data/lib/haveapi/fs/cache.rb +71 -0
  18. data/lib/haveapi/fs/cleaner.rb +56 -0
  19. data/lib/haveapi/fs/component.rb +237 -0
  20. data/lib/haveapi/fs/components/action_dir.rb +106 -0
  21. data/lib/haveapi/fs/components/action_errors.rb +49 -0
  22. data/lib/haveapi/fs/components/action_exec.rb +12 -0
  23. data/lib/haveapi/fs/components/action_exec_edit.rb +90 -0
  24. data/lib/haveapi/fs/components/action_input.rb +40 -0
  25. data/lib/haveapi/fs/components/action_message.rb +19 -0
  26. data/lib/haveapi/fs/components/action_output.rb +79 -0
  27. data/lib/haveapi/fs/components/action_status.rb +32 -0
  28. data/lib/haveapi/fs/components/cache_stats.rb +19 -0
  29. data/lib/haveapi/fs/components/component_list.rb +24 -0
  30. data/lib/haveapi/fs/components/create_action_dir.rb +15 -0
  31. data/lib/haveapi/fs/components/delete_action_dir.rb +22 -0
  32. data/lib/haveapi/fs/components/directory.rb +45 -0
  33. data/lib/haveapi/fs/components/directory_reset.rb +8 -0
  34. data/lib/haveapi/fs/components/executable.rb +75 -0
  35. data/lib/haveapi/fs/components/file.rb +43 -0
  36. data/lib/haveapi/fs/components/groff_help_file.rb +9 -0
  37. data/lib/haveapi/fs/components/help_file.rb +28 -0
  38. data/lib/haveapi/fs/components/html_help_file.rb +24 -0
  39. data/lib/haveapi/fs/components/index_filter.rb +63 -0
  40. data/lib/haveapi/fs/components/info_files.rb +19 -0
  41. data/lib/haveapi/fs/components/instance_create.rb +20 -0
  42. data/lib/haveapi/fs/components/instance_edit.rb +49 -0
  43. data/lib/haveapi/fs/components/list_item.rb +28 -0
  44. data/lib/haveapi/fs/components/md_help_file.rb +24 -0
  45. data/lib/haveapi/fs/components/meta_dir.rb +42 -0
  46. data/lib/haveapi/fs/components/meta_file.rb +21 -0
  47. data/lib/haveapi/fs/components/parameter.rb +132 -0
  48. data/lib/haveapi/fs/components/pry.rb +9 -0
  49. data/lib/haveapi/fs/components/remote_control_file.rb +92 -0
  50. data/lib/haveapi/fs/components/resource_action_dir.rb +72 -0
  51. data/lib/haveapi/fs/components/resource_dir.rb +161 -0
  52. data/lib/haveapi/fs/components/resource_id.rb +15 -0
  53. data/lib/haveapi/fs/components/resource_instance_dir.rb +146 -0
  54. data/lib/haveapi/fs/components/rfuse_check.rb +3 -0
  55. data/lib/haveapi/fs/components/root.rb +75 -0
  56. data/lib/haveapi/fs/components/save_instance.rb +11 -0
  57. data/lib/haveapi/fs/components/unsaved_list.rb +24 -0
  58. data/lib/haveapi/fs/components/update_action_dir.rb +31 -0
  59. data/lib/haveapi/fs/context.rb +43 -0
  60. data/lib/haveapi/fs/exceptions.rb +0 -0
  61. data/lib/haveapi/fs/factory.rb +59 -0
  62. data/lib/haveapi/fs/fs.rb +198 -0
  63. data/lib/haveapi/fs/help.rb +91 -0
  64. data/lib/haveapi/fs/main.rb +134 -0
  65. data/lib/haveapi/fs/remote_control.rb +29 -0
  66. data/lib/haveapi/fs/version.rb +5 -0
  67. data/lib/haveapi/fs/worker.rb +77 -0
  68. data/lib/haveapi/fs.rb +65 -0
  69. data/templates/help/html/action_dir.erb +33 -0
  70. data/templates/help/html/action_errors.erb +4 -0
  71. data/templates/help/html/action_input.erb +40 -0
  72. data/templates/help/html/action_output.erb +21 -0
  73. data/templates/help/html/index_filter.erb +16 -0
  74. data/templates/help/html/layout.erb +45 -0
  75. data/templates/help/html/resource_action_dir.erb +18 -0
  76. data/templates/help/html/resource_dir.erb +18 -0
  77. data/templates/help/html/resource_instance_dir.erb +64 -0
  78. data/templates/help/html/root.erb +42 -0
  79. data/templates/help/md/action_dir.erb +29 -0
  80. data/templates/help/md/action_errors.erb +2 -0
  81. data/templates/help/md/action_input.erb +23 -0
  82. data/templates/help/md/action_output.erb +11 -0
  83. data/templates/help/md/index_filter.erb +11 -0
  84. data/templates/help/md/layout.erb +14 -0
  85. data/templates/help/md/resource_action_dir.erb +10 -0
  86. data/templates/help/md/resource_dir.erb +15 -0
  87. data/templates/help/md/resource_instance_dir.erb +42 -0
  88. data/templates/help/md/root.erb +34 -0
  89. metadata +231 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6a14a50210ec4ce355b9ecc5dae75ea593a86036
4
+ data.tar.gz: dac3cc874105f07b4ebae90e9b9642f4c1640979
5
+ SHA512:
6
+ metadata.gz: 7c671e57fc944d0b69bb3e965302250931bfb5fd3c2e79a131bd4e3fba0bf0ed96b87966f40bf7606af6ff050a050fc55b980db26c6d3dd42c888034c6515188
7
+ data.tar.gz: 19e2183b8864263c8efe4499d64854e739aca10169ad8f952b5ac1a6c02dd0ef637a4bc24d3aa8d3dcd2b0a7c377f9b20d30ba783de2f10cf34945ef3f7b6148
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --files 'lib/**/*.rb' --output-dir=html_doc --markup markdown
data/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+ * Mon Apr 18 2016 - version 0.1.0
2
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Jakub Skokan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,338 @@
1
+ HaveAPI Filesystem
2
+ ==================
3
+ `haveapi-fs` is a virtual read-write file system created using FUSE. It works
4
+ with any API based on [HaveAPI](https://github.com/vpsfreecz/haveapi) and
5
+ allows it to be browsed and interacted with as directories and files. The file
6
+ system can be easily extended to add custom directories/files or modify
7
+ behaviour for your API's needs.
8
+
9
+ ## Requirements
10
+ FUSE has to be enabled in kernel and userspace utilities installed, e.g. on
11
+ Debian:
12
+
13
+ $ apt-get install fuse libfuse-dev
14
+
15
+ ## Installation
16
+
17
+ $ gem install haveapi-fs
18
+
19
+ ## Usage
20
+
21
+ $ haveapi-fs -h
22
+ Usage:
23
+ haveapi-fs api_url mountpoint [-h] [-d] [-o [opt,optkey=value,...]]
24
+
25
+ Fuse options: (2.9)
26
+ -h help - print this help output
27
+ -d |-o debug enable internal FUSE debug output
28
+
29
+ Filesystem options:
30
+ version=VERSION API version to use
31
+ auth_method=METHOD Authentication method (basic, token, noauth)
32
+ user Username
33
+ password Password
34
+ token Authentication token
35
+ nodaemonize Stay in the foreground
36
+ log Enable logging while daemonized
37
+ index_limit=LIMIT Limit number of objects in resource directory
38
+
39
+ ## `/etc/fstab` entry
40
+
41
+ There are two ways in which `haveapi-fs` can be added to `/etc/fstab`. Both
42
+ require that the `haveapi-fs` executable is in `$PATH`. The first approach is
43
+ to use `mount.fuse`:
44
+
45
+ # <fs> <mountpoint> <type> <opts> <dump/pass>
46
+ haveapi-fs#https://api.domain.tld /mnt/api.domain.tld fuse user 0 0
47
+
48
+ The other way is to link `/sbin/mount.haveapi-fs` to `haveapi-fs`, e.g.:
49
+
50
+ $ ln -s `which haveapi-fs` /sbin/mount.haveapi-fs
51
+
52
+ Then we can use filesystem type `haveapi-fs` in fstab directly:
53
+
54
+ # <fs> <mountpoint> <type> <opts> <dump/pass>
55
+ https://api.domain.tld /mnt/api.domain.tld haveapi-fs user 0 0
56
+
57
+ ## Example
58
+ The following example uses [vpsadmin-api](https://github.com/vpsfreecz/vpsadmin-api),
59
+ which requires users to be authenticated.
60
+
61
+ `haveapi-fs` supports all available authentication methods, it defaults to
62
+ HTTP basic and it will prompt the user to input credentials, if they are not
63
+ supplied as options using `-o`.
64
+
65
+ $ haveapi-fs https://api.vpsfree.cz /mnt/api.vpsfree.cz
66
+ User name: <username>
67
+ Password:
68
+
69
+ The root directory contains a list of top-level resources in the API
70
+ represented by directories. `help.{html,man,md,txt}` files are to be found in
71
+ every directory in this file system and contain information about the current
72
+ directory.
73
+
74
+ $ cd /mnt/api.vpsfree.cz
75
+ $ tree -L 1
76
+ .
77
+ ├── location/
78
+ ├── environment/
79
+ ├── node/
80
+ ├── vps/
81
+ ├── help.html
82
+ ├── help.man
83
+ ├── help.md
84
+ ├── help.txt
85
+ ├── .client_version
86
+ ├── .fs_version
87
+ ├── .protocol_version
88
+ ├── .reset
89
+ └── .unsaved
90
+
91
+ Inside a resource directory we can see the objects themselves as directories
92
+ whose name is their id.
93
+
94
+ $ tree -L 1 vps
95
+ vps
96
+ ├── 198/
97
+ ├── 199/
98
+ ├── 202/
99
+ ├── actions/
100
+ ├── by-environment/
101
+ ├── by-limit/
102
+ ├── by-location/
103
+ ├── by-node/
104
+ ├── by-object_state/
105
+ ├── by-offset/
106
+ ├── by-os_template/
107
+ ├── create.yml
108
+ ├── help.html
109
+ ├── help.man
110
+ ├── help.md
111
+ └── help.txt
112
+
113
+ Directory `actions/` contains resource-level actions like `Index` and `Create`.
114
+ Directories named as `by-<input_param>` represent input parameters of action
115
+ `Index` and serve as a quick way to filter by them, e.g.:
116
+
117
+ $ tree -L 1 vps/by-environment/3/by-node/5
118
+ vps/by-environment/3/by-node/5
119
+ ├── 202/
120
+ ├── actions/
121
+ ├── by-environment/
122
+ ├── by-limit/
123
+ ├── by-location/
124
+ ├── by-node/
125
+ ├── by-object_state/
126
+ ├── by-offset/
127
+ ├── by-os_template/
128
+ ├── create.yml
129
+ ├── help.html
130
+ ├── help.man
131
+ ├── help.md
132
+ └── help.txt
133
+
134
+ Only VPS #202 matches the filters.
135
+
136
+ Object directory contains a list of attributes, instance-level actions and
137
+ subresources. Associated resources can be browsed as directories.
138
+
139
+ $ tree -L 1 vps/199/
140
+ vps/199/
141
+ ├── actions/
142
+ ├── id
143
+ ├── hostname
144
+ ├── node/
145
+ ├── node_id
146
+ ├── os_template/
147
+ ├── os_template_id
148
+ ├── ...
149
+ ├── edit.yml
150
+ ├── help.html
151
+ ├── help.man
152
+ ├── help.md
153
+ ├── help.txt
154
+ └── save
155
+
156
+ Now let's look at the action directory:
157
+
158
+ $ tree -L 1 vps/199/actions/update/
159
+ vps/199/actions/update/
160
+ ├── errors/
161
+ ├── exec
162
+ ├── exec.yml
163
+ ├── help.html
164
+ ├── help.man
165
+ ├── help.md
166
+ ├── help.txt
167
+ ├── input/
168
+ ├── message
169
+ ├── output/
170
+ ├── reset
171
+ └── status
172
+
173
+ On the lowest level, actions are always invoked using file `exec`. All
174
+ executable files can be run in two ways, either write `1` into them or execute
175
+ them, e.g.:
176
+
177
+ $ echo 1 > vps/199/actions/restart/exec
178
+
179
+ is the same as
180
+
181
+ $ ./vps/199/actions/restart/exec
182
+
183
+ The success of this operation can be checked in files `status`, `message` and
184
+ directory `errors`. Use executable file `reset` to reset the state of these
185
+ files.
186
+
187
+ Input and output parameters are accessible as files in directories `input`
188
+ and `output`.
189
+
190
+ ## Authentication
191
+ Authentication method is selected using option `auth_method`. Accepted values
192
+ are `basic`, `token` and `noauth`. If the option is not specified, config file
193
+ of [haveapi-client](https://github.com/vpsfreecz/haveapi-client) is checked,
194
+ otherwise it defaults to HTTP basic.
195
+
196
+ If needed parameters are not provided as options, the program prompts for them
197
+ on stdin.
198
+
199
+ ## Executables
200
+ All executables can be called either by writing `1` to them or executing them.
201
+
202
+ ## Run actions using YAML files
203
+ Resource directory has `create.yml` to create a new instance, instance
204
+ directory has `edit.yml` to update an instance and actions have `exec.yml`.
205
+
206
+ All these files contain a hash of input parameters and their values for
207
+ respective actions. The action is called when this file is saved, closed and
208
+ is not empty.
209
+
210
+ ## Unsaved data
211
+ The filesystem tracks changed and unsaved files and takes care not to lose
212
+ them. Normal directories and files are freed from memory after some period of
213
+ inactivity, but unsaved files are held forever. A list of such files can be
214
+ found in a hidden file `.unsaved` located in every directory. The file always
215
+ contains paths to unsaved files in the current directory and all its
216
+ descendants.
217
+
218
+ To drop these unsaved files, use executable `.reset`, which is also located in
219
+ every directory.
220
+
221
+ ## Access time, modification time and creation time
222
+ Access time is always updated, it is used to decide which directories/files may
223
+ be freed from memory. Components not accessed within the last 10 minutes are
224
+ regularly freed.
225
+
226
+ Modification time is changed only for files representing input parameters or
227
+ instance attributes.
228
+
229
+ Creation time is advertised as the time at which the component (directory/file)
230
+ was created in memory, i.e. for some components that is when they were fetched
231
+ from the API. As of now, components with creation time older than 30 minutes
232
+ are regularly freed from memory to ensure that the files and data you see are
233
+ still actually in the API, or have not been modified.
234
+
235
+ ## Limiting number of fetched objects
236
+ By default, resource dir contains all its objects. For some APIs, it may be
237
+ undesirable, as they may contain too many objects and it is useless and slow to
238
+ fetch them all. For this reason, there is option `index_limit`, e.g.
239
+ `index_limit=2000` to fetch 2000 objects from every resource at most.
240
+
241
+ ## Extending the file system
242
+ Internally, every directory and file is represented by a `Component` object.
243
+ Components are arranged in a tree structure, where directories are branches and
244
+ files are leaves. Any component can be modified or replaced.
245
+
246
+ The following example demonstrates how to add a custom file to an existing
247
+ component.
248
+
249
+ ```ruby
250
+ #!/usr/bin/env ruby
251
+ require 'haveapi/fs'
252
+
253
+ module CustomComponents
254
+ # Extends ResourceInstanceDir and adds file `extended.txt`
255
+ class InstanceDir < HaveAPI::Fs::Components::ResourceInstanceDir
256
+ # If not specified, class name is used as a help file name
257
+ help_file :resource_instance_dir
258
+
259
+ # This method returns directory contents. Return entries from the superclass
260
+ # and add our own file.
261
+ def contents
262
+ super + %w(extended.txt)
263
+ end
264
+
265
+ protected
266
+ # `new_child` is called whenever a path in the file system is accessed for
267
+ # the first time. It returns the class and arguments that will represent
268
+ # a component under `name`.
269
+ #
270
+ # First, we let the superclass to try to find the component. If it does not
271
+ # exist, we check whether it's our custom file.
272
+ def new_child(name)
273
+ if child = super
274
+ child
275
+
276
+ elsif name == :'extended.txt'
277
+ SomeFile
278
+
279
+ else
280
+ nil
281
+ end
282
+ end
283
+ end
284
+
285
+ # Component representing `extended.txt`
286
+ class SomeFile < HaveAPI::Fs::Components::File
287
+ # This method returns file contents. File size is deduced from the return
288
+ # value and access times are managed by the file system by default, so this
289
+ # method is all that is needed. Default permissions make this file
290
+ # read-only.
291
+ def read
292
+ "you have been extended!\n"
293
+ end
294
+ end
295
+ end
296
+
297
+ # Replace ResourceInstanceDir with our InstanceDir in component factory.
298
+ # Whenever the file system would create ResourceInstanceDir instance, it will
299
+ # create InstanceDir instead.
300
+ HaveAPI::Fs::Factory.replace(
301
+ HaveAPI::Fs::Components::ResourceInstanceDir,
302
+ CustomComponents::InstanceDir
303
+ )
304
+
305
+ # Mount the file system
306
+ HaveAPI::Fs.main
307
+ ```
308
+
309
+ ## API requirements
310
+ For the file system to work correctly, the API has comply with the following
311
+ requirements:
312
+
313
+ - `Index` and `Show` actions must return parameter `id`
314
+ - `Update` action should return the same parameters as `Show`
315
+ - If the API uses authentication, it has to have resource `User` and action
316
+ `User.current` that is like a `Show` for the current user, not knowing his
317
+ `id` yet
318
+ - `Index` input parameter `limit` has the meaning from
319
+ `HaveAPI::Actions::Paginable`
320
+
321
+ ## Troubleshooting
322
+ Whenever `haveapi-fs` crashes, throws IO errors or misbehaves, helpful
323
+ information can be found in the log file. Logging is disabled by default when
324
+ daemonized, as it can grow large. It can be enabled using option `log`. The log
325
+ file is located at `~/.haveapi-fs/<api domain>/haveapi-fs.log`.
326
+
327
+ If `haveapi-fs` is run in the foreground using option `nodaemonize`, it logs
328
+ to standard output.
329
+
330
+ Whenever reporting an error, send also contents of the log file or search it
331
+ for a relevant backtrace.
332
+
333
+ ## Known issues
334
+ - On some distributions, `man` cannot directly open `help.man` files, because
335
+ it uses suid bit to run as another user. Other users by default cannot
336
+ access this file system. This can be changed in `/etc/fuse.conf` and then by
337
+ using mount option `allow_other`. A workaround is to open the manual
338
+ indirectly, e.g. `cat help.man | man -l -`
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'