Initial commit

This commit is contained in:
Eugene Kirpichov 2012-09-07 17:38:58 -07:00
commit 560671b4eb
25 changed files with 635 additions and 0 deletions

View File

@ -0,0 +1,5 @@
fixtures:
repositories:
"xinetd": "git://github.com/ghoneycutt/puppet-xinetd"
symlinks:
"rsync": "#{source_dir}"

View File

@ -0,0 +1,5 @@
source :rubygems
puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 2.7']
gem 'puppet', puppetversion
gem 'puppetlabs_spec_helper', '>= 0.1.0'

2
deployment/puppet/rsync/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
metadata.json
pkg/

View File

@ -0,0 +1,2 @@
* 2012-06-07 0.1.0
- Initial release

View File

@ -0,0 +1,17 @@
Puppet Labs Rsync Module - Puppet module for managing Rsync
Copyright (C) 2012 Puppet Labs Inc
Puppet Labs can be contacted at: info@puppetlabs.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,9 @@
name 'puppetlabs-rsync'
version '0.1.0'
source 'https://github.com/puppetlabs/puppetlabs-rsync'
author 'Puppet Labs'
license 'Apache License 2.0'
summary 'Puppet module to install and configure rsync'
project_page 'https://github.com/puppetlabs/puppetlabd-rsync'
dependency 'puppetlabs/xinetd', '>= 1.1.0'

View File

@ -0,0 +1,59 @@
# puppetlabs-rsync #
puppetlabs-rsync manages rsync clients, repositories, and servers as well as
providing defines to easily grab data via rsync.
# Definition: rsync::get #
get files via rsync
## Parameters: ##
$source - source to copy from
$path - path to copy to, defaults to $name
$user - username on remote system
$purge - if set, rsync will use '--delete'
$exlude - string to be excluded
$keyfile - ssh key used to connect to remote host
$timeout - timeout in seconds, defaults to 900
## Actions: ##
get files via rsync
## Requires: ##
$source must be set
## Sample Usage: ##
# get file 'foo' via rsync
rsync::get { '/foo':
source => "rsync://${rsyncServer}/repo/foo/",
require => File['/foo'],
}
# Definition: rsync::server::module #
sets up a rsync server
## Parameters: ##
$path - path to data
$comment - rsync comment
$motd - file containing motd info
$read_only - yes||no, defaults to yes
$write_only - yes||no, defaults to no
$list - yes||no, defaults to no
$uid - uid of rsync server, defaults to 0
$gid - gid of rsync server, defaults to 0
$incoming_chmod - incoming file mode, defaults to 644
$outgoing_chmod - outgoing file mode, defaults to 644
## Actions: ##
sets up an rsync server
## Requires: ##
$path must be set
## Sample Usage: ##
# setup default rsync repository
rsync::server::module{ 'repo':
path => $base,
require => File[$base],
}

View File

@ -0,0 +1,2 @@
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'

View File

@ -0,0 +1,9 @@
__________________
< I <3 Puppet Labs >
------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||

View File

@ -0,0 +1,75 @@
# Definition: rsync::get
#
# get files via rsync
#
# Parameters:
# $source - source to copy from
# $path - path to copy to, defaults to $name
# $user - username on remote system
# $purge - if set, rsync will use '--delete'
# $exlude - string to be excluded
# $keyfile - path to ssh key used to connect to remote host, defaults to /home/${user}/.ssh/id_rsa
# $timeout - timeout in seconds, defaults to 900
#
# Actions:
# get files via rsync
#
# Requires:
# $source must be set
#
# Sample Usage:
#
# rsync::get { '/foo':
# source => "rsync://${rsyncServer}/repo/foo/",
# require => File['/foo'],
# } # rsync
#
define rsync::get (
$source,
$path = undef,
$user = undef,
$purge = undef,
$exclude = undef,
$keyfile = undef,
$timeout = '900'
) {
if $keyfile {
$Mykeyfile = $keyfile
} else {
$Mykeyfile = "/home/${user}/.ssh/id_rsa"
}
if $user {
$MyUser = "-e 'ssh -i ${Mykeyfile} -l ${user}' ${user}@"
}
if $purge {
$MyPurge = '--delete'
}
if $exclude {
$MyExclude = "--exclude=${exclude}"
}
if $path {
$MyPath = $path
} else {
$MyPath = $name
}
$rsync_options = "-a ${MyPurge} ${MyExclude} ${MyUser}${source} ${MyPath}"
exec { "rsync ${name}":
command => "rsync -q ${rsync_options}",
path => [ '/bin', '/usr/bin' ],
# perform a dry-run to determine if anything needs to be updated
# this ensures that we only actually create a Puppet event if something needs to
# be updated
# TODO - it may make senes to do an actual run here (instead of a dry run)
# and relace the command with an echo statement or something to ensure
# that we only actually run rsync once
onlyif => "test `rsync --dry-run --itemize-changes ${rsync_options} | wc -l` -gt 0",
timeout => $timeout,
}
}

