marionetta 0.4.1 → 0.4.2
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/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
|