puppet-masterless 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/puppet-masterless +180 -0
- metadata +46 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f25c87151bb067f0180ff521e3d9321de1bde8c6
|
4
|
+
data.tar.gz: 27e83b426523ea8d6424f44826d9ce552ae20aa6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 54f080712152dad70216e838c52664572e945e25fea3f15a4507a8208cece077cd087fbdc6c19a42b7e3c9f7b2db59e180b8bada031bb577dbe0ef8d7de2017c
|
7
|
+
data.tar.gz: bdab25968892f155f6fb37e0ebb462a975db8476c36978572b01463561a57ec82b2363ca851357dfb7954c8094d47509fcb39a75e768f4a1878d93e3c8e3c478
|
@@ -0,0 +1,180 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Usage: puppet-masterless <subcommand> [<argument> ...] [-- puppet arguments ...]
|
4
|
+
#
|
5
|
+
# Applies a local puppet project to a remote host.
|
6
|
+
#
|
7
|
+
# Available subcommands:
|
8
|
+
#
|
9
|
+
# package
|
10
|
+
# apply
|
11
|
+
#
|
12
|
+
# Available arguments:
|
13
|
+
#
|
14
|
+
# confdir <directory>
|
15
|
+
# hiera_config <file>
|
16
|
+
# manifest <file>
|
17
|
+
# modulepath <directory>
|
18
|
+
# puppet <executable>
|
19
|
+
# to <hostname>
|
20
|
+
# as <username>
|
21
|
+
# file <file>
|
22
|
+
#
|
23
|
+
# At least <confdir> must be specified.
|
24
|
+
#
|
25
|
+
|
26
|
+
require 'shellwords'
|
27
|
+
|
28
|
+
module PuppetMasterless
|
29
|
+
ARCHIVE_NAME = 'puppet-masterless'
|
30
|
+
ARCHIVE_OPTIONS = '--ignore-failed-read --exclude-vcs'
|
31
|
+
DEFAULT_PUPPET = 'puppet'
|
32
|
+
REMOTE_USER = 'root'
|
33
|
+
REMOTE_WORKDIR = '/tmp'
|
34
|
+
|
35
|
+
class Main
|
36
|
+
def initialize
|
37
|
+
@files = []
|
38
|
+
@args = []
|
39
|
+
@path = ARCHIVE_NAME
|
40
|
+
@puppet = DEFAULT_PUPPET
|
41
|
+
@user = REMOTE_USER
|
42
|
+
@workdir = REMOTE_WORKDIR
|
43
|
+
@output = "#{ARCHIVE_NAME}.sh"
|
44
|
+
end
|
45
|
+
|
46
|
+
def banner
|
47
|
+
File.read(__FILE__).lines[1..23].map { |s| s.gsub(/^# ?/, '') }
|
48
|
+
end
|
49
|
+
|
50
|
+
def usage n = 1
|
51
|
+
STDERR.puts(banner)
|
52
|
+
exit(n)
|
53
|
+
end
|
54
|
+
|
55
|
+
def collect args
|
56
|
+
while word = args.shift
|
57
|
+
case word
|
58
|
+
when 'with', 'and'
|
59
|
+
when 'confdir' then @confdir = args.shift
|
60
|
+
when 'manifest' then @manifest = args.shift
|
61
|
+
when 'modulepath' then @modulepath = args.shift
|
62
|
+
when 'hiera_config' then @hiera_config = args.shift
|
63
|
+
when 'puppet' then @puppet = args.shift
|
64
|
+
when 'to' then @hostname = args.shift
|
65
|
+
when 'as' then @user = args.shift
|
66
|
+
when 'file' then @files << args.shift
|
67
|
+
when '--', nil then @args = args.slice!(0..-1)
|
68
|
+
else fail 'Invalid argument: ' << word
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate
|
74
|
+
fail 'No confdir specified' unless @confdir
|
75
|
+
fail 'No puppet specified' unless @puppet
|
76
|
+
|
77
|
+
@manifest ||= File.join(@confdir, 'manifests')
|
78
|
+
@modulepath ||= File.join(@confdir, 'modules')
|
79
|
+
@hiera_config ||= File.join(@confdir, 'hiera.yaml')
|
80
|
+
|
81
|
+
fail 'No such confdir: ' << @confdir unless File.directory?(@confdir)
|
82
|
+
fail 'No such manifest: ' << @manifest unless File.exist?(@manifest)
|
83
|
+
|
84
|
+
@modulepath = nil unless File.directory?(@modulepath)
|
85
|
+
@hiera_config = nil unless File.file?(@hiera_config)
|
86
|
+
end
|
87
|
+
|
88
|
+
def package
|
89
|
+
create_distribution
|
90
|
+
end
|
91
|
+
|
92
|
+
def apply
|
93
|
+
if @hostname
|
94
|
+
create_distribution
|
95
|
+
apply_remote
|
96
|
+
else
|
97
|
+
apply_local
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def archive_command
|
104
|
+
"tar -czf- #{ARCHIVE_OPTIONS} --transform 's|^|#{@path.gsub("'", "'\''")}/|' \
|
105
|
+
#{@files.shelljoin} \
|
106
|
+
#{@manifest.shellescape} \
|
107
|
+
#{@modulepath.shellescape if @modulepath} \
|
108
|
+
#{@hiera_config.shellescape if @hiera_config}"
|
109
|
+
end
|
110
|
+
|
111
|
+
def local_apply_command
|
112
|
+
command = "exec #{@puppet} apply #{@manifest.shellescape} --verbose --show_diff --color true --confdir #{@confdir.shellescape}"
|
113
|
+
command << ' --modulepath ' << @modulepath.shellescape if @modulepath
|
114
|
+
command << ' --hiera_config ' << @hiera_config.shellescape if @hiera_config
|
115
|
+
command << ' ' << @args.shelljoin
|
116
|
+
end
|
117
|
+
|
118
|
+
def remote_apply_command
|
119
|
+
"sudo -u #{@user.shellescape} #{@workdir.shellescape}/#{@output.shellescape}"
|
120
|
+
end
|
121
|
+
|
122
|
+
def remote_cleanup_command
|
123
|
+
"sudo -u #{@user.shellescape} rm -f #{@workdir.shellescape}/#{@output.shellescape} -r #{@workdir.shellescape}/#{@path.shellescape}"
|
124
|
+
end
|
125
|
+
|
126
|
+
def apply_local
|
127
|
+
STDERR.puts('Notice: Applying locally')
|
128
|
+
fail 'Apply command failed' unless system(local_apply_command)
|
129
|
+
end
|
130
|
+
|
131
|
+
def apply_remote
|
132
|
+
STDERR.puts('Notice: Copying to ' << @hostname)
|
133
|
+
fail 'Copy command failed' unless system("scp -q #{@output.shellescape} #{@hostname.shellescape}:#{@workdir.shellescape}")
|
134
|
+
STDERR.puts('Notice: Applying to ' << @hostname)
|
135
|
+
fail 'Apply command failed' unless system("ssh -q -t #{@hostname.shellescape} #{remote_apply_command.shellescape}")
|
136
|
+
ensure
|
137
|
+
system("ssh -q -t #{@hostname.shellescape} #{remote_cleanup_command.shellescape}")
|
138
|
+
end
|
139
|
+
|
140
|
+
def create_distribution
|
141
|
+
STDERR.puts("Notice: Creating distribution")
|
142
|
+
|
143
|
+
File.open(@output, 'w') do |o|
|
144
|
+
o.puts("#!/bin/sh -e")
|
145
|
+
o.puts("sed '0,/^# EOF$/d' \"$0\" | tar -xzf-")
|
146
|
+
o.puts("cd #{@path.shellescape}")
|
147
|
+
o.puts(local_apply_command)
|
148
|
+
o.puts("exit 1")
|
149
|
+
o.puts("# EOF")
|
150
|
+
o.chmod(0755)
|
151
|
+
end
|
152
|
+
|
153
|
+
unless system(archive_command << ' >> ' << @output.shellescape)
|
154
|
+
fail 'Archive command failed: ' << archive_command
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
main = PuppetMasterless::Main.new
|
161
|
+
|
162
|
+
begin
|
163
|
+
case ARGV.shift
|
164
|
+
when 'package'
|
165
|
+
main.collect(ARGV)
|
166
|
+
main.validate
|
167
|
+
main.package
|
168
|
+
when 'apply'
|
169
|
+
main.collect(ARGV)
|
170
|
+
main.validate
|
171
|
+
main.apply
|
172
|
+
when '-h', '--help', nil
|
173
|
+
main.usage(0)
|
174
|
+
else
|
175
|
+
main.usage(1)
|
176
|
+
end
|
177
|
+
rescue => e
|
178
|
+
STDERR.puts("Error: #{File.basename($0)}: #{e.message}")
|
179
|
+
exit(1)
|
180
|
+
end
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: puppet-masterless
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Evan Hanson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-01-05 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Packages and optionally applies a multi-file Puppet project to a remote
|
14
|
+
host via SSH.
|
15
|
+
email: evanh@catalyst.net.nz
|
16
|
+
executables:
|
17
|
+
- puppet-masterless
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- bin/puppet-masterless
|
22
|
+
homepage: https://gitlab.wgtn.cat-it.co.nz/devtools/puppet-masterless
|
23
|
+
licenses:
|
24
|
+
- GPLv3
|
25
|
+
metadata: {}
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 2.6.12
|
43
|
+
signing_key:
|
44
|
+
specification_version: 4
|
45
|
+
summary: Apply a local puppet project to a remote host
|
46
|
+
test_files: []
|