etch 3.12
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/Rakefile +16 -0
- data/bin/etch +101 -0
- data/bin/etch_cron_wrapper +18 -0
- data/bin/etch_to_trunk +45 -0
- data/etc/ca.pem +1 -0
- data/etc/dhparams +9 -0
- data/lib/etch.rb +1391 -0
- data/lib/etchclient.rb +2420 -0
- data/lib/versiontype.rb +84 -0
- data/man/man8/etch.8 +204 -0
- metadata +78 -0
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rake/gempackagetask'
|
2
|
+
spec = Gem::Specification.new do |s|
|
3
|
+
s.name = 'etch'
|
4
|
+
s.summary = 'Etch system configuration management client'
|
5
|
+
s.add_dependency('facter')
|
6
|
+
s.version = '3.12'
|
7
|
+
s.author = 'Jason Heiss'
|
8
|
+
s.email = 'etch-users@lists.sourceforge.net'
|
9
|
+
s.homepage = 'http://etch.sourceforge.net'
|
10
|
+
s.platform = Gem::Platform::RUBY
|
11
|
+
s.required_ruby_version = '>=1.8'
|
12
|
+
s.files = Dir['**/**']
|
13
|
+
s.executables = [ 'etch', 'etch_to_trunk', 'etch_cron_wrapper' ]
|
14
|
+
end
|
15
|
+
Rake::GemPackageTask.new(spec).define
|
16
|
+
|
data/bin/etch
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
##############################################################################
|
3
|
+
# Etch configuration file management tool
|
4
|
+
##############################################################################
|
5
|
+
|
6
|
+
# Ensure we can find etchclient.rb
|
7
|
+
$:.unshift(File.dirname(__FILE__))
|
8
|
+
|
9
|
+
require 'optparse'
|
10
|
+
require 'etchclient'
|
11
|
+
|
12
|
+
#
|
13
|
+
# Parse the command line options
|
14
|
+
#
|
15
|
+
|
16
|
+
options = {}
|
17
|
+
@generateall = nil
|
18
|
+
|
19
|
+
opts = OptionParser.new(nil, 24, ' ')
|
20
|
+
opts.banner = 'Usage: etch [options] [/path/to/config/file | command] [otherfile ...]'
|
21
|
+
opts.on('--generate-all', 'Request all configuration.') do |opt|
|
22
|
+
@generateall = opt
|
23
|
+
end
|
24
|
+
opts.on('--dry-run', '-n', 'Make no changes.') do |opt|
|
25
|
+
options[:dryrun] = opt
|
26
|
+
end
|
27
|
+
opts.on('--damp-run', "Perform a dry run but run 'setup' entries for files.") do |opt|
|
28
|
+
# Rather than sprinkle checks of two different variables throught the code, if
|
29
|
+
# we're asked to do a damp run then just set the dry run flag to a unique
|
30
|
+
# value. Then we can just check for that specific value at the one place where
|
31
|
+
# the two modes differ: enabling or disabling the execution of 'setup'
|
32
|
+
# entries.
|
33
|
+
options[:dryrun] = 'damp'
|
34
|
+
end
|
35
|
+
opts.on('--interactive', 'Prompt for confirmation before each change.') do |opt|
|
36
|
+
options[:interactive] = opt
|
37
|
+
end
|
38
|
+
opts.on('--full-file', 'Display full new file contents instead of a diff.') do |opt|
|
39
|
+
options[:fullfile] = opt
|
40
|
+
end
|
41
|
+
opts.on('--filename-only', 'Display filename of changed files instead of a diff.') do |opt|
|
42
|
+
options[:filenameonly] = opt
|
43
|
+
end
|
44
|
+
opts.on('--disable-force', 'Ignore the disable_etch file. Use with caution.') do |opt|
|
45
|
+
options[:disableforce] = opt
|
46
|
+
end
|
47
|
+
opts.on('--lock-force', 'Force the removal of any existing lockfiles.') do |opt|
|
48
|
+
options[:lockforce] = opt
|
49
|
+
end
|
50
|
+
opts.on('--local DIR', 'Read configuration from local directory, not server.') do |opt|
|
51
|
+
options[:local] = opt
|
52
|
+
end
|
53
|
+
opts.on('--server SERVER', 'Point etch to an alternate server.') do |opt|
|
54
|
+
options[:server] = opt
|
55
|
+
end
|
56
|
+
opts.on('--tag TAG', 'Request a specific repository tag from the server.') do |opt|
|
57
|
+
options[:tag] = opt
|
58
|
+
end
|
59
|
+
opts.on('--key PRIVATE_KEY', 'Use this private key for signing messages to server.') do |opt|
|
60
|
+
options[:key] = opt
|
61
|
+
end
|
62
|
+
opts.on('--test-base TESTDIR', 'Use an alternate local working directory.') do |opt|
|
63
|
+
options[:varbase] = opt
|
64
|
+
end
|
65
|
+
opts.on('--debug', 'Print lots of messages about what etch is doing.') do |opt|
|
66
|
+
options[:debug] = opt
|
67
|
+
end
|
68
|
+
opts.on('--version', 'Show etch client version.') do |opt|
|
69
|
+
puts Etch::Client::VERSION
|
70
|
+
exit
|
71
|
+
end
|
72
|
+
opts.on_tail('-h', '--help', 'Show this message.') do
|
73
|
+
puts opts
|
74
|
+
exit
|
75
|
+
end
|
76
|
+
|
77
|
+
leftovers = opts.parse(ARGV)
|
78
|
+
files = []
|
79
|
+
commands = []
|
80
|
+
leftovers.each do |leftover|
|
81
|
+
if leftover[0,1] == File::SEPARATOR
|
82
|
+
files << leftover
|
83
|
+
else
|
84
|
+
commands << leftover
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Display a usage message if the user did not specify a valid action to perform.
|
89
|
+
if files.empty? && commands.empty? && !@generateall
|
90
|
+
puts opts
|
91
|
+
exit
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# Do stuff
|
96
|
+
#
|
97
|
+
|
98
|
+
etchclient = Etch::Client.new(options)
|
99
|
+
status = etchclient.process_until_done(files, commands)
|
100
|
+
exit status
|
101
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require 'digest/sha1'
|
5
|
+
|
6
|
+
# Seed the random number generator with the hostname of this box so that
|
7
|
+
# we get a consistent random number. We want to run the registration at a
|
8
|
+
# consistent time on each individual box, but randomize the runs across
|
9
|
+
# the environment.
|
10
|
+
srand(Digest::SHA1.hexdigest(Socket.gethostname)[0,7].hex)
|
11
|
+
|
12
|
+
# Cron job is set to run every hour
|
13
|
+
MAX_SLEEP = 60 * 60
|
14
|
+
|
15
|
+
sleep(rand(MAX_SLEEP))
|
16
|
+
|
17
|
+
exec('/usr/sbin/etch', '--generate-all')
|
18
|
+
|
data/bin/etch_to_trunk
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
require 'nventory'
|
4
|
+
|
5
|
+
@username = ENV['LOGNAME']
|
6
|
+
|
7
|
+
if ARGV.length == 0
|
8
|
+
abort "Usage: #{File.basename($0)} <server1> [<server2> <server3>]"
|
9
|
+
end
|
10
|
+
|
11
|
+
# The etch servers run in UTC
|
12
|
+
ENV['TZ'] = 'UTC'
|
13
|
+
currentheadtag = Time.now.strftime('trunk-%Y%m%d-%H00')
|
14
|
+
|
15
|
+
# Find the requested clients
|
16
|
+
nvclient = NVentory::Client.new
|
17
|
+
results = nvclient.get_objects('nodes', {}, { 'name' => ARGV }, {}, {})
|
18
|
+
ARGV.each do |name|
|
19
|
+
if results.empty? && results[name].nil?
|
20
|
+
abort "No entry found for #{name}"
|
21
|
+
else
|
22
|
+
if !results[name]['config_mgmt_tag'].nil? &&
|
23
|
+
!results[name]['config_mgmt_tag'].empty?
|
24
|
+
puts "Changing #{name} from #{results[name]['config_mgmt_tag']} to #{currentheadtag}"
|
25
|
+
else
|
26
|
+
puts "Setting #{name} to #{currentheadtag}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
while true
|
32
|
+
print "Proceed? [y|n] "
|
33
|
+
response = $stdin.gets.chomp
|
34
|
+
if response == 'y'
|
35
|
+
break
|
36
|
+
elsif response == 'n'
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Update the clients
|
42
|
+
successcount = nvclient.set_objects('nodes', results, {'config_mgmt_tag' => currentheadtag}, @username)
|
43
|
+
|
44
|
+
puts "#{File.basename($0)} operation succeeded for #{successcount} of #{results.size} nodes"
|
45
|
+
|
data/etc/ca.pem
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Add your SSL certificate authority's cert(s) to this file
|
data/etc/dhparams
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
-----BEGIN DH PARAMETERS-----
|
2
|
+
MIIBCAKCAQEA3HySq1WdL67BCSRCJCZYMUIojAWAsvK63D3cOGk0wI9UeM/yeVhz
|
3
|
+
jTswvHOVPZFKIBg1Aeo2eAEdPryDnmjVTgvLbuWkCPouQhBCVsQ1El9ZcXPix1rC
|
4
|
+
tYsg4Kll1jgnwFoHf4xvjPnD/SqsASAiDxYlh4CFVyT1gLgSiUU0rIdudgO3agI5
|
5
|
+
NgiyGOKwyHmNOOQSKA62M/JnoxcBDC7Nou3lqtHpR5yWsUz+csyk+hXZeUba97bm
|
6
|
+
M8OB0PmfK4Vo6JpdO+yc8hjeYBoMsH7g/l3Gm1JqUxxctcY/OuJ+2nkXwsD66E3D
|
7
|
+
yZCoiVd3u4OqAxNO/GG0iUmskjIvokMhUwIBAg==
|
8
|
+
-----END DH PARAMETERS-----
|
9
|
+
|