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