wmdeit-cf-wmdelib/lxc-host.cf

392 lines
11 KiB
CFEngine3

# example lxc_host.cfg
# cfg data => '
# {
# "bridge": "lxcbr0",
# "netmask": "255.255.255.0",
# "network": "10.0.1.0/24",
# "addr": "10.0.1.1",
# "dhcp_range": "10.0.1.200,10.0.1.254"
# "dhcp_max": 253,
# }';
bundle agent lxc_host( cfg )
{
vars:
# var ip wird in mergedata verwendet, und mergedata mag keine flachen Variablen,
# sondern braucht Arrays auf die eine oder andere Weise
'ip[thirdoctet]' string => format( "%02x", nth( splitstring( $(cfg[addr]), '\.', 4 ), 2 ) );
"cfg_ip" data => mergedata( cfg, ip );
debian|ubuntu::
'lxc_path' string => '/etc/lxc';
'lxc_net_path' string => '/etc/default/lxc-net';
'lxc_net_tmpl' string => 'debian.lxc-net.mustache';
'lxc_default_path' string => '$(lxc_path)/default.conf';
'lxc_default_tmpl' string => 'default.conf.mustache';
'lxc_hosts_d' string => '$(lxc_path)/hosts.d';
debian::
'pkg_list' slist => { 'lxc','lxc-templates','debian-archive-keyring' };
ubuntu::
'pkg_list' slist => { 'lxc','lxc-templates','ubuntu-archive-keyring' };
fedora|centos|redhat::
'lxc_net_path' string => '/etc/lxc-net';
methods:
'Ensure the packages required for LXC are installed'
usebundle => wmde_install_packages(@(pkg_list),'lxc'),
comment => "The packages to install are defined in var `pkg_list`.",
handle => "lxc_installed";
reports:
"The agent $(default:def.agent_name) has been prepared as a host for lx containers.";
"The host provides the network on $(cfg[bridge]) with address $(cfg[addr]).";
"It will configure LXC via DHCP in the range $(cfg[dhcp_range]).";
"Static mappings are in /etc/lxc/hosts.d.";
"This is the third octet: $(ip[thirdoctet]).";
files:
"$(lxc_path)/."
acl => lxc_dnsmasq,
depends_on => { "lxc_installed" };
"$(lxc_path)/dnsmasq.conf"
perms => mog('644','root','root'),
content => "dhcp-hostsdir=$(lxc_hosts_d)",
depends_on => { "lxc_installed" };
"$(lxc_hosts_d)/."
create => "true",
perms => mog('755','root','root'),
handle => "lxchostsdir",
depends_on => { "lxc_installed" };
"/usr/local/bin/lxc-hooks"
perms => mog('700','root','root'),
copy_from => local_cp("$(sys.workdir)/inputs/wmdelib/scripts/lxc-hooks.sh"),
depends_on => { "lxc_installed" },
handle => "lxchookscript";
debian|ubuntu::
"$(lxc_net_path)"
perms => mog('644','root', 'root'),
template_data => @(cfg_ip),
template_method => 'mustache',
edit_template => "$(sys.workdir)/inputs/$(def.wmde_libdir)/templates/lxc_host/$(lxc_net_tmpl)",
depends_on => { "lxc_installed" };
"$(lxc_default_path)"
perms => mog('644','root', 'root'),
template_data => @(cfg_ip),
template_method => 'mustache',
edit_template => "$(sys.workdir)/inputs/$(def.wmde_libdir)/templates/lxc_host/$(lxc_default_tmpl)",
depends_on => { "lxc_installed" };
}
body acl lxc_dnsmasq
{
acl_method => "append";
acl_type => "posix";
aces => {
"user:dnsmasq:rx:allow"
};
}
# example lxc.cfg
# cfg data => '
# {
# "name": "proxy",
# "dist": "debian",
# "release": "bookworm",
# "arch": "amd64",
# "bridge": "lxcbr0",
# "ip": "10.0.11.80",
# "group": "",
# "autostart": true,
# "policy": "absent|present",
# "state": "stopped|running",
# }';
# name
# lxc.container.conf:
# # Parameters passed to the template: --dist $(cfg[dist]) --arch $(cfg[arch]) --release $(cfg[release])
bundle agent lxc( cfg )
{
classes:
"cfg_array" expression => strcmp( type( "cfg", "true" ), "data array" );
vars:
cfg_array::
"index" slist => getindices( @(cfg) );
methods:
cfg_array::
"Iterate over config array: $(index)"
usebundle => _lxc( @(cfg[$(index)]) );
!cfg_array::
"Forward config to"
usebundle => _lxc( @(cfg) );
files:
reports:
cfg_array::
"Iterated over cfg array.";
}
# Although all attributes are passed in one data object there are
# qualitative differences. All need the name element.
# lxc-create needs dist, arch and release.
# lxc config file needs autostart and group
# dnsmasq needs the ip
bundle agent _lxc( cfg )
{
classes:
"lxc_exists" expression => returnszero( "/usr/bin/lxc-info $(cfg[name]) 2> /dev/null", "noshell" ), scope => "bundle";
"lxc_host_file_exists" expression => fileexists( "$(lxc_host_file)" ), scope => "bundle";
"lxc_policy_exists" expression => isvariable( "cfg[policy]" );
"lxc_state_exists" expression => isvariable( "cfg[state]" );
lxc_policy_exists::
"lxc_policy_valid" expression => regcmp( "(absent|present)", "$(cfg[policy])" );
lxc_policy_valid::
'present' expression => strcmp( "present", "$(cfg[policy])" );
!lxc_policy_exists::
'present';
lxc_state_exists::
"lxc_state_valid" expression => regcmp( "(stopped|running)", "$(cfg[state])" );
lxc_state_valid::
'running' expression => strcmp( "running", "$(cfg[state])" );
!lxc_state_exists::
'running';
lxc_exists::
"lxc_correct_distribution" expression => regline( '^# Parameters passed to the template: --dist $(cfg[dist]) --arch $(cfg[arch]) --release $(cfg[release])$', "$(lxc_dir)/config" ), scope => "bundle";
vars:
"lxc_host_file" string => "$(lxc_host.lxc_hosts_d)/$(cfg[name])";
"lxc_dir" string => "/var/lib/lxc/$(cfg[name])";
"lxc_rootfs" string => "$(lxc_dir)/rootfs";
'autostart' string => $(cfg[autostart]);
'group' string => $(cfg[group]);
files:
!lxc_exists & present::
"/var/lib/lxc/$(cfg[name])/config"
edit_line => lxc_config( "$(autostart)", "$(group)" ),
depends_on => { "lxc_$(cfg[name])_created" },
handle => "$(cfg[name])_config_created";
methods:
!lxc_exists & present::
"Ensure existence of container ($(cfg[name]))"
usebundle => lxc_create( @(cfg) ),
handle => "lxc_$(cfg[name])_created";
"Ensure static mapping in dnsmasq"
usebundle => lxc_add_static_mapping( @(cfg) ),
depends_on => { "lxc_$(cfg[name])_created" },
handle => "lxc_$(cfg[name])_mapped_statically";
lxc_exists & !present::
"Ensure absence of container ($cfg[name])"
usebundle => lxc_destroy( @(cfg) ),
handle => "lxc_$(cfg[name])_destroyed";
"Ensure absence of static mapping"
usebundle => lxc_remove_static_mapping( @(cfg) ),
depends_on => { "lxc_$(cfg[name])_destroyed" },
handle => "lxc_$(cfg[name])_unmapped_statically";
"Ensure dnsmasq picks up current lxc host configs"
usebundle => reload_dnsmasq,
depends_on => { "lxc_$(cfg[name])_unmapped_statically" },
handle => "reloaded_dnsmasq_for_$(cfg[name])";
present & running::
"Ensure running state of container ($(cfg[name]))"
usebundle => lxc_start( @(cfg[name]) ),
handle => "lxc_$(cfg[name])_started";
present & !running::
"Ensure stopped state of container ($(cfg[name]))"
usebundle => lxc_stop( @(cfg[name]) ),
handle => "lxc_$(cfg[name])_stopped";
reports:
lxc_exists & lxc_correct_distribution::
"LX Container $(cfg[name]) already configured, nothing to do";
!lxc_exists & present::
"LXC $(cfg[name]) did not exist and should have been created.";
lxc_exists & !present::
"LXC $(cfg[name]) did exist and should have been destroyed.";
present & running::
"LXC $(cfg[name]) should now be in state RUNNING.";
present & !running::
"LXC $(cfg[name]) should now be in state STOPPED.";
}
bundle edit_line lxc_config( autostart, group )
{
classes:
"autostart_true"
expression => some( $(autostart_lc), true_statements ),
depends_on => { "$(autostart)_lowercased" };
"group_provided"
expression => isgreaterthan( $(group_length), 0 );
vars:
"autostart_lc"
string => string_downcase( $(autostart) ),
handle => "$(autostart)_lowercased";
"group_length"
int => string_length( $(group) );
"true_statements"
slist => { "yes", "true", "on", "1" },
handle => "truth";
insert_lines:
"# This file is managed by CFEngine. Manual changes will be overwritten."
location => first_line;
autostart_true::
"lxc.start.auto = 1";
!autostart_true::
"lxc.start.auto = 0";
group_provided::
"lxc.group = $(group)";
reports:
"autostart ist $(autostart)";
"group ist $(group)";
}
body location first_line
{
before_after => "before";
first_last => "first";
select_line_matching => ".*";
}
bundle agent lxc_add_static_mapping( cfg )
{
files:
"$(lxc_host.lxc_hosts_d)/$(cfg[name])"
perms => mog( '644', 'root', 'root' ),
content => "$(cfg[name]),$(cfg[ip])",
handle => "mapped_$(cfg[name])";
reports:
"mapped $(cfg[name]) to $(cfg[ip])"
depends_on => { "mapped_$(cfg[name])" };
}
bundle agent lxc_remove_static_mapping( cfg )
{
files:
"$(lxc_host.lxc_hosts_d)/$(cfg[name])"
delete => tidy,
classes => if_repaired(dnsmasq_reload);
reports:
dnsmasq_reload::
"mapped $(cfg[name]) to $(cfg[ip])";
}
# When files for static mappings are added dnsmasq automatically loads
# them. But dnsmasq doesn't remove them automatically again when the
# file gets removed.
bundle agent reload_dnsmasq
{
processes:
dnsmasq_reload::
"dnsmasq"
signals => { "hup" };
}
# DOWNLOAD_KEYSERVER="keyserver.ubuntu.com" lxc-create -n manual -t download -- -d debian -a amd64 -r bookworm
bundle agent lxc_create( cfg )
{
classes:
"lxc_dir_btrfs" expression => strcmp( execresult( "/usr/bin/stat -f -c %T /var/lib/lxc" , "noshell", "stdout" ), "btrfs" );
vars:
!lxc_dir_btrfs::
"create_args" slist => {
"-n",
$(cfg[name]),
"-t",
"download",
"--",
"-d",
$(cfg[dist]),
"-a",
$(cfg[arch]),
"-r",
$(cfg[release]),
};
lxc_dir_btrfs::
"create_args" slist => {
"-n",
$(cfg[name]),
"-t",
"download",
"-B",
"btrfs",
"--",
"-d",
$(cfg[dist]),
"-a",
$(cfg[arch]),
"-r",
$(cfg[release]),
};
commands:
"/usr/bin/lxc-create"
arglist => { @(create_args) },
contain => lxc_commands,
handle => "lxc_$(cfg[name])_created";
reports:
"LXC $(cfg[name]) has been created"
depends_on => { "lxc_$(cfg[name])_created" };
}
bundle agent lxc_destroy( cfg )
{
methods:
"Ensure LXC is stopped"
usebundle => lxc_stop( $(cfg[name]) ),
handle => "stopped_$(cfg[name])";
commands:
"/usr/bin/lxc-destroy"
arglist => {
"-n",
$(cfg[name])
},
depends_on => { "stopped_$(cfg[name])" },
handle => "destroyed_$(cfg[name])";
}
bundle agent lxc_start( name )
{
classes:
"lxc_running"
expression => strcmp( execresult( "/usr/bin/lxc-info -n $(name) -s -H", "noshell", "stdout" ), "RUNNING" ),
scope => "bundle";
commands:
!lxc_running::
"/usr/bin/lxc-start"
arglist => {
"-n",
$(name)
},
handle => "lxc_$(name)_started";
reports:
!lxc_running::
"$(name) has been started"
depends_on => { "lxc_$(name)_started" };
}
bundle agent lxc_stop( name )
{
classes:
"lxc_running"
expression => strcmp( execresult( "/usr/bin/lxc-info -n $(name) -s -H", "noshell", "stdout" ), "RUNNING" ),
scope => "bundle";
commands:
lxc_running::
"/usr/bin/lxc-stop"
arglist => {
"-n",
$(name)
},
handle => "lxc_$(name)_stopped";
reports:
lxc_running::
"$(name) has been stopped"
depends_on => { "lxc_$(name)_stopped" };
}
body contain lxc_commands
{
useshell => "noshell";
no_output => "true";
}