Bootstrapping CFEngine with Cobbler Snippets and Systemd

Cobbler’s snippets are a module based approach to kickstart scripts. Without any doubt these are really handy to customize kickstart scripts without duplicating the efforts. Recently I wanted to get my hands dirty with RHEL 7 new features. So I fired up my home lab VMs with my old cobbler snippet which was for CentOS 6.x.

In CentOS6.x, you can use /etc/rc.d/rc.local to execute any script/command after all the services are up. But in RHEL/CentOS 7.x, upstart init is replaced by Systemd (very similar to Solaris SMF). There’s still /etc/rc.d/rc.local, but there’s no guarantee that it won’t run until the end. This is because Systemd runs services in parallel.

Problem is, although I could bootstrap CFEngine in the %post section of kickstart script, but it does not guarantee the actual environment that CFEngine expects after a complete OS boot. So while I still could have CFEngine bootstrapped as part of the kickstart installation process, I wanted to do it as part of the “First Boot” (first time when OS boots up after getting installed) process.

So how do I do that. Found out it’s really easy to write up a unit file (it helps systemd to determine dependencies among different services) and then make it run at the end of the default target (a Target is Systemd equivalent of SysV run level, essentially containing a bunch of services to start or stop).

Here’s my cobbler snippet (my GitHub repo) that does the following:

  1. Detects the profile i.e whether it’s CentOS 6.x or CentOS 7.x
  2. If it’s CentOS 6.x, make use if /etc/rc.d/rc.local to run the CFEngine bootstrap script
  3. If it’s CentOS 7.x, create /root/bootstrap_cfe bootstrap script and then write up a temporary systemd service that self destroys itself after the first run

Few things to note:

“After=default.target”  ensures that the service is run only after everything else in the default target has completed.

“WantedBy=default.target” ensures that the service actually runs while executing default target

“Type=forking”  I dont’ know yet the reason, but for shell script, forking is the only type that executes it. Other types do not do anything.

# CFEngine Boot Strap preparation
# detect profile
# if it's CentOS 6.*, we can use /etc/rc.d/rc.local
# if it's CentOS 7.*, we have to use systemd unit file

#set $prf = $getVar('$profile', None)
#if 'CentOS6' in $prf
#raw
mv /etc/rc.d/rc.local /root/rc.local.bak

cat >>/etc/rc.d/rc.local <<‘EOF’ #!/bin/bash if [[ -f /etc/centos-release ]]; then release=$( egrep -o “release 7|6\.” /etc/centos-release ) else release=”None” fi if [[ “${release}” != ‘release 6′ ]]; then exit 1 fi curl -o /tmp/cfengine.rpm “http://192.168.56.201/cfengine/cfengine-community-3.6.5-1.x86_64.rpm&#8221; rm -f /etc/yum.repos.d/*.repo yum -q -y –disablerepo=’*’ install /tmp/cfengine.rpm if [[ $? == 0 ]]; then touch /root/cfe-installed fi if [[ -f /root/cfe-installed ]]; then /var/cfengine/bin/cf-agent –bootstrap 192.168.56.201 fi sleep 2 rm -f /tmp/cfengine.rpm mv /root/rc.local.bak /etc/rc.d/rc.local chmod 744 /etc/rc.d/rc.local EOF chmod 744 /etc/rc.d/rc.local #end raw # end of CentOS6.* CFEngine bootstrap #else if ‘CentOS7’ in $prf # create the bootstrap script #raw cat >>/root/bootstrap_cfe <<‘EOF’ #!/bin/bash if [[ -f /etc/centos-release ]]; then release=$( egrep -o “release 7|6\.” /etc/centos-release ) else release=”None” fi if [[ “${release}” != ‘release 7′ ]]; then exit 1 fi curl -o /tmp/cfengine.rpm “http://192.168.56.201/cfengine-el7/cfengine-community-3.6.5-1.el7.x86_64.rpm&#8221; rm -f /etc/yum.repos.d/*.repo yum -q -y –disablerepo=’*’ install /tmp/cfengine.rpm if [[ $? == 0 ]]; then touch /root/cfe-installed fi if [[ -f /root/cfe-installed ]]; then /var/cfengine/bin/cf-agent –bootstrap 192.168.56.201 fi sleep 2 rm -f /tmp/cfengine.rpm systemctl disable systemd-cfengine-bootstrap.service rm -f /usr/lib/systemd/system/systemd-cfengine-bootstrap.service rm -f /etc/systemd/system/multi-user.target.wants/systemd-cfengine-bootstrap.service EOF chmod 744 /root/bootstrap_cfe # end of bootstrap script file # now create systemd unit file cat >/usr/lib/systemd/system/systemd-cfengine-bootstrap.service <<‘EOF’
[Unit]
Description=CFEngine Bootstrap
After=default.target

[Service]
Type=forking
ExecStart=/root/bootstrap_cfe

[Install]
WantedBy=default.target
EOF
# now enable the service for next boot
systemctl enable systemd-cfengine-bootstrap.service
#end raw

#else
# No profile matched for CFEngine bootstrap
#end if

Advertisements

About admin_xor

Un*x/Linux junkie, loves to program, automate, automate and automate
This entry was posted in Uncategorized and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s