392 lines
11 KiB
CFEngine3
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";
|
|
}
|