linecook 0.6.2 → 1.0.0

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