outsource in library, rework jails env
This commit is contained in:
parent
de798d18cc
commit
b40eed619a
@ -1,5 +1,13 @@
|
|||||||
{
|
{
|
||||||
"settings": {
|
"settings": {
|
||||||
|
"soa": "ns1.higgsboson.tk.",
|
||||||
|
"serial": 114,
|
||||||
|
"refresh": "1H",
|
||||||
|
"hostmaster": "hostmaster.higgsboson.tk",
|
||||||
|
"domain": "eva.higgsboson.tk",
|
||||||
|
"retry": "4H",
|
||||||
|
"expire": "3W",
|
||||||
|
"minimum": "1D",
|
||||||
"ip4_subnet": "192.168.67.0/24",
|
"ip4_subnet": "192.168.67.0/24",
|
||||||
"ip6_subnet": "2a03:b0c0:2:d0:1::/80",
|
"ip6_subnet": "2a03:b0c0:2:d0:1::/80",
|
||||||
"flavor": "default",
|
"flavor": "default",
|
||||||
|
181
scripts/jail
181
scripts/jail
@ -1,7 +1,6 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
require "optparse"
|
require_relative "lib/utils.rb"
|
||||||
require "shellwords"
|
require_relative "lib/jail.rb"
|
||||||
require_relative "utils"
|
|
||||||
|
|
||||||
OPTION_PARSER = OptionParser.new do |opts|
|
OPTION_PARSER = OptionParser.new do |opts|
|
||||||
opts.banner = "Usage: jails [options] [subcommand [options]]"
|
opts.banner = "Usage: jails [options] [subcommand [options]]"
|
||||||
@ -20,173 +19,6 @@ def usage
|
|||||||
exit(0)
|
exit(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
ROOT_PATH = Pathname.new(File.expand_path("../.." ,__FILE__))
|
|
||||||
EZJAIL_CONFIG_PATH = Pathname.new("/usr/local/etc/ezjail/")
|
|
||||||
|
|
||||||
class Jail
|
|
||||||
def initialize(name, properties={})
|
|
||||||
@name = name
|
|
||||||
@properties = properties
|
|
||||||
end
|
|
||||||
attr_accessor :name, :properties
|
|
||||||
|
|
||||||
def ip4
|
|
||||||
extract_ip("ip4")
|
|
||||||
end
|
|
||||||
def ip6
|
|
||||||
extract_ip("ip6")
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def extract_ip(type)
|
|
||||||
ips = @properties[type] || []
|
|
||||||
ips.map do |addr|
|
|
||||||
# example: em0|192.168.67.0 -> 192.168.67.0
|
|
||||||
addr =~ /\|?([^|]+)$/
|
|
||||||
$1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class JailRegistry < Registry
|
|
||||||
def add(name)
|
|
||||||
data["jails"] ||= {}
|
|
||||||
data["settings"] ||= {}
|
|
||||||
|
|
||||||
ip4 = next_address("ip4")
|
|
||||||
ip6 = next_address("ip6")
|
|
||||||
data["jails"][name] = {
|
|
||||||
"ip4" => [ip4],
|
|
||||||
"ip6" => [ip6]
|
|
||||||
}
|
|
||||||
ipconfig = "#{ip4},#{ip6}"
|
|
||||||
flavour = []
|
|
||||||
if settings["flavour"]
|
|
||||||
flavour = ["-f", settings["flavour"]]
|
|
||||||
end
|
|
||||||
sh("ezjail-admin", "create", *flavour, name, ipconfig)
|
|
||||||
end
|
|
||||||
|
|
||||||
def env(name)
|
|
||||||
jail_data = data["jails"][name] or die("no jail with name #{name} found")
|
|
||||||
jail_data = default_jail_conf.merge(jail_data)
|
|
||||||
templ = Template.new(ROOT_PATH.join("templates/jail_env.erb"))
|
|
||||||
properties = jail_properties(name, jail_data)
|
|
||||||
puts(templ.render(name: name, properties: properties))
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_pf_vars
|
|
||||||
templ = Template.new(ROOT_PATH.join("templates/pf.erb"))
|
|
||||||
path = ROOT_PATH.join("pf_vars.conf")
|
|
||||||
|
|
||||||
atomic_write(path, templ.render(jails: jails))
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_config_symlinks
|
|
||||||
conf_path = ROOT_PATH.join("scripts/jail_conf")
|
|
||||||
FileUtils.mkdir_p(EZJAIL_CONFIG_PATH)
|
|
||||||
jails.each do |jail|
|
|
||||||
FileUtils.ln_sf(conf_path, EZJAIL_CONFIG_PATH.join(jail.name))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_fstabs
|
|
||||||
templ = Template.new(ROOT_PATH.join("templates/fstab.erb"))
|
|
||||||
jails.each do |jail|
|
|
||||||
fstab = settings["fstab"].dup
|
|
||||||
fstab.concat(jail.properties["fstab"] || [])
|
|
||||||
fstab.map! do |entry|
|
|
||||||
entry % { name: jail.name }
|
|
||||||
end
|
|
||||||
|
|
||||||
path = "/etc/fstab.#{jail.name}"
|
|
||||||
atomic_write(path, templ.render(fstab: fstab))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def settings
|
|
||||||
{
|
|
||||||
"ip4_subnet" => "192.168.10.0/24",
|
|
||||||
"ip6_subnet" => "fd7d:aed0:18aa::/48",
|
|
||||||
"fstab" => [
|
|
||||||
"/usr/jails/basejail /usr/jails/%{name}/basejail nullfs ro 0 0",
|
|
||||||
],
|
|
||||||
}.merge(data["settings"])
|
|
||||||
end
|
|
||||||
|
|
||||||
def default_jail_conf
|
|
||||||
{
|
|
||||||
"exec_start" => "/bin/sh /etc/rc",
|
|
||||||
"exec_stop" => nil,
|
|
||||||
"hostname" => "%{name}",
|
|
||||||
"rootdir" => "/usr/jails/%{name}",
|
|
||||||
"mount_enable" => true,
|
|
||||||
"devfs_ruleset" => "devfsrules_jails",
|
|
||||||
"procfs_enable" => true,
|
|
||||||
"fdescfs_enable" => true,
|
|
||||||
"image" => nil,
|
|
||||||
"imagetype" => nil,
|
|
||||||
"attachparams" => nil,
|
|
||||||
"attachblocking" => nil,
|
|
||||||
"forceblocking" => nil,
|
|
||||||
"zfs_datasets" => nil,
|
|
||||||
"cpuset" => nil,
|
|
||||||
"fib" => nil,
|
|
||||||
"parentzfs" => nil,
|
|
||||||
"parameters" => nil,
|
|
||||||
"post_start_script" => nil,
|
|
||||||
"retention_policy" => nil
|
|
||||||
}.merge(data["default_jail_conf"])
|
|
||||||
end
|
|
||||||
|
|
||||||
def jail_properties(name, properties)
|
|
||||||
props = properties.dup
|
|
||||||
|
|
||||||
ips = props.delete("ip4") || []
|
|
||||||
ips.concat(props.delete("ip6") || [])
|
|
||||||
unless ips.empty?
|
|
||||||
props["ip"] = ips.join(",")
|
|
||||||
end
|
|
||||||
props.each do |prop, value|
|
|
||||||
props[prop] = serialize_property(name, value)
|
|
||||||
end
|
|
||||||
|
|
||||||
props
|
|
||||||
end
|
|
||||||
|
|
||||||
def serialize_property(name, value)
|
|
||||||
str = case value
|
|
||||||
when TrueClass
|
|
||||||
return value ? "YES" : "NO"
|
|
||||||
when String
|
|
||||||
value % { name: name }
|
|
||||||
else
|
|
||||||
value
|
|
||||||
end
|
|
||||||
Shellwords.escape(str)
|
|
||||||
end
|
|
||||||
|
|
||||||
def jails
|
|
||||||
data["jails"].map do |name, properties|
|
|
||||||
Jail.new(name, properties)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def next_address(type)
|
|
||||||
subnets = []
|
|
||||||
data["jails"].each do |k,v|
|
|
||||||
if v[type].is_a? Array
|
|
||||||
v[type].each do |subnet|
|
|
||||||
subnets << NetAddr::CIDR.create(subnet)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
subnet = settings["#{type}_subnet"]
|
|
||||||
next_free_subnet(NetAddr::CIDR.create(subnet), subnets)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def main(args)
|
def main(args)
|
||||||
OPTION_PARSER.order!(args)
|
OPTION_PARSER.order!(args)
|
||||||
|
|
||||||
@ -198,19 +30,18 @@ def main(args)
|
|||||||
when "add"
|
when "add"
|
||||||
name = args.first or die "name required"
|
name = args.first or die "name required"
|
||||||
registry.add(name)
|
registry.add(name)
|
||||||
registry.save
|
|
||||||
when nil
|
when nil
|
||||||
usage
|
usage
|
||||||
when "regenerate"
|
when "regenerate"
|
||||||
when "env"
|
|
||||||
name = args.first or die "name required"
|
|
||||||
registry.env(name)
|
|
||||||
else
|
else
|
||||||
die "unknown subcommand #{command}"
|
die "unknown subcommand #{command}"
|
||||||
end
|
end
|
||||||
registry.update_pf_vars
|
registry.update_pf_vars
|
||||||
registry.update_fstabs
|
registry.update_fstabs
|
||||||
registry.update_config_symlinks
|
registry.update_jail_config
|
||||||
|
registry.update_zone
|
||||||
|
registry.update_rzone
|
||||||
|
registry.save
|
||||||
end
|
end
|
||||||
|
|
||||||
main(ARGV)
|
main(ARGV)
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
echo "TODO"
|
|
||||||
exit 1
|
|
183
scripts/lib/jail.rb
Normal file
183
scripts/lib/jail.rb
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
require "optparse"
|
||||||
|
require "shellwords"
|
||||||
|
require_relative "utils.rb"
|
||||||
|
|
||||||
|
ROOT_PATH = Pathname.new(File.expand_path("../../.." ,__FILE__))
|
||||||
|
EZJAIL_CONFIG_PATH = Pathname.new("/usr/local/etc/ezjail/")
|
||||||
|
|
||||||
|
class Jail
|
||||||
|
def initialize(name, properties={})
|
||||||
|
@name = name
|
||||||
|
@properties = properties
|
||||||
|
end
|
||||||
|
attr_accessor :name, :properties
|
||||||
|
|
||||||
|
def ip4
|
||||||
|
extract_ip("ip4")
|
||||||
|
end
|
||||||
|
def ip6
|
||||||
|
extract_ip("ip6")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def extract_ip(type)
|
||||||
|
ips = @properties[type] || []
|
||||||
|
ips.map do |addr|
|
||||||
|
# example: em0|192.168.67.0 -> 192.168.67.0
|
||||||
|
addr =~ /\|?([^|]+)$/
|
||||||
|
$1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pointers(&block)
|
||||||
|
subnet_arpa = subnet.arpa
|
||||||
|
version = subnet.version
|
||||||
|
|
||||||
|
data["network"].each do |name, data|
|
||||||
|
next unless data["ipv#{version}"]
|
||||||
|
arpa = NetAddr::CIDR.create(data["ipv#{version}"]).arpa
|
||||||
|
addr = arpa[0, arpa.size - subnet_arpa.size - 1]
|
||||||
|
yield addr, name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class JailRegistry < Registry
|
||||||
|
def add(name)
|
||||||
|
data["jails"] ||= {}
|
||||||
|
data["settings"] ||= {}
|
||||||
|
|
||||||
|
ip4 = next_address("ip4")
|
||||||
|
ip6 = next_address("ip6")
|
||||||
|
data["jails"][name] = {
|
||||||
|
"ip4" => [ip4],
|
||||||
|
"ip6" => [ip6]
|
||||||
|
}
|
||||||
|
ipconfig = "#{ip4},#{ip6}"
|
||||||
|
flavour = []
|
||||||
|
if settings["flavour"]
|
||||||
|
flavour = ["-f", settings["flavour"]]
|
||||||
|
end
|
||||||
|
sh("ezjail-admin", "create", *flavour, name, ipconfig)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_pf_vars
|
||||||
|
templ = Template.new(ROOT_PATH.join("templates/pf.erb"))
|
||||||
|
path = ROOT_PATH.join("pf_vars.conf")
|
||||||
|
|
||||||
|
atomic_write(path, templ.render(jails: jails))
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_jail_config
|
||||||
|
jails.each do |jail|
|
||||||
|
jail_data = default_jail_conf.merge(jail.properties)
|
||||||
|
templ = Template.new(ROOT_PATH.join("templates/jail.erb"))
|
||||||
|
properties = jail_properties(jail.name, jail_data)
|
||||||
|
conf_path = EZJAIL_CONFIG_PATH.join(jail.name)
|
||||||
|
atomic_write(conf_path, templ.render(name: jail.name, properties: properties))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_fstabs
|
||||||
|
templ = Template.new(ROOT_PATH.join("templates/fstab.erb"))
|
||||||
|
jails.each do |jail|
|
||||||
|
fstab = settings["fstab"].dup
|
||||||
|
fstab.concat(jail.properties["fstab"] || [])
|
||||||
|
fstab.map! do |entry|
|
||||||
|
entry % { name: jail.name }
|
||||||
|
end
|
||||||
|
|
||||||
|
path = "/etc/fstab.#{jail.name}"
|
||||||
|
atomic_write(path, templ.render(fstab: fstab))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_zone
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_rzone
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def settings
|
||||||
|
{
|
||||||
|
"ip4_subnet" => "192.168.10.0/24",
|
||||||
|
"ip6_subnet" => "fd7d:aed0:18aa::/48",
|
||||||
|
"fstab" => [
|
||||||
|
"/usr/jails/basejail /usr/jails/%{name}/basejail nullfs ro 0 0",
|
||||||
|
],
|
||||||
|
}.merge(data["settings"])
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_jail_conf
|
||||||
|
{
|
||||||
|
"exec_start" => "/bin/sh /etc/rc",
|
||||||
|
"exec_stop" => nil,
|
||||||
|
"hostname" => "%{name}",
|
||||||
|
"rootdir" => "/usr/jails/%{name}",
|
||||||
|
"mount_enable" => true,
|
||||||
|
"devfs_ruleset" => "devfsrules_jails",
|
||||||
|
"procfs_enable" => true,
|
||||||
|
"fdescfs_enable" => true,
|
||||||
|
"image" => nil,
|
||||||
|
"imagetype" => nil,
|
||||||
|
"attachparams" => nil,
|
||||||
|
"attachblocking" => nil,
|
||||||
|
"forceblocking" => nil,
|
||||||
|
"zfs_datasets" => nil,
|
||||||
|
"cpuset" => nil,
|
||||||
|
"fib" => nil,
|
||||||
|
"parentzfs" => nil,
|
||||||
|
"parameters" => nil,
|
||||||
|
"post_start_script" => nil,
|
||||||
|
"retention_policy" => nil
|
||||||
|
}.merge(data["default_jail_conf"])
|
||||||
|
end
|
||||||
|
|
||||||
|
def jail_properties(name, properties)
|
||||||
|
props = properties.dup
|
||||||
|
|
||||||
|
ips = []
|
||||||
|
ips.concat(props.delete("ip4") || [])
|
||||||
|
ips.concat(props.delete("ip6") || [])
|
||||||
|
unless ips.empty?
|
||||||
|
props["ip"] = ips.join(",")
|
||||||
|
end
|
||||||
|
props.each do |prop, value|
|
||||||
|
props[prop] = serialize_property(name, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
props
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialize_property(name, value)
|
||||||
|
str = case value
|
||||||
|
when TrueClass
|
||||||
|
return value ? "YES" : "NO"
|
||||||
|
when String
|
||||||
|
value % { name: name }
|
||||||
|
else
|
||||||
|
value
|
||||||
|
end
|
||||||
|
Shellwords.escape(str)
|
||||||
|
end
|
||||||
|
|
||||||
|
def jails
|
||||||
|
data["jails"].map do |name, properties|
|
||||||
|
Jail.new(name, properties)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def next_address(type)
|
||||||
|
subnets = []
|
||||||
|
data["jails"].each do |k,v|
|
||||||
|
if v[type].is_a? Array
|
||||||
|
v[type].each do |subnet|
|
||||||
|
subnets << NetAddr::CIDR.create(subnet)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
subnet = settings["#{type}_subnet"]
|
||||||
|
next_free_subnet(NetAddr::CIDR.create(subnet), subnets)
|
||||||
|
end
|
||||||
|
end
|
@ -7,7 +7,7 @@ require "pry"
|
|||||||
require "netaddr"
|
require "netaddr"
|
||||||
|
|
||||||
class Registry
|
class Registry
|
||||||
PATH = Pathname.new(File.expand_path("../../jails.json", __FILE__))
|
PATH = Pathname.new(File.expand_path("../../../jails.json", __FILE__))
|
||||||
def initialize
|
def initialize
|
||||||
@data = JSON.load(File.open(Registry::PATH))
|
@data = JSON.load(File.open(Registry::PATH))
|
||||||
end
|
end
|
@ -1,3 +1,4 @@
|
|||||||
|
# THIS FILE WAS GENERATED, CHANGES WILL BE OVERWRITTEN
|
||||||
<% properties.each do |property,value| -%>
|
<% properties.each do |property,value| -%>
|
||||||
export jail_<%= name %>_<%= property %>=<%= value %>
|
export jail_<%= name %>_<%= property %>=<%= value %>
|
||||||
<% end -%>
|
<% end -%>
|
26
templates/rzone.erb
Normal file
26
templates/rzone.erb
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
@ IN SOA <%= data["zone"]["soa"] %> <%= data["zone"]["hostmaster"] %> (
|
||||||
|
<%= data["zone"]["serial"] %> ; serial
|
||||||
|
<%= data["zone"]["refresh"] %> ; refresh
|
||||||
|
<%= data["zone"]["retry"] %> ; retry
|
||||||
|
<%= data["zone"]["expire"] %> ; expire
|
||||||
|
<%= data["zone"]["minimum"] %>) ; minimum
|
||||||
|
<% data["jails"].each do |name, value| -%>
|
||||||
|
<% if value["ns"] -%>
|
||||||
|
IN NS <%= name %>
|
||||||
|
<% end -%>
|
||||||
|
<% end -%>
|
||||||
|
|
||||||
|
<% data["jails"].each do |name, value| -%>
|
||||||
|
<% if value["ns"] -%>
|
||||||
|
<% if value["ipv4"] -%>
|
||||||
|
<%= name %> A <%= value["ipv4"] %>
|
||||||
|
<% end -%>
|
||||||
|
<% if value["ipv6"] -%>
|
||||||
|
<%= name %> AAAA <%= value["ipv6"] %>
|
||||||
|
<% end -%>
|
||||||
|
<% end -%>
|
||||||
|
<% end -%>
|
||||||
|
|
||||||
|
<% pointers do |addr, name| -%>
|
||||||
|
<%= addr %> PTR <%= name %>.<%= data["zone"]["domain"] %>.
|
||||||
|
<% end -%>
|
28
templates/zone.erb
Normal file
28
templates/zone.erb
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
@ IN SOA <%= data["zone"]["soa"] %> <%= data["zone"]["hostmaster"] %> (
|
||||||
|
<%= data["zone"]["serial"] %> ; serial
|
||||||
|
<%= data["zone"]["refresh"] %> ; refresh
|
||||||
|
<%= data["zone"]["retry"] %> ; retry
|
||||||
|
<%= data["zone"]["expire"] %> ; expire
|
||||||
|
<%= data["zone"]["minimum"] %>) ; minimum
|
||||||
|
<% data["jails"].each do |name, value| -%>
|
||||||
|
<% if value["ns"] -%>
|
||||||
|
IN NS <%= name %>
|
||||||
|
<% end -%>
|
||||||
|
<% end -%>
|
||||||
|
|
||||||
|
<% jails.each do |jail| %>
|
||||||
|
<% jail.cname -%>
|
||||||
|
<%= name %> CNAME <%= jail.cname %>
|
||||||
|
<% end -%>
|
||||||
|
<% jail.srv.each do |srv| -%>
|
||||||
|
<%= name %> SRV <%= srv %>
|
||||||
|
<% end -%>
|
||||||
|
<% jail.ip4.each do |ip| -%>
|
||||||
|
<%= name %> A <%= ip %>
|
||||||
|
ipv4.<%= name %> A <%= ip %>
|
||||||
|
<% end -%>
|
||||||
|
<% if value["ipv6"] -%>
|
||||||
|
<%= name %> AAAA <%= ip(value["ipv6"]) %>
|
||||||
|
ipv6.<%= name %> AAAA <%= ip(value["ipv6"]) %>
|
||||||
|
<% end -%>
|
||||||
|
<% end -%>
|
Loading…
Reference in New Issue
Block a user