From 04d010a54a67de92c41d39b77f2f9519c7a0614f Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 31 Dec 2014 15:40:42 -0600 Subject: [PATCH] Introduce user provider and resource - Fixes #269, adds an `elasticsearch_user` resource with provider that creates a user, group, and removes the automatic homedir - Pins chef to 11.16.4 since chef 12 and many libraries like poise aren't compatible yet, explicit depends on rspec - Adds a unit test with chefspec matcher under `libraries/matchers.rb` for testing chef resources were created with correct data and actions - Adds an `elasticsearch_test` kitchenCI suite that tests edge cases, so the default test suite can test the expected way people use the cookbook - Tweak rubocop rules to avoid style complaints about methods that are too complex (controversial rule) and compact class styles (also controversial at the moment) - Updated `README.md` with an example of how to use the `elasticsearch_user` resource --- .kitchen.yml | 7 +- .rubocop.yml | 8 +++ Gemfile | 2 + README.md | 30 +++++++- libraries/matchers.rb | 9 +++ libraries/user.rb | 70 +++++++++++++++++++ metadata.rb | 1 + recipes/default.rb | 7 +- .../cookbooks/elasticsearch_test/metadata.rb | 1 + .../elasticsearch_test/recipes/default.rb | 4 +- .../elasticsearch_test/recipes/user.rb | 15 ++++ .../default/serverspec/default_spec.rb | 8 --- .../default/serverspec/user_spec.rb | 11 +++ .../serverspec/spec_helper.rb | 5 ++ .../serverspec/user_spec.rb | 23 ++++++ test/unit/spec/default_spec.rb | 17 +---- 16 files changed, 185 insertions(+), 33 deletions(-) create mode 100644 libraries/matchers.rb create mode 100644 libraries/user.rb create mode 100644 test/fixtures/cookbooks/elasticsearch_test/recipes/user.rb delete mode 100644 test/integration/default/serverspec/default_spec.rb create mode 100644 test/integration/default/serverspec/user_spec.rb create mode 100644 test/integration/elasticsearch_test/serverspec/spec_helper.rb create mode 100644 test/integration/elasticsearch_test/serverspec/user_spec.rb diff --git a/.kitchen.yml b/.kitchen.yml index 0eabad95d..fcd92962d 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -9,7 +9,7 @@ driver: name: vagrant # provide a default test-kitchen driver, vagrant driver_config: - require_chef_omnibus: latest + require_chef_omnibus: 11.16.4 provisioner: name: chef_zero @@ -39,3 +39,8 @@ suites: run_list: recipe[elasticsearch] attributes: foo: 'bar' + + - name: elasticsearch_test + run_list: recipe[elasticsearch_test] + attributes: + foo: 'bar' diff --git a/.rubocop.yml b/.rubocop.yml index a6994e70e..5da8d98ee 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,13 @@ # Rubocop, we're buddies and all, but we're going to have to disagree on the following - +# Allow compact class definitions +Style/ClassAndModuleChildren: + Enabled: false + +# Allow more complex ruby methods +Metrics/AbcSize: + Max: 50 + # Disable requirement of "encoding" headers on files Encoding: Enabled: false diff --git a/Gemfile b/Gemfile index 59d46c995..90e3ec80f 100644 --- a/Gemfile +++ b/Gemfile @@ -7,8 +7,10 @@ end group :unit do gem 'berkshelf', '~> 3' + gem 'chef', '>= 11.16' gem 'chefspec' gem 'chef-sugar' + gem 'rspec' end group :kitchen_common do diff --git a/README.md b/README.md index a660f865b..405340ef2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,34 @@ # Elasticsearch Chef Cookbook -This branch contains the next version of the cookbook. +This branch contains the next version of the cookbook. This cookbook has been +converted into a library cookbook. + +## Recipes + +### default + +The default recipe creates an elasticsearch user and group with the default +options. + +## Resources + +### elasticsearch_user + +Creates a user and group on the system for use by elasticsearch. Here is an +example with many of the default options and default values (all options except +a resource name may be omitted): + +```ruby +elasticsearch_user 'elasticsearch' do + username 'elasticsearch' + groupname 'elasticsearch' + homedir '/usr/local/elasticsearch' + shell '/bin/bash' + comment 'Elasticsearch User' + + action :create +end +``` ## Testing diff --git a/libraries/matchers.rb b/libraries/matchers.rb new file mode 100644 index 000000000..738b199e0 --- /dev/null +++ b/libraries/matchers.rb @@ -0,0 +1,9 @@ +# encoding: UTF-8 +if defined?(ChefSpec) + def create_elasticsearch_user(resource_name) + ChefSpec::Matchers::ResourceMatcher.new( + :elasticsearch_user, + :create, + resource_name) + end +end diff --git a/libraries/user.rb b/libraries/user.rb new file mode 100644 index 000000000..43f87f757 --- /dev/null +++ b/libraries/user.rb @@ -0,0 +1,70 @@ +class Chef + # Chef Resource for declaring a user and group for Elasticsearch + class Resource::ElasticsearchUser < Resource + include Poise + + actions(:create, :remove) + + attribute(:username, kind_of: String, default: lazy { name }) # default to resource name + attribute(:uid, kind_of: Integer) + attribute(:shell, kind_of: String, default: '/bin/bash') + attribute(:comment, kind_of: String, default: 'Elasticsearch User') + + attribute(:homedir_name, kind_of: String, default: lazy { username }) # default to username + attribute(:homedir_parent, kind_of: String, default: '/usr/local') # windows requires override + attribute(:homedir, kind_of: String, default: lazy { ::File.join(homedir_parent, homedir_name) }) # combination of next two + + attribute(:groupname, kind_of: String, default: lazy { username }) # default to username + attribute(:gid, kind_of: Integer) + end + + # Chef Provider for creating a user and group for Elasticsearch + class Provider::ElasticsearchUser < Provider + include Poise + + def action_create + converge_by("create elasticsearch_user resource #{new_resource.name}") do + notifying_block do + group new_resource.groupname do + gid new_resource.gid + action :create + system true + end + + user new_resource.username do + comment new_resource.comment + home new_resource.homedir + shell new_resource.shell + uid new_resource.uid + gid new_resource.groupname + supports manage_home: false + action :create + system true + end + + bash 'remove the elasticsearch user home' do + user 'root' + code "rm -rf #{new_resource.homedir}" + not_if { ::File.symlink?("#{new_resource.homedir}") } + only_if { ::File.directory?("#{new_resource.homedir}") } + end + end + end + end + + def action_remove + converge_by("remove elasticsearch_user resource #{new_resource.name}") do + notifying_block do + # delete user before deleting the group + user new_resource.username do + action :remove + end + + group new_resource.groupname do + action :remove + end + end + end + end + end +end diff --git a/metadata.rb b/metadata.rb index 442dec920..75c5ac48a 100644 --- a/metadata.rb +++ b/metadata.rb @@ -11,3 +11,4 @@ depends 'yum' depends 'chef-sugar' depends 'curl' +depends 'poise' diff --git a/recipes/default.rb b/recipes/default.rb index dfbe41dd3..84096a8c6 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -7,9 +7,4 @@ include_recipe 'chef-sugar' include_recipe 'curl' -ruby_block 'dummy_block for test coverage' do - block do - # some Ruby code - end - action :run -end +elasticsearch_user 'elasticsearch' diff --git a/test/fixtures/cookbooks/elasticsearch_test/metadata.rb b/test/fixtures/cookbooks/elasticsearch_test/metadata.rb index 5de808d22..43c80e2f1 100644 --- a/test/fixtures/cookbooks/elasticsearch_test/metadata.rb +++ b/test/fixtures/cookbooks/elasticsearch_test/metadata.rb @@ -10,3 +10,4 @@ depends 'apt' depends 'yum' depends 'chef-sugar' +depends 'elasticsearch' diff --git a/test/fixtures/cookbooks/elasticsearch_test/recipes/default.rb b/test/fixtures/cookbooks/elasticsearch_test/recipes/default.rb index 581e9f680..252871903 100644 --- a/test/fixtures/cookbooks/elasticsearch_test/recipes/default.rb +++ b/test/fixtures/cookbooks/elasticsearch_test/recipes/default.rb @@ -1,4 +1,4 @@ # this is a test fixture used to test that the elasticsearch cookbook's -# provided LWRPs and recipes can be used correctly from a wrapper +# resources, providers, and recipes can be used correctly from a wrapper -include_recipe 'chef-sugar' # placeholder while we're writing recipes still +include_recipe 'elasticsearch_test::user' diff --git a/test/fixtures/cookbooks/elasticsearch_test/recipes/user.rb b/test/fixtures/cookbooks/elasticsearch_test/recipes/user.rb new file mode 100644 index 000000000..3e0a68477 --- /dev/null +++ b/test/fixtures/cookbooks/elasticsearch_test/recipes/user.rb @@ -0,0 +1,15 @@ +# create user with all non-default overriden options +elasticsearch_user 'foo bar baz' do + groupname 'bar' + username 'foo' + uid 1111 + gid 2222 + shell '/bin/sh' + homedir '/usr/local/myhomedir' +end + +elasticsearch_user 'deleteme' + +elasticsearch_user 'deleteme' do + action :remove +end diff --git a/test/integration/default/serverspec/default_spec.rb b/test/integration/default/serverspec/default_spec.rb deleted file mode 100644 index d5ca99991..000000000 --- a/test/integration/default/serverspec/default_spec.rb +++ /dev/null @@ -1,8 +0,0 @@ -# Encoding: utf-8 - -require_relative 'spec_helper' - -describe command('which curl') do - its(:stdout) { should match(/curl/) } - its(:exit_status) { should eq 0 } -end diff --git a/test/integration/default/serverspec/user_spec.rb b/test/integration/default/serverspec/user_spec.rb new file mode 100644 index 000000000..00d1aaac3 --- /dev/null +++ b/test/integration/default/serverspec/user_spec.rb @@ -0,0 +1,11 @@ +# normal user with defaults +describe group('elasticsearch') do + it { should exist } +end + +describe user('elasticsearch') do + it { should exist } + it { should have_home_directory '/usr/local/elasticsearch' } + it { should have_login_shell '/bin/bash' } + it { should belong_to_group 'elasticsearch' } +end diff --git a/test/integration/elasticsearch_test/serverspec/spec_helper.rb b/test/integration/elasticsearch_test/serverspec/spec_helper.rb new file mode 100644 index 000000000..c4a0121b8 --- /dev/null +++ b/test/integration/elasticsearch_test/serverspec/spec_helper.rb @@ -0,0 +1,5 @@ +# Encoding: utf-8 +require 'serverspec' + +set :backend, :exec +set :path, '/sbin:/usr/local/sbin:$PATH' diff --git a/test/integration/elasticsearch_test/serverspec/user_spec.rb b/test/integration/elasticsearch_test/serverspec/user_spec.rb new file mode 100644 index 000000000..2b242db03 --- /dev/null +++ b/test/integration/elasticsearch_test/serverspec/user_spec.rb @@ -0,0 +1,23 @@ +require_relative 'spec_helper' + +# extra user to test all non-defaults +describe group('bar') do + it { should exist } + it { should have_gid(2222) } +end + +describe user('foo') do + it { should exist } + it { should have_uid(1111) } + it { should have_home_directory '/usr/local/myhomedir' } + it { should have_login_shell '/bin/sh' } + it { should belong_to_group 'bar' } +end + +describe group('deleteme') do + it { should_not exist } +end + +describe user('deleteme') do + it { should_not exist } +end diff --git a/test/unit/spec/default_spec.rb b/test/unit/spec/default_spec.rb index fb4cdfa7e..0f5e02eec 100644 --- a/test/unit/spec/default_spec.rb +++ b/test/unit/spec/default_spec.rb @@ -17,22 +17,9 @@ # any platform specific data you want available to your test can be loaded here property = load_platform_properties(platform: platform, platform_version: version) - # added as an example, but this probably isn't a great one, since we shouldn't be - # testing resources that are not created/executed by our cookbook. - it 'upgrades curl' do - - # example of using a platform specific property to override a package name - curl_package_name = property['curl_package'] || 'curl' - - # ensure package is installed (action is :upgrade) - expect(chef_run).to upgrade_package(curl_package_name) - + it 'creates elasticsearch_user' do + expect(chef_run).to create_elasticsearch_user('elasticsearch') end - - it 'creates a dummy ruby block for test coverage' do - expect(chef_run).to run_ruby_block('dummy_block for test coverage') - end - end end end