Commit 130ac1dd authored by Paul Cammish's avatar Paul Cammish
Browse files

Completed FTP fixes, removed symbiosis-skel

parent 116d8f0e
#!/usr/bin/ruby
#
# NAME
# sympl-skel - Populate new domains from a skeleton
#
# SYNOPSIS
# sympl-skel [ --etc path ] [ --prefix prefix ] [ domain ... ]
#
# OPTIONS
# --etc path Set the directory in which configuration is stored.
# Defaults to /etc
#
# --prefix prefix Set the directory prefix for sympl. Defaults to /srv.
#
# --help Show the help information for this script.
#
# --manual Show the manual for this script.
#
# --verbose Show verbose information.
#
# --debug Show debug information.
#
# USAGE
#
# This command checks to see if any domains do not have config dirs and
# populates the ones that don't with the contents of the skeleton directory.
#
# If domains are passed as arguments, it only checks and populates those
# domains.
#
# At the end of this process, hooks are run (see HOOKS)
#
# If an error occurred populating a domain, the script exits with exit code 1
# If a hook returns a non-zero exit code, this script exits with exit code 2
#
# HOOKS
#
# Hooks are executed from the /etc/sympl/skel-hooks.d directory, given the
# following conditions:
#
# * The file is executable
# * The file's name is made up only of alphanumerics, underscore (_) and hyphen
# (-)
#
# If any domain is altered by sympl-skel, at the end of the process all
# the hooks are called with 'domain-populated' passed as their only command-line
# argument and the list of domains that were altered is written to standard
# input, one per line.
#
# AUTHOR
# Telyn <telyn@bytemark.co.uk>
#
require 'English'
require 'getoptlong'
opts = GetoptLong.new(
['--help', '-h', GetoptLong::NO_ARGUMENT],
['--manual', '-m', GetoptLong::NO_ARGUMENT],
['--verbose', '-v', GetoptLong::NO_ARGUMENT],
['--debug', '-d', GetoptLong::NO_ARGUMENT],
['--prefix', '-p', GetoptLong::REQUIRED_ARGUMENT],
['--etc', '-e', GetoptLong::REQUIRED_ARGUMENT]
)
manual = help = false
$VERBOSELOCAL = false
$DEBUG = false
prefix = '/srv'
etc = '/etc'
opts.each do |opt, arg|
case opt
when '--help'
help = true
when '--manual'
manual = true
when '--verbose'
$VERBOSELOCAL = true
when '--debug'
$DEBUG = true
when '--prefix'
prefix = arg
when '--etc'
etc = arg
end
end
if help || manual
require 'symbiosis/utils'
Symbiosis::Utils.show_help(__FILE__) if help
Symbiosis::Utils.show_manual(__FILE__) if manual
exit 0
end
v = $VERBOSELOCAL
$VERBOSELOCAL = false
#
# The requires spawn a massive stack of warnings in verbose mode. So let's
# hide them.
#
require 'symbiosis'
require 'symbiosis/domains'
require 'symbiosis/domain_skeleton'
$VERBOSELOCAL = v
Symbiosis.etc = etc
Symbiosis.prefix = prefix
domains = []
ARGV.each do |arg|
domain = Symbiosis::Domains.find(arg.to_s, prefix)
if domain.nil?
warn "** Unable to find/parse domain #{arg.inspect}"
next
end
domains << domain
end
domains = Symbiosis::Domains.all(prefix) if ARGV.empty?
%w[INT TERM].each do |sig|
trap(sig) do
if Process.uid.zero?
Process.euid = 0
Process.egid = 0
end
exit 1
end
end
exit_code = 0
updated_domains = Symbiosis::DomainSkeleton.new.populate!(domains)
domain_errors = updated_domains.reject { |_, err| err.nil? }
unless domain_errors.empty?
# some error occurred
exit_code = 1
end
domains_for_hooks = updated_domains.select { |_, err| err.nil? }
.keys
exit exit_code if domains_for_hooks.empty?
exit_code = 2 unless Symbiosis::DomainSkeleton::Hooks.run!('domains-populated',
domains_for_hooks)
exit exit_code
usr/bin/sympl-encrypt-password usr/bin/symbiosis-encrypt-password
usr/bin/sympl-ip usr/bin/symbiosis-ip
usr/bin/sympl-skel usr/bin/symbiosis-skel
usr/bin/sympl-ssl usr/bin/symbiosis-ssl
usr/bin/sympl-test usr/bin/symbiosis-test
usr/sbin/sympl-configure-ips usr/sbin/symbiosis-configure-ips
......
rm_conffile /etc/ssl/Makefile 2015:1101
......@@ -16,15 +16,15 @@
%:
dh $@ --buildsystem=ruby --with ruby --with-systemd
override_dh_installinit:
# This service is called by sympl-skel.path, so no need to do
# anything other than install it.
dh_installinit --no-start --no-scripts --name sympl-skel
# GROSS HACK. dh_installinit doesn't seem to support systemd units
# other than service, so install it directly.
dh_install debian/sympl-skel.path lib/systemd/system/
dh_systemd_enable sympl-skel.path
dh_systemd_start sympl-skel.path
#override_dh_installinit:
# # This service is called by sympl-skel.path, so no need to do
# # anything other than install it.
# dh_installinit --no-start --no-scripts --name sympl-skel
# # GROSS HACK. dh_installinit doesn't seem to support systemd units
# # other than service, so install it directly.
# dh_install debian/sympl-skel.path lib/systemd/system/
# dh_systemd_enable sympl-skel.path
# dh_systemd_start sympl-skel.path
override_dh_auto_build-indep:
$(MAKE) docs
......
[Unit]
Description=Service for sympl-skel. Activated by sympl-skel.path
[Service]
ExecStart=/usr/bin/sympl-skel
[Unit]
Description=Watcher for sympl-skel automated domain population
[Path]
PathExistsGlob=/srv/*
[Install]
WantedBy=multi-user.target
require 'symbiosis/hooks'
require 'symbiosis/utils'
require 'pathname'
module Symbiosis
# Manages copying a domain skeleton into a freshly-made domain
class DomainSkeleton
attr_reader :skel_dir
def initialize(skel_dir = Symbiosis.path_in_etc('sympl', 'skel.d'))
@skel_dir = skel_dir
end
def params
Dir.glob(File.join(@skel_dir, '**', '*'))
.select { |f| File.file?(f) }
end
def should_populate?(domain)
Dir.mkdir domain.config_dir
rescue Errno::EEXIST
false
end
# after running should_populate? the config directory will have the wrong
# uid, so set it right
def ensure_config_owner(domain)
File.lchown domain.uid, domain.gid, domain.config_dir
end
def path_relative_to_skel(path)
skel = Pathname.new(@skel_dir)
pathname = Pathname.new(path)
pathname.relative_path_from(skel).to_s
end
def read_file(rel_path)
verbose "Reading skeleton #{rel_path}"
src_path = File.join(@skel_dir, rel_path)
Symbiosis::Utils.safe_open(src_path, File::RDONLY, &:read)
end
def write_file!(new_path, domain, contents)
verbose "Writing #{new_path}"
Symbiosis::Utils.safe_open(new_path, File::WRONLY | File::CREAT,
mode: 0o644,
uid: domain.uid,
gid: domain.gid) do |fh|
fh.truncate(0)
fh.write(contents)
end
end
def copy_file!(rel_path, domain)
contents = read_file rel_path
new_path = File.join domain.directory, rel_path
new_dir = File.dirname new_path
verbose "Ensuring #{new_dir} exists"
Symbiosis::Utils.mkdir_p new_dir
write_file! new_path, domain, contents
end
def copy!(domain)
params.each do |path|
copy_file! path_relative_to_skel(path), domain
end
true
end
# returns an array of key-value pair arrays
# where the key is the domain name and the
# value is an error or nil. If nil the copy for that
# domain was successful.
def try_copy!(domains)
domains.map do |domain|
begin
ensure_config_owner(domain)
verbose "Copying skeleton to #{domain.directory}..."
copy! domain
verbose "Copy completed for #{domain.directory}"
[domain.name, nil]
rescue StandardError => e
warn "Error copying to #{domain.directory} - #{e}"
puts e.backtrace.join("\n")
[domain.name, e]
end
end
end
def populate!(domains)
verbose 'Checking which domains to populate...'
domains = domains.select { |domain| should_populate? domain }
verbose "Populating [#{domains.join(', ')}]"
# convert [ [key, value], ... ] from try_copy! to a hash
Hash[try_copy!(domains)]
end
def verbose(str)
warn str if $VERBOSELOCAL
end
# Hooks for DomainSkeleton
# by default these live in /etc/sympl/skel-hooks.d
class Hooks < Symbiosis::Hooks
HOOKS_DIR = File.join('sympl', 'skel-hooks.d')
def self.run!(event, domains)
Symbiosis::DomainSkeleton::Hooks.new.run!(event, domains)
end
def initialize(hooks_dir = Symbiosis.path_in_etc(HOOKS_DIR))
super hooks_dir
end
end
end
end
# encoding: UTF-8
require 'test/unit'
require 'tmpdir'
require 'symbiosis'
require 'symbiosis/domain'
require 'symbiosis/domain_skeleton'
require './helpers.rb'
# tests for DomainSkeleton - ensure hooks work, ensure skeleton copies correctly
class TestDomainSkeleton < Test::Unit::TestCase
def setup
Process.egid = 1000 if Process.gid.zero?
Process.euid = 1000 if Process.uid.zero?
Symbiosis.etc = File.realpath Dir.mktmpdir('etc')
Symbiosis.prefix = File.realpath Dir.mktmpdir('srv')
@verbose = $VERBOSELOCAL || $DEBUG ? ' --verbose ' : ''
testd = File.dirname(__FILE__)
@script = File.expand_path(File.join(testd,"..","bin","sympl-skel"))
@script = '/usr/bin/sympl-skel' unless File.exist?(@script)
@script += @verbose
make_skeleton
end
def make_skeleton
skelpath = Symbiosis.path_in_etc('sympl/skel.d')
Symbiosis::Utils.mkdir_p File.join(skelpath, 'test', 'deep')
Symbiosis::Utils.set_param 'test-param', 'this is a test', skelpath
Symbiosis::Utils.set_param 'test-param', 'also a test', File.join(skelpath, 'test')
Symbiosis::Utils.set_param 'test-param', 'deep test', File.join(skelpath, 'test', 'deep')
@skel = Symbiosis::DomainSkeleton.new skelpath
end
def teardown
unless $DEBUG
FileUtils.rm_rf Symbiosis.etc if File.directory?(Symbiosis.etc)
FileUtils.rm_rf Symbiosis.prefix if File.directory?(Symbiosis.prefix)
end
Process.euid = 0 if Process.uid.zero?
Process.egid = 0 if Process.gid.zero?
end
def test_copy
domain = Symbiosis::Domain.new(nil, Symbiosis.prefix)
domain.create
@skel.copy! domain
assert_equal 'this is a test', domain.get_param('test-param')
assert_equal 'also a test', domain.get_param('test/test-param')
assert_equal 'deep test', domain.get_param('test/deep/test-param')
end
def test_hooks
hooks_dir = Symbiosis.path_in_etc('sympl', 'skel-hooks.d')
result = TestHelpers.make_test_hook hooks_dir
domain = Symbiosis::Domain.new(nil, Symbiosis.prefix)
domain.create
success = Symbiosis::DomainSkeleton::Hooks.run! 'domains-populated', [domain.name]
assert_equal true, success
assert_equal "domains-populated\n", result.args
assert_equal "#{domain.name}\n", result.output
end
def test_symbiosis_skel
hooks_dir = Symbiosis.path_in_etc('sympl', 'skel-hooks.d')
result = TestHelpers.make_test_hook hooks_dir
domain = Symbiosis::Domain.new(nil, Symbiosis.prefix)
domain.create
FileUtils.rm_rf domain.config_dir
pid = spawn("#{@script} --etc=#{Symbiosis.etc} --prefix=#{Symbiosis.prefix}")
_, status = Process.wait2(pid)
assert_equal 0, status.exitstatus
assert_equal "domains-populated\n", result.args
assert_equal "#{domain.name}\n", result.output
end
end
......@@ -177,17 +177,22 @@ begin
exit PERMANENT_ERROR
end
# Override the uid/gid, based on the target chroot dir
# This ensures whatever user is used, they have the right
# ownership
uid_override = File.stat(user.chroot_dir).uid
gid_override = File.stat(user.chroot_dir).gid
#
# Work out results before printing.
#
uid_override = File.stat(#{user.chroot_dir}).uid
gid_override = File.stat(#{user.chroot_dir}).gid
results = [ "uid:#{uid_override}",
"gid:#{gid_override}",
"dir:#{user.chroot_dir}" ]
results << "user_quota_size:#{user.quota}" unless user.quota.nil? or user.quota == 0
#
# Woo-hoo success!
#
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment