diff --git a/.fixtures.yml b/.fixtures.yml index 9d10937..8ad30e2 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -3,5 +3,6 @@ fixtures: stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib.git" staging: "https://github.com/nanliu/puppet-staging.git" concat: "https://github.com/puppetlabs/puppet-concat.git" + consul: "https://github.com/solarkennedy/puppet-consul" symlinks: consul_template: "#{source_dir}" diff --git a/README.markdown b/README.markdown index 8c0c16f..aa55434 100644 --- a/README.markdown +++ b/README.markdown @@ -1,5 +1,12 @@ #consul_template for Puppet +### NOTICE: + +This fork is not backwards compatible with its upstream. The configuration +mechanism has been modified to be driven by config_hash/config_defaults instead +of individual parameters to provide access to the full set of options and avoid +the need to make changes here as consul-template options evolve. + ##Installation ###What This Module Affects @@ -33,14 +40,9 @@ set to 'package', its installed using the system package manager. - `group` Default: root. - `manage_user` Default: false. Module handles creating the user. - `manage_group` Default: false. Module handles creating the group. -- `consul_host` Default: localhost. Hostanme of consul agent to query -- `consul_port` Default: 8500. Port number the API is running on -- `consul_token` Default: ''. ACL token to use when querying consul -- `consul_retry` Default: 10s. Time in seconds to wait before retrying consul requests -- `consul_wait` Default: undef. Min:Max time to wait before consul-template renders a new template to disk and triggers refresh. Specified in the format min:max according to [Go time duration format](http://golang.org/pkg/time/#ParseDuration) -- `consul_max_stale` Default: undef. The maximum staleness of a query. If specified, Consul will distribute work among all servers instead of just the leader. - `init_style` Init style to use for consul-template service. -- `log_level` Default: info. Logging level to use for consul-template service. Can be 'debug', 'warn', 'err', 'info' +- `config_hash` Default: {}. Consul-template configuration options. See https://github.com/hashicorp/consul-template#options +- `config_defaults` Default: {}. Consul-template configuration option defaults. @@ -51,18 +53,31 @@ The simplest way to use this module is: include consul_template ``` -Or to specify parameters: +consul-template options can be passed via hiera: + +``` +consul_template::config_defaults: + deduplicate: + enabled: true + log_level: info + retry: 10s + syslog: true + token: +``` + +Or to specify class parameters: ```puppet class { 'consul_template': service_enable => false - log_level => 'debug', init_style => 'upstart', - consul_wait => '5s:30s', - consul_max_stale => '1s' + config_hash => { + log_level => 'debug', + wait => '5s:30s', + max_stale => '1s' + } } ``` - ## Watch files To declare a file that you wish to populate from Consul key-values, you use the @@ -76,8 +91,10 @@ consul_template::watch { 'common': 'var1' => 'foo', 'var2' => 'bar', }, - destination => '/tmp/common.json', - command => 'true', + config_hash => { + destination => '/tmp/common.json', + command => 'true', + }, } ``` diff --git a/Rakefile b/Rakefile index ea3b9c9..f44d959 100644 --- a/Rakefile +++ b/Rakefile @@ -31,6 +31,7 @@ exclude_paths = [ ] PuppetLint.configuration.ignore_paths = exclude_paths PuppetSyntax.exclude_paths = exclude_paths +PuppetSyntax.future_parser = true desc "Run acceptance tests" RSpec::Core::RakeTask.new(:acceptance) do |t| diff --git a/manifests/config.pp b/manifests/config.pp index 0ae9f77..d9055be 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -3,89 +3,31 @@ # This class is called from consul_template for service config. # class consul_template::config ( - $consul_host, - $consul_port, - $consul_token, - $consul_retry, - $purge = true, + $config_hash = {}, + $purge = true, ) { + # Using our parent module's pretty_config & pretty_config_indent just because + $content_full = consul_sorted_json($config_hash, $consul::pretty_config, $consul::pretty_config_indent) + # remove the closing } and it's surrounding newlines + $content = regsubst($content_full, "\n}\n$", '') - concat::fragment { 'header': - target => 'consul-template/config.json', - content => inline_template("consul = \"<%= @consul_host %>:<%= @consul_port %>\"\ntoken = \"<%= @consul_token %>\"\nretry = \"<%= @consul_retry %>\"\n\n"), - order => '00', + $config_file = "${consul_template::config_dir}/config/config.json" + concat::fragment { 'consul-service-pre': + target => $config_file, + # add the opening template array so that we can insert watch fragments + content => "${content},\n \"template\": [\n", + order => '1', } - # Set the log level - concat::fragment { 'log_level': - target => 'consul-template/config.json', - content => inline_template("log_level = \"${::consul_template::log_level}\"\n"), - order => '01' - } + # Realizes concat::fragments from consul_template::watches that make up 1 or + # more template configs. + Concat::Fragment <| target == 'consul-template/config.json' |> - # Set wait param if specified - if $::consul_template::consul_wait { - concat::fragment { 'consul_wait': - target => 'consul-template/config.json', - content => inline_template("wait = \"${::consul_template::consul_wait}\"\n\n"), - order => '02', - } - } - - # Set max_stale param if specified - if $::consul_template::consul_max_stale { - concat::fragment { 'consul_max_stale': - target => 'consul-template/config.json', - content => inline_template("max_stale = \"${::consul_template::consul_max_stale}\"\n\n"), - order => '03', - } - } - - if $::consul_template::deduplicate { - concat::fragment { 'dedup-base': - target => 'consul-template/config.json', - content => inline_template("deduplicate {\n enabled = true\n"), - order => '04', - } - - if $::consul_template::deduplicate_prefix { - concat::fragment { 'dedup-prefix': - target => 'consul-template/config.json', - content => inline_template(" prefix = \"${::consul_template::deduplicate_prefix}\"\n"), - order => '05', - } - } - - concat::fragment { 'dedup-close': - target => 'consul-template/config.json', - content => inline_template("}\n"), - order => '06', - } - } - - if $::consul_template::vault_enabled { - concat::fragment { 'vault-base': - target => 'consul-template/config.json', - content => inline_template("vault {\n address = \"${::consul_template::vault_address}\"\n token = \"${::consul_template::vault_token}\"\n"), - order => '07', - } - if $::consul_template::vault_ssl { - concat::fragment { 'vault-ssl1': - target => 'consul-template/config.json', - content => inline_template(" ssl {\n enabled = true\n verify = ${::consul_template::vault_ssl_verify}\n"), - order => '08', - } - concat::fragment { 'vault-ssl2': - target => 'consul-template/config.json', - content => inline_template(" cert = \"${::consul_template::vault_ssl_cert}\"\n ca_cert = \"${::consul_template::vault_ssl_ca_cert}\"\n }\n"), - order => '09', - } - } - concat::fragment { 'vault-baseclose': - target => 'consul-template/config.json', - content => "}\n\n", - order => '10', - } + concat::fragment { 'consul-service-post': + target => $config_file, + # close off the template array and the whole object + content => " ],\n}", + order => '99', } file { [$consul_template::config_dir, "${consul_template::config_dir}/config"]: @@ -97,7 +39,7 @@ class consul_template::config ( mode => '0755', } -> concat { 'consul-template/config.json': - path => "${consul_template::config_dir}/config/config.json", + path => $config_file, owner => $consul_template::user, group => $consul_template::group, mode => $consul_template::config_mode, diff --git a/manifests/init.pp b/manifests/init.pp index 98cea52..97d97b3 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -22,33 +22,15 @@ # [*init_style*] # What style of init system your system uses. # +# [*config_hash*] +# Consul-template configuration options. See https://github.com/hashicorp/consul-template#options +# # [*config_mode*] # Set config file mode # # [*purge_config_dir*] # Purge config files no longer generated by Puppet # -# [*vault_enabled*] -# Do we want to configure Hashicopr Vault? Defaults to false. -# -# [*vault_address*] -# HTTP/HTTPS URL of the vault service -# -# [*vault_token*] -# Auth token to use for Vault -# -# [*vault_ssl*] -# Should we use SSL? Defaults to true -# -# [*vault_ssl_verify*] -# Should we verify the SSL certificate? Defaults to true -# -# [*vault_ssl_cert*] -# What is the path to the cert.pem -# -# [*vault_ssl_ca_cert*] -# What is the path to the ca cert.pem -# # [*data_dir*] # Path to a directory to create to hold some data. Defaults to '' # @@ -84,27 +66,13 @@ class consul_template ( $extra_options = '', $service_enable = true, $service_ensure = 'running', - $consul_host = 'localhost', - $consul_port = '8500', - $consul_token = '', - $consul_retry = '10s', - $consul_wait = undef, - $consul_max_stale = undef, - $deduplicate = false, - $deduplicate_prefix = undef, + $config_hash = {}, + $config_defaults = {}, $init_style = $consul_template::params::init_style, - $log_level = $consul_template::params::log_level, $logrotate_compress = 'nocompress', $logrotate_files = 4, $logrotate_on = false, $logrotate_period = 'daily', - $vault_enabled = false, - $vault_address = '', - $vault_token = '', - $vault_ssl = true, - $vault_ssl_verify = true, - $vault_ssl_cert = '', - $vault_ssl_ca_cert = '', $data_dir = '', $user = $consul_template::params::user, $group = $consul_template::params::group, @@ -119,6 +87,8 @@ class consul_template ( validate_bool($manage_user) validate_bool($manage_group) validate_hash($watches) + validate_hash($config_hash) + validate_hash($config_defaults) $real_download_url = pick($download_url, "${download_url_base}${version}/${package_name}_${version}_${os}_${arch}.${download_extension}") @@ -126,13 +96,15 @@ class consul_template ( create_resources(consul_template::watch, $watches) } + $config_base = { + consul => 'localhost:8500', + } + $config_hash_real = deep_merge($config_base, $config_defaults, $config_hash) + anchor { '::consul_template::begin': } -> class { '::consul_template::install': } -> class { '::consul_template::config': - consul_host => $consul_host, - consul_port => $consul_port, - consul_token => $consul_token, - consul_retry => $consul_retry, + config_hash => $config_hash_real, purge => $purge_config_dir, } ~> class { '::consul_template::service': } -> diff --git a/manifests/params.pp b/manifests/params.pp index 57a49c7..ee8c3e2 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -6,7 +6,6 @@ class consul_template::params { $install_method = 'url' - $log_level = 'info' $package_name = 'consul-template' $package_ensure = 'latest' $version = '0.11.0' diff --git a/manifests/watch.pp b/manifests/watch.pp index 779c455..029891a 100644 --- a/manifests/watch.pp +++ b/manifests/watch.pp @@ -4,24 +4,33 @@ # This is a single instance of a configuration file to watch # for changes in Consul and update the local file define consul_template::watch ( - $command, - $destination, - $source = undef, - $template = undef, - $template_vars = {}, + $config_hash = {}, + $config_defaults = {}, + $template = undef, + $template_vars = {}, ) { include consul_template - if $template == undef and $source == undef { - err ('Specify either template or source parameter for consul_template::watch') + $config_hash_real = deep_merge($config_defaults, $config_hash) + if $template == undef and $config_hash_real['source'] == undef { + err ('Specify either template parameter or config_hash["source"] for consul_template::watch') } - if $template != undef and $source != undef { - err ('Specify either template or source parameter for consul_template::watch - but not both') + if $template != undef and $config_hash_real['source'] != undef { + err ('Specify either template parameter or config_hash["source"] for consul_template::watch - but not both') } - if $template != undef { - file { "${consul_template::config_dir}/${name}.ctmpl": + if $template == undef { + # source is specified in config_hash + $config_source = {} + $frag_name = $config_hash_real['source'] + } else { + # source is specified as a template + $source = "${consul_template::config_dir}/${name}.ctmpl" + $config_source = { + source => $source, + } + file { $source: ensure => present, owner => $consul_template::user, group => $consul_template::group, @@ -30,20 +39,18 @@ define consul_template::watch ( before => Concat::Fragment["${name}.ctmpl"], notify => Service['consul-template'], } + $frag_name = $source } - if $source != undef { - $source_name = $source - $frag_name = $source - } else { - $source_name = "${consul_template::config_dir}/${name}.ctmpl" - $frag_name = "${name}.ctmpl" - } - - concat::fragment { $frag_name: + $config_hash_all = deep_merge($config_hash_real, $config_source) + $content_full = consul_sorted_json($config_hash_all, $consul::pretty_config, $consul::pretty_config_indent) + $content = regsubst(regsubst($content_full, "}\n$", '}'), "\n", "\n ", 'G') + @concat::fragment { $frag_name: target => 'consul-template/config.json', - content => "template {\n source = \"${source_name}\"\n destination = \"${destination}\"\n command = \"${command}\"\n}\n\n", - order => '10', - notify => Service['consul-template'] + # NOTE: this will result in all watches having , after them in the JSON + # array. That won't pass strict JSON parsing, but luckily HCL is fine with it. + content => " $content,\n", + order => '50', + notify => Service['consul-template'], } } diff --git a/spec/defines/watch_spec.rb b/spec/defines/watch_spec.rb index 618df2c..ea46544 100644 --- a/spec/defines/watch_spec.rb +++ b/spec/defines/watch_spec.rb @@ -7,8 +7,10 @@ describe 'consul_template::watch', :type => :define do describe "consul_template::watch define on OS family #{osfamily}" do let(:title) { 'test_watcher' } let(:params) {{ - :destination => '/var/tmp/consul_template', - :command => '/bin/test', + :config_hash => { + 'destination' => '/var/tmp/consul_template', + 'command' => '/bin/test', + } }} let(:facts) {{ :osfamily => osfamily, @@ -30,10 +32,12 @@ describe 'consul_template::watch', :type => :define do describe "consul_template::watch define on OS family #{osfamily}" do let(:title) { 'test_watcher' } let(:params) {{ - :template => 'consul_template_spec/test_template', + :template => 'consul_template_spec/test_template', :template_vars => { 'foo' => 'bar' }, - :destination => '/var/tmp/consul_template', - :command => '/bin/test', + :config_hash => { + 'destination' => '/var/tmp/consul_template', + 'command' => '/bin/test', + } }} let(:facts) {{ :osfamily => osfamily,