linecook 1.2.1 → 2.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.
- data/{History → History.rdoc} +3 -2
- data/README.rdoc +93 -0
- data/bin/linecook +32 -56
- data/bin/linecook_run +19 -6
- data/bin/linecook_scp +12 -4
- data/doc/vm_setup.rdoc +75 -0
- data/lib/linecook.rb +3 -2
- data/lib/linecook/attributes.rb +33 -8
- data/lib/linecook/command.rb +61 -0
- data/lib/linecook/command_set.rb +85 -0
- data/lib/linecook/command_utils.rb +20 -0
- data/lib/linecook/commands/build.rb +108 -57
- data/lib/linecook/commands/compile.rb +181 -0
- data/lib/linecook/commands/{helper.rb → compile_helper.rb} +123 -94
- data/lib/linecook/commands/run.rb +43 -39
- data/lib/linecook/commands/snapshot.rb +24 -24
- data/lib/linecook/commands/ssh.rb +7 -7
- data/lib/linecook/commands/start.rb +10 -10
- data/lib/linecook/commands/state.rb +7 -7
- data/lib/linecook/commands/stop.rb +3 -3
- data/lib/linecook/commands/{vbox_command.rb → virtual_box_command.rb} +31 -29
- data/lib/linecook/cookbook.rb +149 -131
- data/lib/linecook/executable.rb +28 -0
- data/lib/linecook/package.rb +177 -361
- data/lib/linecook/proxy.rb +4 -10
- data/lib/linecook/recipe.rb +289 -369
- data/lib/linecook/test.rb +114 -98
- data/lib/linecook/utils.rb +31 -41
- data/lib/linecook/version.rb +2 -6
- metadata +120 -68
- data/HowTo/Control Virtual Machines +0 -106
- data/HowTo/Generate Scripts +0 -268
- data/HowTo/Run Scripts +0 -87
- data/HowTo/Setup Virtual Machines +0 -76
- data/README +0 -117
- data/lib/linecook/commands.rb +0 -11
- data/lib/linecook/commands/command.rb +0 -58
- data/lib/linecook/commands/command_error.rb +0 -12
- data/lib/linecook/commands/env.rb +0 -89
- data/lib/linecook/commands/init.rb +0 -86
- data/lib/linecook/commands/package.rb +0 -57
- data/lib/linecook/template.rb +0 -17
- data/lib/linecook/test/command_parser.rb +0 -75
- data/lib/linecook/test/file_test.rb +0 -197
- data/lib/linecook/test/regexp_escape.rb +0 -86
- data/lib/linecook/test/shell_test.rb +0 -177
- data/lib/linecook/test/shim.rb +0 -71
- data/templates/Gemfile +0 -3
- data/templates/Rakefile +0 -146
- data/templates/_gitignore +0 -4
- data/templates/attributes/project_name.rb +0 -3
- data/templates/config/ssh +0 -14
- data/templates/cookbook +0 -10
- data/templates/files/example.txt +0 -1
- data/templates/helpers/project_name/echo.erb +0 -4
- data/templates/packages/abox.yml +0 -2
- data/templates/project_name.gemspec +0 -30
- data/templates/recipes/abox.rb +0 -16
- data/templates/templates/example.erb +0 -1
- data/templates/test/project_name_test.rb +0 -24
- data/templates/test/test_helper.rb +0 -14
@@ -1,106 +0,0 @@
|
|
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.
|
data/HowTo/Generate Scripts
DELETED
@@ -1,268 +0,0 @@
|
|
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 -Ilib
|
16
|
-
|
17
|
-
Or if you have a proper Gemfile in your project dir:
|
18
|
-
|
19
|
-
linecook build
|
20
|
-
|
21
|
-
This tutorial is designed such that if you make the files as specified, you
|
22
|
-
can use it to rebuild the same package (functionally or literally) at the end
|
23
|
-
of each section.
|
24
|
-
|
25
|
-
== Packages
|
26
|
-
|
27
|
-
Packages are located in the packages directory by default. The simplest
|
28
|
-
package is a directory containing a single executable script. Assuming a bare
|
29
|
-
Ubuntu VM and a bash shell, start with this script to setup a minimal
|
30
|
-
development environment:
|
31
|
-
|
32
|
-
[packages/demo/run]
|
33
|
-
sudo apt-get -y install git
|
34
|
-
git config --global user.name "John Doe"
|
35
|
-
git config --global user.email "john.doe@example.com"
|
36
|
-
sudo apt-get -y install ruby
|
37
|
-
|
38
|
-
This package represents the end result of 'linecook build'. To actually build
|
39
|
-
it, a package file need to be made. The package file describes what goes into
|
40
|
-
the package and is written in YAML; by default the package file is named like
|
41
|
-
the final package, but with a .yml extension.
|
42
|
-
|
43
|
-
As an example, this package file generates the 'run' script from the 'demo' recipe and puts it into the package during build.
|
44
|
-
|
45
|
-
[packages/demo.yml]
|
46
|
-
linecook:
|
47
|
-
package:
|
48
|
-
recipes:
|
49
|
-
run: demo # package/path: recipe_name
|
50
|
-
|
51
|
-
However this package file is overly verbose; the recipe with the same name as
|
52
|
-
the package is used to generate the run script by default, so this equivalent:
|
53
|
-
|
54
|
-
[packages/demo.yml]
|
55
|
-
{}
|
56
|
-
|
57
|
-
At this point a build (ie 'linecook build') raises an error; To see the
|
58
|
-
package file in action we need the demo recipe.
|
59
|
-
|
60
|
-
== Recipes
|
61
|
-
|
62
|
-
Recipes are ruby code that generates text during a build. Typically the text
|
63
|
-
is shell script, and therefore the result of a recipe is a script file, but
|
64
|
-
the text could be a config file, SQL, or whatever.
|
65
|
-
|
66
|
-
Specifically recipes are code that gets executed in the context of a
|
67
|
-
Linecook::Recipe instance. These instances have a 'target' IO object (usually
|
68
|
-
a Tempfile) to which the generated text is written. The most basic recipe
|
69
|
-
simply writes the script content to the target.
|
70
|
-
|
71
|
-
[recipes/demo.rb]
|
72
|
-
target.puts <<-SCRIPT
|
73
|
-
sudo apt-get -y install ruby1.8
|
74
|
-
sudo apt-get -y install git
|
75
|
-
git config --global user.name "John Doe"
|
76
|
-
git config --global user.email "john.doe@example.com"
|
77
|
-
SCRIPT
|
78
|
-
|
79
|
-
Now a build will write the script to the target, then move the corresponding
|
80
|
-
Tempfile to become 'packages/demo/run'. As code, recipes work like this:
|
81
|
-
|
82
|
-
class Recipe
|
83
|
-
attr_accessor :target
|
84
|
-
def initialize
|
85
|
-
@target = ""
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
recipe = Recipe.new
|
90
|
-
recipe.instance_eval File.read('recipes/demo.rb')
|
91
|
-
recipe.target[0, 31] # => "sudo apt-get -y install ruby1.8"
|
92
|
-
|
93
|
-
This exercise illustrates the great and powerful truth of recipes - they are
|
94
|
-
simply a context to generate text and write it to a file. A direct consequence
|
95
|
-
of this design is that commands (for example debugging command) can always be
|
96
|
-
inserted into a script in a trivial manner.
|
97
|
-
|
98
|
-
Obviously recipes can do more.
|
99
|
-
|
100
|
-
== Attributes
|
101
|
-
|
102
|
-
Attributes allow variables to be separated from the recipe code, such that
|
103
|
-
they may be overridden on a per-package basis, in the package file. Recipes
|
104
|
-
have a nested 'attrs' hash (which is literally a Hash) that merges together
|
105
|
-
the defaults and overrides to provide attributes access.
|
106
|
-
|
107
|
-
Using attributes:
|
108
|
-
|
109
|
-
[attributes/git.rb]
|
110
|
-
attrs['git']['package'] = 'git'
|
111
|
-
attrs['git']['config']['user.name'] = 'John Doe'
|
112
|
-
attrs['git']['config']['user.email'] = 'john.doe@example.com'
|
113
|
-
|
114
|
-
[attributes/ruby.rb]
|
115
|
-
attrs['ruby']['package'] = 'ruby1.9.1'
|
116
|
-
|
117
|
-
[packages/demo.yml]
|
118
|
-
ruby:
|
119
|
-
package: ruby1.8
|
120
|
-
|
121
|
-
[recipes/demo.rb]
|
122
|
-
attributes 'ruby'
|
123
|
-
attributes 'git'
|
124
|
-
#########################################################################
|
125
|
-
target.puts <<-SCRIPT
|
126
|
-
sudo apt-get -y install #{attrs['ruby']['package']}
|
127
|
-
sudo apt-get -y install #{attrs['git']['package']}
|
128
|
-
git config --global user.name "#{attrs['git']['config']['user.name']}"
|
129
|
-
git config --global user.email "#{attrs['git']['config']['user.email']}"
|
130
|
-
SCRIPT
|
131
|
-
|
132
|
-
Attribute files must be included using the Recipe#attributes method; no
|
133
|
-
attributes are included by default. This ensures that attributes will be
|
134
|
-
deterministic in cases where two attribute files (unwisely) use the same
|
135
|
-
namespace.
|
136
|
-
|
137
|
-
The overrides specified in the package file are always available, however.
|
138
|
-
They function as a kind of environment for recipes; since they are overrides,
|
139
|
-
they take precedence over any values set by attribute files.
|
140
|
-
|
141
|
-
Take note of two details. First, there is no special code needed to set nested
|
142
|
-
attributes in an attributes file. Attributes files are executed in the context
|
143
|
-
of a Linecook::Attributes instance which provides this auto-nesting behavior.
|
144
|
-
Second, as a convention, attrs are accessed using string keys because it's
|
145
|
-
cleaner to use string keys in the package file.
|
146
|
-
|
147
|
-
== Helpers
|
148
|
-
|
149
|
-
Helpers allow you to define methods that generate text. Helper methods are
|
150
|
-
defined as ERB files under the 'helpers' directory and compile into an
|
151
|
-
ordinary module under the 'lib' directory. For example (assuming the
|
152
|
-
attribute and package files from above):
|
153
|
-
|
154
|
-
[helpers/demo/install.erb]
|
155
|
-
Installs a package using apt-get.
|
156
|
-
(package)
|
157
|
-
--
|
158
|
-
sudo apt-get -y install <%= package %>
|
159
|
-
|
160
|
-
|
161
|
-
[helpers/demo/set_git_config.erb]
|
162
|
-
Sets a global git config.
|
163
|
-
(key, value)
|
164
|
-
--
|
165
|
-
git config --global <%= key %> "<%= value %>"
|
166
|
-
|
167
|
-
|
168
|
-
[recipes/demo.rb]
|
169
|
-
attributes 'ruby'
|
170
|
-
attributes 'git'
|
171
|
-
helpers 'demo'
|
172
|
-
#########################################################################
|
173
|
-
install attrs['ruby']['package']
|
174
|
-
install attrs['git']['package']
|
175
|
-
['user.name', 'user.email'].each do |key|
|
176
|
-
set_git_config key, attrs['git']['config'][key]
|
177
|
-
end
|
178
|
-
|
179
|
-
When you define a helper, you're literally defining a method in a module that
|
180
|
-
you can use in your recipe to generate text. This example generates the 'Demo'
|
181
|
-
module which adds 'install' and 'set_git_config' into the recipe context. In
|
182
|
-
fact the 'helpers' method is equivalent to:
|
183
|
-
|
184
|
-
require 'demo'
|
185
|
-
extend Demo
|
186
|
-
|
187
|
-
The exact details are elegant but unimportant to the workflow, which can be
|
188
|
-
summed up like this: put an ERB template into a file, include the directory
|
189
|
-
using Recipe#helpers, and now the template is available as a method with
|
190
|
-
inputs. Whenever you call the method, you make text that gets written to
|
191
|
-
target.
|
192
|
-
|
193
|
-
To capture the output of a template without writing it to target, prefix the
|
194
|
-
method with an underscore. The output can then be used as an input to another
|
195
|
-
helper... see the {README}[link:files/README.html] for an example.
|
196
|
-
|
197
|
-
== Files
|
198
|
-
|
199
|
-
Files are files of any sort that you might want to include in a package. They
|
200
|
-
could be an archive of some sort, a binary, or a stock script you don't need a
|
201
|
-
recipe to reproduce.
|
202
|
-
|
203
|
-
Files are typically included via a recipe like this:
|
204
|
-
|
205
|
-
[files/gitconfig]
|
206
|
-
[user]
|
207
|
-
name = John Doe
|
208
|
-
email = john.doe@example.com
|
209
|
-
|
210
|
-
[recipes/demo.rb]
|
211
|
-
target.puts <<-SCRIPT
|
212
|
-
sudo apt-get -y install ruby1.8
|
213
|
-
sudo apt-get -y install git
|
214
|
-
cp "#{ file_path "gitconfig" }" ~/.gitconfig
|
215
|
-
SCRIPT
|
216
|
-
|
217
|
-
The only 'trick' here is that the return value of file_path is a path that
|
218
|
-
will be correct at runtime, when the script is on the remote server
|
219
|
-
(specifically it will be like "${0%/run}/gitconfig", which works because $0
|
220
|
-
will be the full path to the recipe).
|
221
|
-
|
222
|
-
== Templates
|
223
|
-
|
224
|
-
Templates work the same as files except, as you may imagine, they are ERB
|
225
|
-
templates that evaluate with whatever locals you provide them. The attrs hash
|
226
|
-
is local by default.
|
227
|
-
|
228
|
-
[attributes/git.rb]
|
229
|
-
attrs['git']['package'] = 'git'
|
230
|
-
attrs['git']['config']['user.name'] = 'John Doe'
|
231
|
-
attrs['git']['config']['user.email'] = 'john.doe@example.com'
|
232
|
-
|
233
|
-
[templates/gitconfig.erb]
|
234
|
-
[user]
|
235
|
-
name = <%= attrs['git']['config']['user.name'] %>
|
236
|
-
email = <%= attrs['git']['config']['user.email'] %>
|
237
|
-
|
238
|
-
[recipes/demo.rb]
|
239
|
-
attributes 'git'
|
240
|
-
#########################################################################
|
241
|
-
target.puts <<-SCRIPT
|
242
|
-
sudo apt-get -y install ruby1.8
|
243
|
-
sudo apt-get -y install git
|
244
|
-
cp "#{ template_path "gitconfig.erb" }" ~/.gitconfig
|
245
|
-
SCRIPT
|
246
|
-
|
247
|
-
== {Linebook}[http://rubygems.org/gems/linebook/]
|
248
|
-
|
249
|
-
The techniques presented here are sufficient to work with many scripts in many
|
250
|
-
situations but they are quite bare. Eventually, or perhaps immediately, you
|
251
|
-
will want a suite of standard helpers. The canonical helper library is
|
252
|
-
{Linebook}[http://rubygems.org/gems/linebook/].
|
253
|
-
|
254
|
-
See the {Linebook
|
255
|
-
documentation}[http://rubydoc.info/gems/linebook/file/README] to learn helpers
|
256
|
-
for flow control, file system tests, commands, chaining, redirection,
|
257
|
-
heredocs, and other convenience methods.
|
258
|
-
|
259
|
-
[recipes/demo.rb]
|
260
|
-
helpers 'linebook/shell'
|
261
|
-
|
262
|
-
unless_ _file?('/tmp/message') do
|
263
|
-
cat.to('/tmp/message').heredoc do
|
264
|
-
writeln 'hello world!'
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
Enjoy!
|
data/HowTo/Run Scripts
DELETED
@@ -1,87 +0,0 @@
|
|
1
|
-
= Run Scripts
|
2
|
-
|
3
|
-
Linecook runs scripts using the 'run' command. Internally run copies scripts
|
4
|
-
to a server using scp and then executes the script using ssh. More
|
5
|
-
specifically run copies a *package* to the server and executes a script within
|
6
|
-
the package using ssh. A package is simply a directory containing scripts and
|
7
|
-
any files the scripts use.
|
8
|
-
|
9
|
-
To manually recreate what run does, make a directory with an script, copy it,
|
10
|
-
and execute as below (assuming you set up the 'abox' server {as described
|
11
|
-
earlier}[link:files/Tutorial/1%20-%20VM%20Setup.html]). Note that the script
|
12
|
-
is made executable locally such that scp will make the script executable on
|
13
|
-
the server.
|
14
|
-
|
15
|
-
mkdir demo
|
16
|
-
cat > demo/script.sh <<"DOC"
|
17
|
-
echo "# $(whoami)@$(hostname): hello world!"
|
18
|
-
DOC
|
19
|
-
chmod +x demo/script.sh
|
20
|
-
|
21
|
-
scp -r -P 2220 demo linecook@localhost:/tmp/demo
|
22
|
-
ssh -p 2220 linecook@localhost -- "/tmp/demo/script.sh"
|
23
|
-
# linecook@abox-ubuntu: hello world!
|
24
|
-
|
25
|
-
To simplify this a little, move the redundant information used by scp and ssh
|
26
|
-
can into a standard ssh config file. Linecook looks for an ssh config file in
|
27
|
-
'config/ssh' by default:
|
28
|
-
|
29
|
-
mkdir config
|
30
|
-
cat > config/ssh <<DOC
|
31
|
-
Host abox
|
32
|
-
User linecook
|
33
|
-
HostName localhost
|
34
|
-
Port 2220
|
35
|
-
DOC
|
36
|
-
|
37
|
-
Now run will copy the package under the 'packages' directory with the same
|
38
|
-
name as the Host config, and execute the specified script:
|
39
|
-
|
40
|
-
mkdir packages
|
41
|
-
mv demo packages/abox
|
42
|
-
linecook run --script script.sh abox
|
43
|
-
# linecook@abox-ubuntu: hello world!
|
44
|
-
|
45
|
-
To run multiple packages at once, simply add more hosts to the ssh config
|
46
|
-
file. Run copies each package to the appropriate host and then runs the same
|
47
|
-
script on each (in alphabetic order by host). So say you also set up a 'bbox'
|
48
|
-
same as 'abox':
|
49
|
-
|
50
|
-
cat >> config/ssh <<DOC
|
51
|
-
Host abox
|
52
|
-
Port 2220
|
53
|
-
|
54
|
-
Host bbox
|
55
|
-
Port 2221
|
56
|
-
|
57
|
-
Host *
|
58
|
-
User linecook
|
59
|
-
HostName localhost
|
60
|
-
DOC
|
61
|
-
cp packages/abox packages/bbox
|
62
|
-
|
63
|
-
Then:
|
64
|
-
|
65
|
-
linecook run --script script.sh abox bbox
|
66
|
-
# linecook@abox-ubuntu: hello world!
|
67
|
-
# linecook@bbox-ubuntu: hello world!
|
68
|
-
|
69
|
-
Note that by default run will execute the 'run' script on all hosts configured
|
70
|
-
in 'config/ssh'. Leveraging these defaults simplifies the last command:
|
71
|
-
|
72
|
-
mv packages/abox/script.sh packages/abox/run
|
73
|
-
mv packages/bbox/script.sh packages/bbox/run
|
74
|
-
linecook run
|
75
|
-
# linecook@abox-ubuntu: hello world!
|
76
|
-
# linecook@bbox-ubuntu: hello world!
|
77
|
-
|
78
|
-
If you've never used scp/ssh with a config file then this may seem unfamiliar
|
79
|
-
but hopefully quite graceful. For scp/ssh masters, these are equivalent for
|
80
|
-
each host:
|
81
|
-
|
82
|
-
linecook run --remote-dir=/tmp/linecook SCRIPT ARGS...
|
83
|
-
|
84
|
-
scp -q -r -p -F config/ssh packages/host "host:/tmp/linecook"
|
85
|
-
ssh -q -t -t -F config/ssh host -- "/tmp/linecook/SCRIPT ARGS..."
|
86
|
-
|
87
|
-
Now that you can run scripts, onward to generating scripts!
|