linecook 0.6.2 → 1.0.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 (72) hide show
  1. data/History +139 -0
  2. data/HowTo/Control Virtual Machines +106 -0
  3. data/HowTo/Generate Scripts +263 -0
  4. data/HowTo/Run Scripts +87 -0
  5. data/HowTo/Setup Virtual Machines +76 -0
  6. data/License.txt +1 -1
  7. data/README +78 -59
  8. data/bin/linecook +12 -5
  9. data/bin/linecook_run +45 -0
  10. data/bin/linecook_scp +50 -0
  11. data/lib/linecook.rb +1 -3
  12. data/lib/linecook/attributes.rb +49 -12
  13. data/lib/linecook/commands.rb +9 -4
  14. data/lib/linecook/commands/build.rb +69 -0
  15. data/lib/linecook/commands/command.rb +13 -3
  16. data/lib/linecook/commands/command_error.rb +6 -0
  17. data/lib/linecook/commands/env.rb +74 -8
  18. data/lib/linecook/commands/helper.rb +271 -24
  19. data/lib/linecook/commands/init.rb +10 -6
  20. data/lib/linecook/commands/package.rb +36 -18
  21. data/lib/linecook/commands/run.rb +66 -0
  22. data/lib/linecook/commands/snapshot.rb +114 -0
  23. data/lib/linecook/commands/ssh.rb +39 -0
  24. data/lib/linecook/commands/start.rb +34 -0
  25. data/lib/linecook/commands/state.rb +32 -0
  26. data/lib/linecook/commands/stop.rb +22 -0
  27. data/lib/linecook/commands/vbox_command.rb +130 -0
  28. data/lib/linecook/cookbook.rb +112 -55
  29. data/lib/linecook/package.rb +293 -109
  30. data/lib/linecook/proxy.rb +19 -0
  31. data/lib/linecook/recipe.rb +321 -62
  32. data/lib/linecook/template.rb +7 -101
  33. data/lib/linecook/test.rb +196 -141
  34. data/lib/linecook/test/command_parser.rb +75 -0
  35. data/lib/linecook/test/file_test.rb +153 -35
  36. data/lib/linecook/test/shell_test.rb +176 -0
  37. data/lib/linecook/utils.rb +25 -7
  38. data/lib/linecook/version.rb +4 -4
  39. data/templates/Rakefile +44 -47
  40. data/templates/_gitignore +1 -1
  41. data/templates/attributes/project_name.rb +4 -4
  42. data/templates/config/ssh +15 -0
  43. data/templates/files/help.txt +1 -0
  44. data/templates/helpers/project_name/assert_content_equal.erb +15 -0
  45. data/templates/helpers/project_name/create_dir.erb +9 -0
  46. data/templates/helpers/project_name/create_file.erb +8 -0
  47. data/templates/helpers/project_name/install_file.erb +8 -0
  48. data/templates/packages/abox.yml +4 -0
  49. data/templates/recipes/abox.rb +22 -0
  50. data/templates/recipes/abox_test.rb +14 -0
  51. data/templates/templates/todo.txt.erb +3 -0
  52. data/templates/test/project_name_test.rb +19 -0
  53. data/templates/test/test_helper.rb +14 -0
  54. metadata +43 -41
  55. data/cookbook +0 -0
  56. data/lib/linecook/commands/helpers.rb +0 -28
  57. data/lib/linecook/commands/vbox.rb +0 -85
  58. data/lib/linecook/helper.rb +0 -117
  59. data/lib/linecook/shell.rb +0 -11
  60. data/lib/linecook/shell/posix.rb +0 -145
  61. data/lib/linecook/shell/test.rb +0 -254
  62. data/lib/linecook/shell/unix.rb +0 -117
  63. data/lib/linecook/shell/utils.rb +0 -138
  64. data/templates/README +0 -90
  65. data/templates/files/file.txt +0 -1
  66. data/templates/helpers/project_name/echo.erb +0 -5
  67. data/templates/recipes/project_name.rb +0 -20
  68. data/templates/scripts/project_name.yml +0 -7
  69. data/templates/templates/template.txt.erb +0 -3
  70. data/templates/vbox/setup/virtual_box +0 -86
  71. data/templates/vbox/ssh/id_rsa +0 -27
  72. data/templates/vbox/ssh/id_rsa.pub +0 -1
