From 2ec492af4093ce7f9564cebe686cb9eeda6a11f9 Mon Sep 17 00:00:00 2001 From: John Bellone Date: Sun, 8 Feb 2015 16:01:24 -0500 Subject: [PATCH] Add HWRPs for installing and managing consul. I am channeling @someara and @reset here. After taking a look at the new [httpd library cookbook][1] as well as the [Mysql library cookbook][2] I think this is an excellent example of using HWRP for defining the building blocks of a quality cookbook. [1]: https://github.com/chef-cookbooks/httpd [2]: https://github.com/chef-cookbooks/mysql --- .gitattributes | 7 +- .gitignore | 66 ++- .kitchen.yml | 4 +- .rspec | 1 + .rubocop_todo.yml | 51 -- .travis.yml | 1 + Berksfile | 8 +- CHANGELOG.md | 3 +- Gemfile | 48 +- Guardfile | 16 + LICENSE | 5 +- README.md | 512 +----------------- Rakefile | 10 - Thorfile | 12 - Vagrantfile | 19 +- attributes/default.rb | 136 +---- cluster.rb | 39 -- libraries/consul.rb | 60 -- libraries/consul_config.rb | 147 +++++ libraries/consul_definition.rb | 56 ++ libraries/consul_service.rb | 175 ++++++ libraries/consul_ui.rb | 50 -- libraries/consul_watch.rb | 42 ++ libraries/encrypt.rb | 21 - libraries/matchers.rb | 28 +- metadata.rb | 34 +- providers/check_def.rb | 40 -- providers/event_watch_def.rb | 35 -- providers/key_watch_def.rb | 35 -- providers/service_def.rb | 43 -- providers/service_watch_def.rb | 35 -- providers/services_watch_def.rb | 18 - recipes/_service.rb | 252 --------- recipes/default.rb | 50 +- recipes/install_binary.rb | 48 -- recipes/install_packages.rb | 34 -- recipes/install_source.rb | 47 -- recipes/ui.rb | 40 -- resources/check_def.rb | 56 -- resources/event_watch_def.rb | 45 -- resources/key_watch_def.rb | 46 -- resources/service_def.rb | 72 --- resources/service_watch_def.rb | 45 -- resources/services_watch_def.rb | 27 - .../cookbooks/consul_spec/metadata.rb | 3 - .../recipes/check_def_with_id_create.rb | 9 - .../recipes/check_def_with_id_delete.rb | 5 - .../recipes/check_def_without_id_create.rb | 7 - .../recipes/check_def_without_id_delete.rb | 4 - .../consul_spec/recipes/event_watch_create.rb | 4 - .../consul_spec/recipes/event_watch_delete.rb | 4 - .../consul_spec/recipes/key_watch_create.rb | 5 - .../consul_spec/recipes/key_watch_delete.rb | 4 - .../consul_spec/recipes/service_def_create.rb | 7 - .../consul_spec/recipes/service_def_delete.rb | 5 - spec/spec_helper.rb | 97 ---- spec/support/matchers.rb | 35 -- spec/unit/resources/check_def_spec.rb | 65 --- spec/unit/resources/event_watch_def_spec.rb | 27 - spec/unit/resources/key_watch_def_spec.rb | 27 - spec/unit/resources/service_def_spec.rb | 26 - templates/default/consul-init.erb | 121 ----- templates/default/consul-sysconfig.erb | 1 - templates/default/consul-systemd.erb | 17 - templates/default/consul.conf.erb | 23 - templates/default/sv-consul-log-run.erb | 5 - templates/default/sv-consul-run.erb | 8 - .../{consul_spec.rb => default_spec.rb} | 0 .../default/serverspec/spec_helper.rb | 5 - .../helpers/serverspec/spec_helper.rb | 3 + .../{consul_spec.rb => default_spec.rb} | 0 test/integration/ui/serverspec/spec_helper.rb | 4 - test/spec/libraries/consul_config_spec.rb | 77 +++ test/spec/libraries/consul_service_spec.rb | 73 +++ test/spec/recipes/default_recipe.rb | 16 + test/spec/spec_helper.rb | 40 ++ 76 files changed, 868 insertions(+), 2378 deletions(-) delete mode 100644 .rubocop_todo.yml create mode 100644 Guardfile delete mode 100644 Rakefile delete mode 100644 Thorfile delete mode 100644 cluster.rb delete mode 100644 libraries/consul.rb create mode 100644 libraries/consul_config.rb create mode 100644 libraries/consul_definition.rb create mode 100644 libraries/consul_service.rb delete mode 100644 libraries/consul_ui.rb create mode 100644 libraries/consul_watch.rb delete mode 100644 libraries/encrypt.rb delete mode 100644 providers/check_def.rb delete mode 100644 providers/event_watch_def.rb delete mode 100644 providers/key_watch_def.rb delete mode 100644 providers/service_def.rb delete mode 100644 providers/service_watch_def.rb delete mode 100644 providers/services_watch_def.rb delete mode 100644 recipes/_service.rb delete mode 100644 recipes/install_binary.rb delete mode 100644 recipes/install_packages.rb delete mode 100644 recipes/install_source.rb delete mode 100644 recipes/ui.rb delete mode 100644 resources/check_def.rb delete mode 100644 resources/event_watch_def.rb delete mode 100644 resources/key_watch_def.rb delete mode 100644 resources/service_def.rb delete mode 100644 resources/service_watch_def.rb delete mode 100644 resources/services_watch_def.rb delete mode 100644 spec/fixtures/cookbooks/consul_spec/metadata.rb delete mode 100644 spec/fixtures/cookbooks/consul_spec/recipes/check_def_with_id_create.rb delete mode 100644 spec/fixtures/cookbooks/consul_spec/recipes/check_def_with_id_delete.rb delete mode 100644 spec/fixtures/cookbooks/consul_spec/recipes/check_def_without_id_create.rb delete mode 100644 spec/fixtures/cookbooks/consul_spec/recipes/check_def_without_id_delete.rb delete mode 100644 spec/fixtures/cookbooks/consul_spec/recipes/event_watch_create.rb delete mode 100644 spec/fixtures/cookbooks/consul_spec/recipes/event_watch_delete.rb delete mode 100644 spec/fixtures/cookbooks/consul_spec/recipes/key_watch_create.rb delete mode 100644 spec/fixtures/cookbooks/consul_spec/recipes/key_watch_delete.rb delete mode 100644 spec/fixtures/cookbooks/consul_spec/recipes/service_def_create.rb delete mode 100644 spec/fixtures/cookbooks/consul_spec/recipes/service_def_delete.rb delete mode 100644 spec/spec_helper.rb delete mode 100644 spec/support/matchers.rb delete mode 100644 spec/unit/resources/check_def_spec.rb delete mode 100644 spec/unit/resources/event_watch_def_spec.rb delete mode 100644 spec/unit/resources/key_watch_def_spec.rb delete mode 100644 spec/unit/resources/service_def_spec.rb delete mode 100644 templates/default/consul-init.erb delete mode 100644 templates/default/consul-sysconfig.erb delete mode 100644 templates/default/consul-systemd.erb delete mode 100644 templates/default/consul.conf.erb delete mode 100644 templates/default/sv-consul-log-run.erb delete mode 100644 templates/default/sv-consul-run.erb rename test/integration/default/serverspec/localhost/{consul_spec.rb => default_spec.rb} (100%) delete mode 100644 test/integration/default/serverspec/spec_helper.rb create mode 100644 test/integration/helpers/serverspec/spec_helper.rb rename test/integration/ui/serverspec/localhost/{consul_spec.rb => default_spec.rb} (100%) delete mode 100644 test/integration/ui/serverspec/spec_helper.rb create mode 100644 test/spec/libraries/consul_config_spec.rb create mode 100644 test/spec/libraries/consul_service_spec.rb create mode 100644 test/spec/recipes/default_recipe.rb create mode 100644 test/spec/spec_helper.rb diff --git a/.gitattributes b/.gitattributes index f5bf9825..c9a5faed 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,8 @@ +Gemfile export-ignore +Berksfile export-ignore +Vagrantfile export-ignore +Thorfile export-ignore +Guardfile export-ignore +.gitattributes export-ignore .gitignore export-ignore .gitmodules export-ignore -.gitattributes export-ignore diff --git a/.gitignore b/.gitignore index fcaab8d9..78151583 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,54 @@ +# Ignore docs files +_gh_pages +_site +.ruby-version +.node-version +Gemfile.lock + +# Numerous always-ignore extensions +*.diff +*.err +*.orig +*.log +*.rej +*.swo +*.swp +*.zip +*.vi *~ -*# -.#* -\#*# -.*.sw[a-z] -*.un~ -pkg/ -# Berkshelf -.vagrant -/cookbooks -Berksfile.lock +# OS or Editor folders +.DS_Store +._* +Thumbs.db +.cache +.project +.settings +.tmproj +*.esproj +nbproject +*.sublime-project +*.sublime-workspace +.idea -# Bundler -Gemfile.lock -bin/* -.bundle/* +# Komodo +*.komodoproject +.komodotools + +# grunt-html-validation +validation-status.json +validation-report.json -.kitchen/ -.kitchen.local.yml +# Folders to ignore +bin +node_modules +tmp +vendor +.bundle -coverage/ +# Chef specifics to ignore +.chef +.chefdk +.kitchen +.vagrant +Berksfile.lock diff --git a/.kitchen.yml b/.kitchen.yml index ee4c48db..35385b06 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -8,8 +8,8 @@ provisioner: platforms: - name: ubuntu-14.04 - name: ubuntu-12.04 - - name: centos-7.0 - - name: centos-6.5 + - name: centos-7.1 + - name: centos-6.6 suites: - name: default diff --git a/.rspec b/.rspec index 83e16f80..2cdc09b7 100644 --- a/.rspec +++ b/.rspec @@ -1,2 +1,3 @@ --color --require spec_helper +--default-path test/spec diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml deleted file mode 100644 index 075130f4..00000000 --- a/.rubocop_todo.yml +++ /dev/null @@ -1,51 +0,0 @@ -# This configuration was generated by `rubocop --auto-gen-config` -# on 2014-07-04 11:27:45 -0400 using RuboCop version 0.24.1. -# The point is for the user to remove these configuration records -# one by one as the offenses are removed from the code base. -# Note that changes in the inspected code, or installation of new -# versions of RuboCop, may require this file to be generated again. - -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -Style/AlignParameters: - Enabled: false - -# Offense count: 1 -Style/CyclomaticComplexity: - Max: 7 - -# Offense count: 4 -# Configuration parameters: MaxLineLength. -Style/IfUnlessModifier: - Enabled: false - -# Offense count: 1 -Style/Lambda: - Enabled: false - -# Offense count: 9 -# Configuration parameters: AllowURI. -Style/LineLength: - Max: 119 - -# Offense count: 1 -# Configuration parameters: EnforcedStyle, SupportedStyles. -Style/Next: - Enabled: false - -# Offense count: 4 -# Configuration parameters: MaxSlashes. -Style/RegexpLiteral: - Enabled: false - -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -Style/StringLiterals: - Enabled: false - -# Offense count: 2 -# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. -Style/TrailingComma: - Enabled: false diff --git a/.travis.yml b/.travis.yml index 4faed68c..92e95513 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: ruby script: bin/rspec rvm: - 2.1 + - 2.2 branches: only: - master diff --git a/Berksfile b/Berksfile index 95238856..9042e42c 100644 --- a/Berksfile +++ b/Berksfile @@ -1,7 +1,3 @@ -source 'https://supermarket.getchef.com' - +source 'https://supermarket.chef.io' +cookbook 'chef-vault', git: 'https://github.com/johnbellone/chef-vault-cookbook' metadata - -group :test do - cookbook "consul_spec", path: "spec/fixtures/cookbooks/consul_spec" -end diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ec76ba1..0fb3dc94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +# 1.0.0 + # 0.10 Fixes several bugs, minor enhancements and changes default version of Consul to 0.5.2. @@ -21,7 +23,6 @@ Consul to 0.5.2. * Lock to Chef 11 compatible version of libarchive cookbook # 0.9.0 - * Enhancements - Adds support for publishing to statsd URL. [@akerekes](https://github.com/akerekes) - Adds support for Arch Linux. ([@logankoester](https://github.com/logankoester)) diff --git a/Gemfile b/Gemfile index 9fb0da36..07f0e559 100644 --- a/Gemfile +++ b/Gemfile @@ -1,16 +1,40 @@ source 'https://rubygems.org' -gem 'berkshelf' -gem 'rake' -gem 'rspec' -gem 'rubocop' -gem 'foodcritic' -gem 'tailor' -gem 'coveralls', require: false -gem 'stove' - -group :test, :integration do +gem 'chef-vault', '~> 2.6' + +group :lint do + gem 'rubocop' +end + +group :kitchen_common do + gem 'test-kitchen', '~> 1.4' +end + +group :kitchen_vagrant do + gem 'kitchen-vagrant', '~> 0.17' +end + +group :kitchen_cloud do + gem 'kitchen-openstack', '~> 1.8' +end + +group :unit do + gem 'berkshelf' gem 'chefspec' - gem 'test-kitchen' - gem 'kitchen-vagrant' +end + +group :integration do gem 'serverspec' end + +group :development do + gem 'guard' + gem 'guard-kitchen' + gem 'guard-rspec' + gem 'guard-rubocop' + gem 'rake' + gem 'stove' +end + +group :doc do + gem 'yard' +end diff --git a/Guardfile b/Guardfile new file mode 100644 index 00000000..2ca644c1 --- /dev/null +++ b/Guardfile @@ -0,0 +1,16 @@ +# More info at https://github.com/guard/guard#readme +guard 'rubocop' do + watch(%r{^attributes/.+\.rb$}) + watch(%r{^providers/.+\.rb$}) + watch(%r{^recipes/.+\.rb$}) + watch(%r{^resources/.+\.rb$}) + watch(%r{^libraries/.+\.rb$}) + watch('metadata.rb') +end + +guard :rspec, :cmd => 'chef exec /opt/chefdk/embedded/bin/rspec', all_on_start: false, notification: false do + watch(%r{^(recipes|libraries|providers|resources)/(.+)\.rb$}) do |m| + "test/spec/#{m[0]}/#{m[1]}_spec.rb" + end + watch('test/spec/spec_helper.rb') { 'test/spec' } +end diff --git a/LICENSE b/LICENSE index ca60bb87..4f55d866 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,4 @@ -Copyright 2014 John Bellone -Copyright 2014 Bloomberg Finance L.P. +Copyright 2014, 2015 Bloomberg Finance L.P. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -11,4 +10,4 @@ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file +limitations under the License. diff --git a/README.md b/README.md index e44611f3..f6e9e4c7 100644 --- a/README.md +++ b/README.md @@ -1,491 +1,37 @@ consul-cookbook =============== - [![Join the chat at https://gitter.im/johnbellone/consul-cookbook](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/johnbellone/consul-cookbook?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ![Release](http://img.shields.io/github/release/johnbellone/consul-cookbook.svg) -[![Build Status](http://img.shields.io/travis/johnbellone/consul-cookbook.svg)][5] -[![Code Coverage](http://img.shields.io/coveralls/johnbellone/consul-cookbook.svg)][6] - -Installs and configures [Consul][1] client, server and UI. +[![Build Status](http://img.shields.io/travis/johnbellone/consul-cookbook.svg)](http://travis-ci.org/johnbellone/consul-cookbook) +[![Code Coverage](http://img.shields.io/coveralls/johnbellone/consul-cookbook.svg)](https://coveralls.io/r/johnbellone/consul-cookbook) -## Supported Platforms -- CentOS 6.5, 7.0 -- RHEL 6.5, 7.0 -- Ubuntu 12.04, 14.04 -- Arch Linux +[Application cookbook][0] which installs and configures [Consul][1]. ## Attributes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyTypeDescriptionDefault
['consul']['version']StringVersion to install0.5.0
['consul']['base_url']StringBase URL for binary downloadshttps://dl.bintray.com/mitchellh/consul/
['consul']['encrypt']StringEncryption string for consul cluster.nil
['consul']['install_method']StringMethod to install consul with when using default recipe: binary or sourcebinary
['consul']['install_dir']StringDirectory to install binary to./usr/local/bin
['consul']['service_mode']StringMode to run consul as: bootstrap, cluster, server, or clientbootstrap
['consul']['bootstrap_expect']StringWhen bootstrapping a cluster, the number of server nodes to expect.nil
['consul']['data_dir']StringLocation to store consul's data in/var/lib/consul
['consul']['config_dir']StringLocation to read service definitions from (directoy will be created)/etc/consul.d
['consul']['servers']Array StringsConsul servers to join[]
['consul']['retry_on_join']BooleanSet to true to wait for servers to be up before try to elect a leaderfalse
['consul']['bind_addr']Stringaddress that should be bound to for internal cluster communications0.0.0.0
['consul']['datacenter']StringName of Datacenterdc1
['consul']['domain']StringDomain for service lookup dns queries.consul
['consul']['enable_syslog']Booleanenables logging to syslognil
['consul']['log_level']String - The level of logging to show after the Consul agent has started. - Available: "trace", "debug", "info", "warn", "err" - info
['consul']['node_name']StringThe name of this node in the clusterhostname of the machine
['consul']['advertise_addr']Stringaddress that we advertise to other nodes in the clusterValue of bind_addr
['consul']['init_style']StringService init mode for running consul as: init, runit or systemdinit
['consul']['service_user']StringFor runit/systemd service: run consul as this user (init uses 'root')consul
['consul']['service_group']StringFor runit/systemd service: run consul as this group (init uses 'root')consul
['consul']['bind_interface']String - Interface to bind to, such as 'eth1'. Sets bind_addr - attribute to the IP of the specified interface if it exists. - nil
['consul']['advertise_interface']String - Interface to advertise, such as 'eth1'. Sets advertise_addr - attribute to the IP of the specified interface if it exists. - nil
['consul']['extra_params']hash - Pass a hash of extra params to the default.json config file - {}
['consul']['encrypt_enabled']Boolean - To enable Consul gossip encryption - false
['consul']['verify_incoming']Boolean - If set to True, Consul requires that all incoming connections make use of TLS. - false
['consul']['verify_outgoing']Boolean - If set to True, Consul requires that all outgoing connections make use of TLS. - false
['consul']['key_file']String - The content of PEM encoded private key - nil
['consul']['key_file_path']String - Path where the private key is stored on the disk - /etc/consul.d/key.pem
['consul']['ca_file']String - The content of PEM encoded ca cert - nil
['consul']['ca_file_path']String - Path where ca is stored on the disk - /etc/consul.d/ca.pem
['consul']['cert_file']String - The content of PEM encoded cert. It should only contain the public key. - nil
['consul']['cert_file_path']String - Path where cert is stored on the disk - /etc/consul.d/cert.pem
['consul']['statsd_addr']StringThis provides the address of a statsd instance (UDP).nil
- -### Databag Attributes (optional) -Following attributes, if exist in the [encrypted databag][7], override the node attributes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyDatabag itemTypeDescription
key_file['consul']['encrypt']StringThe content of PEM encoded private key
key_file_{fqdn}['consul']['encrypt']StringNode's(identified by fqdn) unique PEM encoded private key. If it exists, it will override the databag and node key_file attribute
ca_file['consul']['encrypt']StringThe content of PEM encoded ca cert
encrypt['consul']['encrypt']StringConsul Gossip encryption key
cert_file['consul']['encrypt']StringThe content of PEM encoded cert
cert_file_{fqdn}['consul']['encrypt']StringNode's(identified by fqdn) unique PEM encoded cert. If it exists, it will override the databag and node cert_file attribute
- -### Consul UI Attributes - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyTypeDescriptionDefault
['consul']['client_addr']StringAddress to bind to0.0.0.0
['consul']['client_interface']String - Interface to advertise, such as 'eth1'. Sets advertise_addr - attribute to the IP of the specified interface if it exists. - nil
['consul']['serve_ui']BooleanDetermines whether the consul service also serve's the UIfalse
- -## Usage -The easiest way to bootstrap a cluster is to use the cluster recipe -and use [Chef provisioning][8] which is a relatively new -extension. This extension allows you to use any driver and easily -stand up a cluster. Once the [Chef Development Kit][9] has been -installed you can run the following command to provision a cluster. - -```ruby -gem install chef-provisioning chef-provisioning-fog -export CHEF_DRIVER=fog:AWS -chef-client -z cluster.rb -``` - -Please follow the [Chef provisioning README][10] which provides more -detailed information about provisioning. You'll need to configure -your credentials prior to provisioning. - -### consul::default -The default recipe will install the Consul agent using the -`consul::install_binary` recipe. It will also configure and -start consul at the machine boot. - -### consul::install_binary -If you only wish to simply install the binary from the official -mirror you simply include `consul::install_binary` in your node's -`run_list`: - -```json -{ - "run_list": [ - "recipe[consul::install_binary]" - ] -} -``` - -### consul::install_source -Instead if you wish to install Consul from source you simply need -to include `consul::install_source` in your node's `run_list`. This -will also configure the Go language framework on the node to build -the application. - -```json -{ - "run_list": [ - "recipe[consul::install_source]" - ] -} -``` - -### consul::ui -Installing the separate Consul UI simply requires you to include -the `consul::ui` recipe in your node's `run_list`. - -```json -{ - "run_list": [ - "recipe[consul::ui]" - ] -} -``` - -### LWRP - -##### Adding key watch - consul_key_watch_def 'key-watch-name' do - key "/key/path" - handler "chef-client" - end - - -##### Adding event watch - consul_event_watch_def 'event-name' do - handler "chef-client" - end - -##### Adding services watch - consul_services_watch_def 'services-name' do - handler "chef-client" - end - -##### Adding service watch - consul_service_watch_def 'service-name' do - passingonly true - handler "chef-client" - end - -##### Adding service without check - - consul_service_def 'voice1' do - port 5060 - tags ['_sip._udp'] - notifies :reload, 'service[consul]' - end - -##### Adding services with checks - - consul_service_def 'voice1' do - port 5060 - tags ['_sip._udp'] - check( - interval: '10s', - script: 'echo ok' - ) - notifies :reload, 'service[consul]' - end - - consul_service_def 'server1' do - port 80 - tags ['http'] - check( - interval: '10s', - http: 'http://localhost:80' - ) - notifies :reload, 'service[consul]' - end - -##### Removing service - - consul_service_def 'voice1' do - action :delete - notifies :reload, 'service[consul]' - end - -> Be sure to notify the Consul resource to restart when your service def changes. - -#### Getting Started - -To bootstrap a consul cluster follow the following steps: - 0. Make sure that ports 8300-8302 (by default, if you configured different ones open those) UDP/TCP are all open. - 1. Bootstrap a few (preferablly 3 nodes) to be your consul servers, these will be the KV masters. - 2. Put `node['consul']['servers'] =["Array of the bootstrapped servers ips or dns names"]` in your environment. - 3. Apply the consul cookbook to these nodes with `node['consul']['service_mode'] = 'cluster'` (I put this in this in a CONSUL_MASTER role). - 4. Let these machines converge, once you can run `consul members` and get a list of all of the servers your ready to move on - 5. Apply the consul cookbook to the rest of your nodes with `node['consul']['service_mode'] = 'client'` (I put this in the environment) - 6. Start adding services and checks to your cookbooks. - 7. If you want to get values out of consul to power your chef, curl localhost:8500/v1/kv/key/path?raw in your cookbook. - -## Authors - -Created and maintained by [John Bellone][3] [@johnbellone][2] () and a growing community of [contributors][4]. - +This cookbook provides node attributes which can be used to fine tune +how the recipes install and configure the Consul client, server and +UI. These values are passed into the resource/providers for +validation prior to converging. + +| Key | Type | Description | Default | +|---------|--------|----------------|-----------| +| ['consul']['version'] | String | Installation version | 0.5.1 | +| ['consul']['remote_url'] | String | Remote URL for download. | https://dl.bintray.com/mitchellh/consul | +| ['consul']['service_name'] | String | Name of the service (operating system) | consul | +| ['consul']['service_user'] | String | Name of the service user | consul | +| ['consul']['service_group'] | String | Name of the service group | consul | + +## Resources/Providers +This cookbook provides resource and provider primitives to manage the +Consul client, server and UI. These primitives are what is used in the +recipes, and should be used in your own [wrapper cookbooks][2]. + +### consul_client +### consul_config +### consul_service +### consul_watch +### consul_definition + +[0]: http://blog.vialstudios.com/the-environment-cookbook-pattern/#theapplicationcookbook [1]: http://consul.io -[2]: https://twitter.com/johnbellone -[3]: https://github.com/johnbellone -[4]: https://github.com/johnbellone/consul-cookbook/graphs/contributors -[5]: http://travis-ci.org/johnbellone/consul-cookbook -[6]: https://coveralls.io/r/johnbellone/consul-cookbook -[7]: https://docs.getchef.com/essentials_data_bags.html -[8]: https://github.com/opscode/chef-provisioning -[9]: https://github.com/opscode/chef-dk -[10]: https://github.com/opscode/chef-provisioning/blob/master/README.md +[2]: http://blog.vialstudios.com/the-environment-cookbook-pattern#thewrappercookbook diff --git a/Rakefile b/Rakefile deleted file mode 100644 index a483f66f..00000000 --- a/Rakefile +++ /dev/null @@ -1,10 +0,0 @@ -require 'rspec/core/rake_task' -require 'stove/rake_task' - -Stove::RakeTask.new - -RSpec::Core::RakeTask.new(:test) do |t| - t.pattern = 'spec/**/*_spec.rb' -end - -task default: :spec diff --git a/Thorfile b/Thorfile deleted file mode 100644 index b23ee163..00000000 --- a/Thorfile +++ /dev/null @@ -1,12 +0,0 @@ -# encoding: utf-8 - -require 'bundler' -require 'bundler/setup' -require 'berkshelf/thor' - -begin - require 'kitchen/thor_tasks' - Kitchen::ThorTasks.new -rescue LoadError - puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI'] -end diff --git a/Vagrantfile b/Vagrantfile index 13c92636..46b63468 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,22 +1,15 @@ Vagrant.configure('2') do |config| - # Set the version of chef to install using the vagrant-omnibus plugin - config.omnibus.chef_version = :latest - - # Enabling the Berkshelf plugin. To enable this globally, add this configuration - # option to your ~/.vagrant.d/Vagrantfile file config.berkshelf.enabled = true + config.omnibus.chef_version = :latest - # Every Vagrant virtual environment requires a box to build off of. - config.vm.box = 'opscode-ubuntu-12.04' - - # The url from where the 'config.vm.box' box will be fetched if it - # doesn't already exist on the user's system. - config.vm.box_url = "https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_provisionerless.box" + config.vm.box = ENV.fetch('VAGRANT_VM_BOX', 'opscode-ubuntu-14.04') + config.vm.box_url = ENV.fetch('VAGRANT_VM_BOX_URL', 'https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_ubuntu-14.04_provisionerless.box') config.vm.define :bootstrap, primary: true do |guest| guest.vm.network :private_network, ip: '172.16.38.10' - guest.vm.provision :chef_solo do |chef| - chef.run_list = ['recipe[consul::default]', 'recipe[consul::ui]'] + guest.vm.provision :chef_zero do |chef| + chef.nodes_path = File.expand_path('../.vagrant/chef/nodes', __FILE__) + chef.run_list = %w(recipe[consul::default]) end end end diff --git a/attributes/default.rb b/attributes/default.rb index 08218272..8025c88e 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -1,49 +1,39 @@ # -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. +# Cookbook: consul +# License: Apache 2.0 # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Copyright 2014, 2015 Bloomberg Finance L.P. # -default['consul']['base_url'] = "https://dl.bintray.com/mitchellh/consul/%{version}.zip" -default['consul']['version'] = '0.5.2' -default['consul']['install_method'] = 'binary' -default['consul']['install_dir'] = '/usr/local/bin' -default['consul']['checksums'] = { - '0.3.0_darwin_amd64' => '9dfbc70c01ebbc3e7dba0e4b31baeddbdcbd36ef99f5ac87ca6bbcc7405df405', - '0.3.0_linux_386' => '2513496374f8f15bda0da4da33122e93f82ce39f661ee3e668c67a5b7e98fd5f', - '0.3.0_linux_amd64' => 'da1337ab3b236bad19b791a54a8df03a8c2a340500a392000c21608696957b15', - '0.3.0_web_ui' => '0ab215e6aa7c94ccdb2c074732b8706940d37386b88c9421f1e4bc2501065476', - '0.3.0_windows_386' => '5d42e143eeb7c348ed8f7e15c6223e02ce0221dc0e076d15c8e6bdf88c8cd5d2', +default['consul']['service_name'] = 'consul' +default['consul']['service_user'] = 'consul' +default['consul']['service_group'] = 'consul' - '0.3.1_darwin_amd64' => 'e310d54244b207702143f1667d61bf0147d1bd656a29496d8b58eea07078d1dc', - '0.3.1_linux_386' => '9b8340fdf464a99fc9dc108115602c761b703a16277fbd9f4f164123cf2a9f11', - '0.3.1_linux_amd64' => 'c33da8ac24f01eefe8549e8d4d301b4e18a71b61f06ae1377a88ccd6eab2cfbb', - '0.3.1_web_ui' => 'd8982803fffb84d3202260161f6310bd6bddb5b12bf690cf00210cd659a31ddd', - '0.3.1_windows_386' => '102bda6e02b193a9417e80795875bf7d18259fc5daff3d048d274beef690eb26', +default['consul']['bag_name'] = 'secrets' +default['consul']['bag_item'] = 'consul' - '0.4.0_darwin_amd64' => '87a1b0f37e773d92c939ca7dd6a50985acc4fb4aaec31384756ef896aef4035b', - '0.4.0_linux_386' => 'e2d494654cfed1b9248734f5cb9d34dba9f356dffdcc8a09ab0ab85d170dba7c', - '0.4.0_linux_amd64' => '4f8cd1cc5d90be9e1326fee03d3c96289a4f8b9b6ccb062d228125a1adc9ea0c', - '0.4.0_windows_386' => '895387de34352f29e8cb91066b44750a958d4a44a88ac39e164cf9c62b521b08', - '0.4.0_web_ui' => '0ee574e616864b658ba6ecf16db1183b63c5a4a36401880fb0404a2ea18536a6', +default['consul']['config']['data_dir'] = '/var/lib/consul' +default['consul']['config']['ca_file'] = '/etc/ssl/CA/consul.crt' +default['consul']['config']['cert_file'] = '/etc/ssl/certs/consul.crt' +default['consul']['config']['client_addr'] = '0.0.0.0' +default['consul']['config']['key_file'] = '/etc/ssl/private/consul.key' +default['consul']['config']['ports'] = { + 'dns' => 8600, + 'http' => 8500, + 'rpc' => 8400, + 'serf_lan' => 8301, + 'serf_wan' => 8302, + "server" => 8300, +} - '0.4.1_darwin_amd64' => '957fe9ba27bbaf99539cd534db8ac8ec4c9fa1c6b3b4675d0c0eb3a7fbfb646c', - '0.4.1_linux_386' => 'a496d6fd8ff5b460aea50be5d20fbd95cb5d30e9018259a0540273a17fae1c25', - '0.4.1_linux_amd64' => '2cf6e59edf348c3094c721eb77436e8c789afa2c35e6e3123a804edfeb1744ac', - '0.4.1_windows_386' => '61906f5d73a0d991dae5d75a25299f183670efa473cd155c715eefc98ce49cc8', - '0.4.1_web_ui' => 'e02929ed44f5392cadd5513bdc60b7ab7363d1670d59e64d2422123229962fa0', +default['consul']['service']['install_method'] = :binary +default['consul']['service']['config_file'] = '/etc/consul.json' +default['consul']['service']['config_dir'] = '/etc/consul.d' +default['consul']['binary_url'] = "https://dl.bintray.com/mitchellh/consul/%{filename}.zip" +default['consul']['source_url'] = 'https://github.com/hashicorp/consul' +default['consul']['version'] = '0.5.2' +default['consul']['checksums'] = { '0.5.0_darwin_amd64' => '24d9758c873e9124e0ce266f118078f87ba8d8363ab16c2e59a3cd197b77e964', '0.5.0_linux_386' => '4b6147c30596a30361d4753d409f8a1af9518f54f5ed473a4c4ac973738ac0fd', '0.5.0_linux_amd64' => '161f2a8803e31550bd92a00e95a3a517aa949714c19d3124c46e56cfdc97b088', @@ -62,73 +52,3 @@ '0.5.2_windows_386' => '2e866812de16f1a6138a0fd1eebc76143f1314826e3b52597a55ac510ae94be6', '0.5.2_web_ui' => 'ad883aa52e1c0136ab1492bbcedad1210235f26d59719fb6de3ef6464f1ff3b1', } -default['consul']['source_revision'] = 'master' -default['consul']['use_packagecloud_repo'] = true - -# Service attributes -default['consul']['service_mode'] = 'bootstrap' -default['consul']['retry_on_join'] = false - -# In the cluster mode, set the default cluster size to 3 -default['consul']['bootstrap_expect'] = 3 -default['consul']['data_dir'] = '/var/lib/consul' -default['consul']['config_dir'] = '/etc/consul.d' -default['consul']['logfile'] = '/var/log/consul.log' -case node['platform_family'] -when 'debian' - default['consul']['etc_config_dir'] = '/etc/default/consul' -when 'rhel' - default['consul']['etc_config_dir'] = '/etc/sysconfig/consul' -else - default['consul']['etc_config_dir'] = '/etc/sysconfig/consul' -end - -default['consul']['servers'] = [] -default['consul']['init_style'] = 'init' # 'init', 'runit', 'systemd' - -case node['consul']['init_style'] -when 'runit' || 'systemd' - default['consul']['service_user'] = 'consul' - default['consul']['service_group'] = 'consul' -else - default['consul']['service_user'] = 'root' - default['consul']['service_group'] = 'root' -end - -default['consul']['ports'] = { - 'dns' => 8600, - 'http' => 8500, - 'rpc' => 8400, - 'serf_lan' => 8301, - 'serf_wan' => 8302, - "server" => 8300, -} - -# Consul DataBag -default['consul']['data_bag'] = 'consul' -default['consul']['data_bag_encrypt_item'] = 'encrypt' - -# Gossip encryption -default['consul']['encrypt_enabled'] = false -default['consul']['encrypt'] = nil -# TLS support -default['consul']['verify_incoming'] = false -default['consul']['verify_outgoing'] = false -# Cert in pem format -default['consul']['ca_cert'] = nil -default['consul']['ca_path'] = "%{config_dir}/ca.pem" -default['consul']['cert_file'] = nil -default['consul']['cert_path'] = "%{config_dir}/cert.pem" -# Cert in pem format. It can be unique for each host -default['consul']['key_file'] = nil -default['consul']['key_file_path'] = "%{config_dir}/key.pem" - -# Optionally bind to a specific interface -default['consul']['bind_interface'] = nil -default['consul']['advertise_interface'] = nil -default['consul']['client_interface'] = nil - -# UI attributes -default['consul']['client_addr'] = '0.0.0.0' -default['consul']['serve_ui'] = false -default['consul']['extra_params'] = {} diff --git a/cluster.rb b/cluster.rb deleted file mode 100644 index 12a515af..00000000 --- a/cluster.rb +++ /dev/null @@ -1,39 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -include_recipe 'chef-provisioning::default' - -num_quorum = ENV.fetch('CONSUL_QUORUM', 3) - -batch = machine_batch do - 1.upto(num_quorum).each do |index| - machine "consul-#{index}" do - recipe 'consul::default' - attributes(consul: { service_mode: 'cluster' }) - end - end -end - -include_recipe 'chef-sugar::default' -node.default['consul']['servers'] = batch.machines.each { |m| best_ip_for(m.node) } - -machine 'consul-ui' do - recipe 'consul::ui' - attributes(consul: { - service_mode: 'client', - servers: node['consul']['servers'] - }) -end diff --git a/libraries/consul.rb b/libraries/consul.rb deleted file mode 100644 index ca59249e..00000000 --- a/libraries/consul.rb +++ /dev/null @@ -1,60 +0,0 @@ -# -# Copyright 2014-2015 John Bellone -# Copyright 2014-2015 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the 'License'); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an 'AS IS' BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -class Chef - module Consul - class << self - def active_binary(node) - File.join(node['consul']['install_dir'], 'consul') - end - - def cached_archive(node) - File.join(Chef::Config[:file_cache_path], File.basename(remote_url(node))) - end - - def latest_binary(node) - File.join(install_path(node), 'consul') - end - - def remote_checksum(node) - node['consul']['checksums'].fetch(remote_filename(node)) - end - - def remote_filename(node) - [node['consul']['version'], node['os'], arch(node)].join('_') - end - - def remote_url(node) - node['consul']['base_url'] % { version: remote_filename(node) } - end - - def source_binary(node) - File.join(node['go']['gobin'], 'consul') - end - - def install_path(node) - File.join(['/opt', 'consul', node['consul']['version']]) - end - - private - - def arch(node) - node['kernel']['machine'] =~ /x86_64/ ? 'amd64' : '386' - end - end - end -end diff --git a/libraries/consul_config.rb b/libraries/consul_config.rb new file mode 100644 index 00000000..9910362f --- /dev/null +++ b/libraries/consul_config.rb @@ -0,0 +1,147 @@ +# +# Cookbook: consul +# License: Apache 2.0 +# +# Copyright (C) 2014, 2015 Bloomberg Finance L.P. +# +require 'poise' + +class Chef::Resource::ConsulConfig < Chef::Resource + include Poise(fused: true) + provides(:consul_config) + actions(:create, :delete) + + # @!attribute path + # @return [String] + attribute(:path, kind_of: String, name_attribute: true) + + # @!attribute owner + # @return [String] + attribute(:user, kind_of: String, default: 'consul') + + # @!attribute group + # @return [String] + attribute(:group, kind_of: String, default: 'consul') + + # @see: http://www.consul.io/docs/agent/options.html + attribute(:acl_datacenter, kind_of: String) + attribute(:acl_default_policy, kind_of: String) + attribute(:acl_down_policy, kind_of: String) + attribute(:acl_master_token, kind_of: String) + attribute(:acl_token, kind_of: String) + attribute(:acl_ttl, kind_of: String) + attribute(:addresses, kind_of: [Hash, Mash]) + attribute(:advertise_addr, kind_of: String) + attribute(:bind_addr, kind_of: String) + attribute(:bootstrap, equal_to: [true, false], default: false) + attribute(:bootstrap_expect, kind_of: Integer, default: 3) + attribute(:ca_file, kind_of: String) + attribute(:cert_file, kind_of: String) + attribute(:check_update_interval, kind_of: String) + attribute(:client_addr, kind_of: String) + attribute(:data_dir, kind_of: String) + attribute(:datacenter, kind_of: String) + attribute(:disable_anonymous_signature, equal_to: [true, false], default: false) + attribute(:disable_remote_exec, equal_to: [true, false], default: false) + attribute(:disable_update_check, equal_to: [true, false], default: false) + attribute(:dns_config, kind_of: [Hash, Mash]) + attribute(:domain, kind_of: String) + attribute(:enable_debug, equal_to: [true, false], default: false) + attribute(:enable_syslog, equal_to: [true, false], default: false) + attribute(:encrypt, kind_of: String) + attribute(:key_file, kind_of: String) + attribute(:leave_on_terminate, equal_to: [true, false], default: false) + attribute(:log_level, equal_to: %w(INFO DEBUG WARN), default: 'INFO') + attribute(:node_name, kind_of: String) + attribute(:ports, kind_of: [Hash, Mash]) + attribute(:protocol, kind_of: String) + attribute(:recurser, kind_of: String) + attribute(:retry_interval, kind_of: Integer) + attribute(:server, equal_to: [true, false], default: true) + attribute(:server_name, kind_of: String) + attribute(:skip_leave_on_interrupt, equal_to: [true, false], default: false) + attribute(:start_join, kind_of: Array) + attribute(:statsd_addr, kind_of: String) + attribute(:statsite_addr, kind_of: String) + attribute(:syslog_facility, kind_of: String) + attribute(:ui_dir, kind_of: String) + attribute(:verify_incoming, equal_to: [true, false], default: false) + attribute(:verify_outgoing, equal_to: [true, false], default: false) + attribute(:watches, kind_of: [Hash, Mash], default: {}) + + # Transforms the resource into a JSON format which matches the + # Consul service's configuration format. + def to_json + for_keeps = %i{acl_datacenter acl_default_policy acl_down_policy acl_master_token acl_token acl_ttl addresses advertise_addr bind_addr bootstrap bootstrap_expect ca_file cert_file check_update_interval client_addr data_dir datacenter disable_anonymous_signature disable_remote_exec disable_update_check dns_config domain enable_debug enable_syslog encrypt key_file leave_on_terminate log_level node_name ports protocol recurser retry_interval server server_name skip_leave_on_interrupt start_join statsd_addr statsite_addr syslog_facility ui_dir verify_incoming verify_outgoing watches} + config = to_hash.keep_if do |k, v| + for_keeps.include?(k.to_sym) + end + JSON.pretty_generate(config, quirks_mode: true) + end + + def tls? + verify_incoming || verify_outgoing + end + + action(:create) do + notifying_block do + if new_resource.tls? + include_recipe 'chef-vault::default' + + directory ::File.dirname(new_resource.ca_file) do + recursive true + end + + item = chef_vault_item(node['consul']['bag_name'], node['consul']['bag_item']) + file new_resource.ca_file do + content item['ca_certificate'] + mode '0644' + owner new_resource.user + group new_resource.group + end + + directory ::File.dirname(new_resource.cert_file) do + recursive true + end + + file new_resource.cert_file do + content item['certificate'] + mode '0644' + owner new_resource.user + group new_resource.group + end + + directory ::File.dirname(new_resource.key_file) do + recursive true + end + + file new_resource.key_file do + sensitive true + content item['private_key'] + mode '0644' + owner new_resource.user + group new_resource.group + end + end + + directory ::File.dirname(new_resource.path) do + recursive true + end + + file new_resource.path do + owner new_resource.user + group new_resource.group + content new_resource.to_json + mode '0644' + end + end + end + + action(:delete) do + notifying_block do + file new_resource.path do + action :delete + end + end + end +end diff --git a/libraries/consul_definition.rb b/libraries/consul_definition.rb new file mode 100644 index 00000000..97397e37 --- /dev/null +++ b/libraries/consul_definition.rb @@ -0,0 +1,56 @@ +# +# Cookbook: consul +# License: Apache 2.0 +# +# Copyright (C) 2014, 2015 Bloomberg Finance L.P. +# +require 'poise' + +class Chef::Resource::ConsulDefinition < Chef::Resource + include Poise(fused: true) + provides(:consul_definition) + actions(:create, :delete) + + # @!attribute path + # @return [String] + attribute(:path, kind_of: String, name_attribute: true) + + # @!attribute id + # @return [String, NilClass] + attribute(:id, kind_of: String) + + # @!attribute user + # @return [String] + attribute(:user, kind_of: String, default: 'consul') + + # @!attribute group + # @return [String] + attribute(:group, kind_of: String, default: 'consul') + + def to_json + for_keeps = %i{} + config = to_hash.keep_if do |k, v| + for_keeps.include?(k.to_sym) + end + JSON.pretty_generate(config, quirks_mode: true) + end + + action(:create) do + notifying_block do + file new_resource.path do + content new_resource.to_json + user new_resource.user + group new_resource.group + mode '0600' + end + end + end + + action(:delete) do + notifying_block do + file new_resource.path do + action :delete + end + end + end +end diff --git a/libraries/consul_service.rb b/libraries/consul_service.rb new file mode 100644 index 00000000..2a549f1a --- /dev/null +++ b/libraries/consul_service.rb @@ -0,0 +1,175 @@ +# +# Cookbook: consul +# License: Apache 2.0 +# +# Copyright (C) 2014, 2015 Bloomberg Finance L.P. +# +require 'poise_service/service_mixin' + +# Resource for managing the Consul service on an instance. +# @since 1.0.0 +class Chef::Resource::ConsulService < Chef::Resource + provides(:consul_service) + include PoiseService::ServiceMixin + + # @!attribute service_name + # @return [String] + attribute(:service_name, kind_of: String, name_attribute: true) + + # @!attribute version + # @return [String] + attribute(:version, kind_of: String, required: true) + + # @!attribute install_method + # @return [Symbol] + attribute(:install_method, default: :binary, equal_to: %i{source binary package}) + + # @!attribute install_path + # @return [String] + attribute(:install_path, kind_of: String, default: '/srv') + + # @!attribute config_filename + # @return [String] + attribute(:config_file, kind_of: String, default: '/etc/consul.json') + + # @!attribute user + # @return [String] + attribute(:user, kind_of: String, default: 'consul') + + # @!attribute group + # @return [String] + attribute(:group, kind_of: String, default: 'consul') + + # @!attribute environment + # @return [String] + attribute(:environment, kind_of: Hash, default: lazy { default_environment }) + + # @!attribute package_name + # @return [String] + attribute(:package_name, kind_of: String, default: 'consul') + + # @!attribute binary_url + # @return [String] + attribute(:binary_url, kind_of: String) + + # @!attribute source_url + # @return [String] + attribute(:source_url, kind_of: String) + + # @!attribute data_dir + # @return [String] + attribute(:data_dir, kind_of: String, default: '/var/lib/consul') + + # @!attribute config_dir + # @return [String] + attribute(:config_dir, kind_of: String, default: '/etc/consul.d') + + def default_environment + { GOMAXPROCS: [node['cpu']['total'], 2].max, PATH: '/usr/local/bin:/usr/bin:/bin' } + end + + def command + "consul agent -config-file=#{config_file} -config-dir=#{config_dir}" + end + + def binary_checksum + node['consul']['checksums'].fetch(binary_filename) + end + + def binary_filename + arch = node['kernel']['machine'] =~ /x86_64/ ? 'amd64' : '386' + [version, node['os'], arch].join('_') + end +end + +# Provider for managing the Consul service on an instance. +# @since 1.0.0 +class Chef::Provider::ConsulService < Chef::Provider + provides(:consul_service) + include PoiseService::ServiceMixin + + def action_enable + notifying_block do + directory new_resource.data_dir do + recursive true + owner new_resource.user + group new_resource.group + mode '0744' + end + + directory new_resource.config_dir do + recursive true + mode '0644' + end + + package new_resource.package_name do + version new_resource.version unless new_resource.version.nil? + only_if { new_resource.install_method == :package } + end + + if new_resource.install_method == :binary + artifact = libartifact_file "consul-#{new_resource.version}" do + artifact_name 'consul' + artifact_version new_resource.version + install_path new_resource.install_path + remote_url new_resource.binary_url % { filename: new_resource.binary_filename } + remote_checksum new_resource.binary_checksum + end + + link '/usr/local/bin/consul' do + to ::File.join(artifact.current_path, 'consul') + end + end + + if new_resource.install_method == :source + include_recipe 'golang::default' + + source_dir = directory ::File.join(new_resource.install_path, 'consul', 'src') do + recursive true + end + + git ::File.join(source_dir.path, "consul-#{new_resource.version}") do + repository new_resource.source_url + reference new_resource.version + action :checkout + end + + golang_package 'github.com/hashicorp/consul' do + action :install + end + + directory ::File.join(new_resource.install_path, 'bin') + + link ::File.join(new_resource.install_path, 'bin', 'consul') do + to ::File.join(source_dir.path, "consul-#{new_resource.version}", 'consul') + end + end + end + super + end + + def action_disable + notifying_block do + file new_resource.filename do + action :delete + end + + directory new_resource.config_dir do + action :delete + end + + directory new_resource.data_dir do + action :delete + end + end + super + end + + def service_options(service) + service.command(new_resource.command) + service.directory(new_resource.data_dir) + service.user(new_resource.user) + service.environment(new_resource.environment) + service.restart_on_update(true) + end +end diff --git a/libraries/consul_ui.rb b/libraries/consul_ui.rb deleted file mode 100644 index 33194a8e..00000000 --- a/libraries/consul_ui.rb +++ /dev/null @@ -1,50 +0,0 @@ -# -# Copyright 2014-2015 John Bellone -# Copyright 2014-2015 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the 'License'); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an 'AS IS' BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -class Chef - module ConsulUI - class << self - def active_path(node) - File.join(node['consul']['data_dir'], 'ui') - end - - def cached_archive(node) - File.join(Chef::Config[:file_cache_path], File.basename(remote_url(node))) - end - - def install_path(node) - File.join(['/opt', 'consul_ui', node['consul']['version']]) - end - - def latest_dist(node) - File.join(install_path(node), 'dist') - end - - def remote_filename(node) - [node['consul']['version'], 'web_ui'].join('_') - end - - def remote_checksum(node) - node['consul']['checksums'].fetch(remote_filename(node)) - end - - def remote_url(node) - node['consul']['base_url'] % { version: remote_filename(node) } - end - end - end -end diff --git a/libraries/consul_watch.rb b/libraries/consul_watch.rb new file mode 100644 index 00000000..6f46aa17 --- /dev/null +++ b/libraries/consul_watch.rb @@ -0,0 +1,42 @@ +# +# Cookbook: consul +# License: Apache 2.0 +# +# Copyright (C) 2014, 2015 Bloomberg Finance L.P. +# +require 'poise' + +class Chef::Resource::ConsulWatch < Chef::Resource + include Poise(fused: true) + provides(:consul_watch) + actions(:create, :delete) + + # @!attribute watch_name + # @return [String] + attribute(:watch_name, kind_of: String, name_attribute: true) + + # @!attribute watch_type + # @return [String] + attribute(:watch_type, equal_to: %w(checks event key keyprefix service)) + + # @!attribute datacenter + # @return [String] + attribute(:datacenter, kind_of: String) + + # @!attribute handler + # @return [String] + attribute(:handler, kind_of: String) + + # @!attribute token + # @return [String] + attribute(:token, kind_of: String) + + action(:create) do + execute new_resource.command do + guard_interpreter :default + end + end + + action(:delete) do + end +end diff --git a/libraries/encrypt.rb b/libraries/encrypt.rb deleted file mode 100644 index 8dd65488..00000000 --- a/libraries/encrypt.rb +++ /dev/null @@ -1,21 +0,0 @@ -class Chef - class Recipe - # Don't throw the error if it doesn't exist - def consul_encrypted_dbi - begin - # loads the secret from /etc/chef/encrypted_data_bag_secret - Chef::EncryptedDataBagItem.load(node['consul']['data_bag'], node['consul']['data_bag_encrypt_item']) - rescue Net::HTTPServerException => e - raise e unless e.response.code == '404' - end - end - - def consul_dbi_key_with_node_default(dbi, key) - value = dbi[key] - Chef::Log.warn "Consul encrypt key=#{key} doesn't exist in the databag. \ -Reading it from node's attributes" if value.nil? - value ||= node['consul'][key] - value - end - end -end diff --git a/libraries/matchers.rb b/libraries/matchers.rb index 1485ac28..1f87917f 100644 --- a/libraries/matchers.rb +++ b/libraries/matchers.rb @@ -1,17 +1,25 @@ if defined?(ChefSpec) - def create_consul_service_def(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:consul_service_def, :create, resource_name) - end + %i{create delete}.each do |action| + define_method(:"#{action}_consul_client") do |resource_name| + ChefSpec::Matchers::ResourceMatcher.new(:consul_client, action, resource_name) + end - def delete_consul_service_def(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:consul_service_def, :delete, resource_name) - end + define_method(:"#{action}_consul_config") do |resource_name| + ChefSpec::Matchers::ResourceMatcher.new(:consul_config, action, resource_name) + end + + define_method(:"#{action}_consul_definition") do |resource_name| + ChefSpec::Matchers::ResourceMatcher.new(:consul_definition, action, resource_name) + end - def create_consul_event_watch_def(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:consul_event_watch_def, :create, resource_name) + define_method(:"#{action}_consul_watch") do |resource_name| + ChefSpec::Matchers::ResourceMatcher.new(:consul_watch, action, resource_name) + end end - def delete_consul_key_watch_def(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:consul_key_watch_def, :create, resource_name) + %i{enable disable stop start restart reload}.each do |action| + define_method(:"#{action}_consul_service") do |resource_name| + ChefSpec::Matchers::ResourceMatcher.new(:consul_service, action, resource_name) + end end end diff --git a/metadata.rb b/metadata.rb index 35c2c2b8..3871b49e 100644 --- a/metadata.rb +++ b/metadata.rb @@ -1,29 +1,21 @@ name 'consul' maintainer 'John Bellone' maintainer_email 'jbellone@bloomberg.net' -license 'Apache v2.0' -description 'Installs/Configures Consul client, server and UI.' -long_description 'Installs/Configures Consul client, server and UI.' -version '0.10.0' +license 'Apache 2.0' +description 'Application cookbook which installs and configures Consul.' +long_description 'Application cookbook which installs and configures Consul.' +version '1.0.0' -recipe 'consul', 'Installs and starts consul service.' -recipe 'consul::install_binary', 'Installs consul service from binary.' -recipe 'consul::install_source', 'Installs consul service from source.' -recipe 'consul::ui', 'Installs consul ui service.' +recipe 'consul::default', 'Installs, configures and starts the Consul service.' -%w(redhat centos).each do |name| - supports name, '~> 7.0' - supports name, '~> 6.5' -end - -supports 'ubuntu', '= 12.04' -supports 'ubuntu', '= 14.04' +supports 'centos', '>= 6.5' +supports 'redhat', '>= 6.5' +supports 'ubuntu', '>= 12.04' supports 'arch' -recommends 'chef-provisioning' - -depends 'libarchive', "~> 0.4.0" +depends 'chef-vault' +depends 'libartifact', '~> 1.2' depends 'golang', '~> 1.4' -depends 'runit' -depends 'yum-repoforge' -depends 'packagecloud' +depends 'poise', '~> 2.0' +depends 'poise-service' +depends 'selinux' diff --git a/providers/check_def.rb b/providers/check_def.rb deleted file mode 100644 index 69a81b84..00000000 --- a/providers/check_def.rb +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use_inline_resources - -action :create do - file new_resource.path_with_name do - action :delete - only_if { new_resource.id } - end - - file new_resource.path do - user node['consul']['service_user'] - group node['consul']['service_group'] - mode 0600 - content new_resource.to_json - - action :create - end -end - -action :delete do - file new_resource.path do - action :delete - end -end diff --git a/providers/event_watch_def.rb b/providers/event_watch_def.rb deleted file mode 100644 index 68debf19..00000000 --- a/providers/event_watch_def.rb +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use_inline_resources - -action :create do - file new_resource.path do - user node['consul']['service_user'] - group node['consul']['service_group'] - mode 0600 - content new_resource.to_json - - action :create - end -end - -action :delete do - file new_resource.path do - action :delete - end -end diff --git a/providers/key_watch_def.rb b/providers/key_watch_def.rb deleted file mode 100644 index 68debf19..00000000 --- a/providers/key_watch_def.rb +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use_inline_resources - -action :create do - file new_resource.path do - user node['consul']['service_user'] - group node['consul']['service_group'] - mode 0600 - content new_resource.to_json - - action :create - end -end - -action :delete do - file new_resource.path do - action :delete - end -end diff --git a/providers/service_def.rb b/providers/service_def.rb deleted file mode 100644 index 4d643f84..00000000 --- a/providers/service_def.rb +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use_inline_resources if defined? use_inline_resources - -def set_updated - r = yield - new_resource.updated_by_last_action(r.updated_by_last_action?) -end - -action :create do - set_updated do - file new_resource.path do - user node['consul']['service_user'] - group node['consul']['service_group'] - mode 0600 - content new_resource.to_json - action :create - end - end -end - -action :delete do - set_updated do - file new_resource.path do - action :delete - end - end -end diff --git a/providers/service_watch_def.rb b/providers/service_watch_def.rb deleted file mode 100644 index 68debf19..00000000 --- a/providers/service_watch_def.rb +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -use_inline_resources - -action :create do - file new_resource.path do - user node['consul']['service_user'] - group node['consul']['service_group'] - mode 0600 - content new_resource.to_json - - action :create - end -end - -action :delete do - file new_resource.path do - action :delete - end -end diff --git a/providers/services_watch_def.rb b/providers/services_watch_def.rb deleted file mode 100644 index 9f9506a6..00000000 --- a/providers/services_watch_def.rb +++ /dev/null @@ -1,18 +0,0 @@ -use_inline_resources - -action :create do - file new_resource.path do - user node['consul']['service_user'] - group node['consul']['service_group'] - mode 0600 - content new_resource.to_json - - action :create - end -end - -action :delete do - file new_resource.path do - action :delete - end -end diff --git a/recipes/_service.rb b/recipes/_service.rb deleted file mode 100644 index 281f0fe7..00000000 --- a/recipes/_service.rb +++ /dev/null @@ -1,252 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require 'json' - -# Configure directories -consul_directories = [] -consul_directories << node['consul']['data_dir'] -consul_directories << node['consul']['config_dir'] -consul_directories << '/var/lib/consul' - -# Select service user & group -if node['consul']['init_style'] == 'runit' - include_recipe 'runit::default' - consul_directories << '/var/log/consul' -end - -consul_user = node['consul']['service_user'] -consul_group = node['consul']['service_group'] - -# Create service user -user "consul service user: #{consul_user}" do - not_if { consul_user == 'root' } - username consul_user - home '/dev/null' - shell '/bin/false' - comment 'consul service user' -end - -# Create service group -group "consul service group: #{consul_group}" do - not_if { consul_group == 'root' } - group_name consul_group - members consul_user - append true -end - -# Create service directories -consul_directories.uniq.each do |dirname| - directory dirname do - owner consul_user - group consul_group - mode 0755 - end - - execute "chown -R #{consul_user}:#{consul_group} #{dirname}" -end - -# Determine service params -service_config = JSON.parse(node['consul']['extra_params'].to_json) -service_config['data_dir'] = node['consul']['data_dir'] -num_cluster = node['consul']['bootstrap_expect'].to_i -join_mode = node['consul']['retry_on_join'] ? 'retry_join' : 'start_join' - -case node['consul']['service_mode'] -when 'bootstrap' - service_config['server'] = true - service_config['bootstrap'] = true -when 'cluster' - service_config['server'] = true - if num_cluster > 1 - service_config['bootstrap_expect'] = num_cluster - service_config[join_mode] = node['consul']['servers'] - else - service_config['bootstrap'] = true - end -when 'server' - service_config['server'] = true - service_config[join_mode] = node['consul']['servers'] -when 'client' - service_config[join_mode] = node['consul']['servers'] -else - Chef::Application.fatal! %Q(node['consul']['service_mode'] must be "bootstrap", "cluster", "server", or "client") -end - -iface_addr_map = { - bind_interface: :bind_addr, - advertise_interface: :advertise_addr, - client_interface: :client_addr -} - -iface_addr_map.each_pair do |interface,addr| - next unless node['consul'][interface] - - if node["network"]["interfaces"][node['consul'][interface]] - ip = node["network"]["interfaces"][node['consul'][interface]]["addresses"].detect{|k,v| v[:family] == "inet"}.first - node.default['consul'][addr] = ip - else - Chef::Application.fatal!("Interface specified in node['consul'][#{interface}] does not exist!") - end -end - -if node['consul']['serve_ui'] - service_config['ui_dir'] = Chef::ConsulUI.active_path(node) - service_config['client_addr'] = node['consul']['client_addr'] -end - -additional_options = ['recursor', 'statsd_addr', 'leave_on_terminate', 'rejoin_after_leave', 'disable_remote_exec', 'acl_datacenter', 'acl_token', 'acl_default_policy', 'acl_down_policy', 'acl_master_token'] - -additional_options.each do |option| - if node['consul'][option] - service_config[option] = node['consul'][option] - end -end - -copy_params = [ - :bind_addr, :datacenter, :domain, :log_level, :node_name, :advertise_addr, :ports, :enable_syslog, :statsd_addr -] -copy_params.each do |key| - if node['consul'][key] - if key == :ports - Chef::Application.fatal! 'node[:consul][:ports] must be a Hash' unless node[:consul][key].kind_of?(Hash) - end - - service_config[key] = node['consul'][key] - end -end - -dbi = nil -# Gossip encryption -if node.consul.encrypt_enabled - # Fetch the databag only once, and use empty hash if it doesn't exists - dbi = consul_encrypted_dbi || {} - secret = consul_dbi_key_with_node_default(dbi, 'encrypt') - raise "Consul encrypt key is empty or nil" if secret.nil? or secret.empty? - service_config['encrypt'] = secret -else - # for backward compatibilty - service_config['encrypt'] = node.consul.encrypt unless node.consul.encrypt.nil? -end - -# TLS encryption -if node.consul.verify_incoming || node.consul.verify_outgoing - dbi = consul_encrypted_dbi || {} if dbi.nil? - service_config['verify_outgoing'] = node.consul.verify_outgoing - service_config['verify_incoming'] = node.consul.verify_incoming - - ca_path = node.consul.ca_path % { config_dir: node.consul.config_dir } - service_config['ca_file'] = ca_path - - cert_path = node.consul.cert_path % { config_dir: node.consul.config_dir } - service_config['cert_file'] = cert_path - - key_path = node.consul.key_file_path % { config_dir: node.consul.config_dir } - service_config['key_file'] = key_path - - # Search for key_file_hostname since key and cert file can be unique/host - key_content = dbi['key_file_' + node.fqdn] || consul_dbi_key_with_node_default(dbi, 'key_file') - cert_content = dbi['cert_file_' + node.fqdn] || consul_dbi_key_with_node_default(dbi, 'cert_file') - ca_content = consul_dbi_key_with_node_default(dbi, 'ca_cert') - - # Save the certs if exists - {ca_path => ca_content, key_path => key_content, cert_path => cert_content}.each do |path, content| - unless content.nil? or content.empty? - file path do - user consul_user - group consul_group - mode 0600 - action :create - content content - end - end - end -end - -consul_config_filename = File.join(node['consul']['config_dir'], 'default.json') - -file consul_config_filename do - user consul_user - group consul_group - mode 0600 - action :create - content JSON.pretty_generate(service_config, quirks_mode: true) - # https://github.com/johnbellone/consul-cookbook/issues/72 - notifies :restart, "service[consul]" -end - -case node['consul']['init_style'] -when 'init' - if platform?("ubuntu") - init_file = '/etc/init/consul.conf' - init_tmpl = 'consul.conf.erb' - init_mode = 0644 - else - init_file = '/etc/init.d/consul' - init_tmpl = 'consul-init.erb' - init_mode = 0755 - end - - template node['consul']['etc_config_dir'] do - source 'consul-sysconfig.erb' - mode 0644 - notifies :create, "template[#{init_file}]", :immediately - end - - template init_file do - source init_tmpl - mode init_mode - variables( - consul_logfile: node['consul']['logfile'] - ) - notifies :restart, 'service[consul]', :immediately - end - - service 'consul' do - provider Chef::Provider::Service::Upstart if platform?("ubuntu") - supports status: true, restart: true, reload: true - action [:enable, :start] - subscribes :restart, "file[#{consul_config_filename}]" - subscribes :restart, "link[#{Chef::Consul.active_binary(node)}]" - end -when 'runit' - runit_service 'consul' do - supports status: true, restart: true, reload: true - action [:enable, :start] - subscribes :restart, "file[#{consul_config_filename}]" - subscribes :restart, "link[#{Chef::Consul.active_binary(node)}]" - log true - end - - service 'consul' do - supports status: true, restart: true, reload: true - reload_command "'#{node['runit']['sv_bin']}' hup consul" - end -when 'systemd' - template '/etc/systemd/system/consul.service' do - source 'consul-systemd.erb' - mode 0644 - notifies :restart, 'service[consul]', :immediately - end - - service 'consul' do - supports status: true, restart: true, reload: true - action [:enable, :start] - subscribes :restart, "file[#{consul_config_filename}]" - subscribes :restart, "link[#{Chef::Consul.active_binary(node)}]" - end -end diff --git a/recipes/default.rb b/recipes/default.rb index 05d96fbd..c20e1715 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -1,27 +1,33 @@ # -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. +# Cookbook Name:: consul +# License:: Apache 2.0 # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# Copyright 2014, 2015 Bloomberg Finance L.P. # +include_recipe 'selinux::permissive' + +poise_service_user node['consul']['service_user'] do + group node['consul']['service_group'] +end + +consul_config node['consul']['service']['config_file'] do |resource| + user node['consul']['service_user'] + group node['consul']['service_group'] + + node['consul']['config'].each_pair { |k, v| resource.send(k, v) } + notifies :restart, "consul_service[#{node['consul']['service_name']}]", :delayed +end + +consul_service node['consul']['service_name'] do + user node['consul']['service_user'] + group node['consul']['service_group'] + version node['consul']['version'] + install_method node['consul']['service']['install_method'] + install_path node['consul']['service']['install_path'] + config_dir node['consul']['service']['config_dir'] + config_file node['consul']['service']['config_file'] -case node['consul']['install_method'] -when 'binary' - include_recipe 'consul::install_binary' -when 'source' - include_recipe 'consul::install_source' -when 'packages' - include_recipe 'consul::install_packages' -else - Chef::Application.fatal!("[consul::default] unknown install method, method=#{node['consul']['install_method']}") + package_name node['consul']['package_name'] + binary_url node['consul']['binary_url'] + source_url node['consul']['source_url'] end diff --git a/recipes/install_binary.rb b/recipes/install_binary.rb deleted file mode 100644 index 6117c149..00000000 --- a/recipes/install_binary.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -include_recipe 'libarchive::default' - -archive = remote_file Chef::Consul.cached_archive(node) do - source Chef::Consul.remote_url(node) - checksum Chef::Consul.remote_checksum(node) -end - -libarchive_file 'consul.zip' do - path archive.path - extract_to Chef::Consul.install_path(node) - extract_options :no_overwrite - - action :extract -end - -directory File.basename(Chef::Consul.active_binary(node)) do - recursive true - action :create -end - -# JW TODO: Remove after next major release. -file Chef::Consul.active_binary(node) do - action :delete - not_if "test -L #{Chef::Consul.active_binary(node)}" -end - -link Chef::Consul.active_binary(node) do - to Chef::Consul.latest_binary(node) -end - -include_recipe 'consul::_service' diff --git a/recipes/install_packages.rb b/recipes/install_packages.rb deleted file mode 100644 index 3b5b94e4..00000000 --- a/recipes/install_packages.rb +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# NOTE: This is only supported for Ubuntu 12.04LTS and 14.04LTS. - -if node['consul']['use_packagecloud_repo'] - - packagecloud_repo "darron/consul" do - type "deb" - end - - packagecloud_repo "darron/consul-webui" do - type "deb" - end - -end - -package 'consul' -package 'consul-webui' - -include_recipe 'consul::_service' diff --git a/recipes/install_source.rb b/recipes/install_source.rb deleted file mode 100644 index 8b49d293..00000000 --- a/recipes/install_source.rb +++ /dev/null @@ -1,47 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -include_recipe 'golang::default' - -directory File.join(node['go']['gopath'], 'src/github.com/hashicorp') do - owner 'root' - group 'root' - mode '00755' - recursive true - action :create -end - -git File.join(node['go']['gopath'], '/src/github.com/hashicorp/consul') do - repository 'https://github.com/hashicorp/consul.git' - reference node['consul']['source_revision'] - action :checkout -end - -golang_package 'github.com/hashicorp/consul' do - action :install -end - -directory File.basename(Chef::Consul.active_binary(node)) do - recursive true - action :create -end - -link Chef::Consul.active_binary(node) do - to Chef::Consul.source_binary(node) -end - -include_recipe 'consul::_service' diff --git a/recipes/ui.rb b/recipes/ui.rb deleted file mode 100644 index 6be1fef0..00000000 --- a/recipes/ui.rb +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2014 Benny Wong -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -include_recipe 'libarchive::default' - -archive = remote_file Chef::ConsulUI.cached_archive(node) do - source Chef::ConsulUI.remote_url(node) - checksum Chef::ConsulUI.remote_checksum(node) -end - -libarchive_file 'consul_ui.zip' do - path archive.path - extract_to Chef::ConsulUI.install_path(node) - extract_options :no_overwrite - - action :extract -end - -# JW TODO: Remove after next major release. -directory Chef::ConsulUI.active_path(node) do - action :delete - recursive true - not_if "test -L #{Chef::ConsulUI.active_path(node)}" -end - -link Chef::ConsulUI.active_path(node) do - to Chef::ConsulUI.latest_dist(node) -end diff --git a/resources/check_def.rb b/resources/check_def.rb deleted file mode 100644 index 1efb45ff..00000000 --- a/resources/check_def.rb +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require 'json' - -actions :create, :delete -default_action :create - -attribute :name, name_attribute: true, required: true, kind_of: String -attribute :id, kind_of: String -attribute :script, kind_of: String -attribute :http, kind_of: String -attribute :ttl, kind_of: String -attribute :interval, kind_of: String -attribute :notes, kind_of: String - -def path - ::File.join(node['consul']['config_dir'], "check-#{id || name}.json") -end - -def path_with_name - ::File.join(node['consul']['config_dir'], "check-#{name}.json") -end - -def to_json - JSON.pretty_generate(to_hash) -end - -def to_hash - hash = { - check: { - name: name - } - } - hash[:check][:id] = id unless id.nil? - hash[:check][:script] = script unless script.nil? - hash[:check][:ttl] = ttl unless ttl.nil? - hash[:check][:http] = http unless http.nil? - hash[:check][:interval] = interval unless interval.nil? - hash[:check][:notes] = notes unless notes.nil? - hash -end diff --git a/resources/event_watch_def.rb b/resources/event_watch_def.rb deleted file mode 100644 index 1772d76f..00000000 --- a/resources/event_watch_def.rb +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require 'json' - -actions :create, :delete -default_action :create - -attribute :name, name_attribute: true, required: true, kind_of: String -attribute :handler, required: true, kind_of: String - -def path - ::File.join(node['consul']['config_dir'], "event-watch-#{name}.json") -end - -def to_json - JSON.pretty_generate(to_hash) -end - -def to_hash - hash = { - watches:[ - { - type: 'event', - name: name, - handler: handler - } - ] - } - hash -end diff --git a/resources/key_watch_def.rb b/resources/key_watch_def.rb deleted file mode 100644 index 4d698fba..00000000 --- a/resources/key_watch_def.rb +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require 'json' - -actions :create, :delete -default_action :create - -attribute :name, name_attribute: true, required: true, kind_of: String -attribute :key, required: true, kind_of: String -attribute :handler, required: true, kind_of: String - -def path - ::File.join(node['consul']['config_dir'], "key-watch-#{name}.json") -end - -def to_json - JSON.pretty_generate(to_hash) -end - -def to_hash - hash = { - watches:[ - { - type: 'key', - key: key, - handler: handler - } - ] - } - hash -end diff --git a/resources/service_def.rb b/resources/service_def.rb deleted file mode 100644 index 33b972d1..00000000 --- a/resources/service_def.rb +++ /dev/null @@ -1,72 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require 'json' - -actions :create, :delete -default_action :create - -attribute :name, name_attribute: true, required: true, kind_of: String -attribute :id, kind_of: String -attribute :port, kind_of: Integer -attribute :tags, kind_of: Array, default: nil -attribute :check, kind_of: Hash, default: nil, callbacks: { - 'Checks must be a hash containing either a `:ttl` key/value or a `:script/:http` and `:interval` key/value' => ->(check) do - Chef::Resource::ConsulServiceDef.validate_check(check) - end -} - -def self.validate_check(check) - unless check.is_a?(Hash) - return false - end - - if check.key?(:ttl) && ( [:interval, :script, :http].none?{|key| check.key?(key)} ) - return true - end - - if check.key?(:interval) && check.key?(:script) - return true - end - - if check.key?(:interval) && check.key?(:http) - return true - end - - false -end - -def path - ::File.join(node['consul']['config_dir'], "service-#{id || name}.json") -end - -def to_json - JSON.pretty_generate(to_hash) -end - -def to_hash - hash = { - service: { - name: name - } - } - hash[:service][:id] = id unless id.nil? - hash[:service][:port] = port unless port.nil? - hash[:service][:tags] = tags unless tags.nil? - hash[:service][:check] = check unless check.nil? - hash -end diff --git a/resources/service_watch_def.rb b/resources/service_watch_def.rb deleted file mode 100644 index 4f469aa0..00000000 --- a/resources/service_watch_def.rb +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright 2014 John Bellone -# Copyright 2014 Bloomberg Finance L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require 'json' - -actions :create, :delete -default_action :create - -attribute :service, name_attribute: true, required: true, kind_of: String -attribute :handler, required: true, kind_of: String -attribute :passingonly, required: false, kind_of: [TrueClass, FalseClass] -attribute :tag, required: false, kind_of: String - -def path - ::File.join(node['consul']['config_dir'], "service-watch-#{name}.json") -end - -def to_json - JSON.pretty_generate({'watches'=> [to_hash]}) -end - -def to_hash - hash = { - type: "service" - } - hash[:service] = name - hash[:handler] = handler unless handler.nil? - hash[:tag] = tag unless tag.nil? - hash[:passingonly] = passingonly unless passingonly.nil? - hash -end diff --git a/resources/services_watch_def.rb b/resources/services_watch_def.rb deleted file mode 100644 index d1fdaf19..00000000 --- a/resources/services_watch_def.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'json' - -actions :create, :delete -default_action :create - -attribute :name, name_attribute: true, required: true, kind_of: String -attribute :handler, required: true, kind_of: String - -def path - ::File.join(node['consul']['config_dir'], "watch-services.json") -end - -def to_json - JSON.pretty_generate(to_hash) -end - -def to_hash - hash = { - watches:[ - { - type: 'services', - handler: handler - } - ] - } - hash -end diff --git a/spec/fixtures/cookbooks/consul_spec/metadata.rb b/spec/fixtures/cookbooks/consul_spec/metadata.rb deleted file mode 100644 index a40a72e5..00000000 --- a/spec/fixtures/cookbooks/consul_spec/metadata.rb +++ /dev/null @@ -1,3 +0,0 @@ -name 'consul_spec' - -depends 'consul' diff --git a/spec/fixtures/cookbooks/consul_spec/recipes/check_def_with_id_create.rb b/spec/fixtures/cookbooks/consul_spec/recipes/check_def_with_id_create.rb deleted file mode 100644 index ad49a705..00000000 --- a/spec/fixtures/cookbooks/consul_spec/recipes/check_def_with_id_create.rb +++ /dev/null @@ -1,9 +0,0 @@ -include_recipe "consul" -consul_check_def "dummy name" do - id "uniqueid" - script "curl http://localhost:8888/health" - interval "10s" - ttl "50s" - http "http://localhost:8888/health" - notes "Blahblah" -end diff --git a/spec/fixtures/cookbooks/consul_spec/recipes/check_def_with_id_delete.rb b/spec/fixtures/cookbooks/consul_spec/recipes/check_def_with_id_delete.rb deleted file mode 100644 index 0ebaa855..00000000 --- a/spec/fixtures/cookbooks/consul_spec/recipes/check_def_with_id_delete.rb +++ /dev/null @@ -1,5 +0,0 @@ -include_recipe "consul" -consul_check_def "dummy name" do - id "uniqueid" - action :delete -end diff --git a/spec/fixtures/cookbooks/consul_spec/recipes/check_def_without_id_create.rb b/spec/fixtures/cookbooks/consul_spec/recipes/check_def_without_id_create.rb deleted file mode 100644 index 563686a5..00000000 --- a/spec/fixtures/cookbooks/consul_spec/recipes/check_def_without_id_create.rb +++ /dev/null @@ -1,7 +0,0 @@ -include_recipe "consul" -consul_check_def "dummy name" do - script "curl http://localhost:8888/health" - interval "10s" - ttl "50s" - notes "Blahblah" -end diff --git a/spec/fixtures/cookbooks/consul_spec/recipes/check_def_without_id_delete.rb b/spec/fixtures/cookbooks/consul_spec/recipes/check_def_without_id_delete.rb deleted file mode 100644 index 7d314cec..00000000 --- a/spec/fixtures/cookbooks/consul_spec/recipes/check_def_without_id_delete.rb +++ /dev/null @@ -1,4 +0,0 @@ -include_recipe "consul" -consul_check_def "dummy name" do - action :delete -end diff --git a/spec/fixtures/cookbooks/consul_spec/recipes/event_watch_create.rb b/spec/fixtures/cookbooks/consul_spec/recipes/event_watch_create.rb deleted file mode 100644 index fad2acf5..00000000 --- a/spec/fixtures/cookbooks/consul_spec/recipes/event_watch_create.rb +++ /dev/null @@ -1,4 +0,0 @@ -include_recipe "consul" -consul_event_watch_def "dummy" do - handler "chef-client" -end diff --git a/spec/fixtures/cookbooks/consul_spec/recipes/event_watch_delete.rb b/spec/fixtures/cookbooks/consul_spec/recipes/event_watch_delete.rb deleted file mode 100644 index ff1318c2..00000000 --- a/spec/fixtures/cookbooks/consul_spec/recipes/event_watch_delete.rb +++ /dev/null @@ -1,4 +0,0 @@ -include_recipe "consul" -consul_event_watch_def "dummy" do - action :delete -end diff --git a/spec/fixtures/cookbooks/consul_spec/recipes/key_watch_create.rb b/spec/fixtures/cookbooks/consul_spec/recipes/key_watch_create.rb deleted file mode 100644 index 26c6a9b8..00000000 --- a/spec/fixtures/cookbooks/consul_spec/recipes/key_watch_create.rb +++ /dev/null @@ -1,5 +0,0 @@ -include_recipe "consul" -consul_key_watch_def "dummy" do - key "/key/path" - handler "chef-client" -end diff --git a/spec/fixtures/cookbooks/consul_spec/recipes/key_watch_delete.rb b/spec/fixtures/cookbooks/consul_spec/recipes/key_watch_delete.rb deleted file mode 100644 index 679f115a..00000000 --- a/spec/fixtures/cookbooks/consul_spec/recipes/key_watch_delete.rb +++ /dev/null @@ -1,4 +0,0 @@ -include_recipe "consul" -consul_key_watch_def "dummy" do - action :delete -end diff --git a/spec/fixtures/cookbooks/consul_spec/recipes/service_def_create.rb b/spec/fixtures/cookbooks/consul_spec/recipes/service_def_create.rb deleted file mode 100644 index 6b6be73e..00000000 --- a/spec/fixtures/cookbooks/consul_spec/recipes/service_def_create.rb +++ /dev/null @@ -1,7 +0,0 @@ -include_recipe "consul" -consul_service_def "dummy" do - id "uniqueid" - port 8888 - tags ['releases', 'v1'] - check :interval => "10s", :script => "curl http://localhost:8888/health" -end diff --git a/spec/fixtures/cookbooks/consul_spec/recipes/service_def_delete.rb b/spec/fixtures/cookbooks/consul_spec/recipes/service_def_delete.rb deleted file mode 100644 index 8a78f6a5..00000000 --- a/spec/fixtures/cookbooks/consul_spec/recipes/service_def_delete.rb +++ /dev/null @@ -1,5 +0,0 @@ -include_recipe "consul" -consul_service_def "dummy" do - id "uniqueid" - action :delete -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb deleted file mode 100644 index ceae4944..00000000 --- a/spec/spec_helper.rb +++ /dev/null @@ -1,97 +0,0 @@ -require 'chefspec' -require 'chefspec/berkshelf' -require 'chefspec/cacher' -require 'chefspec/server' -require 'coveralls' - -require_relative 'support/matchers' - -Coveralls.wear! - -RSpec.configure do |config| - config.color = true - config.alias_example_group_to :describe_recipe, type: :recipe - config.alias_example_group_to :describe_resource, type: :resource - - config.filter_run :focus - config.run_all_when_everything_filtered = true - - Kernel.srand config.seed - config.order = :random - - if config.files_to_run.one? - config.default_formatter = 'doc' - end - - config.expect_with :rspec do |expectations| - expectations.syntax = :expect - end - - config.mock_with :rspec do |mocks| - mocks.syntax = :expect - mocks.verify_partial_doubles = true - end -end - -at_exit { ChefSpec::Coverage.report! } - -RSpec.shared_context 'recipe tests', type: :recipe do - before do - stub_command("test -L /usr/local/bin/consul").and_return(true) - end - - let(:chef_run) { ChefSpec::Runner.new(node_attributes).converge(described_recipe) } - - def node_attributes - { - platform: 'ubuntu', - version: '12.04' - } - end -end - -RSpec.shared_context "resource tests", type: :resource do - before do - stub_command("test -L /usr/local/bin/consul").and_return(true) - end - - let(:chef_run) do - ChefSpec::SoloRunner.new(node_attributes.merge(step_into)).converge(example_recipe) - end - - let(:example_recipe) do - fail %( -Please specify the name of the test recipe that executes your recipe: - - let(:example_recipe) do - "consul_spec::service_def" - end - -) - end - - let(:node) { chef_run.node } - - def node_attributes - { - platform: 'ubuntu', - version: '12.04' - } - end - - let(:step_into) do - { step_into: [cookbook_name] } - end - - def cookbook_recipe_names - described_recipe.split("::", 2) - end - - def cookbook_name - cookbook_recipe_names.first - end - - def recipe_name - cookbook_recipe_names.last - end -end diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb deleted file mode 100644 index 422b8a5f..00000000 --- a/spec/support/matchers.rb +++ /dev/null @@ -1,35 +0,0 @@ -def start_runit_service(name) - ChefSpec::Matchers::ResourceMatcher.new(:runit_service, :start, name) -end - -def stop_runit_service(name) - ChefSpec::Matchers::ResourceMatcher.new(:runit_service, :stop, name) -end - -def enable_runit_service(name) - ChefSpec::Matchers::ResourceMatcher.new(:runit_service, :enable, name) -end - -def disable_runit_service(name) - ChefSpec::Matchers::ResourceMatcher.new(:runit_service, :disable, name) -end - -def install_golang_package(name) - ChefSpec::Matchers::ResourceMatcher.new(:golang_package, :install, name) -end - -def uninstall_golang_package(name) - ChefSpec::Matchers::ResourceMatcher.new(:golang_package, :uninstall, name) -end - -def put_ark(name) - ChefSpec::Matchers::ResourceMatcher.new(:ark, :put, name) -end - -def dump_ark(name) - ChefSpec::Matchers::ResourceMatcher.new(:ark, :dump, name) -end - -def install_ark(name) - ChefSpec::Matchers::ResourceMatcher.new(:ark, :install, name) -end diff --git a/spec/unit/resources/check_def_spec.rb b/spec/unit/resources/check_def_spec.rb deleted file mode 100644 index 0e037421..00000000 --- a/spec/unit/resources/check_def_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'spec_helper' -require 'chefspec/berkshelf' - -describe_resource "consul_check_def" do - describe "with id" do - let(:check_def_path) { "/etc/consul.d/check-uniqueid.json" } - - describe "create" do - let(:example_recipe) { "consul_spec::check_def_with_id_create" } - - it "removes any check previously registered by name" do - expect(chef_run).to delete_file("/etc/consul.d/check-dummy name.json") - end - - it "register the check" do - ['"name": "dummy name"', - '"id": "uniqueid"', - '"script": "curl http://localhost:8888/health"', - '"http": "http://localhost:8888/health"', - '"interval": "10s"', - '"ttl": "50s"', - '"notes": "Blahblah"'].each do |content| - expect(chef_run).to render_file(check_def_path) - .with_content(content) - end - end - end - - describe "delete" do - let(:example_recipe) { "consul_spec::check_def_with_id_delete" } - - it "de-register the check" do - expect(chef_run).to delete_file(check_def_path) - end - end - end - - describe "without id" do - let(:check_def_path) { "/etc/consul.d/check-dummy name.json" } - - describe "create" do - let(:example_recipe) { "consul_spec::check_def_without_id_create" } - - it "does not remove checks previously registered by name" do - expect(chef_run).not_to delete_file("/etc/consul.d/check-dummy name.json") - end - - it "register the check" do - ['"name": "dummy name"', '"script": "curl http://localhost:8888/health"', - '"interval": "10s"', '"ttl": "50s"', '"notes": "Blahblah"'].each do |content| - expect(chef_run).to render_file(check_def_path) - .with_content(content) - end - end - end - - describe "delete" do - let(:example_recipe) { "consul_spec::check_def_without_id_delete" } - - it "de-register the check" do - expect(chef_run).to delete_file(check_def_path) - end - end - end -end diff --git a/spec/unit/resources/event_watch_def_spec.rb b/spec/unit/resources/event_watch_def_spec.rb deleted file mode 100644 index 040cc377..00000000 --- a/spec/unit/resources/event_watch_def_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'spec_helper' -require 'chefspec/berkshelf' - -describe_resource "consul_event_watch_def" do - let(:service_def_path) { "/etc/consul.d/event-watch-dummy.json" } - - describe "create" do - let(:example_recipe) { "consul_spec::event_watch_create" } - - it "register the service" do - ['"name": "dummy"', '"type": "event"', - '"handler": "chef-client"'].each do |content| - expect(chef_run).to render_file(service_def_path) - .with_content(content) - end - end - end - - describe "delete" do - let(:example_recipe) { "consul_spec::event_watch_delete" } - - it "de-register the service" do - expect(chef_run).to delete_file(service_def_path) - expect(chef_run.file(service_def_path)) - end - end -end diff --git a/spec/unit/resources/key_watch_def_spec.rb b/spec/unit/resources/key_watch_def_spec.rb deleted file mode 100644 index c807fa0c..00000000 --- a/spec/unit/resources/key_watch_def_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'spec_helper' -require 'chefspec/berkshelf' - -describe_resource "consul_key_watch_def" do - let(:service_def_path) { "/etc/consul.d/key-watch-dummy.json" } - - describe "create" do - let(:example_recipe) { "consul_spec::key_watch_create" } - - it "register the service" do - ['"key": "/key/path"', '"type": "key"', - '"handler": "chef-client"'].each do |content| - expect(chef_run).to render_file(service_def_path) - .with_content(content) - end - end - end - - describe "delete" do - let(:example_recipe) { "consul_spec::key_watch_delete" } - - it "de-register the service" do - expect(chef_run).to delete_file(service_def_path) - expect(chef_run.file(service_def_path)) - end - end -end diff --git a/spec/unit/resources/service_def_spec.rb b/spec/unit/resources/service_def_spec.rb deleted file mode 100644 index bc139d98..00000000 --- a/spec/unit/resources/service_def_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'spec_helper' -require 'chefspec/berkshelf' - -describe_resource "consul_service_def" do - let(:service_def_path) { "/etc/consul.d/service-uniqueid.json" } - - describe "create" do - let(:example_recipe) { "consul_spec::service_def_create" } - - it "register the service" do - ['"name": "dummy"', '"port": 8888', - '"script": "curl http://localhost:8888/health"'].each do |content| - expect(chef_run).to render_file(service_def_path) - .with_content(content) - end - end - end - - describe "delete" do - let(:example_recipe) { "consul_spec::service_def_delete" } - - it "de-register the service" do - expect(chef_run).to delete_file(service_def_path) - end - end -end diff --git a/templates/default/consul-init.erb b/templates/default/consul-init.erb deleted file mode 100644 index df91e9ca..00000000 --- a/templates/default/consul-init.erb +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/bash -### BEGIN INIT INFO -# Provides: consul -# Required-Start: $network $remote_fs $syslog -# Required-Stop: $network $remote_fs $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Consul Service Discovery Platform -# Description: Consul is a tool for discovering and configuring services -# in your infrastructure. It provides several key features: -# * Service Discovery -# * Health Checking -# * Key/Valuye Store -# * Multi Datacenter -### END INIT INFO - -if [ -f <%= node['consul']['etc_config_dir'] %> ]; then -. <%= node['consul']['etc_config_dir'] %> -fi - -export GOMAXPROCS=${GOMAXPROCS} - -CMD="<%= Chef::Consul.active_binary(node) %> agent -config-dir <%= node['consul']['config_dir'] %>" -NAME="consul" - -PIDFILE="/var/run/$NAME.pid" -LOGFILE="<%= @consul_logfile %>" - -get_pid() { - cat "$PIDFILE" -} - -is_running() { - [ -f "$PIDFILE" ] && ps `get_pid` > /dev/null 2>&1 -} - -case "$1" in - start) - if is_running; then - echo "$NAME already running" - else - echo "Starting $NAME" - exec 2> >(while IFS= read -r line; do logger -t consul "$line"; done) - ${CMD[@]} >> "$LOGFILE" & - echo $! > "$PIDFILE" - if ! is_running; then - echo "Unable to start $NAME, see $LOGFILE" - exit 1 - fi - fi - ;; - stop) - if is_running; then - echo -n "Stopping $NAME..." - kill -INT `get_pid` - for i in 1 2 3 4 5 6 7 8 9 10 - do - if ! is_running; then - break - fi - - echo -n "." - sleep 1 - done - echo - - if is_running; then - kill -9 `get_pid` - fi - - if is_running; then - echo "$NAME not stopped; may still be shutting down or shutdown may have failed" - exit 1 - else - echo "$NAME stopped" - if [ -f "$PIDFILE" ]; then - rm "$PIDFILE" - fi - fi - else - echo "$NAME not running" - fi - ;; - restart) - $0 stop - if is_running; then - echo "Unable to stop $NAME, will not attempt to start" - exit 1 - fi - $0 start - ;; - status) - if is_running; then - echo "$NAME is running" - else - echo "$NAME is stopped" - exit 1 - fi - ;; - reload) - if is_running; then - echo -n "Reloading $NAME..." - kill -HUP `get_pid` - sleep 1 - echo - - if ! is_running; then - echo "$NAME has died, see $LOGFILE" - exit 1 - fi - else - echo "$NAME not running" - fi - ;; - *) - echo "Usage: $0 {start|stop|restart|reload|status}" - exit 1 - ;; -esac - -exit 0 diff --git a/templates/default/consul-sysconfig.erb b/templates/default/consul-sysconfig.erb deleted file mode 100644 index 1c8c50c9..00000000 --- a/templates/default/consul-sysconfig.erb +++ /dev/null @@ -1 +0,0 @@ -GOMAXPROCS=<%= [node['cpu']['total'], 2].max %> diff --git a/templates/default/consul-systemd.erb b/templates/default/consul-systemd.erb deleted file mode 100644 index a591784a..00000000 --- a/templates/default/consul-systemd.erb +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=Consul Agent -Wants=basic.target -After=basic.target network.target - -[Service] -User=<%= node['consul']['service_user'] %> -Group=<%= node['consul']['service_group'] %> -ExecStart=<%= Chef::Consul.active_binary(node) %> agent \ - -config-dir <%= node['consul']['config_dir'] %> -ExecReload=/bin/kill -HUP $MAINPID -KillMode=process -Restart=on-failure -RestartSec=42s - -[Install] -WantedBy=multi-user.target diff --git a/templates/default/consul.conf.erb b/templates/default/consul.conf.erb deleted file mode 100644 index cb42a3f2..00000000 --- a/templates/default/consul.conf.erb +++ /dev/null @@ -1,23 +0,0 @@ -description "Consul Service Discovery Platform" - -emits consul-up - -start on runlevel [2345] -stop on runlevel [!2345] - -script - if [ -f <%= node['consul']['etc_config_dir'] %> ]; then - . <%= node['consul']['etc_config_dir'] %> - fi - export GOMAXPROCS=${GOMAXPROCS} - CMD="<%= Chef::Consul.active_binary(node) %> agent -config-dir <%= node['consul']['config_dir'] %>" - LOGFILE="<%= @consul_logfile %>" - exec $CMD >> "$LOGFILE" -end script - -post-start exec initctl emit consul-up - -kill signal INT - -respawn -respawn limit 10 10 diff --git a/templates/default/sv-consul-log-run.erb b/templates/default/sv-consul-log-run.erb deleted file mode 100644 index 42cd1197..00000000 --- a/templates/default/sv-consul-log-run.erb +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -exec chpst -u '<%= node[:consul][:service_user] %>':'<%= node[:consul][:service_group] %>' \ - svlogd \ - /var/log/consul \ -# # diff --git a/templates/default/sv-consul-run.erb b/templates/default/sv-consul-run.erb deleted file mode 100644 index eda48517..00000000 --- a/templates/default/sv-consul-run.erb +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -export GOMAXPROCS=<%= [node['cpu']['total'], 2].max %> - -exec 2>&1 -exec <%= node['runit']['chpst_bin'] %> \ - -u <%= node['consul']['service_user'] %>:<%= node['consul']['service_group'] %> \ - <%= Chef::Consul.active_binary(node) %> agent -config-dir <%= node['consul']['config_dir'] %> diff --git a/test/integration/default/serverspec/localhost/consul_spec.rb b/test/integration/default/serverspec/localhost/default_spec.rb similarity index 100% rename from test/integration/default/serverspec/localhost/consul_spec.rb rename to test/integration/default/serverspec/localhost/default_spec.rb diff --git a/test/integration/default/serverspec/spec_helper.rb b/test/integration/default/serverspec/spec_helper.rb deleted file mode 100644 index f94e0e67..00000000 --- a/test/integration/default/serverspec/spec_helper.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'serverspec' - -RSpec.configure do |c| - c.path = '/usr/local/bin:/sbin:/bin:/usr/bin' -end diff --git a/test/integration/helpers/serverspec/spec_helper.rb b/test/integration/helpers/serverspec/spec_helper.rb new file mode 100644 index 00000000..37af1b45 --- /dev/null +++ b/test/integration/helpers/serverspec/spec_helper.rb @@ -0,0 +1,3 @@ +require 'serverspec' + +set :backend, :exec diff --git a/test/integration/ui/serverspec/localhost/consul_spec.rb b/test/integration/ui/serverspec/localhost/default_spec.rb similarity index 100% rename from test/integration/ui/serverspec/localhost/consul_spec.rb rename to test/integration/ui/serverspec/localhost/default_spec.rb diff --git a/test/integration/ui/serverspec/spec_helper.rb b/test/integration/ui/serverspec/spec_helper.rb deleted file mode 100644 index 1f1bebea..00000000 --- a/test/integration/ui/serverspec/spec_helper.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'serverspec' - -set :backend, :exec -set :path, '$PATH:/usr/local/bin:/sbin:/bin:/usr/bin' diff --git a/test/spec/libraries/consul_config_spec.rb b/test/spec/libraries/consul_config_spec.rb new file mode 100644 index 00000000..6eed3536 --- /dev/null +++ b/test/spec/libraries/consul_config_spec.rb @@ -0,0 +1,77 @@ +require 'spec_helper' + +describe_recipe 'consul::default' do + context 'with default attributes' do + cached(:chef_run) { ChefSpec::ServerRunner.new(step_into: %w{consul_config}).converge(described_recipe) } + + it { expect(chef_run).not_to include_recipe('chef-vault::default') } + it do + expect(chef_run).to create_file('/etc/consul.d/default.json') + .with(owner: 'consul') + .with(group: 'consul') + .with(mode: '0640') + end + + it 'converges successfully' do + chef_run + end + end + + context 'with verify_incoming & verify_outgoing = true' do + cached(:chef_run) do + ChefSpec::ServerRunner.new(step_into: %w{consul_config}) do |node, server| + server.create_data_bag('secrets', { + 'consul' => { + 'ca_certificate' => 'foo', + 'certificate' => 'bar', + 'private_key' => 'baz' + } + }) + + node.set['consul']['config']['verify_incoming'] = true + node.set['consul']['config']['verify_outgoing'] = true + end.converge(described_recipe) + end + + it { expect(chef_run).to include_recipe('chef-vault::default') } + it { expect(chef_run).to create_directory('/etc/ssl/certs') } + it { expect(chef_run).to create_directory('/etc/ssl/private') } + it { expect(chef_run).to create_directory('/etc/ssl/CA') } + + it do + expect(chef_run).to create_file('/etc/consul.d/default.json') + .with(owner: 'consul') + .with(group: 'consul') + .with(mode: '0640') + end + + it do + expect(chef_run).to create_file('/etc/ssl/CA/consul.crt') + .with(content: 'foo') + .with(owner: 'consul') + .with(group: 'consul') + .with(mode: '0644') + end + + it do + expect(chef_run).to create_file('/etc/ssl/certs/consul.crt') + .with(content: 'bar') + .with(owner: 'consul') + .with(group: 'consul') + .with(mode: '0644') + end + + it do + expect(chef_run).to create_file('/etc/ssl/private/consul.key') + .with(content: 'baz') + .with(sensitive: true) + .with(owner: 'consul') + .with(group: 'consul') + .with(mode: '0640') + end + + it 'converges successfully' do + chef_run + end + end +end diff --git a/test/spec/libraries/consul_service_spec.rb b/test/spec/libraries/consul_service_spec.rb new file mode 100644 index 00000000..11141048 --- /dev/null +++ b/test/spec/libraries/consul_service_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe_recipe 'consul::default' do + context 'with default attributes' do + cached(:chef_run) do + ChefSpec::ServerRunner.new(step_into: %w{consul_service}) do |node, server| + server.create_data_bag('secrets', { + 'consul' => { + 'ca_certificate' => 'foo', + 'certificate' => 'bar', + 'private_key' => 'baz' + } + }) + end.converge(described_recipe) + end + + it { expect(chef_run).to create_libartifact_file('consul-0.5.2') } + it { expect(chef_run).to create_link('/usr/local/bin/consul').with(to: '/srv/consul/0.5.2/consul') } + + it 'converges successfully' do + chef_run + end + end + + context "with node['consul']['service']['install_method'] = :source" do + cached(:chef_run) do + ChefSpec::ServerRunner.new(step_into: %w{consul_service}) do |node, server| + server.create_data_bag('secrets', { + 'consul' => { + 'ca_certificate' => 'foo', + 'certificate' => 'bar', + 'private_key' => 'baz' + } + }) + + node.set['consul']['service']['install_method'] = :source + server.update_node(node) + end.converge(described_recipe) + end + + it { expect(chef_run).to include_recipe('golang::default') } + it { expect(chef_run).to create_directory('/srv/consul/src') } + it { expect(chef_run).to checkout_git('/srv/consul/src/consul-0.5.2') } + it { expect(chef_run).to create_link('/usr/local/bin/consul').with(to: '/srv/consul/0.5.2/consul') } + + it 'converges successfully' do + chef_run + end + end + + context "with node['consul']['service']['install_method'] = :package" do + cached(:chef_run) do + ChefSpec::ServerRunner.new(step_into: %w{consul_service}) do |node, server| + server.create_data_bag('secrets', { + 'consul' => { + 'ca_certificate' => 'foo', + 'certificate' => 'bar', + 'private_key' => 'baz' + } + }) + + node.set['consul']['service']['install_method'] = :package + server.update_node(node) + end.converge(described_recipe) + end + + it { expect(chef_run).to install_package('consul') } + + it 'converges successfully' do + chef_run + end + end +end diff --git a/test/spec/recipes/default_recipe.rb b/test/spec/recipes/default_recipe.rb new file mode 100644 index 00000000..19510f6e --- /dev/null +++ b/test/spec/recipes/default_recipe.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe_recipe 'consul::default' do + cached(:chef_run) { ChefSpec::SoloRunner.converge(described_recipe) } + + context 'with default attributes' do + it { expect(chef_run).to include_recipe('selinux::permissive') } + it { expect(chef_run).to create_poise_service_user('consul').with(group: 'consul') } + it { expect(chef_run).to create_consul_config('/etc/consul.json') } + it { expect(chef_run).to enable_consul_service('consul').with(config_file: '/etc/consul.json') } + + it 'converges successfully' do + chef_run + end + end +end diff --git a/test/spec/spec_helper.rb b/test/spec/spec_helper.rb new file mode 100644 index 00000000..12d3ff8e --- /dev/null +++ b/test/spec/spec_helper.rb @@ -0,0 +1,40 @@ +require 'chefspec' +require 'chefspec/berkshelf' +require 'chefspec/cacher' +require 'chef-vault' + +RSpec.configure do |config| + config.platform = 'ubuntu' + config.version = '14.04' + + config.color = true + config.alias_example_group_to :describe_recipe, type: :recipe + + config.filter_run :focus + config.run_all_when_everything_filtered = true + + Kernel.srand config.seed + config.order = :random + + if config.files_to_run.one? + config.default_formatter = 'doc' + end + + config.expect_with :rspec do |expectations| + expectations.syntax = :expect + end + + config.mock_with :rspec do |mocks| + mocks.syntax = :expect + mocks.verify_partial_doubles = true + end +end + +at_exit { ChefSpec::Coverage.report! } + +RSpec.shared_context 'recipe tests', type: :recipe do + before do + stub_command("test -L /usr/local/bin/consul").and_return(true) + stub_command("/usr/local/go/bin/go version | grep \"go1.4 \"").and_return(true) + end +end