palletjack-tools 0.1.2
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.
- 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