Goal
We wish to use vcsrepo
in Puppet to check out a Subversion repository with a
non-root remote user and custom SSH key pair.
Trouble
Despite the fact that vcsrepo
happily accepts the user
parameter (and does
not complain about the identity
parameter except in debug), it does not
actually use either, so the svn
command runs as root and uses root’s SSH
keys.
Solution
All is not lost, however; Subversion allows for custom protocol tunnel schemes
in ~/.subversion/config
, which allow us to specify the SSH command, with
which we can specify the remote user and identity file:
[tunnels]
ssh_user_<remote_user> = $SVN_SSH ssh -q -l <remote_user> -o IdentityFile=<ssh_identity_file>
Now when specifying the source
parameter to the vcsrepo
resource, we can
use svn+ssh_user_<remote_user>
as the protocol part of the repository
URL.
If we want to keep this under the account of a different local user, we can
use vcsrepo
’s configuration
parameter to point to ~/.subversion
:
vcsrepo { '<local_repo>':
ensure => 'latest',
provider => 'svn',
owner => '<local_user>',
group => '<local_group>',
user => '<local_user>',
source => 'svn+ssh_user_<remote_user>://<svn_host>/<repo_path>',
configuration => '/home/<local_user>/.subversion/config',
}
In Puppet
Since the ~/.subversion/config
file is an ini-format file, we can use the
ini_setting
type from
puppetlabs/inifile
module to put it into place.
ini_setting { '/home/<local_user>/.subversion/config/tunnels/ssh_user_<remote_user>':
path => '/home/<local_user>/.subversion/config',
section => 'tunnels',
setting => 'ssh_user_svn',
value => '$SVN_SSH ssh -q -l svn -o IdentityFile=/home/<local_user>/.ssh/id_rsa',
}
We also want to ensure that the ini_setting
is in place before the vcsrepo
is applied. We could use either the require
or before
metaparameters or
resource chaining, but if we have multiple vcsrepos
, explicitly listing each
one would be tedious; applying to all repos would also catch git
repos,
which is unnecessary. Instead, we can use resource
collectors
to select just the appropriate vcsrepo
resources:
Ini_setting['/home/<local_user>/.subversion/config/tunnels/ssh_user_<remote_user>']
-> Vcsrepo <| user == '<remote_user>' and provider == 'svn' |>
Migration
If the working copy already exists (for example, perhaps it was being managed
with an exec
resource), then the URL of the working copy will be different
and vcsrepo
won’t fix it. A simple svn switch --relocate
with the
repository root will fix it:
local_user$ svn info |grep Root
Repository Root: svn+ssh://<svn_host>/<repo_path>
$ svn switch --relocate 'svn+ssh://<svn_host>/<repo_path>' \
'svn+ssh_user_<remote_user>://<svn_host>/<repo_path>'
Future
It would be nice if vcsrepo
could support user
directly and could use
identity
. I considered submitting a patch to do so, but it seems better to
use the Puppet execution
API but it does
not support changing UIDs in Puppet 2.7 (which I lament to say I am currently
still using). (Not to mention that this is the kind of thing that would be
difficult to test.)