Best Practice Advice - Install script and config variables

I'm attempting to script (bash) the post installation settings of FreeBSD.

I'm trying to programmatically write the settings to /etc/rc.conf, /boot/loader.conf, /etc/sysctl.conf, /etc/devfs.conf, etc. just to name a few. I'm even trying to programmatically create .profile and other skeleton files. Currently, I'm storing my values to be written in arrays, but as I build out these arrays, I'm finding that I have (right now) 12 arrays with a couple having at least 25 elements all in the bash script file.

Is there a better way to do this?

Is there a way to store settings for an install type that can be parsed as needed that's more efficient than arrays in a script? Any best practice advice anyone has on this topic is much appreciated.
 
Last edited by a moderator:
Don't use bash for your post-install script. bash isn't part of base. Use sh(1). It's not that far from bash anyways and is far more portable.

If you must use bash - be sure to use the correct shebang.
Code:
#!/bin/env bash
and not
Code:
#!/bin/bash
Thinking out loud - could some of the skeleton files be done as "here is" documents?

 
Last edited by a moderator:
Don't use bash for your post-install script. bash isn't part of base. Use sh(1). It's not that far from bash anyways and is far more portable.

If you must use bash - be sure to use the correct shebang.

That was part of my conundrum. I'm using bash because I needed to use arrays which isn't found in sh. I have my script broken into two parts: a pre-install script that runs entirely in sh. It checks for the existance of bash and if it doesn't exist, it installs it. It writes a temp file that after reboot if that file exists, it continues with the second script in bash.


sysrc(8) might be an easier way to edit the system configs from a script.

I'm going to look into this tonight!
 
I think you are using bash way out of its comfort zone. Shells are designed primarily for interactive use, and their scripts intended for "short" tasks. If you are doing something complex (for example, which requires arrays), you should probably use different tools.

Note I'm not saying what other tool you should use. Personally, I would go with Python, or awk, or a preprocessing language like m4, but to each their own.
 
I agree that if you need to install a different tool (in your case bash) you are better off installing e.g. Python instead which gives you the added bonus of being able to use Ansible, just to give an example.

I'm curious about awk(1) or m4(1) as I would not have considered awk(1) suitable for this task and I've never even heard of m4(1).
 
My bash script is actually fairly small. There are simple functions that edits config files, installs fonts, installs packages, etc. There's really not much too it logically. A majority now is array declarations/assignments because there are just so many config items to store.

However, I want to get this back on track...I'm not looking to implement a new language like Python or Perl because I'll be right back in the same boat: what is the best practice for handling config values? Because, I'm facing the exact same dilemma of them being in separate files or array values so switching to another language doesn't solve my problem.
 
Here's a small piece of code that writes values to the different files:

Bash:
printArrValues() {
# Parses through property array(s) and writes config files
# takes two values:
#  array of properties
#  filename to write
    declare -a argArray=("${!1}")
    echo $2
  for i in "${argArray[@]}"
do
    local str=$( echo ${i} | cut -d '=' -f1 )
    if ! grep ${str} $_file
    then
      if [ ${str:0:1} = "#" ]   # If it's a comment add a blank line
      then
          echo >> $_file
      fi
      echo  $i >> $_file
    else
        #if the line already exists, rewite it
        # 1) check if is a coment, then ignore
        # 2) rewrite the line as a comment
        # 3) add new line
        echo 'nothing here.'
    fi
done
}

setValues() {
# Function that parses through all of the values that needs to be set
# takes one value:
#  - Platform (svr=server, dsk=desktop)

platform=${1}


# Assign proper arrays depending on platform
case ${platform} in

  dsk) sysctl_props=("${sysctl_props_dsk[@]}")
       loader_props=("${loader_props_dsk[@]}")
       rc_props=("${rc_props_dsk[@]}")
       devfs_props=("${devfs_props_dsk[@]}")
       ;;
  svr)
       sysctl_props=("${sysctl_props_svr[@]}")
       loader_props=("${loader_props_svr[@]}")
       rc_props=("${rc_props_svr[@]}")
       devfs_props=("${devfs_props_svr[@]}")
       ;;
    *) echo 'No platform specified.  Making no changes.'
       ;;
esac


fnames=("/etc/sysctl.conf" "/boot/loader.conf" "/etc/rc.conf" "/etc/devfs.conf")

for file in "${fnames[@]}"
do
  printArrValues props_all[@] ${file}
done

}

And, here is just a sampling of how I use arrays to hold the config values:

Bash:
# /etc/rc.conf Properties
# rc_props_all+=( '' );

rc_props_all+=( '# Synchronize system time' );
rc_props_all+=( 'ntpd_enable="YES"' );
rc_props_all+=( '# Let ntpd make time jumps larger than 1000sec' );
rc_props_all+=( 'ntpd_flags="-g"' );
rc_props_all+=( '# Remote logins' );
rc_props_all+=( 'sshd_enable="YES"' );
rc_props_all+=( '# Auto Update MOTD' );
rc_props_all+=( 'update_motd="YES"');

Please keep in mind that this is a work in progress so there's some unfinished code. I'm not having any issues with the code, it's the logic of whether to use arrays in this manner (which are getting huge) or find a different way to attack this.
 
You could have one file or function that uses sysrc to set the "dsk" profile, another for "srv" profile and a menu to choose between the two.
 
I would look at Ansible and jinja2 template files. I'm not sure it will be able to solve everything you're trying to do, but perhaps most of it and you will only need a few small scripts or better yet, only a few commands to be sent with Ansible (e.g. Ansible has a module that can restart services etc).
 
there's a whole raft of configuration management tools like puppet and chef which you are re-inventing.
I would look at Ansible and jinja2 template files.


I do appreciate the product recommendations - they're now on the list to evaluate. However, and I'm kicking myself for being remiss and not stating this earlier:

I'm taking this approach to better learn FreeBSD and to sharpen my scripting skills.

I have no doubt that the recommend products would speed me through this, but this is more of a personal self teaching project.
 
I have a conversation on that very same topic and I'd like you to join. Maybe I should start a new thread on that? I see the need and that 1000's of people are doing very similar tasks after/during each installation. This should be automated, and colaborated. Let's come together and join our forces!
It is here: FreeBSD CE (Community Edition), or you go into my user profile.
 
what is the best practice for handling config values? Because, I'm facing the exact same dilemma of them being in separate files or array values so switching to another language doesn't solve my problem.
Let me suggest You: GIT for tracking modifications of config files, and ANSIBLE to easy keep installing procedures useful, easy and pretty!

Both tool may be installed on Your sysadmin notebook to be each time (even on road) with You.

P.S.
For anyone who need to backup and monitoring changes in network appliances configs, please take a look on cBackup solution.
(Read and save configs in GIT, very tunable, less powerful than RANCID, but for <300 devices are ok.
Let’s to note than several popular SNMP-based monitoring systems have integration with RANCID, that give more solid Your monitoring system.
Or RANCID replacement: oxidized.
 
Last edited:
Back
Top