Auto Generating candlepin.conf

Summary

If you want the buildconf/scripts/deploy script to auto-generate and install your candlepin.conf file every time, then:

  • Edit /etc/candlepin/candlepin.conf and place the word AUTOGENERATED in the first line of the file. The deploy script will not overwrite your candlepin.conf otherwise.

    $ sudo sh -c "echo '# AUTOGENERATED' | cat - /etc/candlepin/candlepin.conf > /tmp/c.out && mv -f /tmp/c.out /etc/candlepin/candlepin.conf"
    
  • Edit your ~/.candlepinrc file and add the line

    AUTOCONF=1
    
  • Run

    $ bin/deploy
    

The buildr erb task

I have created a buildr task that will automatically generate candlepin.conf based on a template under erb/ and values defined in profiles.yaml and custom.yaml. Simply run buildr erb and the buildr task will begin by searching recursively for every *.erb file under the erb/ directory. Then the task will load custom.yaml in the project base directory. This file is for you and you alone. It is in .gitignore and is not meant to be checked in. For every *.erb file, simply create an entry in custom.yaml that is the name of the template minus the “.erb” extension and then followed by a colon. So for candlepin.conf.erb, your custom.yaml would initially look like

candlepin.conf:

If you don’t have an entry in custom.yaml for a particular template, then the task will try and render the template anyway but it will warn you.

Adding customizations

To add values for the template engine to substitute in, just declare them in custom.yaml. So for example, if you want to turn Candlepin’s pretty printing off in the candlepin.conf.erb template, your custom.yaml would look like

candlepin.conf
  cp_pretty_print: "false"

There are a couple of things to note here. First, white space is important in YAML, so be sure to indent properly. Secondly, make sure to wrap your values in quotes so YAML will treat them as strings. If the word “false” were not in quotes here, the Ruby YAML parser would create an instance of FalseClass instead of String. This is probably not what you want since in Ruby the string “false” will evaluate to true while an instance of the FalseClass will evaluate to false.

Specifics on candlepin.conf.erb

The candlepin.conf.erb template has a few special properties.

  • You can declare logging by creating a custom_logging declaration and then providing a hash of logger names to log levels. Like so

    candlepin.conf:
      custom_logging:
        "org.hibernate.SQL": "DEBUG"
        "org.candlepin.servlet.filter": "DEBUG"
    

    If you want to stop logging on a logger but leave it in the rendered candlepin.conf just put a hash sign in front of the logger name. For example

    candlepin.conf:
      custom_logging:
        "#org.hibernate.SQL": "DEBUG"
        "org.candlepin.servlet.filter": "DEBUG"
    

    will render to

    #log4j.logger.org.hibernate.SQL=DEBUG
    log4j.logger.org.candlepin.servlet.filter=DEBUG
    
  • You can drop any additional stuff into the template without modifying the template by using the additional_properties declaration which is followed by a pipe character.

    candlepin.conf:
      additional_properties: |
        some.brand.new.property=foo
        some.other.new.property=bar
    

    will render to

    some.brand.new.property=foo
    some.other.new.property=bar
    

    The pipe character tells YAML that the following text is a block.

  • Many of the default values are read out of “profiles.yaml”. See below.

The buildconf/scripts/deploy script

  • The script is written so that the “buildr erb” task is only run if the deploy script is given the “-a” flag or your ~/.candlepinrc file has

    AUTOCONF=1
    
  • The script also accepts flags on which database to deploy to and whether or not to install the LogDriver. The flags are
    • -m for MySQL
    • -o for Oracle
    • -l for the log driver
  • Under the covers these flags pass various information to the buildr erb task.

Notes on profiles.yaml

  • You specify buildr with a profile using the “-e” option. Buildr then opens profiles.yaml and looks for a key matching your profile name. All the values under that key are then loaded into Buildr’s profile variable. Let’s suppose your profiles.yaml looks like this

    postgresql:
      driver_class: "org.postgresql.Driver"
    
    oracle:
      driver_class: "oracle.jdbc.OracleDriver"
    

    When running “buildr -e oracle” then profile['driver_class'] would equal “oracle.jdbc.OracleDriver”.

  • You can merge YAML hashes using the << operator and aliases.

    common: &common
      username: "candlepin"
      password: ""
      logdriver_class: "net.rkbloom.logdriver.LogDriver"
    
    postgresql:
      <<: *common
      driver_class: "org.postgresql.Driver"
      jdbc_url: "jdbc:postgresql:candlepin"
      dialect: "org.hibernate.dialect.PostgreSQLDialect"
      quartz_driver: "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"
    

    In this example, when building with -e postgresql you get the username, password, and logdriver_class values too. The ampersand creates an alias to an item. The << merges two hashes, and the asterisk dereferences the alias. See here.

Notes on Writing Templates

  • If you are writing a block of Ruby use the <%- and -%> tags. These tags enable ERB’s trim mode so you don’t leave a lot of extra white space.
  • Profile values can be accessed through the profile function.

    <%= profile.password %>
    
  • Provide defaults: use the || operator to provide a default in case the user has not specified a value in custom.yaml

    jpa.config.hibernate.show_sql=<%= show_hibernate || false %>
    
  • If you need to write to a local variable in the template, use the provided “_” variable followed by a period and then what you want to call your variable. Just declaring variables in the template scope runs the risk of overriding what was provided by the user.

    _.big_string = small_string.upcase
    
  • Do not use Ruby’s “or” operator with assignments. It has a lower precedence than the assignment operator and so the value on the left of the “or” will always end up being assigned. See here

    irb(main):003:0> x = nil or "bar"
    => "bar"
    irb(main):004:0> x
    => nil
    

    so

    _.my_val_with_default = my_val or "default"
    

    will be nil if my_val is not found in custom.yaml.

  • If you need to manipulate a value from custom.yaml, but aren’t sure if it’s going to be there or not, use the get() function and pass it a block. The block will be performed on the value if it is not nil, otherwise nil will be returned.

    <%= get("my_optional_value") { |v| v.upcase } || "some default" %>
    

    If you instead ran

    <%= my_optional_value.upcase || "some default" %>
    

    then you would get an error because you were dereferencing a nil.

  • Pay attention to the names of the values you put in custom.yaml. Because the ERB rendering class is running under Buildr, it gets polluted with a bunch of stuff that Buildr pulls in. Consequently, some names may already be assigned. If this is the case, the renderer will print out a warning but it will override the existing value. For example for the YAML

    candlepin.conf:
      pretty_print: blah
    

    You will see a warning reading

    pretty_print is already defined in ["/usr/share/ruby/pp.rb", 279].  Boldy overriding it!
    

More Information on YAML

For more YAML tricks and tips see

Last modified on 24 March 2016