View File

@ -0,0 +1,10 @@
# Class: rsync
#
# This module manages rsync
#
class rsync {
package { 'rsync':
ensure => installed,
}
}

View File

@ -0,0 +1,23 @@
# Class: rsync::repo
#
# This module creates a rsync repository
#
# Requires:
# class rsync::server
#
class rsync::repo {
include rsync::server
$base = '/data/rsync'
file { $base:
ensure => directory,
}
# setup default rsync repository
rsync::server::module { 'repo':
path => $base,
require => File[$base],
}
}

View File

@ -0,0 +1,59 @@
# Class: rsync::server
#
# The rsync server. Supports both standard rsync as well as rsync over ssh
#
# Requires:
# class xinetd if use_xinetd is set to true
# class rsync
#
class rsync::server(
$use_xinetd = true,
$address = '0.0.0.0',
$motd_file = 'UNSET',
$use_chroot = 'yes'
) inherits rsync {
$rsync_fragments = '/etc/rsync.d'
if($use_xinetd) {
include xinetd
xinetd::service { 'rsync':
bind => $address,
port => '873',
server => '/usr/bin/rsync',
server_args => '--daemon --config /etc/rsync.conf',
require => Package['rsync'],
}
} else {
service { 'rsync':
ensure => running,
enable => true,
subscribe => Exec['compile fragments'],
}
}
if $motd_file != 'UNSET' {
file { '/etc/rsync-motd':
source => 'puppet:///modules/rsync/motd',
}
}
file { $rsync_fragments:
ensure => directory,
}
file { "${rsync_fragments}/header":
content => template('rsync/header.erb'),
}
# perhaps this should be a script
# this allows you to only have a header and no fragments, which happens
# by default if you have an rsync::server but not an rsync::repo on a host
# which happens with cobbler systems by default
exec { 'compile fragments':
refreshonly => true,
command => "ls ${rsync_fragments}/frag-* 1>/dev/null 2>/dev/null && if [ $? -eq 0 ]; then cat ${rsync_fragments}/header ${rsync_fragments}/frag-* > /etc/rsync.conf; else cat ${rsync_fragments}/header > /etc/rsync.conf; fi; $(exit 0)",
subscribe => File["${rsync_fragments}/header"],
path => '/bin:/usr/bin',
}
}

View File

@ -0,0 +1,56 @@
# Definition: rsync::server::module
#
# sets up a rsync server
#
# Parameters:
# $path - path to data
# $comment - rsync comment
# $read_only - yes||no, defaults to yes
# $write_only - yes||no, defaults to no
# $list - yes||no, defaults to yes
# $uid - uid of rsync server, defaults to 0
# $gid - gid of rsync server, defaults to 0
# $incoming_chmod - incoming file mode, defaults to 0644
# $outgoing_chmod - outgoing file mode, defaults to 0644
# $max_connections - maximum number of simultaneous connections allowed, defaults to 0
# $lock_file - file used to support the max connections parameter, defaults to /var/run/rsyncd.lock
# only needed if max_connections > 0
# $secrets_file - path to the file that contains the username:password pairs used for authenticating this module
# $auth_users - list of usernames that will be allowed to connect to this module (must be undef or an array)
# $hosts_allow - list of patterns allowed to connect to this module (man 5 rsyncd.conf for details, must be undef or an array)
# $hosts_deny - list of patterns allowed to connect to this module (man 5 rsyncd.conf for details, must be undef or an array)
#
# sets up an rsync server
#
# Requires:
# $path must be set
#
# Sample Usage:
# # setup default rsync repository
# rsync::server::module { 'repo':
# path => $base,
# require => File[$base],
# }
#
define rsync::server::module (
$path,
$comment = undef,
$read_only = 'yes',
$write_only = 'no',
$list = 'yes',
$uid = '0',
$gid = '0',
$incoming_chmod = '0644',
$outgoing_chmod = '0644',
$max_connections = '0',
$lock_file = '/var/run/rsyncd.lock',
$secrets_file = undef,
$auth_users = undef,
$hosts_allow = undef,
$hosts_deny = undef) {
file { "${rsync::server::rsync_fragments}/frag-${name}":
content => template('rsync/module.erb'),
notify => Exec['compile fragments'],
}
}

View File

