marionetta 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +24 -3
- data/lib/marionetta/command_runner.rb +52 -23
- data/lib/marionetta/group.rb +52 -1
- data/lib/marionetta/manipulators/puppet_manipulator.rb +1 -1
- data/lib/marionetta/manipulators.rb +18 -0
- data/lib/marionetta/rake_helper.rb +6 -0
- data/lib/marionetta.rb +5 -4
- data/marionetta.gemspec +4 -0
- metadata +2 -2
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Marionetta
|
2
2
|
|
3
|
-
Marionetta is a ruby library for executing
|
4
|
-
or more remote machines via SSH.
|
3
|
+
[Marionetta][marionetta] is a ruby library for executing
|
4
|
+
commands on one or more remote machines via SSH.
|
5
5
|
|
6
6
|
It provides puppet provisioning without the need for a puppet
|
7
7
|
master and can also deploy your application code (with
|
@@ -22,6 +22,21 @@ source 'http://rubygems.org'
|
|
22
22
|
gem 'marionetta'
|
23
23
|
```
|
24
24
|
|
25
|
+
[marionetta]: http://drpheltright.github.com/marionetta/
|
26
|
+
|
27
|
+
## Documentation
|
28
|
+
|
29
|
+
Marionetta has [annotated source][docs] that provides the
|
30
|
+
bulk of documentation for Marionetta. Hopefully you'll find
|
31
|
+
the annotations informative on *how to use* this library. If
|
32
|
+
you feel they could be improved please create an issue on
|
33
|
+
GitHub.
|
34
|
+
|
35
|
+
If you prefer looking at the code, check it out on [github][github].
|
36
|
+
|
37
|
+
[docs]: http://drpheltright.github.com/marionetta/docs/marionetta.html
|
38
|
+
[github]: http://github.com/DrPheltRight/marionetta/
|
39
|
+
|
25
40
|
## Using Marionetta in your Rakefile
|
26
41
|
|
27
42
|
Marionetta provides an easy mechanism to generate rake tasks
|
@@ -153,6 +168,12 @@ staging.manipulate_each_server(:deployer, :rollback)
|
|
153
168
|
|
154
169
|
Luke Morton a.k.a. DrPheltRight
|
155
170
|
|
171
|
+
## Collaborating
|
172
|
+
|
173
|
+
Create an issue and send a pull request if you get any bright
|
174
|
+
ideas or have a fix. Feel free to create an issue and not send
|
175
|
+
one too, feedback is always welcome.
|
176
|
+
|
156
177
|
## License
|
157
178
|
|
158
|
-
MIT
|
179
|
+
Licensed under MIT by Luke Morton, 2012.
|
@@ -27,9 +27,15 @@ module Marionetta
|
|
27
27
|
|
28
28
|
### Local execution
|
29
29
|
|
30
|
-
# Local commands are executed with `.system()`.
|
31
|
-
#
|
32
|
-
#
|
30
|
+
# Local commands are executed with `.system()`. We use
|
31
|
+
# `Open4::popen4` to capture the output of the command run
|
32
|
+
# neatly.
|
33
|
+
#
|
34
|
+
# The command run is logged as info, output as debug and
|
35
|
+
# any exceptions thrown are sent as fatal.
|
36
|
+
#
|
37
|
+
# You can optionally pass in a block which receives
|
38
|
+
# `stdout` and `stderr` as arguments:
|
33
39
|
#
|
34
40
|
# cmd.system('ls ~') do |out, err|
|
35
41
|
# puts out
|
@@ -57,6 +63,28 @@ module Marionetta
|
|
57
63
|
return status.exitstatus == 0
|
58
64
|
end
|
59
65
|
|
66
|
+
# Create an archive of a local directory, optionally
|
67
|
+
# saving it to a directory or file path.
|
68
|
+
#
|
69
|
+
def archive(directory, save_to = nil)
|
70
|
+
if save_to.nil?
|
71
|
+
save_to = "#{directory}.#{server[:archive][:ext]}"
|
72
|
+
elsif File.directory?(save_to)
|
73
|
+
dirname = File.basename(directory)
|
74
|
+
save_to = "#{save_to}/#{dirname}.#{server[:archive][:ext]}"
|
75
|
+
end
|
76
|
+
|
77
|
+
archive_cmd = [
|
78
|
+
server[:archive][:command],
|
79
|
+
server[:archive][:flags],
|
80
|
+
['-f', save_to],
|
81
|
+
['-C', File.dirname(directory)],
|
82
|
+
File.basename(directory),
|
83
|
+
]
|
84
|
+
|
85
|
+
system(*archive_cmd.flatten)
|
86
|
+
end
|
87
|
+
|
60
88
|
# The last command run by `.system()` is accessible via
|
61
89
|
# the `.last` attribute.
|
62
90
|
#
|
@@ -72,7 +100,7 @@ module Marionetta
|
|
72
100
|
# A block can be called against this method just like
|
73
101
|
# `.system()` in order to get `stdout` and `stderr`.
|
74
102
|
#
|
75
|
-
#
|
103
|
+
# Example:
|
76
104
|
#
|
77
105
|
# server = Marionetta.default_server
|
78
106
|
# server[:hostname] = 'example.com'
|
@@ -96,25 +124,9 @@ module Marionetta
|
|
96
124
|
system(*ssh_cmd.flatten, &block)
|
97
125
|
end
|
98
126
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
elsif File.directory?(save_to)
|
103
|
-
dirname = File.basename(directory)
|
104
|
-
save_to = "#{save_to}/#{dirname}.#{server[:archive][:ext]}"
|
105
|
-
end
|
106
|
-
|
107
|
-
archive_cmd = [
|
108
|
-
server[:archive][:command],
|
109
|
-
server[:archive][:flags],
|
110
|
-
['-f', save_to],
|
111
|
-
['-C', File.dirname(directory)],
|
112
|
-
File.basename(directory),
|
113
|
-
]
|
114
|
-
|
115
|
-
system(*archive_cmd.flatten)
|
116
|
-
end
|
117
|
-
|
127
|
+
# Extract an archive, optionally to a specified directory
|
128
|
+
# on a remote machine.
|
129
|
+
#
|
118
130
|
def ssh_extract(archive_path, save_to = File.dirname(archive_path))
|
119
131
|
cmds = [
|
120
132
|
"mkdir -p #{save_to}",
|
@@ -132,6 +144,15 @@ module Marionetta
|
|
132
144
|
ssh(cmds.join(' && '))
|
133
145
|
end
|
134
146
|
|
147
|
+
# Using the rsync command copy one file system location to
|
148
|
+
# another. These may be both local or remote, or a mixture
|
149
|
+
# of the two.
|
150
|
+
#
|
151
|
+
# Example:
|
152
|
+
#
|
153
|
+
# rsync('/var/www/logs', '/var/backups/www/logs')
|
154
|
+
# rsync('/var/www/logs', 'ubuntu@example.com:/var/backups/www/logs')
|
155
|
+
#
|
135
156
|
def rsync(from, to)
|
136
157
|
rsync_cmd = [server[:rsync][:command]]
|
137
158
|
|
@@ -144,10 +165,18 @@ module Marionetta
|
|
144
165
|
system(*rsync_cmd.flatten)
|
145
166
|
end
|
146
167
|
|
168
|
+
# Short hand for grabbing a file from `:hostname` saving
|
169
|
+
# to the same location on the local machine unless a path
|
170
|
+
# is specified.
|
171
|
+
#
|
147
172
|
def get(file_path, save_to = File.dirname(file_path))
|
148
173
|
rsync("#{server[:hostname]}:#{file_path}", save_to)
|
149
174
|
end
|
150
175
|
|
176
|
+
# Short hand for putting a file to `:hostname` from the
|
177
|
+
# local machine to the same location on the remote
|
178
|
+
# machine unless a path is specified.
|
179
|
+
#
|
151
180
|
def put(file_path, save_to = File.dirname(file_path))
|
152
181
|
rsync(file_path, "#{server[:hostname]}:#{save_to}")
|
153
182
|
end
|
data/lib/marionetta/group.rb
CHANGED
@@ -1,21 +1,40 @@
|
|
1
|
+
# `Group` represents a collection of `server` hashes and
|
2
|
+
# provides `.each_server()` and `.manipulate_each_server` as
|
3
|
+
# isolated interation methods.
|
4
|
+
#
|
5
|
+
# You can also nest groups within other groups so that
|
6
|
+
# multiple groups can be operated on at once.
|
7
|
+
#
|
8
|
+
# The external requirement for this file is `celluloid` so we
|
9
|
+
# can iterate over `@servers` in parallel.
|
10
|
+
#
|
1
11
|
require 'marionetta'
|
2
12
|
require 'marionetta/manipulators'
|
3
13
|
require 'celluloid'
|
4
14
|
|
5
15
|
module Marionetta
|
6
16
|
class Group
|
7
|
-
attr_reader :name
|
8
17
|
|
18
|
+
# Group name is currently optional.
|
19
|
+
#
|
9
20
|
def initialize(name = nil)
|
10
21
|
@name = name
|
11
22
|
@groups = []
|
12
23
|
@servers = []
|
13
24
|
end
|
14
25
|
|
26
|
+
# The name of the group.
|
27
|
+
#
|
28
|
+
attr_reader :name
|
29
|
+
|
30
|
+
# Nest a group using `.add_group()`.
|
31
|
+
#
|
15
32
|
def add_group(group)
|
16
33
|
@groups << group
|
17
34
|
end
|
18
35
|
|
36
|
+
# Get all descending groups contained within this group.
|
37
|
+
#
|
19
38
|
def groups()
|
20
39
|
groups = @groups
|
21
40
|
|
@@ -26,12 +45,25 @@ module Marionetta
|
|
26
45
|
return groups
|
27
46
|
end
|
28
47
|
|
48
|
+
# Add a `server` hash or build on the default server in a
|
49
|
+
# block.
|
50
|
+
#
|
51
|
+
# Example:
|
52
|
+
#
|
53
|
+
# staging = Marionetta::Group.new(:staging)
|
54
|
+
# staging.add_server(:hostname => 'ubuntu@example.com')
|
55
|
+
# staging.add_server do |s|
|
56
|
+
# s[:hostname] = 'ubuntu@example.com'
|
57
|
+
# end
|
58
|
+
#
|
29
59
|
def add_server(server = nil)
|
30
60
|
server ||= Marionetta.default_server
|
31
61
|
yield server if block_given?
|
32
62
|
@servers << server
|
33
63
|
end
|
34
64
|
|
65
|
+
# Get servers in this group and all descendant groups.
|
66
|
+
#
|
35
67
|
def servers()
|
36
68
|
servers = @servers
|
37
69
|
|
@@ -42,6 +74,16 @@ module Marionetta
|
|
42
74
|
return servers
|
43
75
|
end
|
44
76
|
|
77
|
+
# Iterate over each `server` definition (including nested
|
78
|
+
# servers) in parallel by passing a block.
|
79
|
+
#
|
80
|
+
# each_server do |s|
|
81
|
+
# cmd = Marionetta::CommandRunner.new(s)
|
82
|
+
# cmd.ssh('whoami') do |out|
|
83
|
+
# puts out.read
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
#
|
45
87
|
def each_server()
|
46
88
|
futures = []
|
47
89
|
|
@@ -62,6 +104,15 @@ module Marionetta
|
|
62
104
|
return return_values
|
63
105
|
end
|
64
106
|
|
107
|
+
# Manipulate each server by passing a manipulator key as
|
108
|
+
# registered with `Manipulators` and a method name.
|
109
|
+
#
|
110
|
+
# If manipulator cannot be run on a server definition then
|
111
|
+
# a warn message will be logged.
|
112
|
+
#
|
113
|
+
# If block passed in then the server and return value for
|
114
|
+
# each server will be passed in when complete.
|
115
|
+
#
|
65
116
|
def manipulate_each_server(manipulator_name, method_name)
|
66
117
|
each_server do |s|
|
67
118
|
manipulator = Manipulators[manipulator_name].new(s)
|
@@ -144,7 +144,7 @@ module Marionetta
|
|
144
144
|
puppet_cmd = ['sudo puppet apply']
|
145
145
|
|
146
146
|
if server[:puppet].has_key?(:modules)
|
147
|
-
puppet_cmd <<
|
147
|
+
puppet_cmd << "--modulepath=#{puppet_tmp}/modules"
|
148
148
|
end
|
149
149
|
|
150
150
|
puppet_cmd << 'manifest.pp'
|
@@ -1,9 +1,25 @@
|
|
1
|
+
# `Manipulators` is a container for registering manipulators.
|
2
|
+
#
|
3
|
+
# The interface of a manipulator is:
|
4
|
+
#
|
5
|
+
# self.tasks() an array of methods to expose via
|
6
|
+
# RakeHelpers *optional*
|
7
|
+
#
|
8
|
+
# initialize(server) *required*
|
9
|
+
# can?() *required*
|
10
|
+
#
|
1
11
|
module Marionetta
|
2
12
|
module Manipulators
|
13
|
+
|
14
|
+
# We automatically require the manipulators packaged with
|
15
|
+
# this library. *Is this a good idea?*
|
16
|
+
#
|
3
17
|
require_relative 'manipulators/deployer'
|
4
18
|
require_relative 'manipulators/debloyer'
|
5
19
|
require_relative 'manipulators/puppet_manipulator'
|
6
20
|
|
21
|
+
# A hash of all the manipulators.
|
22
|
+
#
|
7
23
|
def self.all()
|
8
24
|
{
|
9
25
|
:deployer => Deployer,
|
@@ -12,6 +28,8 @@ module Marionetta
|
|
12
28
|
}
|
13
29
|
end
|
14
30
|
|
31
|
+
# Get a manipulator.
|
32
|
+
#
|
15
33
|
def self.[](key)
|
16
34
|
all[key]
|
17
35
|
end
|
@@ -1,3 +1,9 @@
|
|
1
|
+
# `RakeHelper` is provided for those of you who wish to use
|
2
|
+
# Marionetta in your `Rakefile`.
|
3
|
+
#
|
4
|
+
# One method is provided to expose tasks of a specified group,
|
5
|
+
# `.install_group_tasks(group)`.
|
6
|
+
#
|
1
7
|
require 'marionetta'
|
2
8
|
require 'marionetta/manipulators'
|
3
9
|
require 'rake'
|
data/lib/marionetta.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# Marionetta is a ruby library for executing
|
2
|
-
# or more remote machines via SSH.
|
1
|
+
# [Marionetta][homepage] is a ruby library for executing
|
2
|
+
# commands on one or more remote machines via SSH.
|
3
3
|
#
|
4
4
|
# It provides puppet provisioning without the need for a
|
5
5
|
# puppet master and can also deploy your application code
|
@@ -21,12 +21,13 @@
|
|
21
21
|
# where you can report issues and send your well thought out
|
22
22
|
# pull requests.
|
23
23
|
#
|
24
|
+
# [homepage]: http://drpheltright.github.com/marionetta/
|
25
|
+
# [github]: https://github.com/DrPheltRight/marionetta/
|
24
26
|
# [author]: http://lukemorton.co.uk
|
25
|
-
# [github]: https://github.com/DrPheltRight/marionetta
|
26
27
|
#
|
27
28
|
module Marionetta
|
28
29
|
|
29
|
-
VERSION = '0.4.
|
30
|
+
VERSION = '0.4.2'
|
30
31
|
|
31
32
|
### Defining Servers
|
32
33
|
|
data/marionetta.gemspec
CHANGED
@@ -3,10 +3,14 @@ require File.dirname(__FILE__)+'/lib/marionetta'
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "marionetta"
|
5
5
|
s.version = Marionetta::VERSION
|
6
|
+
|
6
7
|
s.homepage = 'https://github.com/DrPheltRight/marionetta'
|
8
|
+
|
7
9
|
s.authors = ["Luke Morton"]
|
8
10
|
s.email = ["lukemorton.dev@gmail.com"]
|
11
|
+
|
9
12
|
s.summary = "Provision using puppet and deploy your servers over SSH."
|
13
|
+
|
10
14
|
s.description = "Marionetta is a ruby library for executing commands on one
|
11
15
|
or more remote machines via SSH. It provides puppet
|
12
16
|
provisioning without the need for a puppet master and can
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marionetta
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: open4
|