data/History CHANGED
@@ -1,3 +1,142 @@
1
+ == 1.0.0 2011/04/26
2
+
3
+ First major release. Significant work on documentation and various bug fixes.
4
+ Simplified run command to only run one script at a time.
5
+
6
+ == 0.20.0 2011/03/17
7
+
8
+ * added callback support
9
+ * changed capture_block to accept capture target, and to return
10
+ the target (not the target output)
11
+ * added capture_str to replace capture_block functionality
12
+
13
+ == 0.19.1 2011/03/15
14
+
15
+ * updated the functionality of Recipe#rewrite
16
+ * removed Recipe#rewriteln
17
+
18
+ == 0.19.0 2011/03/15
19
+
20
+ * optimizations for helpers
21
+ * removed _erbout tricks from Recipe
22
+ * added Recipe#rewrite
23
+
24
+ == 0.18.0 2011/03/10
25
+
26
+ * enforce word method names for helpers
27
+ * linecook prints backtrace on error with $DEBUG
28
+ * added proxy chaining to Recipe
29
+
30
+ == 0.17.0 2011/03/10
31
+
32
+ * added hooks for TESTCASE and NAME to test helpers
33
+ * changed helper sections to be identified by leading dash
34
+
35
+ == 0.16.0 2011/03/09
36
+
37
+ * added mode support to packages
38
+ * removed preview command
39
+ * added outdent to recipes
40
+ * made run allocate a pseudo-tty
41
+ * updates to allow multitests
42
+ * various patches
43
+
44
+ == 0.15.1 2011/02/23
45
+
46
+ * made linecook use Gemfile if available
47
+ * updated scaffold for new project
48
+ * added package file to package dependencies
49
+
50
+ == 0.15.0 2011/02/23
51
+
52
+ Continued overhaul of testing methods and structure.
53
+
54
+ == 0.14.0 2011/02/16
55
+
56
+ Significant overhaul of testing methods and structure. Cleanup of internal
57
+ structure and documentation.
58
+
59
+ == 0.13.1 2011/02/03
60
+
61
+ * added back close methods to template
62
+ * fixed test bug
63
+
64
+ == 0.13.0 2011/02/03
65
+
66
+ * documentation, testing, cleanup
67
+
68
+ == 0.12.0 2011/02/01
69
+
70
+ * added support for multiple vms
71
+ * simplified test methods
72
+
73
+ == 0.11.0 2011/01/28
74
+
75
+ * reworked test methods again
76
+
77
+ == 0.10.0 2011/01/27
78
+
79
+ * updated test methods, adding script/vbox test methods
80
+ * reworked helper generation to inline ERB during generation
81
+ * misc bug fixes
82
+
83
+ == 0.9.5 2011/01/13
84
+
85
+ * removed double-print of preview
86
+ * added more configs to filter preview results
87
+ * moved helper template docs into the method
88
+ * added selection of a range of content from packages
89
+ * added FORCE to scaffold Rakefile to force helper/package creation
90
+
91
+ == 0.9.4 2011/01/13
92
+
93
+ * improved preview functionality
94
+ * made script_test run scripts in export dir
95
+ * made recipe add attrs to template locals
96
+
97
+ == 0.9.3 2011/01/13
98
+
99
+ * bug fixes in commands
100
+ * added configuration of default vmname
101
+
102
+ == 0.9.2 2011/01/13
103
+
104
+ * added package reset to script tests
105
+ * added preview command
106
+
107
+ == 0.9.1 2011/01/12
108
+
109
+ * added script_test test method
110
+ * added auto-incrementing variables to recipe
111
+
112
+ == 0.9.0 2011/01/12
113
+
114
+ * added 'share' command to setup a vbox share
115
+ * converted 'scripts' to 'packages' in scaffold/rake tasks
116
+ * removed helpers from manifest, now require directly
117
+ * corrected documentation
118
+
119
+ == 0.8.3 2011/01/11
120
+
121
+ * bug fixes
122
+
123
+ == 0.8.1 2011/01/11
124
+
125
+ * added sorted hashes to env
126
+ * bugfix - env did not display cookbook config
127
+
128
+ == 0.8.0 2011/01/11
129
+
130
+ * now detect helpers using lazydoc (::helper)
131
+ * bugfix env command didn't work
132
+ * bugfix for using nested capture path
133
+ * now nest resources in manifest by type
134
+
135
+ == 0.7.0 2011/01/10
136
+
137
+ * removed shell helpers (to linebook)
138
+ * reworked internals for saner testing
139
+
1
140
  == 0.6.2 2011/01/06
