palletjack-tools 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/Gemfile +4 -0
- data/Rakefile +6 -0
- data/exe/create_domain +52 -0
- data/exe/create_ipv4_interface +51 -0
- data/exe/create_system +45 -0
- data/exe/dump_pallet +50 -0
- data/exe/palletjack2kea +108 -0
- data/exe/palletjack2knot +170 -0
- data/exe/palletjack2pxelinux +191 -0
- data/exe/palletjack2salt +140 -0
- data/exe/palletjack2unbound +129 -0
- data/palletjack-tools.gemspec +37 -0
- data.tar.gz.sig +0 -0
- metadata +200 -0
- metadata.gz.sig +3 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1698a81a8f10fd0ae9b078c077a157d62185388d
|
4
|
+
data.tar.gz: 8e00cb7db1fe2051f3ebe34e015f7285dff5cc07
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 41a4e3b367d5f38d5b9514df1e6f8e01571046d46cd5d70ab38f1a4913c44fd9930986af3a4e72b1b9a9978b542a58e26cbe96947c2b39dd15b13505685fd17b
|
7
|
+
data.tar.gz: 1993440970282599886f25403198dc39c86e8f3128451f6a8d63dbef26f2b71b0e5be1b49051f3372ca09490b0dfbaccf72b49669cfbebafea1eda42d628197f
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data/Gemfile
ADDED
data/Rakefile
ADDED
data/exe/create_domain
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Create a domain and IPv4 network in a warehouse
|
4
|
+
#
|
5
|
+
# Data model assumptions:
|
6
|
+
# - Each domain corresponds uniquely to one IPv4 network
|
7
|
+
|
8
|
+
require 'palletjack/tool'
|
9
|
+
|
10
|
+
class CreateDomain < PalletJack::Tool
|
11
|
+
def parse_options(opts)
|
12
|
+
opts.banner =
|
13
|
+
"Usage: #{$PROGRAM_NAME} -w <warehouse> -d <domain> -n <IPv4 network>
|
14
|
+
|
15
|
+
Create domain and ipv4_network objects in a warehouse"
|
16
|
+
|
17
|
+
opts.on('-d DOMAIN', '--domain DOMAIN', 'domain name', String) {|domain|
|
18
|
+
options[:domain] = domain }
|
19
|
+
opts.on('-n NETWORK', '--network NETWORK',
|
20
|
+
'IPv4 network, in CIDR format', String) {|network|
|
21
|
+
options[:network] = network.gsub(/\//, '_') }
|
22
|
+
|
23
|
+
required_option :domain
|
24
|
+
required_option :network
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
CreateDomain.run do
|
29
|
+
|
30
|
+
# Create the IPv4 Network object
|
31
|
+
|
32
|
+
pallet_dir 'ipv4_network', :network
|
33
|
+
pallet_box 'ipv4_network', :network, 'dhcp' do
|
34
|
+
{ net:{ dhcp:{ 'tftp-server' => '', 'boot-file' => '' } } }
|
35
|
+
end
|
36
|
+
pallet_box 'ipv4_network', :network, 'identity' do
|
37
|
+
{ net:{ ipv4:{ gateway:'' },
|
38
|
+
dns:{ resolver:[''] } } }
|
39
|
+
end
|
40
|
+
|
41
|
+
# Create the DNS domain object
|
42
|
+
|
43
|
+
pallet_dir 'domain', :domain
|
44
|
+
pallet_box 'domain', :domain, 'dns' do
|
45
|
+
{ net:{ dns:{ ns:[''], 'soa-ns' => '', 'soa-contact' => '' } } }
|
46
|
+
end
|
47
|
+
pallet_box 'domain', :domain, 'services' do
|
48
|
+
{ net:{ service:{ syslog:[{address:'', port:'514', protocol:'udp' } ] } } }
|
49
|
+
end
|
50
|
+
pallet_links 'domain', :domain, 'ipv4_network' => ['ipv4_network', :network]
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Create a physical and logical IPv4 network interface in a warehouse
|
4
|
+
|
5
|
+
require 'palletjack/tool'
|
6
|
+
|
7
|
+
class CreateIPv4Interface < PalletJack::Tool
|
8
|
+
def parse_options(opts)
|
9
|
+
opts.banner =
|
10
|
+
"Usage: #{$PROGRAM_NAME} -w <warehouse> -s <system> -d <domain> \\
|
11
|
+
-m <MAC address> -i <IPv4 address> -n <IPv4 network>
|
12
|
+
|
13
|
+
Create phy_nic and ipv4_interface objects in a warehouse"
|
14
|
+
|
15
|
+
opts.on('-s SYSTEM', '--system SYSTEM', 'system name', String) {|system|
|
16
|
+
options[:system] = system }
|
17
|
+
opts.on('-d DOMAIN', '--domain DOMAIN', 'domain name',String) {|domain|
|
18
|
+
options[:domain] = domain }
|
19
|
+
opts.on('-m MAC', '--mac MAC', 'MAC address', String) {|mac|
|
20
|
+
options[:mac] = mac }
|
21
|
+
opts.on('-i ADDR', '--ipv4 ADDR', 'IPv4 address', String) {|addr|
|
22
|
+
options[:addr] = addr }
|
23
|
+
opts.on('-n NETWORK', '--network NETWORK', 'IPv4 network, in CIDR format',
|
24
|
+
String) {|network| options[:network] = network.gsub(/\//, '_') }
|
25
|
+
|
26
|
+
required_option :system
|
27
|
+
required_option :domain
|
28
|
+
required_option :mac
|
29
|
+
required_option :addr
|
30
|
+
required_option :network
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
CreateIPv4Interface.run do
|
35
|
+
|
36
|
+
# Create Physical NIC object
|
37
|
+
|
38
|
+
pallet_dir 'phy_nic', :mac
|
39
|
+
pallet_box 'phy_nic', :mac, 'identity' do
|
40
|
+
{ net:{ layer2:{ name:'' } } }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Create IPv4 Interface object
|
44
|
+
|
45
|
+
pallet_dir 'ipv4_interface', :addr
|
46
|
+
pallet_links 'ipv4_interface', :addr,
|
47
|
+
'ipv4_network' => ['ipv4_network', :network],
|
48
|
+
'domain' => ['domain', :domain],
|
49
|
+
'phy_nic' => ['phy_nic', :mac],
|
50
|
+
'system' => ['system', :system]
|
51
|
+
end
|
data/exe/create_system
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Create a system in a warehouse
|
4
|
+
|
5
|
+
require 'palletjack/tool'
|
6
|
+
|
7
|
+
class CreateSystem < PalletJack::Tool
|
8
|
+
def parse_options(opts)
|
9
|
+
opts.banner =
|
10
|
+
"Usage: #{$PROGRAM_NAME} -w <warehouse> -s <system> -d <domain> \\
|
11
|
+
[ -o <os> | -n <netinstall> ]
|
12
|
+
|
13
|
+
Create system objects in a warehouse"
|
14
|
+
|
15
|
+
opts.on('-s SYSTEM', '--system SYSTEM', 'system name', String) {|system|
|
16
|
+
options[:system] = system }
|
17
|
+
opts.on('-d DOMAIN', '--domain DOMAIN', 'domain name', String) {|domain|
|
18
|
+
options[:domain] = domain }
|
19
|
+
opts.on('-o OS', '--os OS', 'operating system name', String) {|os|
|
20
|
+
options[:os] = os }
|
21
|
+
opts.on('-n OS', '--netinstall NETINSTALL', 'network installation profile',
|
22
|
+
String) {|netinstall| options[:netinstall] = netinstall }
|
23
|
+
|
24
|
+
required_option :system
|
25
|
+
required_option :domain
|
26
|
+
required_option :os, :netinstall
|
27
|
+
exclusive_options :os, :netinstall
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
CreateSystem.run do
|
32
|
+
pallet_dir 'system', :system
|
33
|
+
pallet_box 'system', :system, 'role' do
|
34
|
+
{ system:{ role:[ '' ] } }
|
35
|
+
end
|
36
|
+
pallet_links 'system', :system, 'domain' => ['domain', :domain]
|
37
|
+
pallet_links 'system', :system,
|
38
|
+
if options[:os]
|
39
|
+
{ 'os' => ['os', :os], 'netinstall' => [] }
|
40
|
+
elsif options[:netinstall]
|
41
|
+
{ 'os' => [], 'netinstall' => ['netinstall', :netinstall] }
|
42
|
+
else
|
43
|
+
abort('Both --os and --netinstall were nil; should not happen!')
|
44
|
+
end
|
45
|
+
end
|
data/exe/dump_pallet
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Simple script for dumping a specified pallet as YAML.
|
4
|
+
|
5
|
+
require 'palletjack/tool'
|
6
|
+
|
7
|
+
class DumpPallet < PalletJack::Tool
|
8
|
+
def parse_options(parser)
|
9
|
+
|
10
|
+
parser.banner = "Usage: #{$PROGRAM_NAME} [options] [<name> ...]
|
11
|
+
|
12
|
+
Dump the YAML representation of all named pallets in a Palletjack warehouse
|
13
|
+
|
14
|
+
If a name is specified, dump only that pallet. Otherwise, dump all
|
15
|
+
pallets of the specified type."
|
16
|
+
|
17
|
+
# The preset value for options[:type] will be overridden when
|
18
|
+
# the parse! method of the parser is eventually run and finds
|
19
|
+
# a --type option. Keep declarations in that order for clarity.
|
20
|
+
|
21
|
+
options[:type]='system'
|
22
|
+
parser.on('-t TYPE', '--type TYPE',
|
23
|
+
'type (default "system")',
|
24
|
+
String) {|type| options[:type] = type }
|
25
|
+
end
|
26
|
+
|
27
|
+
# Dump the yaml contents of all pallets given to STDOUT
|
28
|
+
|
29
|
+
def dump_pallets(pallets)
|
30
|
+
abort('No matching pallets found.') if pallets.empty?
|
31
|
+
|
32
|
+
pallets.each do |p|
|
33
|
+
puts "---"
|
34
|
+
puts "# #{p.kind}: #{p.name}"
|
35
|
+
puts p.to_yaml
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
DumpPallet.run do
|
41
|
+
# Since the Tool framework uses destructive opts.parse!, all options
|
42
|
+
# were removed from argv, leaving just the names to search for.
|
43
|
+
if argv.empty?
|
44
|
+
dump_pallets jack[kind: options[:type]]
|
45
|
+
else
|
46
|
+
argv.each do |name|
|
47
|
+
dump_pallets jack[kind: options[:type], name: name]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/exe/palletjack2kea
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Write configuration for the Kea DHCP server from a Palletjack warehouse
|
4
|
+
|
5
|
+
require 'palletjack/tool'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
class PalletJack2Kea < PalletJack::Tool
|
9
|
+
def parse_options(opts)
|
10
|
+
opts.banner =
|
11
|
+
"Usage: #{$PROGRAM_NAME} [options] <name> ...
|
12
|
+
|
13
|
+
Write configuration for the Kea DHCP server from a Palletjack warehouse"
|
14
|
+
|
15
|
+
opts.on('-s SERVICE', '--service SERVICE',
|
16
|
+
'service name for global configuration',
|
17
|
+
String) {|service| options[:service] = service }
|
18
|
+
|
19
|
+
required_option :service
|
20
|
+
end
|
21
|
+
|
22
|
+
def dhcp4_option(code, name, data)
|
23
|
+
{
|
24
|
+
'code' => code,
|
25
|
+
'name' => name,
|
26
|
+
'space' => 'dhcp4',
|
27
|
+
'csv-format' => true,
|
28
|
+
'data' => data
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
# The internal representation of the generated configuration, ready
|
33
|
+
# to be tested or printed.
|
34
|
+
|
35
|
+
attr_reader :kea_config
|
36
|
+
|
37
|
+
def process
|
38
|
+
@kea_config = { 'Dhcp4' => {} }
|
39
|
+
|
40
|
+
jack.each(kind:'service', name:options[:service]) do |service_config|
|
41
|
+
@kea_config['Dhcp4'] = service_config['service.kea_v4']
|
42
|
+
end
|
43
|
+
|
44
|
+
@kea_config['Dhcp4']['subnet4'] = []
|
45
|
+
|
46
|
+
jack.each(kind:'ipv4_network') do |net|
|
47
|
+
net_config = {'subnet' => net['net.ipv4.cidr'],
|
48
|
+
'reservations' => [],
|
49
|
+
'option-data' => []}
|
50
|
+
if net['net.ipv4.gateway']
|
51
|
+
net_config['option-data'] <<
|
52
|
+
dhcp4_option(3, 'routers', net['net.ipv4.gateway'])
|
53
|
+
end
|
54
|
+
|
55
|
+
if net['net.dns.resolver']
|
56
|
+
resolvers = ''
|
57
|
+
net['net.dns.resolver'].each do |resolver|
|
58
|
+
resolvers << resolver << ', '
|
59
|
+
end
|
60
|
+
|
61
|
+
net_config['option-data'] <<
|
62
|
+
dhcp4_option(6, 'domain-name-servers', resolvers.chomp(', '))
|
63
|
+
end
|
64
|
+
|
65
|
+
if net['net.dhcp.tftp-server']
|
66
|
+
net_config['option-data'] <<
|
67
|
+
dhcp4_option(66, 'tftp-server-name', net['net.dhcp.tftp-server'])
|
68
|
+
|
69
|
+
# Option 66/tftp-server-name is the standard way of sending a
|
70
|
+
# TFTP server address, but some DHCP clients still want it in
|
71
|
+
# the next-server field.
|
72
|
+
net_config['next-server'] = net['net.dhcp.tftp-server']
|
73
|
+
end
|
74
|
+
|
75
|
+
if net['net.dhcp.boot-file']
|
76
|
+
net_config['option-data'] <<
|
77
|
+
dhcp4_option(67, 'boot-file-name', net['net.dhcp.boot-file'])
|
78
|
+
end
|
79
|
+
|
80
|
+
net.children(kind:'ipv4_interface',
|
81
|
+
none?:{ 'net.layer2.address' => nil }
|
82
|
+
) do |interface|
|
83
|
+
net_config['reservations'] << {
|
84
|
+
'hw-address' => interface['net.layer2.address'],
|
85
|
+
'ip-address' => interface['net.ipv4.address'],
|
86
|
+
'hostname' => interface['net.dns.fqdn'],
|
87
|
+
'option-data' =>
|
88
|
+
[
|
89
|
+
dhcp4_option(15, 'domain-name',
|
90
|
+
interface.parents(kind:'system').first['net.dns.domain'])
|
91
|
+
]
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
@kea_config['Dhcp4']['subnet4'] << net_config
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def output
|
100
|
+
puts git_header('palletjack2kea')
|
101
|
+
|
102
|
+
jj @kea_config
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
if PalletJack2Kea.standalone?(__FILE__)
|
107
|
+
PalletJack2Kea.run
|
108
|
+
end
|
data/exe/palletjack2knot
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Write DNS server zone file from a Palletjack warehouse
|
4
|
+
#
|
5
|
+
# Data model assumptions:
|
6
|
+
# - Each domain corresponds uniquely to one IPv4 network
|
7
|
+
#
|
8
|
+
# The YAML key "net.dns.alias" is used to create CNAME aliases for
|
9
|
+
# each interface. This means that if a "system" object specifies
|
10
|
+
# "net.dns.alias", each of its interfaces will get that alias in its
|
11
|
+
# own domain. Aliases explicitly specified on a single interface will
|
12
|
+
# override this.
|
13
|
+
|
14
|
+
require 'palletjack/tool'
|
15
|
+
require 'dns/zone'
|
16
|
+
require 'ip'
|
17
|
+
|
18
|
+
class PalletJack2Knot < PalletJack::Tool
|
19
|
+
def parse_options(opts)
|
20
|
+
opts.banner =
|
21
|
+
"Usage: #{$PROGRAM_NAME} -w <warehouse> -o <output directory>
|
22
|
+
|
23
|
+
Write DNS server zone files from a Palletjack warehouse"
|
24
|
+
|
25
|
+
opts.on('-o DIR', '--output DIR', 'output directory', String) {|dir|
|
26
|
+
options[:output] = dir
|
27
|
+
options[:zone_dir] = config_path(:output, "zones")
|
28
|
+
}
|
29
|
+
|
30
|
+
required_option :output
|
31
|
+
end
|
32
|
+
|
33
|
+
def zone_config(zone)
|
34
|
+
"
|
35
|
+
#{zone} {
|
36
|
+
file \"zones/#{zone}.zone\";
|
37
|
+
}
|
38
|
+
"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
PalletJack2Knot.run do
|
43
|
+
config_dir :zone_dir
|
44
|
+
|
45
|
+
# Use Unix timestamp as serial number, and get it once so all zones get
|
46
|
+
# the same one
|
47
|
+
serial = Time.now.utc.to_i
|
48
|
+
|
49
|
+
config_file :output, 'zones.conf' do |conf_file|
|
50
|
+
conf_file << git_header('palletjack2knot')
|
51
|
+
|
52
|
+
jack.each(kind:'domain') do |domain|
|
53
|
+
absolute_domain_name = "#{domain['net.dns.domain']}."
|
54
|
+
|
55
|
+
zone = DNS::Zone.new
|
56
|
+
|
57
|
+
zone.origin = absolute_domain_name
|
58
|
+
zone.ttl = domain['net.dns.ttl']
|
59
|
+
|
60
|
+
zone.soa.serial = serial
|
61
|
+
zone.soa.label = absolute_domain_name
|
62
|
+
zone.soa.nameserver = domain['net.dns.soa-ns']
|
63
|
+
zone.soa.email = "#{domain['net.dns.soa-contact']}.".sub('@', '.')
|
64
|
+
|
65
|
+
if domain['net.dns.mx']
|
66
|
+
domain['net.dns.mx'].each do |server|
|
67
|
+
mx = DNS::Zone::RR::MX.new
|
68
|
+
mx.label = absolute_domain_name
|
69
|
+
mx.priority = server['priority']
|
70
|
+
mx.exchange = server['server']
|
71
|
+
zone.records << mx
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
domain['net.dns.ns'].each do |address|
|
76
|
+
ns = DNS::Zone::RR::NS.new
|
77
|
+
ns.label = absolute_domain_name
|
78
|
+
ns.nameserver = address
|
79
|
+
zone.records << ns
|
80
|
+
end
|
81
|
+
|
82
|
+
if domain['net.dns.cname']
|
83
|
+
domain['net.dns.cname'].each do |name, target|
|
84
|
+
cname = DNS::Zone::RR::CNAME.new
|
85
|
+
cname.label = name
|
86
|
+
cname.domainname = target
|
87
|
+
zone.records << cname
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
if domain['net.dns.srv']
|
92
|
+
domain['net.dns.srv'].each do |service|
|
93
|
+
srv = DNS::Zone::RR::SRV.new
|
94
|
+
srv.label = "_#{service['service']}._#{service['protocol']}"
|
95
|
+
srv.target = service['target']
|
96
|
+
srv.port = service['port']
|
97
|
+
service['priority'] ||= 0
|
98
|
+
srv.priority = service['priority']
|
99
|
+
service['weight'] ||= 0
|
100
|
+
srv.weight = service['weight']
|
101
|
+
zone.records << srv
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
domain.children(kind:'ipv4_interface') do |interface|
|
106
|
+
a = DNS::Zone::RR::A.new
|
107
|
+
a.label = interface['net.dns.name']
|
108
|
+
a.address = interface['net.ipv4.address']
|
109
|
+
zone.records << a
|
110
|
+
|
111
|
+
if interface['net.dns.alias']
|
112
|
+
interface['net.dns.alias'].each do |label|
|
113
|
+
cname = DNS::Zone::RR::CNAME.new
|
114
|
+
cname.label = label
|
115
|
+
cname.domainname = interface['net.dns.name']
|
116
|
+
zone.records << cname
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
config_file :zone_dir, "#{domain['net.dns.domain']}.zone" do |zonefile|
|
122
|
+
zonefile << git_header('palletjack2knot', comment_char: ';')
|
123
|
+
zonefile << zone.dump_pretty
|
124
|
+
end
|
125
|
+
|
126
|
+
conf_file << zone_config(domain['net.dns.domain'])
|
127
|
+
|
128
|
+
next unless domain['net.ipv4.cidr']
|
129
|
+
|
130
|
+
# Assume all delegations happen on octet boundaries for now.
|
131
|
+
# TODO: RFC 2317 classless in-addr.arpa delegation
|
132
|
+
|
133
|
+
reverse_zone = DNS::Zone.new
|
134
|
+
|
135
|
+
ip_net = IP.new(domain['net.ipv4.cidr'])
|
136
|
+
absolute_reverse_zone_name = ip_net.to_arpa
|
137
|
+
|
138
|
+
prefix_octets, _ = domain['net.ipv4.prefixlen'].to_i.divmod(8)
|
139
|
+
reverse_zone.origin = absolute_reverse_zone_name.split('.')[-(2 + prefix_octets) .. 5].join('.')
|
140
|
+
|
141
|
+
reverse_zone.ttl = domain['net.dns.ttl']
|
142
|
+
|
143
|
+
reverse_zone.soa.serial = serial
|
144
|
+
reverse_zone.soa.label = "#{reverse_zone.origin}."
|
145
|
+
reverse_zone.soa.nameserver = domain['net.dns.soa-ns']
|
146
|
+
reverse_zone.soa.email = "#{domain['net.dns.soa-contact']}.".sub('@', '.')
|
147
|
+
|
148
|
+
domain['net.dns.ns'].each do |address|
|
149
|
+
ns = DNS::Zone::RR::NS.new
|
150
|
+
ns.label = "#{reverse_zone.origin}."
|
151
|
+
ns.nameserver = address
|
152
|
+
reverse_zone.records << ns
|
153
|
+
end
|
154
|
+
|
155
|
+
domain.children(kind:'ipv4_interface') do |interface|
|
156
|
+
ptr = DNS::Zone::RR::PTR.new
|
157
|
+
ptr.label = IP.new(interface['net.ipv4.address']).to_arpa
|
158
|
+
ptr.name = "#{interface['net.dns.fqdn']}."
|
159
|
+
reverse_zone.records << ptr
|
160
|
+
end
|
161
|
+
|
162
|
+
config_file :zone_dir, "#{reverse_zone.origin}.zone" do |zonefile|
|
163
|
+
zonefile << git_header('palletjack2knot', comment_char: ';')
|
164
|
+
zonefile << reverse_zone.dump_pretty
|
165
|
+
end
|
166
|
+
|
167
|
+
conf_file << zone_config(reverse_zone.origin)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Write PXELINUX boot menus from a Palletjack warehouse
|
4
|
+
#
|
5
|
+
# Data model assumptions:
|
6
|
+
#
|
7
|
+
# Each +os+ object will contain the keys:
|
8
|
+
# host:
|
9
|
+
# kickstart:
|
10
|
+
# baseurl: <URL to OS installation>
|
11
|
+
# pxelinux:
|
12
|
+
# config: <basename of pxelinux menu file w/o .menu>
|
13
|
+
#
|
14
|
+
# Each +netinstall+ object will contain the keys:
|
15
|
+
# host:
|
16
|
+
# kickstart:
|
17
|
+
# label: <human-friendly label for variant>
|
18
|
+
# ksurl: ["none"|<URL to kickstart file>]
|
19
|
+
# pxelinux:
|
20
|
+
# config: <basename of pxelinux menu file w/o .menu>
|
21
|
+
# kernel: <tftp path of pxelinux kernel>
|
22
|
+
# append: <pxelinux kernel parameters>
|
23
|
+
#
|
24
|
+
# PXELINUX directory tree:
|
25
|
+
#
|
26
|
+
# /var/lib/tftpboot/
|
27
|
+
# |- pxelinux.cfg
|
28
|
+
# | |- default -> ../config/default
|
29
|
+
# | |- 01-<MAC address> -> ../config/<OS>-<Variant>.menu
|
30
|
+
# | ...
|
31
|
+
# |- config
|
32
|
+
# | |- default
|
33
|
+
# | |- linux.menu
|
34
|
+
# | |- <OS>.menu
|
35
|
+
# | |- <OS>-<Variant>.menu
|
36
|
+
# | ...
|
37
|
+
# \- boot
|
38
|
+
# |- <OS>
|
39
|
+
# | |- vmlinuz
|
40
|
+
# | |- initrd
|
41
|
+
# | ...
|
42
|
+
# ...
|
43
|
+
#
|
44
|
+
# Point this script's output directory at /var/lib/tftpboot/, and it
|
45
|
+
# will create the MAC address symlinks, and menu tree for linux
|
46
|
+
# installations.
|
47
|
+
#
|
48
|
+
# The boot/... and config/default needs to be populated by other means.
|
49
|
+
|
50
|
+
require 'palletjack/tool'
|
51
|
+
require 'fileutils'
|
52
|
+
|
53
|
+
class PalletJack2PXELinux < PalletJack::Tool
|
54
|
+
|
55
|
+
def parse_options(opts)
|
56
|
+
opts.banner =
|
57
|
+
"Usage: #{$PROGRAM_NAME} -w <warehouse> -o <output directory>
|
58
|
+
|
59
|
+
Write PXELINUX boot configuration files from a Palletjack warehouse"
|
60
|
+
|
61
|
+
opts.on('-o DIR', '--output DIR', 'output directory (tftpboot/)',
|
62
|
+
String) {|dir| options[:output] = dir }
|
63
|
+
|
64
|
+
required_option :output
|
65
|
+
end
|
66
|
+
|
67
|
+
# Generate pxe menus for each OS configuration
|
68
|
+
|
69
|
+
def pxemenu_for_netinstall(netinstall)
|
70
|
+
config=netinstall['host.pxelinux.config']
|
71
|
+
os_label=netinstall['system.os'].gsub(/-/, ' ')
|
72
|
+
ks_label=(netinstall['host.kickstart.label'] ||
|
73
|
+
netinstall['host.kickstart.variant'] )
|
74
|
+
kernel=netinstall['host.pxelinux.kernel']
|
75
|
+
append=netinstall['host.pxelinux.append']
|
76
|
+
|
77
|
+
config_file :output, 'config', "#{config}.menu" do |menufile|
|
78
|
+
menufile << git_header('palletjack2pxelinux')
|
79
|
+
menufile << "
|
80
|
+
UI menu.c32
|
81
|
+
PROMPT 0
|
82
|
+
MENU INCLUDE /config/graphics.conf
|
83
|
+
MENU AUTOBOOT Installing #{os_label} (#{ks_label}) in # seconds
|
84
|
+
TIMEOUT 100
|
85
|
+
|
86
|
+
MENU TITLE Install #{os_label} (#{ks_label})
|
87
|
+
|
88
|
+
LABEL #{config}
|
89
|
+
MENU LABEL ^Install #{os_label} (#{ks_label})
|
90
|
+
MENU DEFAULT
|
91
|
+
KERNEL #{kernel}
|
92
|
+
APPEND #{append}
|
93
|
+
|
94
|
+
LABEL MainMenu
|
95
|
+
MENU LABEL ^Main Menu
|
96
|
+
KERNEL menu.c32
|
97
|
+
APPEND /config/default
|
98
|
+
"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Generate pxe menus for each OS version
|
103
|
+
|
104
|
+
def pxemenu_for_operating_system(os)
|
105
|
+
config=os['host.pxelinux.config']
|
106
|
+
os_label=config.gsub(/-/, ' ')
|
107
|
+
kernel=os['host.pxelinux.kernel']
|
108
|
+
append=os['host.pxelinux.append']
|
109
|
+
|
110
|
+
config_file :output, 'config', "#{config}.menu" do |menufile|
|
111
|
+
menufile << git_header('palletjack2pxelinux')
|
112
|
+
menufile << "
|
113
|
+
UI menu.c32
|
114
|
+
PROMPT 0
|
115
|
+
MENU INCLUDE /config/graphics.conf
|
116
|
+
|
117
|
+
MENU TITLE #{os_label} Installation Menu
|
118
|
+
"
|
119
|
+
|
120
|
+
os.children(kind:'netinstall') do |netinstall|
|
121
|
+
config=netinstall['host.pxelinux.config']
|
122
|
+
ks_label=(netinstall['host.kickstart.label'] ||
|
123
|
+
netinstall['host.kickstart.variant'] )
|
124
|
+
kernel=netinstall['host.pxelinux.kernel']
|
125
|
+
append=netinstall['host.pxelinux.append']
|
126
|
+
|
127
|
+
pxemenu_for_netinstall(netinstall)
|
128
|
+
|
129
|
+
menufile << "
|
130
|
+
LABEL #{config}
|
131
|
+
MENU LABEL Install #{os_label} (#{ks_label})
|
132
|
+
KERNEL menu.c32
|
133
|
+
APPEND /config/#{config}.menu
|
134
|
+
"
|
135
|
+
end
|
136
|
+
|
137
|
+
menufile << "
|
138
|
+
LABEL MainMenu
|
139
|
+
MENU LABEL ^Main Menu
|
140
|
+
KERNEL menu.c32
|
141
|
+
APPEND /config/default
|
142
|
+
"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
PalletJack2PXELinux.run do
|
148
|
+
config_dir :output, 'config'
|
149
|
+
config_dir :output, 'pxelinux.cfg'
|
150
|
+
|
151
|
+
config_file :output, 'config', 'linux.menu' do |menufile|
|
152
|
+
menufile << git_header('palletjack2pxelinux')
|
153
|
+
menufile << "
|
154
|
+
UI menu.c32
|
155
|
+
PROMPT 0
|
156
|
+
MENU INCLUDE /config/graphics.conf
|
157
|
+
|
158
|
+
MENU TITLE Linux Installation Menu
|
159
|
+
"
|
160
|
+
|
161
|
+
jack.each(kind:'os') do |os|
|
162
|
+
next unless config=os['host.pxelinux.config']
|
163
|
+
|
164
|
+
label=config.gsub(/-/, ' ')
|
165
|
+
|
166
|
+
pxemenu_for_operating_system(os)
|
167
|
+
|
168
|
+
menufile << "
|
169
|
+
LABEL #{config}
|
170
|
+
MENU LABEL Install #{label}
|
171
|
+
KERNEL menu.c32
|
172
|
+
APPEND /config/#{config}.menu
|
173
|
+
"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Generate pxe default menu links for each system
|
178
|
+
|
179
|
+
jack.each(kind:'system') do |system|
|
180
|
+
system.children(kind:'ipv4_interface') do |nic|
|
181
|
+
if system['host.pxelinux.config']
|
182
|
+
menuname = "#{system['host.pxelinux.config']}.menu"
|
183
|
+
linkname = "01-#{nic['net.layer2.address'].gsub(':', '-').downcase}"
|
184
|
+
|
185
|
+
FileUtils.ln_s(config_path('..', 'config', menuname),
|
186
|
+
config_path(:output, 'pxelinux.cfg', linkname),
|
187
|
+
:force => true)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
data/exe/palletjack2salt
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Write YAML files containing Salt pillar data.
|
4
|
+
#
|
5
|
+
# Intended to be run from a Git post-update hook or similar, since
|
6
|
+
# running the entire Pallet Jack infrastructure once per minion for
|
7
|
+
# every pillar refresh is a bit excessive, writing YAML files which
|
8
|
+
# will be read by a Salt pillar, in one of two modes of operation:
|
9
|
+
#
|
10
|
+
# 1. Global pillar data
|
11
|
+
#
|
12
|
+
# Intended to be included in an ordinary Salt pillar root.
|
13
|
+
#
|
14
|
+
# Example Salt master configuration:
|
15
|
+
#
|
16
|
+
# pillar_roots:
|
17
|
+
# base:
|
18
|
+
# - /etc/salt/pillar
|
19
|
+
#
|
20
|
+
# Example /etc/salt/pillar/top.sls:
|
21
|
+
#
|
22
|
+
# base:
|
23
|
+
# '*':
|
24
|
+
# - palletjack.global
|
25
|
+
#
|
26
|
+
# 2. Per-minion pillar data
|
27
|
+
#
|
28
|
+
# Intended to be read by the `palletjack_yaml_file` external pillar
|
29
|
+
# (which you will have to install manually).
|
30
|
+
#
|
31
|
+
# Example Salt master configuration:
|
32
|
+
#
|
33
|
+
# ext_pillar:
|
34
|
+
# - palletjack_yaml_file: /var/cache/palletjack/{saltenv}/{minion}.yaml
|
35
|
+
#
|
36
|
+
# Data model assumptions:
|
37
|
+
# - Salt minion ID is FQDN
|
38
|
+
|
39
|
+
require 'palletjack/tool'
|
40
|
+
require 'yaml'
|
41
|
+
|
42
|
+
class PalletJack2Salt < PalletJack::Tool
|
43
|
+
def parse_options(opts)
|
44
|
+
opts.banner =
|
45
|
+
"Usage: #{$PROGRAM_NAME} -w <warehouse> [ -g <dir> ] [ -m <dir> ]
|
46
|
+
|
47
|
+
Write Salt pillar data from a Palletjack warehouse."
|
48
|
+
|
49
|
+
opts.on('-g DIR', '--global DIR', 'global pillar directory',
|
50
|
+
String ) {|dir| options[:global_pillar] = dir }
|
51
|
+
opts.on('-m DIR', '--minion DIR', 'per-minion pillar directory',
|
52
|
+
String) {|dir| options[:minion_pillar] = dir }
|
53
|
+
|
54
|
+
required_option :global_pillar, :minion_pillar
|
55
|
+
end
|
56
|
+
|
57
|
+
# Helpers for generating global pillars
|
58
|
+
|
59
|
+
def process_global_pillar
|
60
|
+
result = {}
|
61
|
+
|
62
|
+
config['pillar.global.each-pallet'].each do |dst_key, kind|
|
63
|
+
result[dst_key] ||= {}
|
64
|
+
|
65
|
+
jack.each(kind: kind) do |pallet|
|
66
|
+
result[dst_key][pallet.name] = pallet.to_hash.except('pallet')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
result
|
71
|
+
end
|
72
|
+
|
73
|
+
# Helpers for generating per-minion pillars
|
74
|
+
|
75
|
+
def ipv4_interfaces(system)
|
76
|
+
result = Hash.new
|
77
|
+
|
78
|
+
system.children(kind:'ipv4_interface') do |interface|
|
79
|
+
result[interface['net.layer2.name']] = {
|
80
|
+
interface['net.ipv4.address'] =>
|
81
|
+
interface.filter('net.ipv4', 'net.layer2').to_hash
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
result
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_minion_pillars
|
89
|
+
result = {}
|
90
|
+
|
91
|
+
jack.each(kind:'system') do |system|
|
92
|
+
yaml_output = {}
|
93
|
+
yaml_output['ipv4_interfaces'] = ipv4_interfaces(system)
|
94
|
+
|
95
|
+
config['pillar.per-minion.each-subtree'].each do |dst_key, src_key|
|
96
|
+
yaml_output[dst_key] = system.fetch(src_key)
|
97
|
+
end
|
98
|
+
|
99
|
+
result[system['net.dns.fqdn']] = { 'palletjack' => yaml_output }
|
100
|
+
end
|
101
|
+
|
102
|
+
result
|
103
|
+
end
|
104
|
+
|
105
|
+
# The internal representation of the generated configuration, ready
|
106
|
+
# to be tested or printed.
|
107
|
+
|
108
|
+
attr_reader :salt_config
|
109
|
+
|
110
|
+
def process
|
111
|
+
@salt_config = {}
|
112
|
+
|
113
|
+
@salt_config[:global] = process_global_pillar if options[:global_pillar]
|
114
|
+
@salt_config[:minion] = process_minion_pillars if options[:minion_pillar]
|
115
|
+
end
|
116
|
+
|
117
|
+
def output
|
118
|
+
if @salt_config[:global]
|
119
|
+
config_dir :global_pillar, 'palletjack'
|
120
|
+
config_file :global_pillar, 'palletjack', 'global.sls' do |slsfile|
|
121
|
+
slsfile << git_header('palletjack2salt')
|
122
|
+
slsfile <<
|
123
|
+
{ 'palletjack' => { 'global' => @salt_config[:global] } }.to_yaml
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
if @salt_config[:minion]
|
128
|
+
@salt_config[:minion].each do |id, config|
|
129
|
+
config_file :minion_pillar, "#{id}.yaml" do |yamlfile|
|
130
|
+
yamlfile << git_header('palletjack2salt')
|
131
|
+
yamlfile << config.to_yaml
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
if PalletJack2Salt.standalone?(__FILE__)
|
139
|
+
PalletJack2Salt.run
|
140
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Write DNS resolver stub declarations from a Palletjack warehouse
|
4
|
+
#
|
5
|
+
# Data model assumptions:
|
6
|
+
#
|
7
|
+
# service:
|
8
|
+
# unbound:
|
9
|
+
# server:
|
10
|
+
# - interface: 0.0.0.0
|
11
|
+
# - access-control: 192.0.2.0/24 allow
|
12
|
+
# - ...
|
13
|
+
#
|
14
|
+
# Other configuration categories than +system+ are not supported.
|
15
|
+
|
16
|
+
require 'palletjack/tool'
|
17
|
+
require 'ip'
|
18
|
+
|
19
|
+
class PalletJack2Unbound < PalletJack::Tool
|
20
|
+
def parse_options(opts)
|
21
|
+
opts.banner =
|
22
|
+
"Usage: #{$PROGRAM_NAME} -w <warehouse> -s <service> -o <output directory>
|
23
|
+
|
24
|
+
Write DNS resolver stub declarations from a Palletjack warehouse
|
25
|
+
into Salt state configuration for unbound.
|
26
|
+
|
27
|
+
E.g.
|
28
|
+
palletjack2unbound -w /etc/salt/respository/warehouse \\
|
29
|
+
-o /etc/salt/repository/state/unbound/files"
|
30
|
+
|
31
|
+
opts.on('-o DIR', '--output DIR', 'output directory', String) {|dir|
|
32
|
+
options[:output] = dir
|
33
|
+
options[:conf_dir] = "#{dir}/conf.d"
|
34
|
+
options[:local_dir] = "#{dir}/local.d"
|
35
|
+
}
|
36
|
+
opts.on('-s SERVICE', '--service SERVICE',
|
37
|
+
'service name for global configuration', String) {|service|
|
38
|
+
options[:service] = service
|
39
|
+
}
|
40
|
+
|
41
|
+
required_option :output
|
42
|
+
required_option :service
|
43
|
+
end
|
44
|
+
|
45
|
+
# Write a stub-zone declaration to a file in conf.d/
|
46
|
+
# If the +transparent+ option is true, also write
|
47
|
+
# a local-zone ... transparent, declaration e.g. to
|
48
|
+
# override the builtin RFC1918 blocking in unbound.
|
49
|
+
|
50
|
+
def stub_zone(zone, stub_addrs, transparent: false)
|
51
|
+
return if stub_addrs.empty?
|
52
|
+
|
53
|
+
config_file :conf_dir, "#{zone}.conf" do |stubfile|
|
54
|
+
stubfile << git_header('palletjack2unbound')
|
55
|
+
stubfile << "
|
56
|
+
stub-zone:
|
57
|
+
name: #{zone}\n"
|
58
|
+
|
59
|
+
stub_addrs.each do |addr|
|
60
|
+
stubfile << " stub-addr: #{addr}\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
if transparent then
|
64
|
+
stubfile << "\nserver:\n local-zone: \"#{zone}\" transparent\n"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Check if +ip+ belongs to some RFC1918 network
|
70
|
+
|
71
|
+
def rfc1918?(ip)
|
72
|
+
rfc1918_nets = [IP.new('10.0.0.0/8'),
|
73
|
+
IP.new('172.16.0.0/12'),
|
74
|
+
IP.new('192.168.0.0/16')]
|
75
|
+
rfc1918_nets.any? {|net| ip.is_in?(net)}
|
76
|
+
end
|
77
|
+
|
78
|
+
# Generate unbound service configuration
|
79
|
+
|
80
|
+
def unbound_config(service_name)
|
81
|
+
service_config = jack.fetch(kind:'service', name: service_name)
|
82
|
+
|
83
|
+
config_file :local_dir, "#{service_name}.conf" do |configfile|
|
84
|
+
configfile << git_header('palletjack2unbound')
|
85
|
+
service_config["service.unbound.server"].each do |config|
|
86
|
+
config.each do |key, value|
|
87
|
+
configfile << "#{key}: #{value}\n"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
PalletJack2Unbound.run do
|
95
|
+
config_dir :conf_dir
|
96
|
+
config_dir :local_dir
|
97
|
+
|
98
|
+
jack.each(kind:'domain') do |domain|
|
99
|
+
zone = domain['net.dns.domain']
|
100
|
+
stub_addrs = []
|
101
|
+
|
102
|
+
domain['net.dns.ns'].each do |ns|
|
103
|
+
jack.each(kind:'ipv4_interface', all?:{'net.dns.fqdn' => ns}) do |ipv4|
|
104
|
+
stub_addrs << ipv4['net.ipv4.address']
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
stub_zone(zone, stub_addrs)
|
109
|
+
|
110
|
+
next unless domain['net.ipv4.cidr']
|
111
|
+
|
112
|
+
# Assume all delegations happen on octet boundaries for now.
|
113
|
+
# TODO: RFC 2317 classless in-addr.arpa delegation
|
114
|
+
|
115
|
+
ip_net = IP.new(domain['net.ipv4.cidr'])
|
116
|
+
reverse_zone = ip_net.to_arpa
|
117
|
+
prefix_octets, _ = domain['net.ipv4.prefixlen'].to_i.divmod(8)
|
118
|
+
reverse_zone =
|
119
|
+
ip_net.to_arpa.split('.')[-(2 + prefix_octets) .. 5].join('.')
|
120
|
+
|
121
|
+
# Make the same assumption that palletjack2knot does;
|
122
|
+
# reverse delegations are made to the same nameserver
|
123
|
+
# as forward delegations.
|
124
|
+
|
125
|
+
stub_zone(reverse_zone, stub_addrs, transparent: rfc1918?(ip_net))
|
126
|
+
end
|
127
|
+
|
128
|
+
unbound_config(options[:service])
|
129
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#-*- ruby -*-
|
2
|
+
# coding: utf-8
|
3
|
+
lib = File.expand_path('../../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'palletjack/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'palletjack-tools'
|
9
|
+
spec.version = PalletJack::VERSION
|
10
|
+
spec.authors = ['Karl-Johan Karlsson']
|
11
|
+
spec.email = ['karl-johan.karlsson@saabgroup.com']
|
12
|
+
spec.summary = 'Tools for the Pallet Jack Lightweight Configuration Management Database'
|
13
|
+
spec.description = spec.summary
|
14
|
+
spec.homepage = 'https://github.com/saab-simc-admin/palletjack'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
|
23
|
+
spec.platform = Gem::Platform::RUBY
|
24
|
+
spec.required_ruby_version = '~>2'
|
25
|
+
|
26
|
+
spec.add_runtime_dependency 'palletjack', PalletJack::VERSION
|
27
|
+
spec.add_runtime_dependency 'dns-zone', '~> 0.3'
|
28
|
+
spec.add_runtime_dependency 'ruby-ip', '~> 0.9'
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
31
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
32
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
33
|
+
spec.add_development_dependency "rspec_structure_matcher", "~> 0.0.6"
|
34
|
+
spec.add_development_dependency "rspec-collection_matchers", "~> 1.1.2"
|
35
|
+
|
36
|
+
spec.has_rdoc = true
|
37
|
+
end
|
data.tar.gz.sig
ADDED
Binary file
|
metadata
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: palletjack-tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Karl-Johan Karlsson
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIDljCCAn6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBIMRYwFAYDVQQDDA1jYWxs
|
14
|
+
ZS5lbmdsdW5kMRkwFwYKCZImiZPyLGQBGRYJc2FhYmdyb3VwMRMwEQYKCZImiZPy
|
15
|
+
LGQBGRYDY29tMB4XDTE2MTEwMjA5MjYyN1oXDTE3MTEwMjA5MjYyN1owSDEWMBQG
|
16
|
+
A1UEAwwNY2FsbGUuZW5nbHVuZDEZMBcGCgmSJomT8ixkARkWCXNhYWJncm91cDET
|
17
|
+
MBEGCgmSJomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
18
|
+
ggEBAM7OxaztzD0LyOwK1mPcg3BhioX1EDVbD/qAFOAzBSGGlAhtmHMqAkyvJMvs
|
19
|
+
iiG7xvBidWUapxiEiBwamXiOTSrp2eW+XSXW9omdWHXjBZcwHqwb1VmAlYRDkSHf
|
20
|
+
dzcM/z4xlV+DJw/pFyMRWzqNdVBtWTbVXAFGjJSqQ6q21ACYJldV9U71AIpXo+oF
|
21
|
+
VEMf6PZS2uhB1G+FgAtnX/xmy7OM1Cy3qc/CaJbWSddpegxWJMUn2HNQxFwIe40g
|
22
|
+
WoEoiFA7qQg9DnR/5i3lW6QyfIaA5k9cv2su1VyjqKLbkFTTTjYw0P1BJmvfXjtc
|
23
|
+
rMl+3HCWYj6UunZwfZi2wDGsBkkCAwEAAaOBijCBhzAJBgNVHRMEAjAAMAsGA1Ud
|
24
|
+
DwQEAwIEsDAdBgNVHQ4EFgQUwHCMEKgrIMaiTkTVLKZn6yOD1SIwJgYDVR0RBB8w
|
25
|
+
HYEbY2FsbGUuZW5nbHVuZEBzYWFiZ3JvdXAuY29tMCYGA1UdEgQfMB2BG2NhbGxl
|
26
|
+
LmVuZ2x1bmRAc2FhYmdyb3VwLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAP9OnE0jP
|
27
|
+
2vRHI/vnOkgCvLFNoOqK/YB4yDVVW69Pza+xIXcmUBvl7DQ+bBdF5AK0B1A7U0rp
|
28
|
+
Pbdj0bpQtWxmUmMIbnE1w6iuVCXAabsyUfHY4mlztToWXMVOXc1SPlJ/S2XXaRd5
|
29
|
+
fiNj/nBTb0YTQA0E4pZ0Aud80qZ2WLdc6FfzHUEMW91BL3bhLeDL40noHK5Lvk52
|
30
|
+
phzVHIrDjCowUMTnGiPZCXEo4KZW76KwYYV6oQ6LzcrYBw5mJ4XpdgQKZgnTnRBP
|
31
|
+
f8wtQllq82VF0AXUYeLtTh1f+DW3WW5BO1e2OCu5eOV7dbyaVPaNK/+rHjCN8kM/
|
32
|
+
DGZSwUoNADmVkQ==
|
33
|
+
-----END CERTIFICATE-----
|
34
|
+
date: 2016-11-02 00:00:00.000000000 Z
|
35
|
+
dependencies:
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: palletjack
|
38
|
+
requirement: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - '='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 0.1.2
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - '='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 0.1.2
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: dns-zone
|
52
|
+
requirement: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ~>
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0.3'
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ~>
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0.3'
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: ruby-ip
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ~>
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0.9'
|
71
|
+
type: :runtime
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0.9'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: bundler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ~>
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '1.13'
|
85
|
+
type: :development
|
86
|
+
prerelease: false
|
87
|
+
version_requirements: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ~>
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '1.13'
|
92
|
+
- !ruby/object:Gem::Dependency
|
93
|
+
name: rake
|
94
|
+
requirement: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ~>
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '10.0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ~>
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '10.0'
|
106
|
+
- !ruby/object:Gem::Dependency
|
107
|
+
name: rspec
|
108
|
+
requirement: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ~>
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '3.0'
|
113
|
+
type: :development
|
114
|
+
prerelease: false
|
115
|
+
version_requirements: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ~>
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '3.0'
|
120
|
+
- !ruby/object:Gem::Dependency
|
121
|
+
name: rspec_structure_matcher
|
122
|
+
requirement: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ~>
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 0.0.6
|
127
|
+
type: :development
|
128
|
+
prerelease: false
|
129
|
+
version_requirements: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.0.6
|
134
|
+
- !ruby/object:Gem::Dependency
|
135
|
+
name: rspec-collection_matchers
|
136
|
+
requirement: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ~>
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: 1.1.2
|
141
|
+
type: :development
|
142
|
+
prerelease: false
|
143
|
+
version_requirements: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ~>
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: 1.1.2
|
148
|
+
description: Tools for the Pallet Jack Lightweight Configuration Management Database
|
149
|
+
email:
|
150
|
+
- karl-johan.karlsson@saabgroup.com
|
151
|
+
executables:
|
152
|
+
- create_domain
|
153
|
+
- create_ipv4_interface
|
154
|
+
- create_system
|
155
|
+
- dump_pallet
|
156
|
+
- palletjack2kea
|
157
|
+
- palletjack2knot
|
158
|
+
- palletjack2pxelinux
|
159
|
+
- palletjack2salt
|
160
|
+
- palletjack2unbound
|
161
|
+
extensions: []
|
162
|
+
extra_rdoc_files: []
|
163
|
+
files:
|
164
|
+
- Gemfile
|
165
|
+
- Rakefile
|
166
|
+
- exe/create_domain
|
167
|
+
- exe/create_ipv4_interface
|
168
|
+
- exe/create_system
|
169
|
+
- exe/dump_pallet
|
170
|
+
- exe/palletjack2kea
|
171
|
+
- exe/palletjack2knot
|
172
|
+
- exe/palletjack2pxelinux
|
173
|
+
- exe/palletjack2salt
|
174
|
+
- exe/palletjack2unbound
|
175
|
+
- palletjack-tools.gemspec
|
176
|
+
homepage: https://github.com/saab-simc-admin/palletjack
|
177
|
+
licenses:
|
178
|
+
- MIT
|
179
|
+
metadata: {}
|
180
|
+
post_install_message:
|
181
|
+
rdoc_options: []
|
182
|
+
require_paths:
|
183
|
+
- lib
|
184
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - ~>
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '2'
|
189
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - '>='
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
requirements: []
|
195
|
+
rubyforge_project:
|
196
|
+
rubygems_version: 2.0.14
|
197
|
+
signing_key:
|
198
|
+
specification_version: 4
|
199
|
+
summary: Tools for the Pallet Jack Lightweight Configuration Management Database
|
200
|
+
test_files: []
|
metadata.gz.sig
ADDED