@ -0,0 +1,61 @@
require 'spec_helper'
describe 'rsync::server', :type => :class do
let :fragment_file do
"/etc/rsync.d/header"
end
describe 'when using default params' do
it {
should contain_class('xinetd')
should contain_xinetd__service('rsync').with({ 'bind' => '0.0.0.0' })
should_not contain_service('rsync')
should_not contain_file('/etc/rsync-motd')
should contain_file(fragment_file).with_content(/^use chroot\s*=\s*yes$/)
should contain_file(fragment_file).with_content(/^address\s*=\s*0.0.0.0$/)
}
end
describe 'when disabling xinetd' do
let :params do
{ :use_xinetd => false }
end
it {
should_not contain_class('xinetd')
should_not contain_xinetd__service('rsync')
should contain_service('rsync')
}
end
describe 'when setting an motd' do
let :params do
{ :motd_file => true }
end
it {
should contain_file('/etc/rsync-motd')
}
end
describe 'when overriding use_chroot' do
let :params do
{ :use_chroot => 'no' }
end
it {
should contain_file(fragment_file).with_content(/^use chroot\s*=\s*no$/)
}
end
describe 'when overriding address' do
let :params do
{ :address => '10.0.0.42' }
end
it {
should contain_file(fragment_file).with_content(/^address\s*=\s*10.0.0.42$/)
}
end
end

View File

@ -0,0 +1,117 @@
require 'spec_helper'
describe 'rsync::get', :type => :define do
let :title do
'foobar'
end
let :common_params do
{
:source => 'example.com'
}
end
describe "when using default class paramaters" do
let :params do
common_params
end
it {
should contain_exec("rsync foobar").with({
'command' => 'rsync -q -a example.com foobar',
'onlyif' => "test `rsync --dry-run --itemize-changes -a example.com foobar | wc -l` -gt 0",
'timeout' => '900'
})
}
end
describe "when setting the timeout" do
let :params do
common_params.merge( { :timeout => '200' } )
end
it {
should contain_exec("rsync foobar").with({ 'timeout' => '200' })
}
end
describe "when setting a user but not a keyfile" do
let :params do
common_params.merge({ :user => 'mr_baz' })
end
it {
should contain_exec("rsync foobar").with({
'command' => 'rsync -q -a -e \'ssh -i /home/mr_baz/.ssh/id_rsa -l mr_baz\' mr_baz@example.com foobar',
'onlyif' => "test `rsync --dry-run --itemize-changes -a -e \'ssh -i /home/mr_baz/.ssh/id_rsa -l mr_baz\' mr_baz@example.com foobar | wc -l` -gt 0",
})
}
end
describe "when setting a keyfile but not a user" do
let :params do
common_params.merge( { :keyfile => "/path/to/keyfile" } )
end
it {
should contain_exec("rsync foobar").with({
'command' => 'rsync -q -a example.com foobar',
'onlyif' => "test `rsync --dry-run --itemize-changes -a example.com foobar | wc -l` -gt 0",
})
}
end
describe "when setting a user and a keyfile" do
let :params do
common_params.merge({
:user => 'mr_baz',
:keyfile => '/path/to/keyfile'
})
end
it {
should contain_exec("rsync foobar").with({
'command' => 'rsync -q -a -e \'ssh -i /path/to/keyfile -l mr_baz\' mr_baz@example.com foobar',
'onlyif' => "test `rsync --dry-run --itemize-changes -a -e \'ssh -i /path/to/keyfile -l mr_baz\' mr_baz@example.com foobar | wc -l` -gt 0",
})
}
end
describe "when setting an exclude path" do
let :params do
common_params.merge({ :exclude => '/path/to/exclude/' })
end
it {
should contain_exec("rsync foobar").with({
'command' => 'rsync -q -a --exclude=/path/to/exclude/ example.com foobar',
'onlyif' => "test `rsync --dry-run --itemize-changes -a --exclude=/path/to/exclude/ example.com foobar | wc -l` -gt 0",
})
}
end
describe "when enabling purge" do
let :params do
common_params.merge({ :purge => true })
end
it {
should contain_exec("rsync foobar").with({
'command' => 'rsync -q -a --delete example.com foobar',
'onlyif' => "test `rsync --dry-run --itemize-changes -a --delete example.com foobar | wc -l` -gt 0"
})
}
end
describe "when setting a custom path" do
let :params do
common_params.merge({ :path => 'barfoo' })
end
it {
should contain_exec("rsync foobar").with({
'command' => 'rsync -q -a example.com barfoo',
'onlyif' => "test `rsync --dry-run --itemize-changes -a example.com barfoo | wc -l` -gt 0"
})
}
end
end

View File