2
141
 
3
142
  * added helper command to build a single helper
@@ -0,0 +1,106 @@
1
+ = Control Virtual Machines
2
+
3
+ Linecook provides these commands to control VirtualBox VMs:
4
+
5
+ # ex: 'linecook start'
6
+ start start a vm
7
+ stop stop a vm
8
+ state print the vm state
9
+ save take a vm snapshop
10
+ ssh ssh to a vm
11
+
12
+ Most of these commands wrap the VirtualBox command line tool VBoxManage in
13
+ very simple ways. With these commands it's straightforward to make an
14
+ iterative script development workflow to build a server component, save the
15
+ server state, build another component, and then at any time reset and rebuild
16
+ the whole thing from scratch.
17
+
18
+ Linecook uses a standard ssh config file to run scripts; the same config file
19
+ is also used to configure the VM control commands. More details are presented
20
+ in the help to {run scripts}[link:files/HowTo/Run%20Scripts.html], but suffice
21
+ these configs will access the 'abox' VM built by the {VM Setup
22
+ procedure}[link:files/HowTo/Setup%20Virtual%20Machines.html]:
23
+
24
+ [config/ssh]
25
+ Host abox
26
+ HostName localhost
27
+ User linecook
28
+ Port 2220
29
+
30
+ Now you can control the VM like this:
31
+
32
+ # start the VM, resetting to a snapshot
33
+ linecook start --snapshot base
34
+
35
+ # ssh to the VM
36
+ linecook ssh
37
+
38
+ # take a snapshot
39
+ linecook snapshot modified
40
+
41
+ # reset a snapshot, removing all children
42
+ linecook snapshot --reset base
43
+
44
+ # stop the VM and go home
45
+ linecook stop
46
+
47
+ == Multiple VMs
48
+
49
+ To control multiple VMs, build and configure ssh access to each. For example
50
+ make a 'bbox' VM as before but configure ssh access on port 2221:
51
+
52
+ - name: bbox
53
+ - hostname: bbox-ubuntu
54
+ VBoxManage modifyvm bbox --natpf1 'bbox-ssh,tcp,,2221,,22'
55
+
56
+ Now add an entry for bbox in the ssh config file (note the * Host can be used
57
+ to declare default settings):
58
+
59
+ [config/ssh]
60
+ Host abox
61
+ Port 2220
62
+
63
+ Host bbox
64
+ Port 2221
65
+
66
+ Host *
67
+ HostName localhost
68
+ User linecook
69
+
70
+ Now same linecook commands will control both VMs:
71
+
72
+ # start all (or a subset) the VMs to a known snapshot
73
+ linecook start --snapshot base
74
+ linecook start --snapshot base abox
75
+
76
+ # ssh to the VMs one at a time
77
+ linecook ssh abox
78
+ linecook ssh bbox
79
+
80
+ # move the current snapshot forward for all (or a subset) the VMs
81
+ linecook snapshot modified
82
+ linecook snapshot modified abox
83
+
84
+ # reset a snapshot, removing all children for all (or a subset) the VMs
85
+ linecook snapshot --reset base
86
+ linecook snapshot --reset base abox
87
+
88
+ # stop all (or a subset) the VMs
89
+ linecook stop
90
+ linecook stop abox
91
+
92
+ == Host and VM Names
93
+
94
+ The Host config corresponds to the package name that will be run on the VM; ie
95
+ the 'abox.yml' package goes to the 'abox' Host. Implicitly the VM will also be
96
+ named 'abox' in VirtualBox (such that if you opened the VirtualBox application
97
+ you'd see 'abox'). If you name it something else, then declare the actual VM
98
+ name next to the Host config using a linecook-specific comment like this:
99
+
100
+ [config/ssh]
101
+ ...
102
+ Host abox # [the_vm_name]
103
+ ...
104
+
105
+ The Host config, 'abox' in this case, is the input for all linecook commands;
106
+ linecook resolves the VM name internally when interacting with VirtualBox.
@@ -0,0 +1,263 @@
1
+ = Generate Scripts
2
+
3
+ Linecook generates scripts and puts them into a directory. Once you have the
4
+ scripts you can compress them, share them, run them, or do whatever you please
5
+ - at that point they're ordinary files sitting in a directory. Linecook refers
6
+ to the directories containing generated scripts as packages.
7
+
8
+ The best way to understand how Linecook generates scripts is to start by
9
+ making a package with a known script, and then rewrite the script using
10
+ Linecook. At each step of the rewrite you can rebuild the package and verify
11
+ the script is reproduced.
12
+
13
+ The command to rebuild a package is:
14
+
15
+ linecook build
16
+
17
+ This tutorial is designed such that if you make the files as specified, you
18
+ can use it to rebuild the same package (functionally or literally) at the end
19
+ of each section.
20
+
21
+ == Packages
22
+
23
+ Packages are located in the packages directory by default. The simplest
24
+ package is a directory containing a single executable script. Assuming a bare
25
+ Ubuntu VM and a bash shell, start with this script to setup a minimal
26
+ development environment:
27
+
28
+ [packages/demo/run]
29
+ sudo apt-get -y install git
30
+ git config --global user.name "John Doe"
31
+ git config --global user.email "john.doe@example.com"
32
+ sudo apt-get -y install ruby
33
+
34
+ This package represents the end result of 'linecook build'. To actually build
35
+ it, a package file need to be made. The package file describes what goes into
36
+ the package and is written in YAML; by default the package file is named like
37
+ the final package, but with a .yml extension.
38
+
39
+ As an example, this package file generates the 'run' script from the 'demo' recipe and puts it into the package during build.
40
+
41
+ [packages/demo.yml]
42
+ linecook:
43
+ package:
44
+ recipes:
45
+ run: demo # package/path: recipe_name
46
+
47
+ However this package file is overly verbose; the recipe with the same name as
48
+ the package is used to generate the run script by default, so this equivalent:
49
+
50
+ [packages/demo.yml]
51
+ {}
52
+
53
+ At this point a build (ie 'linecook build') raises an error; To see the
54
+ package file in action we need the demo recipe.
55
+
56
+ == Recipes
57
+
58
+ Recipes are ruby code that generates text during a build. Typically the text
59
+ is shell script, and therefore the result of a recipe is a script file, but
60
+ the text could be a config file, SQL, or whatever.
61
+
62
+ Specifically recipes are code that gets executed in the context of a
63
+ Linecook::Recipe instance. These instances have a 'target' IO object (usually
64
+ a Tempfile) to which the generated text is written. The most basic recipe
65
+ simply writes the script content to the target.
66
+
67
+ [recipes/demo.rb]
68
+ target.puts <<-SCRIPT
69
+ sudo apt-get -y install ruby1.8
70
+ sudo apt-get -y install git
71
+ git config --global user.name "John Doe"
72
+ git config --global user.email "john.doe@example.com"
73
+ SCRIPT
74
+
75
+ Now a build will write the script to the target, then move the corresponding
76
+ Tempfile to become 'packages/demo/run'. As code, recipes work like this:
77
+
78
+ class Recipe
79
+ attr_accessor :target
80
+ def initialize
81
+ @target = ""
82
+ end
83
+ end
84
+
85
+ recipe = Recipe.new
86
+ recipe.instance_eval File.read('recipes/demo.rb')
87
+ recipe.target[0, 31] # => "sudo apt-get -y install ruby1.8"
88
+
89
+ This exercise illustrates the great and powerful truth of recipes - they are
90
+ simply a context to generate text and write it to a file. A direct consequence
91
+ of this design is that commands (for example debugging command) can always be
92
+ inserted into a script in a trivial manner.
93
+
94
+ Obviously recipes can do more.
95
+
96
+ == Attributes
97
+
98
+ Attributes allow variables to be separated from the recipe code, such that
99
+ they may be overridden on a per-package basis, in the package file. Recipes
100
+ have a nested 'attrs' hash (which is literally a Hash) that merges together
101
+ the defaults and overrides to provide attributes access.
102
+
103
+ Using attributes:
104
+
105
+ [attributes/git.rb]
106
+ attrs['git']['package'] = 'git'
107
+ attrs['git']['config']['user.name'] = 'John Doe'
108
+ attrs['git']['config']['user.email'] = 'john.doe@example.com'
109
+
110
+ [attributes/ruby.rb]
111
+ attrs['ruby']['package'] = 'ruby1.9.1'
112
+
113
+ [packages/demo.yml]
114
+ ruby:
115
+ package: ruby1.8
116
+
117
+ [recipes/demo.rb]
118
+ attributes 'ruby'
119
+ attributes 'git'
120
+ #########################################################################
121
+ target.puts <<-SCRIPT
122
+ sudo apt-get -y install #{attrs['ruby']['package']}
123
+ sudo apt-get -y install #{attrs['git']['package']}
124
+ git config --global user.name "#{attrs['git']['config']['user.name']}"
125
+ git config --global user.email "#{attrs['git']['config']['user.email']}"
126
+ SCRIPT
127
+
128
+ Attribute files must be included using the Recipe#attributes method; no
129
+ attributes are included by default. This ensures that attributes will be
130
+ deterministic in cases where two attribute files (unwisely) use the same
131
+ namespace.
132
+
133
+ The overrides specified in the package file are always available, however.
134
+ They function as a kind of environment for recipes; since they are overrides,
135
+ they take precedence over any values set by attribute files.
136
+
137
+ Take note of two details. First, there is no special code needed to set nested
138
+ attributes in an attributes file. Attributes files are executed in the context
139
+ of a Linecook::Attributes instance which provides this auto-nesting behavior.
140
+ Second, as a convention, attrs are accessed using string keys because it's
141
+ cleaner to use string keys in the package file.
142
+
143
+ == Helpers
144
+
145
+ Helpers allow you to define methods that generate text. Helper methods are
146
+ defined as ERB files under the 'helpers' directory and compile into an
147
+ ordinary module under the 'lib' directory. For example (assuming the
148
+ attribute and package files from above):
149
+
150
+ [helpers/demo/install.erb]
151
+ Installs a package using apt-get.
152
+ (package)
153
+ --
154
+ sudo apt-get -y install <%= package %>
155
+
156
+
157
+ [helpers/demo/set_git_config.erb]
158
+ Sets a global git config.
159
+ (key, value)
160
+ --
161
+ git config --global <%= key %> <%= value %>
162
+
163
+
164
+ [recipes/demo.rb]
165
+ attributes 'ruby'
166
+ attributes 'git'
167
+ helpers 'demo'
168
+ #########################################################################
169
+ install attrs['ruby']['package']
170
+ install attrs['git']['package']
171
+ attrs['git']['config'].each_pair do |key, value|
172
+ set_git_config key, value
173
+ end
174
+
175
+ When you define a helper, you're literally defining a method in a module that
176
+ you can use in your recipe to generate text. This example generates the 'Demo'
177
+ module which adds 'install' and 'set_git_config' into the recipe context. In
178
+ fact the 'helpers' method is equivalent to:
179
+
180
+ require 'demo'
181
+ extend Demo
182
+
183
+ The exact details are elegant but unimportant to the workflow, which can be
184
+ summed up like this: put an ERB template into a file, include the directory
185
+ using Recipe#helpers, and now the template is available as a method with
186
+ inputs. Whenever you call the method, you make text that gets written to
187
+ target.
188
+
189
+ To capture the output of a template without writing it to target, prefix the
190
+ method with an underscore. The output can then be used as an input to another
191
+ helper... see the {README}[link:files/README.html] for an example.
192
+
193
+ == Files
194
+
195
+ Files are files of any sort that you might want to include in a package. They
196
+ could be an archive of some sort, a binary, or a stock script you don't need a
197
+ recipe to reproduce.
198
+
199
+ Files are typically included via a recipe like this:
200
+
201
+ [files/gitconfig]
202
+ [user]
203
+ name = John Doe
204
+ email = john.doe@example.com
205
+
206
+ [recipes/demo.rb]
207
+ target.puts <<-SCRIPT
208
+ sudo apt-get -y install ruby1.8
209
+ sudo apt-get -y install git
210
+ cp "#{ file_path "gitconfig" }" ~/.gitconfig
211
+ SCRIPT
212
+
213
+ The only 'trick' here is that the return value of file_path is a path that
214
+ will be correct at runtime, when the script is on the remote server
215
+ (specifically it will be like "${0%/run}/gitconfig", which works because $0
216
+ will be the full path to the recipe).
217
+
218
+ == Templates
219
+
220
+ Templates work the same as files except, as you may imagine, they are ERB
221
+ templates that evaluate with whatever locals you provide them. The attrs hash
222
+ is local by default.
223
+
224
+ [attributes/git.rb]
225
+ attrs['git']['package'] = 'git'
226
+ attrs['git']['config']['user.name'] = 'John Doe'
227
+ attrs['git']['config']['user.email'] = 'john.doe@example.com'
228
+
229
+ [templates/gitconfig.erb]
230
+ [user]
231
+ name = <%= attrs['git']['config']['user.name'] %>
232
+ email = <%= attrs['git']['config']['user.email'] %>
233
+
234
+ [recipes/demo.rb]
235
+ attributes 'git'
236
+ #########################################################################
237
+ target.puts <<-SCRIPT
238
+ sudo apt-get -y install ruby1.8
239
+ sudo apt-get -y install git
240
+ cp "#{ template_path "gitconfig" }" ~/.gitconfig
241
+ SCRIPT
242
+
243
+ == {Linebook}[http://rubygems.org/gems/linebook/]
244
+
245
+ The techniques presented here are sufficient to work with many scripts in many
246
+ situations but they are quite bare. Eventually, or perhaps immediately, you
247
+ will want a suite of standard helpers. The canonical helper library is
248
+ Linebook (Linecook's version of a Cookbook).
249
+
250
+ See the {Linebook documentation}[http://rubygems.org/gems/linebook/] to learn
251
+ helpers for flow control, file system tests, commands, chaining, redirection,
252
+ heredocs, and other convenience methods.
253
+
254
+ [recipes/demo.rb]
255
+ helpers 'linebook/shell'
256
+
257
+ unless_ _file?('/tmp/message') do
258
+ cat.to('/tmp/message').heredoc do
259
+ writeln 'hello world!'
260
+ end
261
+ end
262
+
263
+ Enjoy!