Rudimentary Configuration Management written in Ruby.

README.md

Notes on tool's architecture

This is Rudimentary Configuration Management (RCM) tool and is super true to its name. Everything is under RCM module/namespace to differentiate with other gems/ruby classes on the system.

Things are dependent on order of execution; especially if a resource is created by another one in the run. In our case, this is experienced for managing /var/www/html/index.html file as it is created by installation of apache2.

Target system configuration

apache2, php5 and libapache2-mod-php5 are installed. Then default /var/www/html/index.html is deleted and /var/www/html/index.php is dropped in its place.

Structure

The layout of the project is as simple as it can be. All objects are in objects folder, while all the functions that execute on those objects, or their collection are in respective file in managers folder. task.rb is the controller and also doubles up as configuration parser and validator via whatchugot, parse_packages, parse_files and parse_services. Config parsing can be moved to its own class, but it was left as it is for this task as I tend to go into a rabbit-hole... and I need to deliver a solution asap.

Configration and resources

YAML parser is natively available in ruby core, and was chosen over JSON for its easier markup. There are only in 3 sections in config.yaml - packages, files and services - and they are processed in that order. Files needed by the program (hello_world.php) are in resources folder. Dependencies can be specified for services, with a condition that path for file and name for package need to appear in respective section. There is no way to specify dependency for package or file at this time.

Objects

All objects are under objects folder. rcm_file, rcm_project and rcm_service provide abstraction of respective resource for RCM purposes. They hold everything needed to evaluate current vs desired state.

Managers

All functions that can be performed on an object or their collection are held in managers folder. Some of the functions in respective classes can be moved to object itself... and this thought would buttress what I mentioned earlier about going into rabbit-hole :P.

For file operations, I rely on FileUtils provided by ruby core, whereas I execute commands on systems for packages. Had I used Python, there was an API available to interact with package system. After all, apt is also a Python application.

How's the tool working

bootstrap.sh ensures ruby2.0 is installed.

task.rb is the main file and contains main. config_<env>.yaml holds environment dependent configuration. If ENVIRONMENT is not set, config.yaml is loaded, otherwise program expects environment dependent configuration as mentioned above.

Config file is loaded at startup and various checks done to make sure configuration is is correct... within the bounds of this task. For example, for file resource desired_state is checked to be one of available types; and it is made sure that local_file is readable if state is set to present. If there are dependencies mentioned for a service, a pointer to the resource is held respectively in depends_file and depends_package in ::RCM::Package object.

State is maintained in 2 objects:

  1. @wanted holds the state as mentioned in config.yaml or config_<env>.yaml. It is populated in parse_packages, parse_files and parse_services.
  2. @got holds the state of resources currently present on the system.

I first get get_current_state of packages and converge_packages because in current configuration, there is a file that appears only upon installation of apache2 package. I then get_current_state of files and converge_files. Finally restart_services_if_needed.