@ -0,0 +1,79 @@
require 'spec_helper'
describe 'rsync::server::module', :type => :define do
let :title do
'foobar'
end
let :pre_condition do
'class { "rsync::server": }'
end
let :fragment_file do
"/etc/rsync.d/frag-foobar"
end
let :mandatory_params do
{ :path => '/some/path' }
end
let :params do
mandatory_params
end
describe "when using default class paramaters" do
it { should contain_file(fragment_file).with_content(/^\[ foobar \]$/) }
it { should contain_file(fragment_file).with_content(/^path\s*=\s*\/some\/path$/) }
it { should contain_file(fragment_file).with_content(/^read only\s*=\s*yes$/) }
it { should contain_file(fragment_file).with_content(/^write only\s*=\s*no$/) }
it { should contain_file(fragment_file).with_content(/^list\s*=\s*yes$/) }
it { should contain_file(fragment_file).with_content(/^uid\s*=\s*0$/) }
it { should contain_file(fragment_file).with_content(/^gid\s*=\s*0$/) }
it { should contain_file(fragment_file).with_content(/^incoming chmod\s*=\s*0644$/) }
it { should contain_file(fragment_file).with_content(/^outgoing chmod\s*=\s*0644$/) }
it { should contain_file(fragment_file).with_content(/^max connections\s*=\s*0$/) }
it { should_not contain_file(fragment_file).with_content(/^lock file\s*=.*$/) }
it { should_not contain_file(fragment_file).with_content(/^secrets file\s*=.*$/) }
it { should_not contain_file(fragment_file).with_content(/^auth users\s*=.*$/) }
it { should_not contain_file(fragment_file).with_content(/^hosts allow\s*=.*$/) }
it { should_not contain_file(fragment_file).with_content(/^hosts deny\s*=.*$/) }
end
describe "when overriding max connections" do
let :params do
mandatory_params.merge({ :max_connections => 1 })
end
it { should contain_file(fragment_file).with_content(/^max connections\s*=\s*1$/) }
it { should contain_file(fragment_file).with_content(/^lock file\s*=\s*\/var\/run\/rsyncd\.lock$/) }
end
{
:comment => 'super module !',
:read_only => 'no',
:write_only => 'yes',
:list => 'no',
:uid => '4682',
:gid => '4682',
:incoming_chmod => '0777',
:outgoing_chmod => '0777',
:secrets_file => '/path/to/secrets',
:hosts_allow => ['localhost', '169.254.42.51'],
:hosts_deny => ['some-host.example.com', '10.0.0.128']
}.each do |k,v|
describe "when overriding #{k}" do
let :params do
mandatory_params.merge({ k => v })
end
it { should contain_file(fragment_file).with_content(/^#{k.to_s.gsub('_', ' ')}\s*=\s*#{v.to_a.join(' ')}$/)}
end
end
describe "when overriding auth_users" do
let :params do
mandatory_params.merge({ :auth_users => ['me', 'you', 'them'] })
end
it { should contain_file(fragment_file).with_content(/^auth users\s*=\s*me, you, them$/)}
end
end

View File

@ -0,0 +1,6 @@
--format
s
--colour
--loadby
mtime
--backtrace

View File

@ -0,0 +1 @@
require 'puppetlabs_spec_helper/module_spec_helper'

View File

@ -0,0 +1,12 @@
# This file is being maintained by Puppet.
# DO NOT EDIT
pid file = /var/run/rsyncd.pid
uid = nobody
gid = nobody
use chroot = <%= use_chroot %>
log format = %t %a %m %f %b
syslog facility = local3
timeout = 300
address = <%= address %>
<% if motd_file != 'UNSET' %>motd file = <%= motd_file %><% end %>

View File

@ -0,0 +1,21 @@
# This file is being maintained by Puppet.
# DO NOT EDIT
[ <%= name %> ]
path = <%= path %>
read only = <%= read_only %>
write only = <%= write_only %>
list = <%= list %>
uid = <%= uid %>
gid = <%= gid %>
incoming chmod = <%= incoming_chmod %>
outgoing chmod = <%= outgoing_chmod %>
max connections = <%= max_connections %>
<% if Integer(max_connections) > 0 %>lock file = <%= lock_file %><% end %>
<% if comment != :undef %>comment = <%= comment %><% end %>
<% if secrets_file != :undef %>secrets file = <%= secrets_file %><% end %>
<% if auth_users != :undef %>auth users = <%= auth_users.to_a.join(', ')%><% end %>
<% if hosts_allow != :undef %>hosts allow = <%= hosts_allow.to_a.join(' ')%><% end %>
<% if hosts_deny != :undef %>hosts deny = <%= hosts_deny.to_a.join(' ')%><% end %>

View File

@ -0,0 +1 @@
include rsync

View File

@ -0,0 +1 @@
include rsync::repo

View File

@ -0,0 +1,3 @@
class { 'rsync::server':
motd_file => '/etc/rsync-motd',
}