From c97959697a49ec58838ec1b8abc7a95d2b01240c Mon Sep 17 00:00:00 2001 From: "Dang H. Nguyen" Date: Sun, 18 Oct 2020 15:13:09 -0700 Subject: [PATCH] - Fixes Issue [#185](https://github.com/chef-cookbooks/chef-splunk/issues/185) * a startup issue was resolved for SplunkForwarder installations with an improved systemd unit file (fix below) * Adds Inspec tests to verify from SplunkForwarder starts (thanks, @jjm) - Fixes Issue [#187](https://github.com/chef-cookbooks/chef-splunk/issues/187) * the systemd unit file is now relegated to the `splunk enable boot-start` command to manage - Adds Inspec tests and sets the verifier in Test Kitchen for some test suites; some are still in serverspec - Render the user-seed.conf with a file resource rather than a template - The default recipe no longer includes the disable recipe; to disable splunk, add `recipe[chef-splunk::disabled]` to a run list explicitly - Disabling splunk will no longer uninstall Splunk Enterprise nor the Splunk Universal Forwarder - Adds `#SecretsHelper` to aid with secrets rotation and maintaining idempotency for handling Splunk's hashed secret values - Improved guards to prevent `service[splunk]` restart/start when it should be disabled. Signed-off-by: Dang H. Nguyen --- CHANGELOG.md | 14 ++ README.md | 8 +- attributes/default.rb | 2 + kitchen.yml | 198 +++++++++--------- libraries/helpers.rb | 49 +++-- libraries/splunk_secrets_helper.rb | 26 +++ recipes/client.rb | 12 +- recipes/default.rb | 6 - recipes/disabled.rb | 18 +- recipes/install_forwarder.rb | 3 + recipes/install_server.rb | 2 + recipes/server.rb | 4 +- recipes/service.rb | 82 +++----- recipes/setup_auth.rb | 40 ++-- recipes/setup_clustering.rb | 2 +- recipes/setup_shclustering.rb | 10 +- recipes/setup_ssl.rb | 6 +- resources/splunk_installer.rb | 109 ++++------ resources/splunk_monitor.rb | 4 +- spec/recipes/disabled_spec.rb | 26 ++- spec/recipes/install_forwarder_spec.rb | 29 ++- spec/recipes/service_spec.rb | 65 ++++-- spec/recipes/setup_auth_spec.rb | 60 +++--- spec/recipes/upgrade_spec.rb | 3 +- templates/outputs.conf.erb | 4 +- templates/splunk-init.erb | 77 ------- templates/splunk-systemd.erb | 22 -- templates/user-seed-conf.erb | 3 - .../serverspec/client_spec.rb | 33 --- .../serverspec/spec_helper.rb | 3 - .../client_lwrps/serverspec/spec_helper.rb | 3 - .../client_lwrps/serverspec/splunkapp_spec.rb | 13 -- .../inspec/client_inputs_outputs_test.rb | 102 +++++++++ test/integration/inspec/client_test.rb | 116 ++++++++++ .../inspec/custom_resources_test.rb | 26 +++ test/integration/inspec/disabled_test.rb | 22 ++ .../inspec/search_head_deployer_test.rb | 22 ++ .../inspec/server_cluster_master_test.rb | 28 +++ test/integration/inspec/server_test.rb | 84 ++++++++ test/integration/inspec/setup_auth_test.rb | 0 .../inspec/uninstall_forwarder_test.rb | 22 ++ test/integration/inspec/upgrade_test.rb | 30 +++ .../serverspec/server_spec.rb | 23 -- .../serverspec/spec_helper.rb | 3 - .../serverspec/server_spec.rb | 13 -- .../serverspec/spec_helper.rb | 3 - .../serverspec/server_spec.rb | 13 -- .../serverspec/spec_helper.rb | 3 - .../server_lwrps/serverspec/spec_helper.rb | 3 - .../server_lwrps/serverspec/splunkapp_spec.rb | 13 -- 50 files changed, 860 insertions(+), 602 deletions(-) create mode 100644 libraries/splunk_secrets_helper.rb delete mode 100755 templates/splunk-init.erb delete mode 100644 templates/splunk-systemd.erb delete mode 100644 templates/user-seed-conf.erb delete mode 100644 test/integration/client-inputs-outputs/serverspec/client_spec.rb delete mode 100644 test/integration/client-inputs-outputs/serverspec/spec_helper.rb delete mode 100644 test/integration/client_lwrps/serverspec/spec_helper.rb delete mode 100644 test/integration/client_lwrps/serverspec/splunkapp_spec.rb create mode 100644 test/integration/inspec/client_inputs_outputs_test.rb create mode 100644 test/integration/inspec/client_test.rb create mode 100644 test/integration/inspec/custom_resources_test.rb create mode 100644 test/integration/inspec/disabled_test.rb create mode 100644 test/integration/inspec/search_head_deployer_test.rb create mode 100644 test/integration/inspec/server_cluster_master_test.rb create mode 100644 test/integration/inspec/server_test.rb create mode 100644 test/integration/inspec/setup_auth_test.rb create mode 100644 test/integration/inspec/uninstall_forwarder_test.rb create mode 100644 test/integration/inspec/upgrade_test.rb delete mode 100644 test/integration/server-cluster-master/serverspec/server_spec.rb delete mode 100644 test/integration/server-cluster-master/serverspec/spec_helper.rb delete mode 100644 test/integration/server-runas-root/serverspec/server_spec.rb delete mode 100644 test/integration/server-runas-root/serverspec/spec_helper.rb delete mode 100644 test/integration/server-runas-splunk/serverspec/server_spec.rb delete mode 100644 test/integration/server-runas-splunk/serverspec/spec_helper.rb delete mode 100644 test/integration/server_lwrps/serverspec/spec_helper.rb delete mode 100644 test/integration/server_lwrps/serverspec/splunkapp_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index ffc69370..5fec4b4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ This file is used to list changes made in each version of the splunk cookbook. +## 6.4.0 (2020-10-17) +- Fixes Issue [#185](https://github.com/chef-cookbooks/chef-splunk/issues/185) + * a startup issue was resolved for SplunkForwarder installations with an improved + systemd unit file (fix below) + * Adds Inspec tests to verify from SplunkForwarder starts (thanks, @jjm) +- Fixes Issue [#187](https://github.com/chef-cookbooks/chef-splunk/issues/187) + * the systemd unit file is now relegated to the `splunk enable boot-start` command to manage +- Adds Inspec tests and sets the verifier in Test Kitchen for some test suites; some are still in serverspec +- Render the user-seed.conf with a file resource rather than a template +- The default recipe no longer includes the disable recipe; to disable splunk, add `recipe[chef-splunk::disabled]` to a run list explicitly +- Disabling splunk will no longer uninstall Splunk Enterprise nor the Splunk Universal Forwarder +- Adds `#SecretsHelper` to aid with secrets rotation and maintaining idempotency for handling Splunk's hashed secret values +- Improved guards to prevent `service[splunk]` restart/start when it should be disabled. + ## 6.3.0 (2020-10-14) - Fixes Issue [#183](https://github.com/chef-cookbooks/chef-splunk/issues/183): make upgrades idempotent - it is no longer necessary to include `chef-splunk::upgrade` to a run list; Instead, set the following: diff --git a/README.md b/README.md index c684b4e8..8603ab58 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ General attributes: * `node['splunk']['data_bag']`: Set this to the name of the data bag where your splunk auth and other secrets are stored (Default: `vault`) * `node['splunk']['disabled']`: Disable the splunk agent by setting - this to true (Default: false) + this to true (Default: false) and adding `recipe[chef-splunk::disabled]` to a node's run list * `node['splunk']['receiver_port']`: The port that the receiver (server) listens to. This is set to the Splunk Enterprise default, 9997. * `node['splunk']['mgmt_port']`: The port that splunkd service @@ -579,9 +579,6 @@ node['splunk']['inputs_conf']['ports'] = ### default -The default recipe will include the `disabled` recipe if -`node['splunk']['disabled']` is true. - It will include the `client` or `server` recipe depending on whether the `is_server` attribute is set. @@ -594,8 +591,7 @@ through a wrapper cookbook. In some cases it may be required to disable Splunk on a particular node. For example, it may be sending too much data to Splunk and exceed the local license capacity. To use the `disabled` recipe, set -the `node['splunk']['disabled']` attribute to true, and include the -recipe on the required node, or just use the `default` recipe. +the `node['splunk']['disabled']` attribute to `true`, and add `recipe[chef-splunk::disabled]` to a node's run list ### install_forwarder diff --git a/attributes/default.rb b/attributes/default.rb index eaa01e5f..41625f96 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -27,6 +27,8 @@ default['splunk']['data_bag'] = 'vault' default['splunk']['setup_auth'] = true +default['splunk']['service_name'] = 'splunk' # Splunk changes this to Splunkd or SplunkForwarder on systemd-managed servers +default['splunk']['startup_script'] = '/etc/init.d/splunk' # Splunk changes this to Splunkd or SplunkForwarder on systemd-managed servers default['splunk']['user'] = { 'username' => 'splunk', 'comment' => 'Splunk Server', diff --git a/kitchen.yml b/kitchen.yml index ac26c40f..6acd6390 100644 --- a/kitchen.yml +++ b/kitchen.yml @@ -12,8 +12,14 @@ provisioner: name: dokken deprecations_as_errors: true chef_license: accept + data_bags_path: test/fixtures/data_bags + product_name: chef + client_rb: + environment: _default + log_level: :debug attributes: - dev_mode: true + chef-vault: + databag_fallback: true splunk: accept_license: true enable_ssl: false @@ -23,114 +29,79 @@ provisioner: startwebserver: 1 web_port: 8000 -verifier: - root_path: '/opt/verifier' - platforms: - - name: debian-9 - driver: - image: dokken/debian-9 - pid_one_command: /bin/systemd - intermediate_instructions: - - RUN /usr/bin/apt-get -y update - - RUN mkdir -p /data/splunk-test - # Disable file locking check by Splunk as it fails on unsupported file systems used in some Docker hosts (e.g. on Mac) - - RUN mkdir -p /opt/splunk/etc - - RUN printf ' - SPLUNK_SERVER_NAME=Splunkd\n - SLPUNK_WEB_NAME=splunkweb\n - OPTIMISTIC_ABOUT_FILE_LOCKING=1\n' > /opt/splunk/etc/splunk-launch.conf - - name: debian-10 driver: image: dokken/debian-10 pid_one_command: /sbin/init - intermediate_instructions: - - RUN /usr/bin/apt-get -y update - - RUN mkdir -p /data/splunk-test - # Disable file locking check by Splunk as it fails on unsupported file systems used in some Docker hosts (e.g. on Mac) - - RUN mkdir -p /opt/splunk/etc - - RUN printf ' - SPLUNK_SERVER_NAME=Splunkd\n - SLPUNK_WEB_NAME=splunkweb\n - OPTIMISTIC_ABOUT_FILE_LOCKING=1\n' > /opt/splunk/etc/splunk-launch.conf - - - name: centos-7 - driver: - image: dokken/centos-7 - pid_one_command: /usr/lib/systemd/systemd - intermediate_instructions: - - RUN mkdir -p /data/splunk-test - # Disable file locking check by Splunk as it fails on unsupported file systems used in some Docker hosts (e.g. on Mac) - - RUN mkdir -p /opt/splunk/etc - - RUN printf ' - SPLUNK_SERVER_NAME=Splunkd\n - SLPUNK_WEB_NAME=splunkweb\n - OPTIMISTIC_ABOUT_FILE_LOCKING=1\n' > /opt/splunk/etc/splunk-launch.conf + # intermediate_instructions: + # - RUN /usr/bin/apt-get -y update + # - RUN mkdir -p /data/splunk-test + # # Disable file locking check by Splunk as it fails on unsupported file systems used in some Docker hosts (e.g. on Mac) + # - RUN mkdir -p /opt/splunk/etc + # - RUN printf ' + # SPLUNK_SERVER_NAME=Splunkd\n + # SLPUNK_WEB_NAME=splunkweb\n + # OPTIMISTIC_ABOUT_FILE_LOCKING=1\n' > /opt/splunk/etc/splunk-launch.conf - name: centos-8 driver: image: dokken/centos-8 pid_one_command: /usr/lib/systemd/systemd - intermediate_instructions: - - RUN mkdir -p /data/splunk-test - # Disable file locking check by Splunk as it fails on unsupported file systems used in some Docker hosts (e.g. on Mac) - - RUN mkdir -p /opt/splunk/etc - - RUN printf ' - SPLUNK_SERVER_NAME=Splunkd\n - SLPUNK_WEB_NAME=splunkweb\n - OPTIMISTIC_ABOUT_FILE_LOCKING=1\n' > /opt/splunk/etc/splunk-launch.conf + # intermediate_instructions: + # - RUN mkdir -p /data/splunk-test + # # Disable file locking check by Splunk as it fails on unsupported file systems used in some Docker hosts (e.g. on Mac) + # - RUN mkdir -p /opt/splunk/etc + # - RUN printf ' + # SPLUNK_SERVER_NAME=Splunkd\n + # SLPUNK_WEB_NAME=splunkweb\n + # OPTIMISTIC_ABOUT_FILE_LOCKING=1\n' > /opt/splunk/etc/splunk-launch.conf - name: ubuntu-20.04 driver: image: dokken/ubuntu-20.04 pid_one_command: /bin/systemd - intermediate_instructions: - - RUN /usr/bin/apt-get -y update - - RUN mkdir -p /data/splunk-test - # Disable file locking check by Splunk as it fails on unsupported file systems used in some Docker hosts (e.g. on Mac) - - RUN mkdir -p /opt/splunk/etc - - RUN printf ' - SPLUNK_SERVER_NAME=Splunkd\n - SLPUNK_WEB_NAME=splunkweb\n - OPTIMISTIC_ABOUT_FILE_LOCKING=1\n' > /opt/splunk/etc/splunk-launch.conf - - - name: ubuntu-18.04 - driver: - image: dokken/ubuntu-18.04 - pid_one_command: /bin/systemd - intermediate_instructions: - - RUN /usr/bin/apt-get -y update - - RUN mkdir -p /data/splunk-test - # Disable file locking check by Splunk as it fails on unsupported file systems used in some Docker hosts (e.g. on Mac) - - RUN mkdir -p /opt/splunk/etc - - RUN printf ' - SPLUNK_SERVER_NAME=Splunkd\n - SLPUNK_WEB_NAME=splunkweb\n - OPTIMISTIC_ABOUT_FILE_LOCKING=1\n' > /opt/splunk/etc/splunk-launch.conf + # intermediate_instructions: + # - RUN /usr/bin/apt-get -y update + # - RUN mkdir -p /data/splunk-test + # # Disable file locking check by Splunk as it fails on unsupported file systems used in some Docker hosts (e.g. on Mac) + # - RUN mkdir -p /opt/splunk/etc + # - RUN printf ' + # SPLUNK_SERVER_NAME=Splunkd\n + # SLPUNK_WEB_NAME=splunkweb\n + # OPTIMISTIC_ABOUT_FILE_LOCKING=1\n' > /opt/splunk/etc/splunk-launch.conf suites: - name: client run_list: - recipe[chef-splunk::default] attributes: - dev_mode: true splunk: accept_license: true + verifier: + name: inspec + inspec_tests: + - path: test/integration/inspec/client_test.rb - name: uninstall_forwarder run_list: - recipe[test::uninstall_forwarder] attributes: - dev_mode: true splunk: accept_license: true + verifier: + name: inspec + inspec_tests: + - path: test/integration/inspec/uninstall_forwarder_test.rb - name: client-inputs-outputs run_list: - recipe[chef-splunk::default] + verifier: + name: inspec + inspec_tests: + - path: test/integration/inspec/client_inputs_outputs_test.rb attributes: - dev_mode: true splunk: accept_license: true outputs_conf: @@ -152,33 +123,34 @@ suites: run_list: - recipe[chef-splunk::default] attributes: - dev_mode: true splunk: - server: - runasroot: true is_server: true accept_license: true + verifier: + name: inspec + inspec_tests: + - path: test/integration/inspec/server_test.rb - - name: server-runas-splunk - run_list: - - recipe[chef-splunk::default] - attributes: - dev_mode: true - splunk: - server: - runasroot: false - is_server: true - accept_license: true - web_port: 8000 + # - name: server-runas-splunk + # run_list: + # - recipe[chef-splunk::default] + # attributes: + # splunk: + # server: + # runasroot: false + # is_server: true + # accept_license: true + # web_port: 8000 + # verifier: + # name: inspec + # inspec_tests: + # - path: test/integration/inspec/server_test.rb - name: server-cluster-master run_list: - recipe[chef-splunk::default] attributes: - dev_mode: true splunk: - server: - runasroot: false is_server: true accept_license: true clustering: @@ -186,42 +158,52 @@ suites: mode: master replication_factor: 5 search_factor: 3 + verifier: + name: inspec + inspec_tests: + - path: test/integration/inspec/server_cluster_master_test.rb - name: server-shdeployer run_list: - recipe[chef-splunk] attributes: - dev_mode: true splunk: - server: - runasroot: false is_server: true accept_license: true shclustering: enabled: true mode: deployer web_port: 8000 + verifier: + root_path: /opt/verifier - name: server-shcluster-member run_list: - recipe[chef-splunk::default] attributes: - dev_mode: true splunk: - server: - runasroot: false is_server: true accept_license: true shclustering: enabled: true web_port: 8000 + verifier: + root_path: /opt/verifier - name: disabled run_list: - recipe[chef-splunk::default] + - recipe[chef-splunk::disabled] + attributes: attributes: splunk: + is_server: true + accept_license: true disabled: true + verifier: + name: inspec + inspec_tests: + - path: test/integration/inspec/disabled_test.rb - name: upgrade_server run_list: @@ -232,6 +214,10 @@ suites: upgrade_enabled: true accept_license: true is_server: true + verifier: + name: inspec + inspec_tests: + - path: test/integration/inspec/upgrade_test.rb - name: upgrade_client run_list: @@ -242,6 +228,10 @@ suites: upgrade_enabled: true accept_license: true is_server: false + verifier: + name: inspec + inspec_tests: + - path: test/integration/inspec/upgrade_test.rb - name: server_resources run_list: @@ -249,12 +239,13 @@ suites: - recipe[test::splunk_app] - recipe[test::splunk_index] attributes: - dev_mode: true splunk: - server: - runasroot: false accept_license: true is_server: true + verifier: + name: inspec + inspec_tests: + - path: test/integration/inspec/custom_resources_test.rb - name: client_resources run_list: @@ -262,9 +253,10 @@ suites: - recipe[test::splunk_app] - recipe[test::splunk_monitor] attributes: - dev_mode: true splunk: - server: - runasroot: false accept_license: true is_server: false + verifier: + name: inspec + inspec_tests: + - path: test/integration/inspec/custom_resources_test.rb diff --git a/libraries/helpers.rb b/libraries/helpers.rb index da56cd03..a32cec58 100644 --- a/libraries/helpers.rb +++ b/libraries/helpers.rb @@ -24,6 +24,30 @@ @shcluster_server_size = nil +def boot_start_cmd(disable = nil) + systemd_managed = systemd? ? 1 : 0 + + if disable.nil? && run_as_root? + "#{splunk_cmd} enable boot-start -systemd-managed #{systemd_managed} --accept-license" + elsif disable.nil? + "#{splunk_cmd} enable boot-start -user #{splunk_runas_user} -systemd-managed #{systemd_managed} --accept-license" + else + "#{splunk_cmd} disable boot-start -systemd-managed #{systemd_managed} --accept-license" + end +end + +# returns the output of splunk's HASHED_PASSWORD command +# this command produces a hash of a clear-text password that can be stored in user-seed.conf, for example +def hash_passwd(pw) + return pw if pw.match?(/^\$\d*\$/) + hash = shell_out("#{splunk_cmd} hash-passwd #{pw}") + hash.stdout.strip +end + +def license_accepted? + node['splunk']['accept_license'] == true +end + def splunk_installed? ::File.exist?(splunk_cmd) end @@ -81,12 +105,13 @@ def splunk_auth(auth) end end -# returns the output of splunk's HASHED_PASSWORD command -# this command produces a hash of a clear-text password that can be stored in user-seed.conf, for example -def hash_passwd(pw) - return pw if pw.match?(/^\$\d*\$/) - hash = shell_out("#{splunk_cmd} hash-passwd #{pw}") - hash.stdout.strip +def splunk_login_successful? + login = shell_out("/opt/splunk/bin/splunk login -auth #{node.run_state['splunk_auth_info']}") + login.stderr.strip.empty? && login.stdout.strip.empty? && login.exitstatus == 0 +end + +def run_as_root? + node['splunk']['server']['runasroot'] == true end def splunk_runas_user @@ -94,10 +119,6 @@ def splunk_runas_user node['splunk']['user']['username'] end -def run_as_root? - node['splunk']['server']['runasroot'] == true -end - def splunk_service_provider if node['init_package'] == 'systemd' Chef::Provider::Service::Systemd @@ -106,10 +127,6 @@ def splunk_service_provider end end -def license_accepted? - node['splunk']['accept_license'] == true -end - # a splunkd instance is either a splunk client (runs universal forwarder only) or a complete server def server? node['splunk']['is_server'] == true @@ -247,3 +264,7 @@ def search_heads_peered? def upgrade_enabled? node['splunk']['upgrade_enabled'] == true end + +def systemd? + node['init_package'] == 'systemd' +end diff --git a/libraries/splunk_secrets_helper.rb b/libraries/splunk_secrets_helper.rb new file mode 100644 index 00000000..15729b69 --- /dev/null +++ b/libraries/splunk_secrets_helper.rb @@ -0,0 +1,26 @@ +module SecretsHelper + require 'iniparse' + + # get either the encrypted secret value locally or descrypted value from the encrypted data bag + def splunk_secret_inspect(file, section, secret_name = 'pass4SymmKey') + key = nil + tag = "force_#{section}_#{secret_name.downcase}_rotation" + + if node.tags.include?(tag) || file.nil? + ::Chef::Log.info("secret rotation occurred for #{secret_name.downcase} in [#{section}]") + node.tags.delete(tag) + elsif ::File.exist?(file) + document = IniParse.parse(::File.read(file)) + key = document[section][secret_name] if document.has_section?(section) && document[section].has_option?(secret_name) + end + + key + end + + # encrypted splunk secrets will start with `$\d$` pattern (e.g., `$6$`) + def splunk_encrypted?(key) + !key.nil? && key.match?(/^\$\d\$/) + end +end + +Chef::Mixin::Template::TemplateContext.include ::SecretsHelper diff --git a/recipes/client.rb b/recipes/client.rb index c9d0cd6e..4337d0d5 100644 --- a/recipes/client.rb +++ b/recipes/client.rb @@ -22,7 +22,6 @@ # used on their own composed in your own wrapper cookbook or role. include_recipe 'chef-splunk::user' unless run_as_root? include_recipe 'chef-splunk::install_forwarder' unless server? -include_recipe 'chef-splunk::service' splunk_servers = search( :node, @@ -59,9 +58,10 @@ mode '644' variables( server_list: server_list, - outputs_conf: node['splunk']['outputs_conf'] + outputs_conf: node['splunk']['outputs_conf'], + conf_file: "#{splunk_dir}/etc/system/local/outputs.conf" ) - notifies :restart, 'service[splunk]' + notifies :restart, 'service[splunk]' unless disabled? owner splunk_runas_user group splunk_runas_user end @@ -72,7 +72,7 @@ group splunk_runas_user mode '644' variables inputs_conf: node['splunk']['inputs_conf'] - notifies :restart, 'service[splunk]' + notifies :restart, 'service[splunk]' unless disabled? not_if { node['splunk']['inputs_conf'].nil? || node['splunk']['inputs_conf']['host'].empty? } end @@ -85,7 +85,5 @@ } ) action :install - notifies :restart, 'service[splunk]' + notifies :restart, 'service[splunk]' unless disabled? end - -include_recipe 'chef-splunk::setup_auth' if setup_auth? diff --git a/recipes/default.rb b/recipes/default.rb index ce688cfd..d960df7c 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -17,12 +17,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -if disabled? - include_recipe 'chef-splunk::disabled' - Chef::Log.debug('Splunk is disabled on this node.') - return -end - # We can rely on loading the chef_vault_item here into the run_state so other # recipes don't have to keep going back to the chef server to access the vault/data bag item vault_item = chef_vault_item(node['splunk']['data_bag'], "splunk_#{node.chef_environment}") diff --git a/recipes/disabled.rb b/recipes/disabled.rb index c0031ff5..104e9ce2 100644 --- a/recipes/disabled.rb +++ b/recipes/disabled.rb @@ -16,6 +16,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # +return unless splunk_installed? unless disabled? log 'splunk is not disabled' do @@ -26,18 +27,9 @@ return end -service 'splunk' do - ignore_failure true - action :stop -end - -package %w(splunk splunkforwarder) do - ignore_failure true - action :remove -end +include_recipe 'chef-splunk::service' -['/etc/init.d/splunk', '/etc/systemd/system/splunk.service'].each do |f| - file f do - action :delete - end +execute 'splunk disable boot-start' do + command boot_start_cmd('disable') + notifies :stop, 'service[splunk]' end diff --git a/recipes/install_forwarder.rb b/recipes/install_forwarder.rb index db09d478..be9dfc0b 100644 --- a/recipes/install_forwarder.rb +++ b/recipes/install_forwarder.rb @@ -18,6 +18,9 @@ # include_recipe 'chef-splunk::user' +node.default['splunk']['service_name'] = 'SplunkForwarder' if systemd? +node.default['splunk']['startup_script'] = '/etc/systemd/system/SplunkForwarder.service' if systemd? + splunk_installer 'splunkforwarder' do if upgrade_enabled? action :upgrade diff --git a/recipes/install_server.rb b/recipes/install_server.rb index 4f00c323..1bfbf944 100644 --- a/recipes/install_server.rb +++ b/recipes/install_server.rb @@ -16,6 +16,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +node.default['splunk']['service_name'] = 'Splunkd' if systemd? +node.default['splunk']['startup_script'] = '/etc/systemd/system/Splunkd.service' if systemd? splunk_installer 'splunk' do if upgrade_enabled? diff --git a/recipes/server.rb b/recipes/server.rb index 70bade1d..a19f1b1f 100644 --- a/recipes/server.rb +++ b/recipes/server.rb @@ -27,7 +27,7 @@ command "#{splunk_cmd} set splunkd-port #{node['splunk']['mgmt_port']} -auth '#{node.run_state['splunk_auth_info']}'" sensitive true unless Chef::Log.debug? not_if { current_mgmt_port == node['splunk']['mgmt_port'] } - notifies :restart, 'service[splunk]' + notifies :restart, 'service[splunk]' unless disabled? end ruby_block 'enable-splunk-receiver-port' do @@ -38,7 +38,7 @@ true if splunk.stderr.include?("Configuration for port #{node['splunk']['receiver_port']} already exists") end not_if { port_open?(node['splunk']['receiver_port']) } - notifies :restart, 'service[splunk]' + notifies :restart, 'service[splunk]' unless disabled? end include_recipe 'chef-splunk::setup_ssl' if enable_ssl? diff --git a/recipes/service.rb b/recipes/service.rb index 3988d690..0792f234 100644 --- a/recipes/service.rb +++ b/recipes/service.rb @@ -47,9 +47,12 @@ end end +include_recipe 'chef-splunk::setup_auth' if setup_auth? + # If we run as splunk user do a recursive chown to that user for all splunk # files if a few specific files are root owned. ruby_block 'splunk_fix_file_ownership' do + action :run block do begin FileUtils.chown_R(splunk_runas_user, splunk_runas_user, splunk_dir) @@ -58,72 +61,43 @@ end end subscribes :run, 'service[splunk]', :before - not_if { node['splunk']['server']['runasroot'] == true } -end - -Chef::Log.info("Node init package: #{node['init_package']}") - -template '/etc/systemd/system/splunk.service' do - source 'splunk-systemd.erb' - mode '644' - variables( - splunkdir: splunk_dir, - splunkuser: splunk_runas_user, - splunkcmd: splunk_cmd, - runasroot: run_as_root?, - accept_license: license_accepted? - ) - notifies :run, 'execute[systemctl daemon-reload]', :immediately - only_if { node['init_package'] == 'systemd' } end -file '/etc/systemd/system/splunkd.service' do - action :delete - notifies :run, 'execute[systemctl daemon-reload]', :immediately +# if the splunk daemon is running as root, executing a normal service restart or stop will fail if the boot +# start script has been modified to execute splunk as a non-root user. +# So, the splunk daemon must be run this way instead +execute "#{splunk_cmd} stop" do + action :nothing + subscribes :run, 'execute[splunk enable boot-start]', :before end file '/etc/init.d/splunk' do action :delete - only_if { node['init_package'] == 'systemd' } -end - -execute 'systemctl daemon-reload' do - action :nothing - only_if { node['init_package'] == 'systemd' } + only_if { systemd? } end -file '/etc/systemd/system/splunk.service' do - action :delete - not_if { node['init_package'] == 'systemd' } - notifies :run, 'execute[systemctl daemon-reload]', :immediately +execute 'splunk enable boot-start' do + command boot_start_cmd + sensitive false + retries 3 + creates node['splunk']['startup_script'] end -template '/etc/init.d/splunk' do - source 'splunk-init.erb' - mode '700' - variables( - splunkdir: splunk_dir, - splunkuser: splunk_runas_user, - splunkcmd: splunk_cmd, - runasroot: run_as_root?, - accept_license: license_accepted? - ) - not_if { node['init_package'] == 'systemd' } - notifies :run, "execute[#{splunk_cmd} stop]", :immediately # must use this if splunk daemon is running as root and needs to switch to non-root user - notifies :restart, 'service[splunk]' -end +default_service_action = if node['splunk']['disabled'] == true + :stop + elsif node['init_package'] == 'systemd' + %i(start enable) + else + :start + end service 'splunk' do - action node['init_package'] == 'systemd' ? %i(start enable) : :start + service_name node['splunk']['service_name'] + action default_service_action supports status: true, restart: true - notifies :run, "execute[#{splunk_cmd} stop]", :before unless correct_runas_user? + status_command "#{splunk_dir}/bin/splunk status" + user splunk_runas_user if systemd? && !run_as_root? + timeout 1800 provider splunk_service_provider -end - -# if the splunk daemon is running as root, executing a normal service restart or stop will fail if the boot -# start script has been modified to execute splunk as a non-root user. -# So, the splunk daemon must be run this way instead -execute "#{splunk_cmd} stop" do - action :nothing - not_if { node['splunk']['server']['runasroot'] == true } + subscribes :restart, 'template[user-seed.conf]', :immediately unless disabled? end diff --git a/recipes/setup_auth.rb b/recipes/setup_auth.rb index e9fa974e..627f9e7a 100644 --- a/recipes/setup_auth.rb +++ b/recipes/setup_auth.rb @@ -27,29 +27,33 @@ include_recipe 'chef-splunk' -user, pw = node.run_state['splunk_auth_info'].split(':') +_user, pw = node.run_state['splunk_auth_info'].split(':') -file "#{splunk_dir}/etc/passwd" do - action :nothing -end - -template 'user-seed.conf' do - path "#{splunk_dir}/etc/system/local/user-seed.conf" - source 'user-seed-conf.erb' - owner splunk_runas_user - group splunk_runas_user - mode '600' - sensitive true unless Chef::Log.debug? - variables user: user, hashed_password: lazy { hash_passwd(pw) } - notifies :delete, "file[#{splunk_dir}/etc/passwd]", :immediately - notifies :restart, 'service[splunk]', :immediately - not_if { ::File.exist?("#{splunk_dir}/etc/system/local/.user-seed.conf") } +file 'etc/passwd' do + path "#{splunk_dir}/etc/passwd" + action :delete + not_if { splunk_login_successful? || ::File.exist?("#{splunk_dir}/etc/system/local/.user-seed.conf") } end file '.user-seed.conf' do + action :nothing path "#{splunk_dir}/etc/system/local/.user-seed.conf" - content "true\n" + subscribes :touch, 'file[user-seed.conf]', :immediately +end + +# Splunk will delete this file the first time splunk is started +# it's a secure way of automating the initial admin password when installing Splunk +file 'user-seed.conf' do + path "#{splunk_dir}/etc/system/local/user-seed.conf" + content lazy { + <<~SEED + [user_info] + USERNAME = admin + HASHED_PASSWORD = #{hash_passwd(pw)} + SEED + } owner splunk_runas_user group splunk_runas_user - mode '600' + mode '0640' + not_if { ::File.exist?("#{splunk_dir}/etc/system/local/.user-seed.conf") || splunk_login_successful? } end diff --git a/recipes/setup_clustering.rb b/recipes/setup_clustering.rb index 05d2790f..85ac053b 100644 --- a/recipes/setup_clustering.rb +++ b/recipes/setup_clustering.rb @@ -71,7 +71,7 @@ command "#{splunk_cmd} edit cluster-config #{splunk_cmd_params} -auth '#{node.run_state['splunk_auth_info']}'" sensitive true unless Chef::Log.debug? not_if { ::File.exist?("#{splunk_dir}/etc/.setup_clustering") } - notifies :restart, 'service[splunk]' + notifies :restart, 'service[splunk]' unless disabled? end file "#{splunk_dir}/etc/.setup_clustering" do diff --git a/recipes/setup_shclustering.rb b/recipes/setup_shclustering.rb index b8ca9232..119b32f2 100644 --- a/recipes/setup_shclustering.rb +++ b/recipes/setup_shclustering.rb @@ -51,7 +51,7 @@ shcluster_secret: node.run_state['splunk_secret'] ) sensitive true unless Chef::Log.debug? - notifies :restart, 'service[splunk]', :immediately + notifies :restart, 'service[splunk]', :immediately unless disabled? end end @@ -104,7 +104,7 @@ "-conf_deploy_fetch_url #{node['splunk']['shclustering']['deployer_url']} " \ "-secret #{node.run_state['splunk_secret']} " \ "-shcluster_label #{node['splunk']['shclustering']['label']}" - notifies :restart, 'service[splunk]', :immediately + notifies :restart, 'service[splunk]', :immediately unless disabled? only_if { init_shcluster_member? } end @@ -121,7 +121,7 @@ sensitive true unless Chef::Log.debug? command "#{splunk_cmd} bootstrap shcluster-captain -auth '#{node.run_state['splunk_auth_info']}' " \ "-servers_list \"#{shcluster_servers_list.join(',')}\"" - notifies :restart, 'service[splunk]', :immediately + notifies :restart, 'service[splunk]', :immediately unless disabled? end elsif ok_to_add_member? captain_mgmt_uri = "https://#{shcluster_captain}:8089" @@ -129,7 +129,7 @@ execute 'add member to search head cluster' do sensitive true unless Chef::Log.debug? command "#{splunk_cmd} add shcluster-member -current_member_uri #{captain_mgmt_uri} -auth '#{node.run_state['splunk_auth_info']}'" - notifies :restart, 'service[splunk]' + notifies :restart, 'service[splunk]' unless disabled? end end @@ -158,6 +158,6 @@ execute 'search head cluster integration with indexer cluster' do sensitive true unless Chef::Log.debug? command shpeer_integration_command - notifies :restart, 'service[splunk]' + notifies :restart, 'service[splunk]' unless disabled? not_if { search_heads_peered? } end diff --git a/recipes/setup_ssl.rb b/recipes/setup_ssl.rb index 66c6e6fa..6295fae6 100644 --- a/recipes/setup_ssl.rb +++ b/recipes/setup_ssl.rb @@ -34,7 +34,7 @@ variables ssl_options owner splunk_runas_user group splunk_runas_user - notifies :restart, 'service[splunk]' + notifies :restart, 'service[splunk]' unless disabled? end file "#{splunk_dir}/etc/auth/splunkweb/#{ssl_options['keyfile']}" do @@ -43,7 +43,7 @@ group splunk_runas_user mode '600' sensitive true unless Chef::Log.debug? - notifies :restart, 'service[splunk]' + notifies :restart, 'service[splunk]' unless disabled? end file "#{splunk_dir}/etc/auth/splunkweb/#{ssl_options['crtfile']}" do @@ -52,5 +52,5 @@ group splunk_runas_user mode '600' sensitive true unless Chef::Log.debug? - notifies :restart, 'service[splunk]' + notifies :restart, 'service[splunk]' unless disabled? end diff --git a/resources/splunk_installer.rb b/resources/splunk_installer.rb index 9d643e3f..5840a2ed 100644 --- a/resources/splunk_installer.rb +++ b/resources/splunk_installer.rb @@ -38,27 +38,13 @@ def cached_package "#{Chef::Config[:file_cache_path]}/#{package_file}" end - def local_package_resource - case node['platform_family'] - when 'rhel', 'fedora', 'suse', 'amazon' - :rpm_package - when 'debian' - :dpkg_package - end - end - - def splunk_service - # during an initial install, the start/restart commands must deal with accepting - # the license. So, we must ensure the service[splunk] resource - # properly deals with the license. - edit_resource(:service, 'splunk') do - action node['init_package'] == 'systemd' ? %i(start enable) : :start - supports status: true, restart: true - stop_command svc_command('stop') - start_command svc_command('start') - restart_command svc_command('restart') - status_command svc_command('status') - provider splunk_service_provider + def download_package + remote_file package_file do + backup false + mode '644' + path cached_package + source new_resource.url + action :create end end end @@ -66,72 +52,51 @@ def splunk_service action :run do return if splunk_installed? - splunk_service - - remote_file package_file do - backup false - mode '644' - path cached_package - source new_resource.url - use_conditional_get true - use_etag true - action :create - not_if { new_resource.url.empty? || new_resource.url.nil? } - end + download_package - declare_resource local_package_resource, new_resource.name do - package_name new_resource.package_name - if new_resource.url.empty? || new_resource.url.nil? - version package_version - else - source cached_package.gsub(/\.Z/, '') + if platform_family?('debian') + dpkg_package new_resource.name do + package_name new_resource.package_name + source cached_package + version new_resource.version unless ::File.exist?(cached_package) + notifies :start, 'service[splunk]' unless node['splunk'].attribute?('disabled') && node['splunk']['disabled'] == true + end + else + package new_resource.name do + package_name new_resource.package_name + source cached_package + version package_version unless ::File.exist?(cached_package) + notifies :start, 'service[splunk]' unless node['splunk'].attribute?('disabled') && node['splunk']['disabled'] == true end - notifies :start, 'service[splunk]' end end action :upgrade do return unless splunk_installed? - splunk_service + download_package - remote_file package_file do - backup false - mode '644' - path cached_package - source new_resource.url - use_conditional_get true - use_etag true - action :create - not_if { new_resource.url.empty? || new_resource.url.nil? } - end - - declare_resource local_package_resource, new_resource.name do - action :upgrade - package_name new_resource.package_name - if new_resource.url.empty? || new_resource.url.nil? - version package_version - else - source cached_package.gsub(/\.Z/, '') + if platform_family?('debian') + dpkg_package new_resource.name do + action :upgrade + package_name new_resource.package_name + source cached_package + version new_resource.version unless ::File.exist?(cached_package) + notifies :start, 'service[splunk]' unless node['splunk'].attribute?('disabled') && node['splunk']['disabled'] == true end - notifies :stop, 'service[splunk]', :before if splunk_installed? - # forwarders can be restarted immediately; otherwise, wait until the end - if package_file =~ /splunkforwarder/ - notifies :start, 'service[splunk]', :immediately - else - notifies :start, 'service[splunk]' + else + package new_resource.name do + action :upgrade + package_name new_resource.package_name + source cached_package + version package_version unless ::File.exist?(cached_package) + notifies :start, 'service[splunk]' unless node['splunk'].attribute?('disabled') && node['splunk']['disabled'] == true end end end action :remove do - find_resource(:service, 'splunk') do - supports status: true, restart: true - provider splunk_service_provider - action node['init_package'] == 'systemd' ? %i(stop disable) : :stop - end - - declare_resource local_package_resource, new_resource.name do + package new_resource.name do action :remove notifies :stop, 'service[splunk]', :before end diff --git a/resources/splunk_monitor.rb b/resources/splunk_monitor.rb index 78fe101f..754b6512 100644 --- a/resources/splunk_monitor.rb +++ b/resources/splunk_monitor.rb @@ -92,10 +92,10 @@ property :source, kind_of: String, default: nil property :crcSalt, kind_of: String, default: '' property :ignoreOlderThan, kind_of: String, default: nil, regex: [ /^(0|[1-9]+[dhms])$/ ] -property :followTail, default: 0, equal_to: [0, 1] +property :followTail, kind_of: Integer, default: 0, equal_to: [0, 1] property :whitelist, kind_of: String, default: nil property :blacklist, kind_of: String, default: nil -property :alwaysOpenFile, default: 0, equal_to: [0, 1] +property :alwaysOpenFile, kind_of: Integer, default: 0, equal_to: [0, 1] property :recursive, kind_of: [TrueClass, FalseClass], default: true property :time_before_close, kind_of: Integer, default: 3 property :followSymlink, kind_of: [TrueClass, FalseClass], default: true diff --git a/spec/recipes/disabled_spec.rb b/spec/recipes/disabled_spec.rb index 6b48bf47..d112f6a0 100644 --- a/spec/recipes/disabled_spec.rb +++ b/spec/recipes/disabled_spec.rb @@ -9,18 +9,13 @@ end context 'splunk is disabled' do - it 'stops the splunk service' do - expect(chef_run).to stop_service('splunk') + it 'disabled splunk boot-start' do + expect(chef_run).to run_execute('splunk disable boot-start') end - it 'uninstalls the splunk and splunkforwarder packages' do - expect(chef_run).to remove_package(%w(splunk splunkforwarder)) - end - - ['/etc/init.d/splunk', '/etc/systemd/system/splunk.service'].each do |f| - it "deletes #{f}" do - expect(chef_run).to delete_file(f) - end + it 'stopped splunk service' do + expect(chef_run).to nothing_execute('/opt/splunkforwarder/bin/splunk stop') + expect(chef_run.execute('/opt/splunkforwarder/bin/splunk stop')).to subscribe_to('execute[splunk disable boot-start]').on(:run).before end it 'does not log debug message' do @@ -50,10 +45,13 @@ end.converge(described_recipe) end - ['/etc/init.d/splunk', '/etc/systemd/system/splunk.service'].each do |f| - it "deletes #{f}" do - expect(chef_run).to delete_file(f) - end + it 'disabled splunk boot-start' do + expect(chef_run).to run_execute('splunk disable boot-start') + end + + it 'stopped splunk service' do + expect(chef_run).to nothing_execute('/opt/splunk/bin/splunk stop') + expect(chef_run.execute('/opt/splunk/bin/splunk stop')).to subscribe_to('execute[splunk disable boot-start]').on(:run).before end end end diff --git a/spec/recipes/install_forwarder_spec.rb b/spec/recipes/install_forwarder_spec.rb index a5ccaf5c..4aba9b96 100644 --- a/spec/recipes/install_forwarder_spec.rb +++ b/spec/recipes/install_forwarder_spec.rb @@ -22,26 +22,35 @@ context "#{platform} family" do let(:url) { platform_under_test[:url] } - let(:chef_run) do - ChefSpec::ServerRunner.new(platform_under_test[:runner]) do |node| - node.force_default['splunk']['forwarder']['version'] = '8.0.1' - node.force_default['splunk']['accept_license'] = true + context 'url value exists' do + let(:chef_run) do + ChefSpec::ServerRunner.new(platform_under_test[:runner]) do |node, server| + create_data_bag_item(server, 'vault', 'splunk__default') + node.force_default['splunk']['forwarder']['version'] = '8.0.1' + node.force_default['splunk']['accept_license'] = true + node.force_default['chef-vault']['databag_fallback'] = true + node.force_default['splunk']['forwarder']['url'] = url + end.converge(described_recipe) end - end - context 'url value exists' do it 'install splunk forwarder from package downloaded from URL' do - chef_run.node.force_default['splunk']['forwarder']['url'] = url - chef_run.converge(described_recipe) expect(chef_run).to run_splunk_installer('splunkforwarder') .with(url: url, package_name: 'splunkforwarder') end end context 'url attribute is empty' do + let(:chef_run) do + ChefSpec::ServerRunner.new(platform_under_test[:runner]) do |node, server| + create_data_bag_item(server, 'vault', 'splunk__default') + node.force_default['splunk']['forwarder']['version'] = '8.0.1' + node.force_default['splunk']['accept_license'] = true + node.force_default['chef-vault']['databag_fallback'] = true + node.force_default['splunk']['forwarder']['url'] = '' + end.converge(described_recipe) + end + it 'should install splunk forwarder from local repo' do - chef_run.node.force_default['splunk']['forwarder']['url'] = '' - chef_run.converge(described_recipe) expect(chef_run).to run_splunk_installer('splunkforwarder') .with(url: '', package_name: 'splunkforwarder') end diff --git a/spec/recipes/service_spec.rb b/spec/recipes/service_spec.rb index 3b9f00c6..dd59fe97 100644 --- a/spec/recipes/service_spec.rb +++ b/spec/recipes/service_spec.rb @@ -3,12 +3,18 @@ describe 'chef-splunk::service' do context 'splunkd as a server' do let(:chef_run) do - ChefSpec::ServerRunner.new do |node| + ChefSpec::ServerRunner.new do |node, server| + create_data_bag_item(server, 'vault', 'splunk__default') node.force_default['splunk']['accept_license'] = true node.force_default['splunk']['is_server'] = true + node.force_default['splunk']['startup_script'] = '/etc/systemd/system/Splunkd.service' end.converge(described_recipe) end + it 'included setup_auth recipe' do + expect(chef_run).to include_recipe('chef-splunk::setup_auth') + end + it 'creates directory /opt/splunk' do expect(chef_run).to create_directory('/opt/splunk').with(mode: '755') end @@ -23,32 +29,61 @@ expect(chef_run).to create_directory('/opt/splunk/var/log/splunk').with(mode: '700') end - it 'created /etc/systemd/system/splunk.service' do - expect(chef_run).to create_template('/etc/systemd/system/splunk.service') + it 'fixes splunk file permissions' do + expect(chef_run).to run_ruby_block('splunk_fix_file_ownership') + expect(chef_run.ruby_block('splunk_fix_file_ownership')).to subscribe_to('service[splunk]').on(:run).before end - it 'deleted /etc/systemd/system/splunkd.service' do - expect(chef_run).to delete_file('/etc/systemd/system/splunkd.service') + it 'enables boot-start' do + expect(chef_run).to run_execute('splunk enable boot-start') + .with(sensitive: false, retries: 3, creates: '/etc/systemd/system/Splunkd.service') end - it 'creates resource execute[systemctl daemon-reload] to do_nothing' do - expect(chef_run.execute('systemctl daemon-reload')).to do_nothing + it 'started splunk service' do + expect(chef_run).to start_service('splunk') end + end - it 'does not delete /etc/systemd/system/splunk.service' do - expect(chef_run).to_not delete_file('/etc/systemd/system/splunk.service') + context 'Splunk is setup as a client' do + let(:chef_run) do + ChefSpec::ServerRunner.new do |node, server| + create_data_bag_item(server, 'vault', 'splunk__default') + node.force_default['splunk']['accept_license'] = true + node.force_default['splunk']['is_server'] = false + node.force_default['splunk']['startup_script'] = '/etc/systemd/system/SplunkForwarder.service' + end.converge(described_recipe) end - it 'does not create /etc/init.d/splunk' do - expect(chef_run).to_not create_template('/etc/init.d/splunk') + it 'included setup_auth recipe' do + expect(chef_run).to include_recipe('chef-splunk::setup_auth') end - it 'starts the splunk service' do - expect(chef_run).to start_service('splunk') + it 'creates directory /opt/splunk' do + expect(chef_run).to_not create_directory('/opt/splunk').with(mode: '755') + end + + %w(/opt/splunk/var /opt/splunk/var/log).each do |d| + it "creates directory #{d}" do + expect(chef_run).to_not create_directory(d).with(mode: '711') + end + end + + it 'creates directory /opt/splunk/var/log/splunk' do + expect(chef_run).to_not create_directory('/opt/splunk/var/log/splunk').with(mode: '700') end - it 'enables the splunk service' do - expect(chef_run).to enable_service('splunk') + it 'fixes splunk file permissions' do + expect(chef_run).to run_ruby_block('splunk_fix_file_ownership') + expect(chef_run.ruby_block('splunk_fix_file_ownership')).to subscribe_to('service[splunk]').on(:run).before + end + + it 'enables boot-start' do + expect(chef_run).to run_execute('splunk enable boot-start') + .with(sensitive: false, retries: 3, creates: '/etc/systemd/system/SplunkForwarder.service') + end + + it 'started splunk service' do + expect(chef_run).to start_service('splunk') end end end diff --git a/spec/recipes/setup_auth_spec.rb b/spec/recipes/setup_auth_spec.rb index 2829a744..ecc9f52c 100644 --- a/spec/recipes/setup_auth_spec.rb +++ b/spec/recipes/setup_auth_spec.rb @@ -2,8 +2,9 @@ describe 'chef-splunk::setup_auth' do context 'default attributes' do - let(:chef_run) do - ChefSpec::ServerRunner.new do |node, _server| + let(:runner) do + ChefSpec::ServerRunner.new do |node, server| + create_data_bag_item(server, 'vault', 'splunk__default') node.force_default['dev_mode'] = true node.force_default['splunk']['is_server'] = true node.force_default['splunk']['accept_license'] = true @@ -12,42 +13,49 @@ end end - before do - allow_any_instance_of(Chef::Recipe).to receive(:chef_vault_item).and_return('auth' => 'admin:notarealpassword') - end - context 'setup_auth is true' do - it 'created user-seed.conf and notifies splunk restart' do - chef_run.converge(described_recipe) do - chef_run.resource_collection.insert( - Chef::Resource::Service.new('splunk', chef_run.run_context) + # since the service[splunk] resource is created in the chef-splunk cookbook and + # the `include_recipe` is mocked in this chefspec, we need to insert + # a generic mock-up into the Resource collection so notifications can be checked + let(:chef_run) do + runner.converge(described_recipe) do + runner.resource_collection.insert( + Chef::Resource::Service.new('splunk', runner.run_context) ) end + end - expect(chef_run).to create_template('user-seed.conf') - .with(mode: '600', sensitive: true, owner: 'root', group: 'root') - expect(chef_run.template('user-seed.conf')).to notify('service[splunk]').to(:restart).immediately + it 'deleted etc/passwd file' do + expect(chef_run).to delete_file('etc/passwd') end - it 'created .user-seed.conf' do - chef_run.converge(described_recipe) do - chef_run.resource_collection.insert( - Chef::Resource::Service.new('splunk', chef_run.run_context) - ) - end - expect(chef_run).to create_file('.user-seed.conf') - .with(mode: '600', owner: 'root', group: 'root') + it 'created user-seed.conf' do + expect(chef_run).to create_file('user-seed.conf').with(mode: '0640', sensitive: false) + end + + it 'created .user-seed.conf only when notified after user-seed.conf is processed' do + expect(chef_run).to nothing_file('.user-seed.conf') + expect(chef_run.file('.user-seed.conf')).to subscribe_to('file[user-seed.conf]').on(:touch).immediately end end context 'setup auth is false' do - it 'logs debug message' do - chef_run.node.force_default['splunk']['setup_auth'] = false - chef_run.converge(described_recipe) do - chef_run.resource_collection.insert( - Chef::Resource::Service.new('splunk', chef_run.run_context) + # since the service[splunk] resource is created in the chef-splunk cookbook and + # the `include_recipe` is mocked in this chefspec, we need to insert + # a generic mock-up into the Resource collection so notifications can be checked + let(:chef_run) do + runner.converge(described_recipe) do + runner.resource_collection.insert( + Chef::Resource::Service.new('splunk', runner.run_context) ) end + end + + before do + runner.node.force_default['splunk']['setup_auth'] = false + end + + it 'logs debug message' do expect(chef_run).to write_log('setup_auth is disabled').with(level: :debug) end end diff --git a/spec/recipes/upgrade_spec.rb b/spec/recipes/upgrade_spec.rb index 3281c4c7..bc968e04 100644 --- a/spec/recipes/upgrade_spec.rb +++ b/spec/recipes/upgrade_spec.rb @@ -4,7 +4,8 @@ let(:url) { 'http://splunk.example.com/server/package437.deb' } let(:chef_run) do - ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '16.04') do |node| + ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '16.04') do |node, server| + create_data_bag_item(server, 'vault', 'splunk__default') node.force_default['splunk']['upgrade_enabled'] = true node.force_default['splunk']['accept_license'] = true node.force_default['splunk']['server']['upgrade']['url'] = url diff --git a/templates/outputs.conf.erb b/templates/outputs.conf.erb index 6f73c94d..ef627840 100644 --- a/templates/outputs.conf.erb +++ b/templates/outputs.conf.erb @@ -1,9 +1,9 @@ [tcpout] defaultGroup = splunk_indexers_<%= node['splunk']['receiver_port'] %> -disabled=false +disabled = false [tcpout:splunk_indexers_<%= node['splunk']['receiver_port'] %>] server = <%= @server_list %> <% @outputs_conf.each_pair do |name, value| -%> -<%= name %> = <%= value %> +<%= name %> = <%= splunk_secret_inspect(@conf_file, "tcpout:splunk_indexers_#{node['splunk']['receiver_port']}", name) || value %> <% end -%> diff --git a/templates/splunk-init.erb b/templates/splunk-init.erb deleted file mode 100755 index 59da26f1..00000000 --- a/templates/splunk-init.erb +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/sh -# -# /etc/init.d/splunk -# init script for Splunk. -# generated by Chef Infra Client. -# -### BEGIN INIT INFO -# Provides: splunkd -# Required-Start: $remote_fs -# Required-Stop: $remote_fs -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start splunk -# Description: Splunk indexer service -### END INIT INFO -# -RETVAL=0 - -splunk_start() { - echo Starting Splunk... -<% if @runasroot %> - "<%= @splunkcmd %>" start --answer-yes --no-prompt -<% else %> - su - <%= @splunkuser %> -c '"<%= @splunkcmd %>" start --answer-yes --no-prompt' -<% end %> - RETVAL=$? - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/splunk -} -splunk_stop() { - echo Stopping Splunk... -<% if @runasroot %> - "<%= @splunkcmd %>" stop -<% else %> - su - <%= @splunkuser %> -c '"<%= @splunkcmd %>" stop' -<% end %> - RETVAL=$? - [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/splunk -} -splunk_restart() { - echo Restarting Splunk... -<% if @runasroot %> - "<%= @splunkcmd %>" restart -<% else %> - su - <%= @splunkuser %> -c '"<%= @splunkcmd %>" restart' -<% end %> - RETVAL=$? - [ $RETVAL -eq 0 ] && touch /var/lock/subsys/splunk -} -splunk_status() { - echo Splunk status: -<% if @runasroot %> - "<%= @splunkcmd %>" status -<% else %> - su - <%= @splunkuser %> -c '"<%= @splunkcmd %>" status' -<% end %> - RETVAL=$? -} -case "$1" in - start) - splunk_start - ;; - stop) - splunk_stop - ;; - restart) - splunk_restart - ;; - status) - splunk_status - ;; - *) - echo "Usage: $0 {start|stop|restart|status}" - exit 1 - ;; -esac - -exit $RETVAL diff --git a/templates/splunk-systemd.erb b/templates/splunk-systemd.erb deleted file mode 100644 index 66caf83f..00000000 --- a/templates/splunk-systemd.erb +++ /dev/null @@ -1,22 +0,0 @@ -# systemd service file for splunk - -[Unit] -Description=Splunk -After=network.target - -[Service] -Type=forking -RemainAfterExit=no -<% if ! @runasroot %> -User=<%= @splunkuser %> -Group=<%= @splunkuser %> -<% end %> -LimitNOFILE=65536 -ExecStart="<%= @splunkcmd %>" start --answer-yes --no-prompt -ExecStop="<%= @splunkcmd %>" stop -ExecReload="<%= @splunkcmd %>" restart -PIDFile=<%= @splunkdir %>/var/run/splunk/splunkd.pid - -[Install] -WantedBy=multi-user.target -Alias=splunkd.service diff --git a/templates/user-seed-conf.erb b/templates/user-seed-conf.erb deleted file mode 100644 index c24d7cb1..00000000 --- a/templates/user-seed-conf.erb +++ /dev/null @@ -1,3 +0,0 @@ -[user_info] -USERNAME = <%= @user %> -HASHED_PASSWORD = <%= @hashed_password %> diff --git a/test/integration/client-inputs-outputs/serverspec/client_spec.rb b/test/integration/client-inputs-outputs/serverspec/client_spec.rb deleted file mode 100644 index 322f3fc8..00000000 --- a/test/integration/client-inputs-outputs/serverspec/client_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'spec_helper' - -describe 'inputs config should be configured per node attributes' do - describe file('/opt/splunkforwarder/etc/system/local/inputs.conf') do - it { should be_file } - its(:content) { should match(%r{\[tcp://:123123\]}) } - its(:content) { should match(/connection_host = dns/) } - its(:content) { should match(/sourcetype = syslog/) } - its(:content) { should match(/source = tcp:123123/) } - end -end - -describe 'outputs config should be configured per node attributes' do - describe file('/opt/splunkforwarder/etc/system/local/outputs.conf') do - it { should be_file } - its(:content) { should match(/defaultGroup = splunk_indexers_9997/) } - # from the default attributes - its(:content) { should match(/forwardedindex.0.whitelist = .*/) } - its(:content) { should match(/forwardedindex.1.blacklist = _.*/) } - its(:content) { should match(/forwardedindex.2.whitelist = _audit/) } - its(:content) { should match(/forwardedindex.filter.disable = false/) } - # servers - its(:content) { should match(/server = server-ubuntu-1204.vagrantup.com:9997/) } - # attributes for dynamic definition - its(:content) { should match(%r{sslCertPath = \$SPLUNK_HOME/etc/certs/cert.pem}) } - its(:content) { should match(/sslCommonNameToCheck = sslCommonName/) } - # it won't be the plaintext 'password' per the attribute, and may - # differ due to salt, just make sure it looks passwordish. - its(:content) { should match(/sslPassword = \$\d/) } - its(:content) { should match(%r{sslRootCAPath = \$SPLUNK_HOME/etc/certs/cacert.pem}) } - its(:content) { should match(/sslVerifyServerCert = false/) } - end -end diff --git a/test/integration/client-inputs-outputs/serverspec/spec_helper.rb b/test/integration/client-inputs-outputs/serverspec/spec_helper.rb deleted file mode 100644 index 37af1b45..00000000 --- a/test/integration/client-inputs-outputs/serverspec/spec_helper.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'serverspec' - -set :backend, :exec diff --git a/test/integration/client_lwrps/serverspec/spec_helper.rb b/test/integration/client_lwrps/serverspec/spec_helper.rb deleted file mode 100644 index 37af1b45..00000000 --- a/test/integration/client_lwrps/serverspec/spec_helper.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'serverspec' - -set :backend, :exec diff --git a/test/integration/client_lwrps/serverspec/splunkapp_spec.rb b/test/integration/client_lwrps/serverspec/splunkapp_spec.rb deleted file mode 100644 index 88fe5167..00000000 --- a/test/integration/client_lwrps/serverspec/splunkapp_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'spec_helper' - -describe 'splunk apps should be installed and enabled' do - describe file('/opt/splunkforwarder/etc/apps/bistro-1.0.2') do - it { should exist } - it { should be_directory } - it { should be_owned_by 'splunk' } - end - describe command('/opt/splunkforwarder/bin/splunk btool --app=bistro-1.0.2 app list') do - its(:exit_status) { should eq 0 } - its(:stdout) { should_not match /disabled\s*=\s*(0|false)/ } - end -end diff --git a/test/integration/inspec/client_inputs_outputs_test.rb b/test/integration/inspec/client_inputs_outputs_test.rb new file mode 100644 index 00000000..4ea31136 --- /dev/null +++ b/test/integration/inspec/client_inputs_outputs_test.rb @@ -0,0 +1,102 @@ +SPLUNK_HOME = '/opt/splunkforwarder'.freeze +SPLUNK_ENCRYPTED_STRING_REGEX = /\$\d\$.*==$/.freeze + +control 'SplunkForwarder installation' do + title 'SplunkForwarder service installation' + + describe package('splunkforwarder') do + it { should be_installed } + end + + describe.one do + describe service('splunk') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + + describe service('SplunkForwarder') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + end + + describe port 8089 do + it { should be_listening } + its('protocols') { should include('tcp') } + end + + describe processes('splunkd') do + it { should exist } + end +end + +control 'SplunkForwarder local system config files' do + title 'SplunkForwarder local system config files' + + %w(inputs.conf outputs.conf server.conf).each do |f| + describe file("#{SPLUNK_HOME}/etc/system/local/#{f}") do + it { should be_file } + it { should exist } + end + end + + describe ini("#{SPLUNK_HOME}/etc/system/local/inputs.conf") do + its('default.host') { should eq 'localhost' } + its('tcp://:123123.connection_host') { should eq 'dns' } + its('tcp://:123123.sourcetype') { should eq 'syslog' } + its('tcp://:123123.source') { should eq 'tcp:123123' } + end + + describe ini("#{SPLUNK_HOME}/etc/system/local/server.conf") do + its('general.serverName') { should_not be_empty } + its('general.serverName') { should_not be_nil } + its('general.pass4SymmKey') { should match(SPLUNK_ENCRYPTED_STRING_REGEX) } + its('sslConfig.sslPassword') { should match(SPLUNK_ENCRYPTED_STRING_REGEX) } + its('lmpool:auto_generated_pool_forwarder.description') { should eq 'auto_generated_pool_forwarder' } + its('lmpool:auto_generated_pool_forwarder.quota') { should eq 'MAX' } + its('lmpool:auto_generated_pool_forwarder.slaves') { should eq '*' } + its('lmpool:auto_generated_pool_forwarder.stack_id') { should eq 'forwarder' } + its('lmpool:auto_generated_pool_free.description') { should eq 'auto_generated_pool_free' } + its('lmpool:auto_generated_pool_free.quota') { should eq 'MAX' } + its('lmpool:auto_generated_pool_free.slaves') { should eq '*' } + its('lmpool:auto_generated_pool_free.stack_id') { should eq 'free' } + end + + describe ini("#{SPLUNK_HOME}/etc/system/local/outputs.conf") do + its('tcpout.defaultGroup') { should eq 'splunk_indexers_9997' } + its('tcpout.disabled') { should eq 'false' } + its('tcpout:splunk_indexers_9997.server') { should match(/\:9997$/) } + its(['tcpout:splunk_indexers_9997', 'forwardedindex.0.whitelist']) { should eq '.*' } + its(['tcpout:splunk_indexers_9997', 'forwardedindex.1.blacklist']) { should eq '_.*' } + its(['tcpout:splunk_indexers_9997', 'forwardedindex.2.whitelist']) { should eq '_audit' } + its(['tcpout:splunk_indexers_9997', 'forwardedindex.filter.disable']) { should eq 'false' } + its('tcpout:splunk_indexers_9997.sslCertPath') { should eq '$SPLUNK_HOME/etc/certs/cert.pem' } + its('tcpout:splunk_indexers_9997.sslCommonNameToCheck') { should eq 'sslCommonName' } + # it won't be the plaintext 'password' per the attribute, and may + # differ due to salt, just make sure it looks passwordish. + its('tcpout:splunk_indexers_9997.sslPassword') { should match(SPLUNK_ENCRYPTED_STRING_REGEX) } + its('tcpout:splunk_indexers_9997.sslRootCAPath') { should eq '$SPLUNK_HOME/etc/certs/cacert.pem' } + its('tcpout:splunk_indexers_9997.sslVerifyServerCert') { should eq 'false' } + end +end + +control 'Splunk admin password validation' do + title 'Splunk admin password' + desc 'validate that the splunk admin password has been properly set' + + describe file("#{SPLUNK_HOME}/etc/system/local/user-seed.conf") do + it { should_not exist } + end + + describe file("#{SPLUNK_HOME}/etc/system/local/.user-seed.conf") do + it { should exist } + end + + # ensure the admin password has been changed from the default `changeme` + describe command("#{SPLUNK_HOME}/bin/splunk login -auth admin:notarealpassword"), :sensitive do + its('stderr') { should be_empty } + its('exit_status') { should eq 0 } + end +end diff --git a/test/integration/inspec/client_test.rb b/test/integration/inspec/client_test.rb new file mode 100644 index 00000000..6e68d20b --- /dev/null +++ b/test/integration/inspec/client_test.rb @@ -0,0 +1,116 @@ +# Inspec tests for splunk forwarder on linux systems. +SPLUNK_HOME = '/opt/splunkforwarder'.freeze +SPLUNK_ENCRYPTED_STRING_REGEX = /\$\d\$.*==$/.freeze + +control 'Splunk Universal Forwarder' do + title 'Verify Splunk Universal Forwarder installation' + only_if { os.linux? } + + describe 'verify inputs config' do + describe file("#{SPLUNK_HOME}/etc/system/local/inputs.conf") do + it { should be_file } + end + + describe ini("#{SPLUNK_HOME}/etc/system/local/inputs.conf") do + its('default.host') { should_not be_nil } + its('default.host') { should_not be_empty } + end + end + + describe 'verify outputs config' do + describe file("#{SPLUNK_HOME}/etc/system/local/outputs.conf") do + it { should be_file } + end + + describe ini("#{SPLUNK_HOME}/etc/system/local/outputs.conf") do + its('tcpout.defaultGroup') { should eq 'splunk_indexers_9997' } + its('tcpout.disabled') { should eq 'false' } + its('tcpout:splunk_indexers_9997.server') { should_not be_empty } + its('tcpout:splunk_indexers_9997.server') { should_not be_nil } + its(['tcpout:splunk_indexers_9997', 'forwardedindex.0.whitelist']) { should eq '.*' } + its(['tcpout:splunk_indexers_9997', 'forwardedindex.1.blacklist']) { should eq '_.*' } + its(['tcpout:splunk_indexers_9997', 'forwardedindex.2.whitelist']) { should eq '_audit' } + its(['tcpout:splunk_indexers_9997', 'forwardedindex.filter.disable']) { should eq 'false' } + end + end + + describe 'verify server config' do + describe file("#{SPLUNK_HOME}/etc/system/local/server.conf") do + it { should be_file } + it { should exist } + end + + describe ini("#{SPLUNK_HOME}/etc/system/local/server.conf") do + its('general.serverName') { should_not be_empty } + its('general.serverName') { should_not be_nil } + its('general.pass4SymmKey') { should match(SPLUNK_ENCRYPTED_STRING_REGEX) } + its('sslConfig.sslPassword') { should match(SPLUNK_ENCRYPTED_STRING_REGEX) } + its('lmpool:auto_generated_pool_forwarder.description') { should eq 'auto_generated_pool_forwarder' } + its('lmpool:auto_generated_pool_forwarder.quota') { should eq 'MAX' } + its('lmpool:auto_generated_pool_forwarder.slaves') { should eq '*' } + its('lmpool:auto_generated_pool_forwarder.stack_id') { should eq 'forwarder' } + its('lmpool:auto_generated_pool_free.description') { should eq 'auto_generated_pool_free' } + its('lmpool:auto_generated_pool_free.quota') { should eq 'MAX' } + its('lmpool:auto_generated_pool_free.slaves') { should eq '*' } + its('lmpool:auto_generated_pool_free.stack_id') { should eq 'free' } + end + end + + describe package('splunkforwarder') do + it { should be_installed } + end + + describe.one do + describe service('splunk') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + + describe service('SplunkForwarder') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + end + + describe port 8089 do + it { should be_listening } + its('protocols') { should include('tcp') } + end + + describe processes('splunkd') do + it { should exist } + end + + describe.one do + describe file('/etc/systemd/system/SplunkForwarder.service') do + it { should exist } + it { should be_file } + end + + describe file('/etc/init.d/splunk') do + it { should exist } + it { should be_file } + end + end +end + +control 'Splunk admin password validation' do + title 'Splunk admin password' + desc 'validate that the splunk admin password has been properly set' + + describe file("#{SPLUNK_HOME}/etc/system/local/user-seed.conf") do + it { should_not exist } + end + + describe file("#{SPLUNK_HOME}/etc/system/local/.user-seed.conf") do + it { should exist } + end + + # the password used for validation here is from the test/fixture/data_bags/vault/splunk__default.rb + describe command("#{SPLUNK_HOME}/bin/splunk validate-passwd notarealpassword") do + its('stderr') { should be_empty } + its('exit_status') { should eq 0 } + end +end diff --git a/test/integration/inspec/custom_resources_test.rb b/test/integration/inspec/custom_resources_test.rb new file mode 100644 index 00000000..74f425e1 --- /dev/null +++ b/test/integration/inspec/custom_resources_test.rb @@ -0,0 +1,26 @@ +control 'Custom Resources' do + title 'Verify custom resources provided by this cookbook' + only_if { os.linux? } + + describe.one do + describe file('/opt/splunkforwarder/etc/apps/bistro-1.0.2') do + it { should exist } + it { should be_directory } + end + describe file('/opt/splunk/etc/apps/bistro-1.0.2') do + it { should exist } + it { should be_directory } + end + end + + describe.one do + describe command('/opt/splunkforwarder/bin/splunk btool --app=bistro-1.0.2 app list') do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not match /disabled\s*=\s*(0|false)/ } + end + describe command('/opt/splunk/bin/splunk btool --app=bistro-1.0.2 app list') do + its(:exit_status) { should eq 0 } + its(:stdout) { should_not match /disabled\s*=\s*(0|false)/ } + end + end +end diff --git a/test/integration/inspec/disabled_test.rb b/test/integration/inspec/disabled_test.rb new file mode 100644 index 00000000..4e994f1b --- /dev/null +++ b/test/integration/inspec/disabled_test.rb @@ -0,0 +1,22 @@ +# Inspec tests for enterprise splunk on linux systems. +control 'Disabled Splunk' do + title 'Verify Splunk is disabled' + only_if { os.linux? } + + describe.one do + %w(splunk splunkforwarder).each do |pkg| + describe package(pkg) do + it { should_not be_installed } + end + end + end + + describe.one do + %w(Splunkd SplunkForwarder splunk).each do |svc| + describe service(svc) do + it { should_not be_running } + it { should_not be_enabled } + end + end + end +end diff --git a/test/integration/inspec/search_head_deployer_test.rb b/test/integration/inspec/search_head_deployer_test.rb new file mode 100644 index 00000000..fe93e37c --- /dev/null +++ b/test/integration/inspec/search_head_deployer_test.rb @@ -0,0 +1,22 @@ +control 'Splunk Search Head Deployer' do + title 'Verify search head deployer provisioning' + only_if { os.linux? } + + describe 'chef-splunk::server should run as "root" user' do + describe command('ps aux | grep "splunkd -p" | head -1 | awk \'{print $1}\'') do + its(:stdout) { should match(/splunk/) } + end + end + + describe 'chef-splunk::server should listen on web_port 8000' do + describe port(8000) do + it { should be_listening.with('tcp') } + end + end + + describe 'server config should be configured per node attributes' do + describe file('/opt/splunk/etc/system/local/server.conf') do + it { should be_file } + end + end +end diff --git a/test/integration/inspec/server_cluster_master_test.rb b/test/integration/inspec/server_cluster_master_test.rb new file mode 100644 index 00000000..75ed6285 --- /dev/null +++ b/test/integration/inspec/server_cluster_master_test.rb @@ -0,0 +1,28 @@ +control 'Splunk Cluster Master' do + title 'Verify cluster master provisioning' + only_if { os.linux? } + + describe 'chef-splunk::server should run as "root" user' do + describe command('ps aux | grep "splunkd -p" | head -1 | awk \'{print $1}\'') do + its(:stdout) { should match(/splunk/) } + end + end + + describe 'chef-splunk::server should listen on web_port 8000' do + describe port(8000) do + it { should be_listening.with('tcp') } + end + end + + describe 'server config should be configured per node attributes' do + describe file('/opt/splunk/etc/system/local/server.conf') do + it { should be_file } + end + + describe ini('/opt/splunk/etc/system/local/server.conf') do + its('clustering.mode') { should eq 'master' } + its('clustering.replication_factor') { should match(/\d*/) } + its('clustering.search_factor') { should match(/\d*/) } + end + end +end diff --git a/test/integration/inspec/server_test.rb b/test/integration/inspec/server_test.rb new file mode 100644 index 00000000..0ca2868a --- /dev/null +++ b/test/integration/inspec/server_test.rb @@ -0,0 +1,84 @@ +# Inspec tests for enterprise splunk on linux systems. +SPLUNK_HOME = '/opt/splunk'.freeze +SPLUNK_ENCRYPTED_STRING_REGEX = /\$\d\$.*==$/.freeze + +control 'Enterprise Splunk' do + title 'Verify Enterprise Splunk server installation' + only_if { os.linux? } + + describe 'chef-splunk::server should listen on web_port 8000' do + describe port(8000) do + its('protocols') { should include('tcp') } + end + end + + describe 'verify inputs config' do + describe file("#{SPLUNK_HOME}/etc/system/local/inputs.conf") do + it { should be_file } + end + + describe ini("#{SPLUNK_HOME}/etc/system/local/inputs.conf") do + its('default.host') { should_not be_nil } + its('default.host') { should_not be_empty } + end + end + + describe package('splunk') do + it { should be_installed } + end + + describe.one do + describe service('splunk') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + + describe service('Splunkd') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + end + + describe port 8089 do + it { should be_listening } + its('protocols') { should include('tcp') } + end + + describe processes('splunkd') do + it { should exist } + end + + describe.one do + describe file('/etc/systemd/system/Splunkd.service') do + it { should exist } + it { should be_file } + end + + describe file('/etc/init.d/splunk') do + it { should exist } + it { should be_file } + end + end +end + +control 'Splunk admin password validation' do + title 'Splunk admin password' + desc 'validate that the splunk admin password has been properly set' + only_if { os.linux? } + + describe file("#{SPLUNK_HOME}/etc/system/local/user-seed.conf") do + it { should_not exist } + end + + describe file("#{SPLUNK_HOME}/etc/system/local/.user-seed.conf") do + it { should exist } + end + + # the password used for validation here is from the test/fixture/data_bags/vault/splunk__default.rb + describe command("#{SPLUNK_HOME}/bin/splunk login -auth admin:notarealpassword") do + its('stderr') { should be_empty } + its('exit_status') { should eq 0 } + end +end diff --git a/test/integration/inspec/setup_auth_test.rb b/test/integration/inspec/setup_auth_test.rb new file mode 100644 index 00000000..e69de29b diff --git a/test/integration/inspec/uninstall_forwarder_test.rb b/test/integration/inspec/uninstall_forwarder_test.rb new file mode 100644 index 00000000..c304b168 --- /dev/null +++ b/test/integration/inspec/uninstall_forwarder_test.rb @@ -0,0 +1,22 @@ +# Inspec tests for splunk forwarder on linux systems. +SPLUNK_HOME = '/opt/splunkforwarder'.freeze +SPLUNK_ENCRYPTED_STRING_REGEX = /\$\d\$.*==$/.freeze + +control 'Splunk Universal Forwarder' do + title 'Verify Splunk Universal Forwarder installation' + only_if { os.linux? } + + describe package('splunkforwarder') do + it { should_not be_installed } + end + + describe.one do + %w(splunk SplunkForwarder).each do |svc| + describe service svc do + it { should_not be_running } + it { should_not be_enabled } + it { shuold_not be_installed } + end + end + end +end diff --git a/test/integration/inspec/upgrade_test.rb b/test/integration/inspec/upgrade_test.rb new file mode 100644 index 00000000..ddcf08b3 --- /dev/null +++ b/test/integration/inspec/upgrade_test.rb @@ -0,0 +1,30 @@ +# Inspec tests for enterprise splunk on linux systems. +SPLUNK_HOME = '/opt/splunk'.freeze +SPLUNK_ENCRYPTED_STRING_REGEX = /\$\d\$.*==$/.freeze + +control 'Splunk Upgrade' do + title 'Verify Splunk upgrade to 8.0.6' + only_if { os.linux? } + + describe.one do + describe package('splunkforwarder') do + it { should be_installed } + its('version') { should match(/8\.0\.6/) } + end + + describe package('splunk') do + it { should be_installed } + its('version') { should match(/8\.0\.6/) } + end + end + + describe.one do + %w(Splunkd SplunkForwarder splunk).each do |svc| + describe service(svc) do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end + end + end +end diff --git a/test/integration/server-cluster-master/serverspec/server_spec.rb b/test/integration/server-cluster-master/serverspec/server_spec.rb deleted file mode 100644 index ffbee33a..00000000 --- a/test/integration/server-cluster-master/serverspec/server_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'spec_helper' - -describe 'chef-splunk::server should run as "root" user' do - describe command('ps aux | grep "splunkd -p" | head -1 | awk \'{print $1}\'') do - its(:stdout) { should match(/splunk/) } - end -end - -describe 'chef-splunk::server should listen on web_port 8000' do - describe port(8000) do - it { should be_listening.with('tcp') } - end -end - -describe 'server config should be configured per node attributes' do - describe file('/opt/splunk/etc/system/local/server.conf') do - it { should be_file } - its(:content) { should match(/\[clustering\]/) } - its(:content) { should match(/^mode = master$/) } - its(:content) { should match(/^replication_factor = 5$/) } - its(:content) { should match(/^search_factor = 3$/) } - end -end diff --git a/test/integration/server-cluster-master/serverspec/spec_helper.rb b/test/integration/server-cluster-master/serverspec/spec_helper.rb deleted file mode 100644 index 37af1b45..00000000 --- a/test/integration/server-cluster-master/serverspec/spec_helper.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'serverspec' - -set :backend, :exec diff --git a/test/integration/server-runas-root/serverspec/server_spec.rb b/test/integration/server-runas-root/serverspec/server_spec.rb deleted file mode 100644 index 6a638f89..00000000 --- a/test/integration/server-runas-root/serverspec/server_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'spec_helper' - -describe 'chef-splunk::server should run as "root" user' do - describe command('ps aux | grep "splunkd -p" | head -1 | awk \'{print $1}\'') do - its(:stdout) { should match(/root/) } - end -end - -describe 'chef-splunk::server should listen on web_port 8000' do - describe port(8000) do - it { should be_listening.with('tcp') } - end -end diff --git a/test/integration/server-runas-root/serverspec/spec_helper.rb b/test/integration/server-runas-root/serverspec/spec_helper.rb deleted file mode 100644 index 37af1b45..00000000 --- a/test/integration/server-runas-root/serverspec/spec_helper.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'serverspec' - -set :backend, :exec diff --git a/test/integration/server-runas-splunk/serverspec/server_spec.rb b/test/integration/server-runas-splunk/serverspec/server_spec.rb deleted file mode 100644 index b32c1161..00000000 --- a/test/integration/server-runas-splunk/serverspec/server_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'spec_helper' - -describe 'chef-splunk::server should run as "splunk" user' do - describe command('ps aux | grep "splunkd -p" | head -1 | awk \'{print $1}\'') do - its(:stdout) { should match(/splunk/) } - end -end - -describe 'chef-splunk::server should listen on web_port 8000' do - describe port(8000) do - it { should be_listening.with('tcp') } - end -end diff --git a/test/integration/server-runas-splunk/serverspec/spec_helper.rb b/test/integration/server-runas-splunk/serverspec/spec_helper.rb deleted file mode 100644 index 37af1b45..00000000 --- a/test/integration/server-runas-splunk/serverspec/spec_helper.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'serverspec' - -set :backend, :exec diff --git a/test/integration/server_lwrps/serverspec/spec_helper.rb b/test/integration/server_lwrps/serverspec/spec_helper.rb deleted file mode 100644 index 37af1b45..00000000 --- a/test/integration/server_lwrps/serverspec/spec_helper.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'serverspec' - -set :backend, :exec diff --git a/test/integration/server_lwrps/serverspec/splunkapp_spec.rb b/test/integration/server_lwrps/serverspec/splunkapp_spec.rb deleted file mode 100644 index df4e9ca4..00000000 --- a/test/integration/server_lwrps/serverspec/splunkapp_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'spec_helper' - -describe 'splunk apps should be installed and enabled' do - describe file('/opt/splunk/etc/apps/bistro-1.0.2') do - it { should exist } - it { should be_directory } - it { should be_owned_by 'splunk' } - end - describe command('/opt/splunk/bin/splunk btool --app=bistro-1.0.2 app list') do - its(:exit_status) { should eq 0 } - its(:stdout) { should_not match /disabled\s*=\s*(0|false)/ } - end -end