diff --git a/Gemfile b/Gemfile index 738c86c8..cc7c7ab2 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' gem 'chef-vault', '~> 2.6' gem 'poise', '~> 2.2' gem 'poise-service', '~> 1.0' -gem 'poise-boiler' +gem 'poise-boiler', '~> 1.1.6' group :lint do gem 'rubocop' diff --git a/README.md b/README.md index c4a2e3ae..35732cd6 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ watches and definitions. We write these out as a separate configuration file in the JSON file format. The provider for both of these resources are identical in functionality. -Below is an example of writing a [Consul service definition][11] for +Below is an example of writing a [Consul service definition][10] for the master instance of Redis. We pass in several parameters and tell the resource to notify the proper instance of the Consul service to reload. @@ -97,7 +97,7 @@ consul_definition 'redis' do end ``` -A [check definition][12] can easily be added as well. You simply have +A [check definition][11] can easily be added as well. You simply have to change the type and pass in the correct parameters. The definition below checks memory utilization using a script on a ten second interval. ```ruby @@ -184,5 +184,5 @@ This is optional, because consul UI can be hosted by any web server. [10]: https://consul.io/docs/agent/services.html [11]: https://consul.io/docs/agent/checks.html [12]: https://consul.io/docs/commands/exec.html -[13]: +[13]:https://en.wikipedia.org/wiki/Quorum_(distributed_computing) [14]: https://github.com/johnbellone/consul-cluster-cookbook diff --git a/attributes/default.rb b/attributes/default.rb index 151615c7..18b888b4 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -28,26 +28,39 @@ default['consul']['service']['install_method'] = 'binary' default['consul']['service']['config_dir'] = '/etc/consul' -default['consul']['service']['binary_url'] = "https://dl.bintray.com/mitchellh/consul/%{filename}.zip" # rubocop:disable Style/StringLiterals +default['consul']['service']['binary_url'] = "https://releases.hashicorp.com/consul/%{version}/consul_%{filename}.zip" # rubocop:disable Style/StringLiterals + default['consul']['service']['source_url'] = 'https://github.com/hashicorp/consul' -default['consul']['version'] = '0.5.2' +default['consul']['version'] = '0.6.0' default['consul']['checksums'] = { - '0.5.0_darwin_amd64' => '24d9758c873e9124e0ce266f118078f87ba8d8363ab16c2e59a3cd197b77e964', - '0.5.0_linux_386' => '4b6147c30596a30361d4753d409f8a1af9518f54f5ed473a4c4ac973738ac0fd', - '0.5.0_linux_amd64' => '161f2a8803e31550bd92a00e95a3a517aa949714c19d3124c46e56cfdc97b088', - '0.5.0_windows_386' => '7fd760ee8a5c2756391cacc1e924ae602b16cdad838db068e564f798383ad714', - '0.5.0_web_ui' => '0081d08be9c0b1172939e92af5a7cf9ba4f90e54fae24a353299503b24bb8be9', - - '0.5.1_darwin_amd64' => '06fef2ffc5a8ad8883213227efae5d1e0aa4192ccb772ec6086103a7a08fadf8', - '0.5.1_linux_386' => 'dad93a02c01de885daee191bcc5a05ca2bf106200da61db33694a658432d8399', - '0.5.1_linux_amd64' => '967ad75865b950698833eaf26415ba48d8a22befb5d4e8c77630ad70f251b100', - '0.5.1_windows_386' => 'bb9e1753cf793ad6f9db34bd6e18fb0fa5b0696a8a51a7f1c61484386dfe6682', - '0.5.1_web_ui' => 'ad883aa52e1c0136ab1492bbcedad1210235f26d59719fb6de3ef6464f1ff3b1', - - '0.5.2_darwin_amd64' => '87be515d7dbab760a61a359626a734f738d46ece367f68422b7dec9197d9eeea', - '0.5.2_linux_386' => '29306ce398109f954ceeea3af79878be4fb0d949f8af3a27c95ccef2101e8f60', - '0.5.2_linux_amd64' => '171cf4074bfca3b1e46112105738985783f19c47f4408377241b868affa9d445', - '0.5.2_windows_386' => '2e866812de16f1a6138a0fd1eebc76143f1314826e3b52597a55ac510ae94be6', - '0.5.2_web_ui' => 'ad883aa52e1c0136ab1492bbcedad1210235f26d59719fb6de3ef6464f1ff3b1' + '0.5.0_darwin_amd64' => '24d9758c873e9124e0ce266f118078f87ba8d8363ab16c2e59a3cd197b77e964', + '0.5.0_linux_386' => '4b6147c30596a30361d4753d409f8a1af9518f54f5ed473a4c4ac973738ac0fd', + '0.5.0_linux_amd64' => '161f2a8803e31550bd92a00e95a3a517aa949714c19d3124c46e56cfdc97b088', + '0.5.0_windows_386' => '7fd760ee8a5c2756391cacc1e924ae602b16cdad838db068e564f798383ad714', + '0.5.0_web_ui' => '0081d08be9c0b1172939e92af5a7cf9ba4f90e54fae24a353299503b24bb8be9', + + '0.5.1_darwin_amd64' => '06fef2ffc5a8ad8883213227efae5d1e0aa4192ccb772ec6086103a7a08fadf8', + '0.5.1_linux_386' => 'dad93a02c01de885daee191bcc5a05ca2bf106200da61db33694a658432d8399', + '0.5.1_linux_amd64' => '967ad75865b950698833eaf26415ba48d8a22befb5d4e8c77630ad70f251b100', + '0.5.1_windows_386' => 'bb9e1753cf793ad6f9db34bd6e18fb0fa5b0696a8a51a7f1c61484386dfe6682', + '0.5.1_web_ui' => 'ad883aa52e1c0136ab1492bbcedad1210235f26d59719fb6de3ef6464f1ff3b1', + + '0.5.2_darwin_amd64' => '87be515d7dbab760a61a359626a734f738d46ece367f68422b7dec9197d9eeea', + '0.5.2_linux_386' => '29306ce398109f954ceeea3af79878be4fb0d949f8af3a27c95ccef2101e8f60', + '0.5.2_linux_amd64' => '171cf4074bfca3b1e46112105738985783f19c47f4408377241b868affa9d445', + '0.5.2_windows_386' => '2e866812de16f1a6138a0fd1eebc76143f1314826e3b52597a55ac510ae94be6', + '0.5.2_web_ui' => 'ad883aa52e1c0136ab1492bbcedad1210235f26d59719fb6de3ef6464f1ff3b1', + + '0.6.0_darwin_386' => '95d57bfcc287bc344ec3ae8372cf735651af1158c5b1345e6f30cd9a9c811815', + '0.6.0_darwin_amd64' => '29ddff01368458048731afa586cec5426c8033a914b43fc83d6442e0a522c114', + '0.6.0_freebsd_386' => 'c5eb9f5c211612148e1e1cd101670fd08fd1abf9b2e541ac2936ab9637626249', + '0.6.0_freebsd_amd64' => 'd7be5c95b971f48ccbd2c53c342dced9a3d0a5bc58f57b4f2e75672d96929923', + '0.6.0_freebsd_arm' => '92f29ad00f8f44d3be43b3b038a904c332757eb2a6848a7d6754583c2791e18b', + '0.6.0_linux_386' => 'f58f3f03a8b48d89bb8be94a6d1767393ad2a410c920b064066e01c7fa24f06c', + '0.6.0_linux_amd64' => '307fa26ae32cb8732aed2b3320ed8daf02c28b50d952cbaae8faf67c79f78847', + '0.6.0_linux_arm' => '425e7332789deb446a486ac25f7143aba5f16453ac46ede39b71ab6a361d8726', + '0.6.0_windows_386' => '8379afd07668933c120880bba8228277e380abb14e07a6c45b94562ac19b37bd', + '0.6.0_windows_amd64' => '182beea0d8d346a9bfd70679621a5542aeeeea1f35be81fa3d3aeec2479bac3d', + '0.6.0_web_ui' => '73c5e7ee50bb4a2efe56331d330e6d7dbf46335599c028344ccc4031c0c32eb0' } diff --git a/libraries/consul_config.rb b/libraries/consul_config.rb index e3a5296b..d142eb39 100644 --- a/libraries/consul_config.rb +++ b/libraries/consul_config.rb @@ -76,6 +76,7 @@ class ConsulConfig < Chef::Resource attribute(:recursors, kind_of: Array) attribute(:retry_interval, kind_of: Integer) attribute(:retry_join, kind_of: Array) + attribute(:rejoin_after_leave, equal_to: [true, false], default: true) 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) @@ -93,7 +94,7 @@ class ConsulConfig < Chef::Resource # 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 advertise_addr_wan bind_addr bootstrap bootstrap_expect 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 leave_on_terminate log_level node_name ports protocol recursor recursors retry_interval retry_join server server_name skip_leave_on_interrupt start_join statsd_addr statsite_addr syslog_facility ui_dir verify_incoming verify_outgoing verify_server_hostname watches} + for_keeps = %i{acl_datacenter acl_default_policy acl_down_policy acl_master_token acl_token acl_ttl addresses advertise_addr advertise_addr_wan bind_addr bootstrap bootstrap_expect 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 leave_on_terminate log_level node_name ports protocol recursor recursors retry_interval retry_join rejoin_after_leave server server_name skip_leave_on_interrupt start_join start_join_wan statsd_addr statsite_addr syslog_facility ui_dir verify_incoming verify_outgoing verify_server_hostname watches} for_keeps << %i{ca_file cert_file key_file} if tls? for_keeps = for_keeps.flatten diff --git a/libraries/consul_service.rb b/libraries/consul_service.rb index 94b9e558..4b97aea6 100644 --- a/libraries/consul_service.rb +++ b/libraries/consul_service.rb @@ -113,7 +113,7 @@ def action_enable 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_url new_resource.binary_url % { version: new_resource.version, filename: new_resource.binary_filename } remote_checksum new_resource.binary_checksum end diff --git a/libraries/consul_ui.rb b/libraries/consul_ui.rb index 6b347695..3e24b7ec 100644 --- a/libraries/consul_ui.rb +++ b/libraries/consul_ui.rb @@ -26,7 +26,7 @@ class ConsulUI < Chef::Resource # @!attribute binary_url # @return [String] - attribute(:binary_url, kind_of: String, default: 'https://dl.bintray.com/mitchellh/consul/%{filename}.zip') + attribute(:binary_url, kind_of: String, default: 'https://releases.hashicorp.com/consul/%{version}/%{filename}.zip') # @!attribute source_url # @return [String] @@ -60,7 +60,7 @@ def action_install owner new_resource.owner group new_resource.group install_path new_resource.install_path - remote_url new_resource.binary_url % { filename: new_resource.binary_filename } + remote_url new_resource.binary_url % { version: new_resource.version, filename: new_resource.binary_filename } remote_checksum new_resource.binary_checksum end end diff --git a/recipes/default.rb b/recipes/default.rb index 6c5f5914..158327d9 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -4,7 +4,11 @@ # # Copyright 2014, 2015 Bloomberg Finance L.P. # -include_recipe 'selinux::disabled' if node['os'] == 'linux' + +if node['os'] == 'linux' + node.default['selinux']['state'] = 'permissive' + include_recipe 'selinux::default' +end if node['firewall']['allow_consul'] include_recipe 'firewall::default' diff --git a/test/spec/libraries/consul_ui_spec.rb b/test/spec/libraries/consul_ui_spec.rb index 0b765be6..4696ea80 100644 --- a/test/spec/libraries/consul_ui_spec.rb +++ b/test/spec/libraries/consul_ui_spec.rb @@ -9,7 +9,7 @@ it do is_expected.to create_libartifact_file('myconsul-ui-0.5.1') .with(owner: 'myconsul',group: 'myconsul', - remote_url: "https://dl.bintray.com/mitchellh/consul/0.5.1_web_ui.zip", + remote_url: "https://releases.hashicorp.com/consul/0.5.1/0.5.1_web_ui.zip", install_path: '/opt') end end diff --git a/test/spec/recipes/default_spec.rb b/test/spec/recipes/default_spec.rb new file mode 100644 index 00000000..12f0c5be --- /dev/null +++ b/test/spec/recipes/default_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +describe 'consul::default' do + context 'When all attributes are default, on an unspecified platform' do + let(:chef_run) do + ChefSpec::SoloRunner.new.converge(described_recipe) + end + + it 'converges successfully' do + chef_run # This should not raise an error + end + end + + context 'When selinux is set to be permissive, on a RHEL distribution' do + let(:chef_run) do + ChefSpec::SoloRunner.new do |node, server| + node.automatic['os'] = 'linux' + node.automatic['platform_family'] = 'rhel' + node.set['selinux']['state'] = 'permissive' + end.converge(described_recipe) + end + + it 'selinux_state action is permissive' do + expect(chef_run).to permissive_selinux_state('SELinux Permissive') + end + end + + context 'When selinux is set to be disabled, on a RHEL distribution' do + let(:chef_run) do + ChefSpec::SoloRunner.new do |node, server| + node.automatic['os'] = 'linux' + node.automatic['platform_family'] = 'rhel' + node.set['selinux']['state'] = 'disabled' + end.converge(described_recipe) + end + + it 'selinux_state action is disabled' do + expect(chef_run).to disabled_selinux_state('SELinux Disabled') + end + end + + context 'When selinux is set to be enforcing, on a RHEL distribution' do + let(:chef_run) do + ChefSpec::SoloRunner.new do |node, server| + node.automatic['os'] = 'linux' + node.automatic['platform_family'] = 'rhel' + node.set['selinux']['state'] = 'enforcing' + end.converge(described_recipe) + end + + it 'selinux_state action is enforcing' do + expect(chef_run).to enforcing_selinux_state('SELinux Enforcing') + end + end +end diff --git a/test/spec/spec_helper.rb b/test/spec/spec_helper.rb index 92092e0f..a03b087e 100644 --- a/test/spec/spec_helper.rb +++ b/test/spec/spec_helper.rb @@ -1,3 +1,4 @@ require 'chefspec' require 'chefspec/berkshelf' require 'poise_boiler/spec_helper' +require_relative('support/chefspec_extensions/automatic_resource_matcher') diff --git a/test/spec/support/chefspec_extensions/automatic_resource_matcher.rb b/test/spec/support/chefspec_extensions/automatic_resource_matcher.rb new file mode 100644 index 00000000..788af65d --- /dev/null +++ b/test/spec/support/chefspec_extensions/automatic_resource_matcher.rb @@ -0,0 +1,77 @@ +# Modified for styling +module ChefSpec + # https://github.com/lynx44/chefspec_extensions + module AutomaticResourceMatcher + def method_missing(meth, *args, &block) + method_name = meth.to_s + if resource_matcher_candidate?(method_name, args) + cookbook_candidates = get_cookbook_candidates(method_name) + cookbook_matches = find_cookbooks_with_matching_resources(cookbook_candidates, method_name) + if cookbook_matches.length == 1 + cookbook = cookbook_matches.first + return create_matcher(args, cookbook[:name], method_name) + end + end + super + end + + private + + def resource_matcher_candidate?(method_name, args) + method_name.count('_') >= 1 && args.length == 1 + end + + def cookbooks + @@cookbooks ||= + cookbook_paths + .map { |cookbook_path| Dir.glob("#{cookbook_path}/*") } + .flatten + .select { |c| File.directory? c } + .map { |c| { name: Pathname.new(c).basename.to_s, path: c } } + .flatten + end + + def cookbook_paths + Chef::Config[:cookbook_path].is_a?(Array) ? Chef::Config[:cookbook_path] : [Chef::Config[:cookbook_path]] + end + + def get_cookbook_candidates(method_name) + cookbooks.select { |c| method_name.include? c[:name] } + end + + def parse_lwrp(cookbook, method_name) + if (method_name.count('_') == 1) + method_name = "#{method_name}_default" + end + + parts = method_name.split("_#{cookbook}_") + { action: parts[0], cookbook: cookbook, resource_name: parts[1] } + end + + def find_cookbooks_with_matching_resources(cookbook_candidates, method_name) + cookbook_matches = [] + cookbook_candidates.each do |cookbook| + resource_parts = parse_lwrp(cookbook[:name], method_name) + cookbook_matches.push(cookbook) if cookbook_has_resource?(cookbook, resource_parts[:resource_name]) + end + cookbook_matches + end + + def cookbook_has_resource?(cookbook, resource_name) + Dir.glob("#{cookbook[:path]}/resources/#{resource_name}.rb").length == 1 + end + + def create_matcher(args, cookbook, method_name) + resource_definition = parse_lwrp(cookbook, method_name) + resource_name = "#{cookbook}_#{resource_definition[:resource_name]}" + if (resource_definition[:resource_name] == 'default') + resource_name = cookbook + end + ChefSpec::Matchers::ResourceMatcher.new(resource_name.to_sym, resource_definition[:action].to_sym, args[0]) + end + end +end + +RSpec.configure do |c| + c.include ChefSpec::AutomaticResourceMatcher +end