From 24f769a0ba44b4f7f5aaed71ee59154ca3c64ae3 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Sat, 21 Nov 2015 16:57:36 -0600 Subject: [PATCH] Additional docs, :package default - Ensure :package is the default installation method everywhere, update docs to reflect. Fixes #389. - Ensure defaults for :package and :tarball are clear; remove incorrect comment on resource. Fixes #391. - Ensure actions are firing correctly when providers really do updates, so restarting is easier. Fixes #394. - Drastically clarify elasticsearch_plugin docs, allow URL specifier for installs. Fixes #392. - Re-comment the node role in the configure resource to be more plain. Fixes #393. - Pass through default service notifications from elasticsearch_service to service. Fixes #392. --- .kitchen.yml | 16 +- README.md | 124 +++++++-- attributes/default.rb | 2 +- libraries/provider_configure.rb | 250 +++++++++--------- libraries/provider_install.rb | 38 +-- libraries/provider_plugin.rb | 68 +++-- libraries/provider_service.rb | 117 +++++--- libraries/provider_user.rb | 62 ++--- libraries/resource_configure.rb | 16 +- libraries/resource_install.rb | 2 +- libraries/resource_plugin.rb | 8 +- libraries/resource_service.rb | 5 +- .../recipes/default_with_plugins.rb | 7 +- .../recipes/{default.rb => tarball.rb} | 0 14 files changed, 428 insertions(+), 287 deletions(-) rename test/fixtures/cookbooks/elasticsearch_test/recipes/{default.rb => tarball.rb} (100%) diff --git a/.kitchen.yml b/.kitchen.yml index 179b8c60e..a099f7d3a 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -35,28 +35,30 @@ platforms: - recipe[elasticsearch_test::fix_nss] # see recipe header suites: - - name: default # install by tarball + - name: tarball # install by tarball require_chef_omnibus: 12.5.1 run_list: - recipe[java] - recipe[elasticsearch_test::default_with_plugins] - - - name: package # install from package - require_chef_omnibus: 12.5.1 attributes: elasticsearch: - install_type: package + install_type: tarball + - name: package # install from package + require_chef_omnibus: 12.5.1 run_list: - recipe[java] - recipe[elasticsearch_test::default_with_plugins] + attributes: + elasticsearch: + install_type: package - - name: override_default # the override-everything use case + - name: override_tarball # the override-everything use case driver_config: require_chef_omnibus: 12.5.1 run_list: - recipe[java] - - recipe[elasticsearch_test::default] + - recipe[elasticsearch_test::tarball] - name: override_package # the override-everything use case driver_config: diff --git a/README.md b/README.md index 121d169eb..1d5510ecf 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,14 @@ and supports Chef 12.5.1, 12.4.3, 12.3.0, 12.2.1, 12.1.2, and higher. It impleme CI as well as more modern testing with chefspec and test-kitchen. It no longer supports some of the more extraneous features such as discovery (use [chef search](https://docs.chef.io/chef_search.html) in your wrapper cookbook) or EBS device creation (use [the aws cookbook](https://github.com/chef-cookbooks/aws)). +**Previous versions** of this cookbook may be found using the git tags on this repository. -The previous version of this cookbook may be found in the [0.3.x branch](https://github.com/elastic/cookbook-elasticsearch/tree/0.3.x). +## Pre-requisites -**NOTE: This cookbook requires java, but does not provide it. Please install -Java before using any recipe in this cookbook. We recommend [this one](https://github.com/agileorbit-cookbooks/java).** +[Java Runtime](https://www.java.com/en/) - This cookbook requires java, but does not provide it. Please install +Java before using any recipe in this cookbook. Please also note that Elasticsearch itself has specific minimum Java version requirements. We recommend [this cookbook](https://github.com/agileorbit-cookbooks/java) to install Java. + +[Elasticsearch](https://www.elastic.co/products/elasticsearch) - This cookbook has been upgraded to support Elasticsearch 2.0 and greater. While this cookbook still works with ES 1.7.x at the time of this writing, we expect to eventually **break compatibility in a minor release bump**. If you must have a cookbook that works with older versions of Elasticsearch, please test and then pin to a specific `major.minor` version and only leave the patch release to float. ## Attributes @@ -18,9 +21,8 @@ of checksums for many different archives and package files of different elasticsearch versions. Both recipes and resources/providers here use those default values. -Please take note that you may use `%s` in your URL and this cookbook will use -sprintf/format to insert the version parameter as a string into your -download_url. +You may use `%s` in your URL and this cookbook will use sprintf/format to insert +the version parameter as a string into your download_url. |Name|Default|Other values| |----|-------|------------| @@ -45,13 +47,47 @@ options. ## Resources -You should be aware that potentially all resources in this cookbook look each -other up in the resource collection. By default, they will look for appropriate -resources named 'default' or 'elasticsearch', as in the examples below. For -example, if you use `elasticsearch_install 'default'`, `elasticsearch_config` -will use the first resource to determine how you installed Elasticsearch. If you -need to override this behavior, all resources accept `instance_name` as an -additional parameter, to be used for matching. +## Notifications and Service Restarts + +The resources provided in this cookbook **do not automatically restart** +services when changes have occurred. This has been done to protect you from +accidental data loss and service outages, as nodes might restart simultaneously +or may not restart at all when bad configuration values are supplied. + +You **must** supply your desired notifications when using each resource if you +want Chef to automatically restart services. Again, we don't recommend this. + +elasticsearch_service will pass through all of the standard `service` resource +actions to the underlying service resource if you wish to notify it. + +### Resource names + +Many of the resources provided in this cookbook need to share configuration +values. For example, the `elasticsearch_service` resource needs to know the path +to the configuration file(s) generated by `elastcisearch_configure` and the path +to the actual ES binary installed by `elasticsearch_install`. And they both need +to know the appropriate system user and group defined by `elasticsearch_user`. + +Search order: In order to make this easy, all resources in this cookbook use the following +search order to locate resources that apply to the same overall +Elasticsearch setup: + +1. Resources that share the same resource name, e.g.: +1. Resources that share the same value for `instance_name` +1. Resources named `default` +1. Resources named `elasticsearch` + +Examples of more complicated resource names are left to the reader, but here we +present a typical example that should work in most cases: + +``` +elasticsearch_user 'default' +elasticsearch_install 'default' +elasticsearch_configure 'default' +elasticsearch_service 'default' + +elasticsearch_plugin 'mobz/elasticsearch-head' +``` ### elasticsearch_user Actions: `:create`, `:remove` @@ -225,21 +261,73 @@ even what version it is. So once we install a plugin to a directory, we generally assume that is the desired one and we don't touch it further. See https://github.com/elastic/cookbook-elasticsearch/issues/264 for more info. +NB: You [may encounter issues on certain distros](http://blog.backslasher.net/java-ssl-crash.html) with NSS 3.16.1 and OpenJDK 7.x. -When running a single instance per machine (VM, etc), it's typically -sufficient to rely on the default value of `plugin_dir`: +Officially supported or commercial plugins require just the plugin name: ``` -elasticsearch_plugin 'mobz/elasticsearch-head' +elasticsearch_plugin 'analysis-icu' do + action :install +end +elasticsearch_plugin 'shield' do + action :install +end +``` + +Plugins from GitHub require a URL of 'username/repository' or 'username/repository/version': + +``` +elasticsearch_plugin 'kopf' do + url 'lmenezes/elasticsearch-kopf' + action :install +end + +elasticsearch_plugin 'kopf' do + url 'lmenezes/elasticsearch-kopf/1.5.7' + action :install +end +``` + +Plugins from Maven Central or Sonatype require 'groupId/artifactId/version': +``` +elasticsearch_plugin 'mapper-attachments' do + url 'org.elasticsearch/elasticsearch-mapper-attachments/2.6.0' + action :install +end +``` + +Plugins can be installed from a custom URL or file location as follows: +``` +elasticsearch_plugin 'mapper-attachments' do + url 'http://some.domain.name//my-plugin-1.0.0.zip' + action :install +end + +elasticsearch_plugin 'mapper-attachments' do + url 'file:/path/to/my-plugin-1.0.0.zip' + action :install +end ``` To run multiple instances per machine, an explicit `plugin_dir` location has to be provided: ``` -elasticsearch_plugin 'mobz/elasticsearch-head' +elasticsearch_plugin 'mobz/elasticsearch-head' do + plugin_dir '/usr/share/elasticsearch_foo/plugins' +end +``` + +If for some reason, you want to name the resource something else, you may +provide the plugin name using the `name` parameter: + +``` +elasticsearch_plugin 'xyzzy' do + name 'kopf' + url 'lmenezes/elasticsearch-kopf' + action :install +end ``` -NB: You [may encounter issues on certain distros](http://blog.backslasher.net/java-ssl-crash.html) with NSS 3.16.1 and OpenJDK 7.x. ## Testing diff --git a/attributes/default.rb b/attributes/default.rb index aa41562c2..42d6c6b71 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -1,6 +1,6 @@ # elasticsearch version & install type default['elasticsearch']['version'] = '2.0.0' -default['elasticsearch']['install_type'] = :tarball +default['elasticsearch']['install_type'] = :package # platform_family keyed download URLs default['elasticsearch']['download_urls']['debian'] = 'https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-%s.deb' diff --git a/libraries/provider_configure.rb b/libraries/provider_configure.rb index bda11d79d..b5d3d8c32 100644 --- a/libraries/provider_configure.rb +++ b/libraries/provider_configure.rb @@ -4,147 +4,149 @@ class ElasticsearchCookbook::ConfigureProvider < Chef::Provider::LWRPBase provides :elasticsearch_configure - action :manage do - converge_by('configure elasticsearch instance') do - # lookup existing ES resources - es_user = find_es_resource(run_context, :elasticsearch_user, new_resource) - es_install = find_es_resource(run_context, :elasticsearch_install, new_resource) - es_svc = find_es_resource(run_context, :elasticsearch_service, new_resource) - - # if a subdir parameter is missing but dir is set, infer the subdir name - # then go and be sure it's also set in the YML hash if it wasn't given there - if new_resource.path_conf[es_install.type] && new_resource.default_configuration['path.conf'].nil? - new_resource.default_configuration['path.conf'] = new_resource.path_conf[es_install.type] - end - - if new_resource.path_data[es_install.type] && new_resource.default_configuration['path.data'].nil? - new_resource.default_configuration['path.data'] = new_resource.path_data[es_install.type] - end + def whyrun_supported? + false + end - if new_resource.path_logs[es_install.type] && new_resource.default_configuration['path.logs'].nil? - new_resource.default_configuration['path.logs'] = new_resource.path_logs[es_install.type] - end + action :manage do + # lookup existing ES resources + es_user = find_es_resource(run_context, :elasticsearch_user, new_resource) + es_install = find_es_resource(run_context, :elasticsearch_install, new_resource) + es_svc = find_es_resource(run_context, :elasticsearch_service, new_resource) + + # if a subdir parameter is missing but dir is set, infer the subdir name + # then go and be sure it's also set in the YML hash if it wasn't given there + if new_resource.path_conf[es_install.type] && new_resource.default_configuration['path.conf'].nil? + new_resource.default_configuration['path.conf'] = new_resource.path_conf[es_install.type] + end - # calculation for memory allocation; 50% or 31g, whatever is smaller - unless new_resource.allocated_memory - half = ((node['memory']['total'].to_i * 0.5).floor / 1024) - malloc_str = (half > 31_000 ? '31g' : "#{half}m") - new_resource.allocated_memory malloc_str - end + if new_resource.path_data[es_install.type] && new_resource.default_configuration['path.data'].nil? + new_resource.default_configuration['path.data'] = new_resource.path_data[es_install.type] + end - # Create ES directories - # - [new_resource.path_conf[es_install.type], "#{new_resource.path_conf[es_install.type]}/scripts", new_resource.path_logs[es_install.type]].each do |path| - d = directory path do - owner es_user.username - group es_user.groupname - mode 0755 - recursive true - action :nothing - end - d.run_action(:create) - new_resource.updated_by_last_action(true) if d.updated_by_last_action? - end + if new_resource.path_logs[es_install.type] && new_resource.default_configuration['path.logs'].nil? + new_resource.default_configuration['path.logs'] = new_resource.path_logs[es_install.type] + end - # Create data path directories - # - data_paths = new_resource.path_data[es_install.type].is_a?(Array) ? new_resource.path_data[es_install.type] : new_resource.path_data[es_install.type].split(',') - - data_paths.each do |path| - d = directory path.strip do - owner es_user.username - group es_user.groupname - mode 0755 - recursive true - action :nothing - end - d.run_action(:create) - new_resource.updated_by_last_action(true) if d.updated_by_last_action? - end + # calculation for memory allocation; 50% or 31g, whatever is smaller + unless new_resource.allocated_memory + half = ((node['memory']['total'].to_i * 0.5).floor / 1024) + malloc_str = (half > 31_000 ? '31g' : "#{half}m") + new_resource.allocated_memory malloc_str + end - # Valid values in /etc/sysconfig/elasticsearch or /etc/default/elasticsearch - # ES_HOME CONF_DIR CONF_FILE DATA_DIR LOG_DIR WORK_DIR PID_DIR - # ES_HEAP_SIZE ES_HEAP_NEWSIZE ES_DIRECT_SIZE ES_JAVA_OPTS - # ES_RESTART_ON_UPGRADE ES_GC_LOG_FILE ES_USER ES_GROUP - # MAX_OPEN_FILES MAX_LOCKED_MEMORY MAX_MAP_COUNT - params = {} - - params[:ES_HOME] = new_resource.path_home[es_install.type] - params[:CONF_DIR] = new_resource.path_conf[es_install.type] - params[:DATA_DIR] = new_resource.path_data[es_install.type] - params[:LOG_DIR] = new_resource.path_logs[es_install.type] - params[:PID_DIR] = new_resource.path_pid[es_install.type] - - params[:ES_USER] = es_user.username - params[:ES_GROUP] = es_user.groupname - - params[:JAVA_HOME] = new_resource.java_home - params[:ES_HEAP_SIZE] = new_resource.allocated_memory - params[:MAX_OPEN_FILES] = new_resource.nofile_limit - params[:MAX_LOCKED_MEMORY] = new_resource.memlock_limit - - params[:ES_JAVA_OPTS] = "" - params[:ES_JAVA_OPTS] << "-server " - params[:ES_JAVA_OPTS] << "-Djava.awt.headless=true " - params[:ES_JAVA_OPTS] << "-Djava.net.preferIPv4Stack=true " - params[:ES_JAVA_OPTS] << "-Xms#{new_resource.allocated_memory} " - params[:ES_JAVA_OPTS] << "-Xmx#{new_resource.allocated_memory} " - params[:ES_JAVA_OPTS] << "-Xss#{new_resource.thread_stack_size} " - params[:ES_JAVA_OPTS] << "#{new_resource.gc_settings.tr("\n", " ")} " if new_resource.gc_settings - params[:ES_JAVA_OPTS] << "-Dfile.encoding=UTF-8 " - params[:ES_JAVA_OPTS] << "-Djna.nosys=true " - params[:ES_JAVA_OPTS] << "#{new_resource.env_options} " if new_resource.env_options - - default_config_name = es_svc.service_name || es_svc.instance_name || new_resource.instance_name || 'elasticsearch' - - shell_template = template 'elasticsearch.in.sh' do - path node['platform_family'] == 'rhel' ? "/etc/sysconfig/#{default_config_name}" : "/etc/default/#{default_config_name}" - source new_resource.template_elasticsearch_env - cookbook new_resource.cookbook_elasticsearch_env - mode 0755 - variables(params: params) - action :nothing - end - shell_template.run_action(:create) - new_resource.updated_by_last_action(true) if shell_template.updated_by_last_action? - - # Create ES logging file - # - logging_template = template 'logging.yml' do - path "#{new_resource.path_conf[es_install.type]}/logging.yml" - source new_resource.template_logging_yml - cookbook new_resource.cookbook_logging_yml + # Create ES directories + # + [new_resource.path_conf[es_install.type], "#{new_resource.path_conf[es_install.type]}/scripts", new_resource.path_logs[es_install.type]].each do |path| + d = directory path do owner es_user.username group es_user.groupname mode 0755 - variables(logging: new_resource.logging) + recursive true action :nothing end - logging_template.run_action(:create) - new_resource.updated_by_last_action(true) if logging_template.updated_by_last_action? - - merged_configuration = new_resource.default_configuration.merge(new_resource.configuration) - merged_configuration['#_seen'] = {} # magic state variable for what we've seen in a config + d.run_action(:create) + new_resource.updated_by_last_action(true) if d.updated_by_last_action? + end - # warn if someone is using symbols. we don't support. - found_symbols = merged_configuration.keys.select { |s| s.is_a?(Symbol) } - unless found_symbols.empty? - Chef::Log.warn("Please change the following to strings in order to work with this Elasticsearch cookbook: #{found_symbols.join(',')}") - end + # Create data path directories + # + data_paths = new_resource.path_data[es_install.type].is_a?(Array) ? new_resource.path_data[es_install.type] : new_resource.path_data[es_install.type].split(',') - yml_template = template 'elasticsearch.yml' do - path "#{new_resource.path_conf[es_install.type]}/elasticsearch.yml" - source new_resource.template_elasticsearch_yml - cookbook new_resource.cookbook_elasticsearch_yml + data_paths.each do |path| + d = directory path.strip do owner es_user.username group es_user.groupname mode 0755 - helpers(ElasticsearchCookbook::Helpers) - variables(config: merged_configuration) + recursive true action :nothing end - yml_template.run_action(:create) - new_resource.updated_by_last_action(true) if yml_template.updated_by_last_action? + d.run_action(:create) + new_resource.updated_by_last_action(true) if d.updated_by_last_action? + end + + # Valid values in /etc/sysconfig/elasticsearch or /etc/default/elasticsearch + # ES_HOME CONF_DIR CONF_FILE DATA_DIR LOG_DIR WORK_DIR PID_DIR + # ES_HEAP_SIZE ES_HEAP_NEWSIZE ES_DIRECT_SIZE ES_JAVA_OPTS + # ES_RESTART_ON_UPGRADE ES_GC_LOG_FILE ES_USER ES_GROUP + # MAX_OPEN_FILES MAX_LOCKED_MEMORY MAX_MAP_COUNT + params = {} + + params[:ES_HOME] = new_resource.path_home[es_install.type] + params[:CONF_DIR] = new_resource.path_conf[es_install.type] + params[:DATA_DIR] = new_resource.path_data[es_install.type] + params[:LOG_DIR] = new_resource.path_logs[es_install.type] + params[:PID_DIR] = new_resource.path_pid[es_install.type] + + params[:ES_USER] = es_user.username + params[:ES_GROUP] = es_user.groupname + + params[:JAVA_HOME] = new_resource.java_home + params[:ES_HEAP_SIZE] = new_resource.allocated_memory + params[:MAX_OPEN_FILES] = new_resource.nofile_limit + params[:MAX_LOCKED_MEMORY] = new_resource.memlock_limit + + params[:ES_JAVA_OPTS] = "" + params[:ES_JAVA_OPTS] << "-server " + params[:ES_JAVA_OPTS] << "-Djava.awt.headless=true " + params[:ES_JAVA_OPTS] << "-Djava.net.preferIPv4Stack=true " + params[:ES_JAVA_OPTS] << "-Xms#{new_resource.allocated_memory} " + params[:ES_JAVA_OPTS] << "-Xmx#{new_resource.allocated_memory} " + params[:ES_JAVA_OPTS] << "-Xss#{new_resource.thread_stack_size} " + params[:ES_JAVA_OPTS] << "#{new_resource.gc_settings.tr("\n", " ")} " if new_resource.gc_settings + params[:ES_JAVA_OPTS] << "-Dfile.encoding=UTF-8 " + params[:ES_JAVA_OPTS] << "-Djna.nosys=true " + params[:ES_JAVA_OPTS] << "#{new_resource.env_options} " if new_resource.env_options + + default_config_name = es_svc.service_name || es_svc.instance_name || new_resource.instance_name || 'elasticsearch' + + shell_template = template 'elasticsearch.in.sh' do + path node['platform_family'] == 'rhel' ? "/etc/sysconfig/#{default_config_name}" : "/etc/default/#{default_config_name}" + source new_resource.template_elasticsearch_env + cookbook new_resource.cookbook_elasticsearch_env + mode 0755 + variables(params: params) + action :nothing + end + shell_template.run_action(:create) + new_resource.updated_by_last_action(true) if shell_template.updated_by_last_action? + + # Create ES logging file + # + logging_template = template 'logging.yml' do + path "#{new_resource.path_conf[es_install.type]}/logging.yml" + source new_resource.template_logging_yml + cookbook new_resource.cookbook_logging_yml + owner es_user.username + group es_user.groupname + mode 0755 + variables(logging: new_resource.logging) + action :nothing + end + logging_template.run_action(:create) + new_resource.updated_by_last_action(true) if logging_template.updated_by_last_action? + + merged_configuration = new_resource.default_configuration.merge(new_resource.configuration) + merged_configuration['#_seen'] = {} # magic state variable for what we've seen in a config + + # warn if someone is using symbols. we don't support. + found_symbols = merged_configuration.keys.select { |s| s.is_a?(Symbol) } + unless found_symbols.empty? + Chef::Log.warn("Please change the following to strings in order to work with this Elasticsearch cookbook: #{found_symbols.join(',')}") + end + + yml_template = template 'elasticsearch.yml' do + path "#{new_resource.path_conf[es_install.type]}/elasticsearch.yml" + source new_resource.template_elasticsearch_yml + cookbook new_resource.cookbook_elasticsearch_yml + owner es_user.username + group es_user.groupname + mode 0755 + helpers(ElasticsearchCookbook::Helpers) + variables(config: merged_configuration) + action :nothing end + yml_template.run_action(:create) + new_resource.updated_by_last_action(true) if yml_template.updated_by_last_action? end end diff --git a/libraries/provider_install.rb b/libraries/provider_install.rb index e8ebeaa75..bf2492cc7 100644 --- a/libraries/provider_install.rb +++ b/libraries/provider_install.rb @@ -6,33 +6,33 @@ class ElasticsearchCookbook::InstallProvider < Chef::Provider::LWRPBase include Chef::DSL::IncludeRecipe provides :elasticsearch_install + def whyrun_supported? + false + end + action :install do install_type = determine_install_type(new_resource, node) - converge_by("#{new_resource.name} - install #{install_type}") do - unless new_resource.version - new_resource.version determine_version(new_resource, node) - end + unless new_resource.version + new_resource.version determine_version(new_resource, node) + end - if install_type == 'tarball' || install_type == 'tar' - install_tarball_wrapper_action - elsif install_type == 'package' - install_package_wrapper_action - else - fail "#{install_type} is not a valid install type" - end + if install_type == 'tarball' || install_type == 'tar' + install_tarball_wrapper_action + elsif install_type == 'package' + install_package_wrapper_action + else + fail "#{install_type} is not a valid install type" end end action :remove do install_type = determine_install_type(new_resource, node) - converge_by("#{new_resource.name} - remove #{install_type}") do - if install_type == 'tarball' || install_type == 'tar' - remove_tarball_wrapper_action - elsif install_type == 'package' - remove_package_wrapper_action - else - fail "#{install_type} is not a valid install type" - end + if install_type == 'tarball' || install_type == 'tar' + remove_tarball_wrapper_action + elsif install_type == 'package' + remove_package_wrapper_action + else + fail "#{install_type} is not a valid install type" end end diff --git a/libraries/provider_plugin.rb b/libraries/provider_plugin.rb index 82cee25cc..9c960e10a 100644 --- a/libraries/provider_plugin.rb +++ b/libraries/provider_plugin.rb @@ -5,6 +5,10 @@ class ElasticsearchCookbook::PluginProvider < Chef::Provider::LWRPBase provides :elasticsearch_plugin + def whyrun_supported? + false + end + action :install do es_user = find_es_resource(run_context, :elasticsearch_user, new_resource) es_install = find_es_resource(run_context, :elasticsearch_install, new_resource) @@ -18,55 +22,47 @@ class ElasticsearchCookbook::PluginProvider < Chef::Provider::LWRPBase Chef::Log.warn("Could not parse #{es_install.version} as floating point number") end - name = new_resource.plugin_name - version = new_resource.version ? "/#{new_resource.version}" : nil - url = new_resource.url ? " -url #{new_resource.url}" : nil + name = new_resource.plugin_name + url = new_resource.url fail "Could not determine the plugin directory (#{es_conf.path_plugins[es_install.type]}). Please check elasticsearch_configure[#{es_conf.name}]." unless es_conf.path_plugins[es_install.type] # may not exist yet if first plugin fail "Could not determine the binary directory (#{es_conf.path_bin[es_install.type]}). Please check elasticsearch_configure[#{es_conf.name}]." unless es_conf.path_bin[es_install.type] && ::File.exist?(es_conf.path_bin[es_install.type]) - converge_by("install plugin #{name}") do - plugin_exists = begin - Dir.entries(es_conf.path_plugins[es_install.type]).any? do |plugin| - next if plugin =~ /^\./ - name.include? plugin - end - rescue - false - end - # shell_out! automatically raises on error, logs command output - unless plugin_exists - # required for package installs that show up with parent dir owned by root - shell_out!("mkdir -p #{es_conf.path_plugins[es_install.type]}") unless ::File.exist?(es_conf.path_plugins[es_install.type]) - shell_out!("chown #{es_user.username}:#{es_user.groupname} #{es_conf.path_plugins[es_install.type]}") + # shell_out! automatically raises on error, logs command output + unless plugin_exists(es_conf.path_plugins[es_install.type], name) + # required for package installs that show up with parent dir owned by root + shell_out!("mkdir -p #{es_conf.path_plugins[es_install.type]}") unless ::File.exist?(es_conf.path_plugins[es_install.type]) + shell_out!("chown #{es_user.username}:#{es_user.groupname} #{es_conf.path_plugins[es_install.type]}") - # do the actual install - shell_out!("#{es_conf.path_bin[es_install.type]}/plugin install #{name}#{version}#{url}".split(' '), user: es_user.username, group: es_user.groupname) + # do the actual install + shell_out!("#{es_conf.path_bin[es_install.type]}/plugin install #{url}".split(' '), user: es_user.username, group: es_user.groupname) - new_resource.updated_by_last_action(true) - end + new_resource.updated_by_last_action(true) end end # action action :remove do + es_user = find_es_resource(run_context, :elasticsearch_user, new_resource) + es_install = find_es_resource(run_context, :elasticsearch_install, new_resource) + es_conf = find_es_resource(run_context, :elasticsearch_configure, new_resource) + name = new_resource.plugin_name fail 'Could not determine the plugin directory. Please set plugin_dir on this resource.' unless new_resource.plugin_dir[es_install.type] - converge_by("remove plugin #{name}") do - plugin_exists = begin - Dir.entries(new_resource.plugin_dir).any? do |plugin| - next if plugin =~ /^\./ - name.include? plugin - end - rescue - false - end - - if plugin_exists - # automatically raises on error, logs command output - shell_out!("#{new_resource.path_bin[es_install.type]}/plugin -remove #{name}".split(' '), user: es_user.username, group: es_user.groupname) - new_resource.updated_by_last_action(true) - end + if plugin_exists(es_conf.path_plugins[es_install.type], name) + # automatically raises on error, logs command output + shell_out!("#{new_resource.path_bin[es_install.type]}/plugin -remove #{name}".split(' '), user: es_user.username, group: es_user.groupname) + new_resource.updated_by_last_action(true) end end # action + + def plugin_exists(path, name) + Dir.entries(path).any? do |plugin| + next if plugin =~ /^\./ + name.include? plugin + end + rescue + false + end + end # provider diff --git a/libraries/provider_service.rb b/libraries/provider_service.rb index 393898f58..e305e071c 100644 --- a/libraries/provider_service.rb +++ b/libraries/provider_service.rb @@ -4,50 +4,89 @@ class ElasticsearchCookbook::ServiceProvider < Chef::Provider::LWRPBase provides :elasticsearch_service include ElasticsearchCookbook::Helpers + def whyrun_supported? + false + end + action :remove do fail "#{new_resource} remove not currently implemented" end action :configure do - converge_by('configure elasticsearch service') do - es_user = find_es_resource(run_context, :elasticsearch_user, new_resource) - es_install = find_es_resource(run_context, :elasticsearch_install, new_resource) - es_conf = find_es_resource(run_context, :elasticsearch_configure, new_resource) - - d_r = directory es_conf.path_pid[es_install.type] do - owner es_user.username - group es_user.groupname - mode '0755' - recursive true - action :nothing - end - d_r.run_action(:create) - new_resource.updated_by_last_action(true) if d_r.updated_by_last_action? - - # Create service - # - init_r = template "/etc/init.d/#{new_resource.service_name}" do - source new_resource.init_source - cookbook new_resource.init_cookbook - owner 'root' - mode 0755 - variables( - # we need to include something about #{progname} fixed in here. - program_name: new_resource.service_name - ) - action :nothing - end - init_r.run_action(:create) - new_resource.updated_by_last_action(true) if init_r.updated_by_last_action? - - svc_r = service new_resource.service_name do - supports :status => true, :restart => true - action :nothing - end - new_resource.service_actions.each do |act| - svc_r.run_action(act) - new_resource.updated_by_last_action(true) if svc_r.updated_by_last_action? - end + es_user = find_es_resource(run_context, :elasticsearch_user, new_resource) + es_install = find_es_resource(run_context, :elasticsearch_install, new_resource) + es_conf = find_es_resource(run_context, :elasticsearch_configure, new_resource) + + d_r = directory es_conf.path_pid[es_install.type] do + owner es_user.username + group es_user.groupname + mode '0755' + recursive true + action :nothing + end + d_r.run_action(:create) + new_resource.updated_by_last_action(true) if d_r.updated_by_last_action? + + # Create service + # + init_r = template "/etc/init.d/#{new_resource.service_name}" do + source new_resource.init_source + cookbook new_resource.init_cookbook + owner 'root' + mode 0755 + variables( + # we need to include something about #{progname} fixed in here. + program_name: new_resource.service_name + ) + action :nothing + end + init_r.run_action(:create) + new_resource.updated_by_last_action(true) if init_r.updated_by_last_action? + + new_resource.service_actions.each do |act| + passthrough_action(act) + end + end + + # Passthrough actions to service[service_name] + # + action :enable do + passthrough_action(:enable) + end + + action :disable do + passthrough_action(:disable) + end + + action :start do + passthrough_action(:start) + end + + action :stop do + passthrough_action(:stop) + end + + action :restart do + passthrough_action(:restart) + end + + action :status do + passthrough_action(:status) + end + + def passthrough_action(action) + svc_r = lookup_service_resource + svc_r.run_action(action) + new_resource.updated_by_last_action(true) if svc_r.updated_by_last_action? + end + + def lookup_service_resource + rc = run_context.resource_collection + rc.find("service[#{new_resource.service_name}]") + rescue + service new_resource.service_name do + supports :status => true, :restart => true + action :nothing end end end diff --git a/libraries/provider_user.rb b/libraries/provider_user.rb index 3c32b9097..9c8a3f7fb 100644 --- a/libraries/provider_user.rb +++ b/libraries/provider_user.rb @@ -4,44 +4,44 @@ class ElasticsearchCookbook::UserProvider < Chef::Provider::LWRPBase provides :elasticsearch_user + def whyrun_supported? + false + end + action :create do - converge_by("create elasticsearch_user resource #{new_resource.name}") do - group_r = group new_resource.groupname do - gid new_resource.gid - action :nothing - system true - end - group_r.run_action(:create) - new_resource.updated_by_last_action(true) if group_r.updated_by_last_action? + group_r = group new_resource.groupname do + gid new_resource.gid + action :nothing + system true + end + group_r.run_action(:create) + new_resource.updated_by_last_action(true) if group_r.updated_by_last_action? - user_r = user new_resource.username do - comment new_resource.comment - shell new_resource.shell - uid new_resource.uid - gid new_resource.groupname - supports(manage_home: false) - action :nothing - system true - end - user_r.run_action(:create) - new_resource.updated_by_last_action(true) if user_r.updated_by_last_action? + user_r = user new_resource.username do + comment new_resource.comment + shell new_resource.shell + uid new_resource.uid + gid new_resource.groupname + supports(manage_home: false) + action :nothing + system true end + user_r.run_action(:create) + new_resource.updated_by_last_action(true) if user_r.updated_by_last_action? end action :remove do - converge_by("remove elasticsearch_user resource #{new_resource.name}") do - # delete user before deleting the group - user_r = user new_resource.username do - action :nothing - end - user_r.run_action(:remove) - new_resource.updated_by_last_action(true) if user_r.updated_by_last_action? + # delete user before deleting the group + user_r = user new_resource.username do + action :nothing + end + user_r.run_action(:remove) + new_resource.updated_by_last_action(true) if user_r.updated_by_last_action? - group_r = group new_resource.groupname do - action :nothing - end - group_r.run_action(:remove) - new_resource.updated_by_last_action(true) if group_r.updated_by_last_action? + group_r = group new_resource.groupname do + action :nothing end + group_r.run_action(:remove) + new_resource.updated_by_last_action(true) if group_r.updated_by_last_action? end end diff --git a/libraries/resource_configure.rb b/libraries/resource_configure.rb index 359bbaf9e..fdc57ede6 100644 --- a/libraries/resource_configure.rb +++ b/libraries/resource_configure.rb @@ -82,9 +82,16 @@ class ElasticsearchCookbook::ConfigureResource < Chef::Resource::LWRPBase # can't access node.name, so expect to have to set set this 'node.name' => Chef::Config[:node_name], - 'path.conf' => nil, # default "/usr/local/etc/elasticsearch" - 'path.data' => nil, # default "/usr/local/var/data/elasticsearch" - 'path.logs' => nil, # default "/usr/local/var/log/elasticsearch" + # if omitted or nil, these will be populated from attributes above + 'path.conf' => nil, # see path_conf above + 'path.data' => nil, # see path_data above + 'path.logs' => nil, # see path_logs above + + # Refer to ES documentation on how to configure these to a + # specific node role/type instead of using the defaults + # + # 'node.data' => ?, + # 'node.master' => ?, 'action.destructive_requires_name' => true, 'node.max_local_storage_nodes' => 1, @@ -97,7 +104,8 @@ class ElasticsearchCookbook::ConfigureResource < Chef::Resource::LWRPBase }) # These settings are merged with the `default_configuration` attribute, - # allowing you to override and set specific settings. + # allowing you to override and set specific settings. Unless you intend to + # wipe out all default settings, your configuration items should go here. # attribute(:configuration, kind_of: Hash, default: {}) end diff --git a/libraries/resource_install.rb b/libraries/resource_install.rb index ca6301269..5f6285f4e 100644 --- a/libraries/resource_install.rb +++ b/libraries/resource_install.rb @@ -15,7 +15,7 @@ class ElasticsearchCookbook::InstallResource < Chef::Resource::LWRPBase # we allow a string or symbol for this value attribute(:type, kind_of: [Symbol], - :equal_to => [:tarball, :package], default: :tarball) + :equal_to => [:tarball, :package], default: :package) # these use `attributes/default.rb` for default values per platform and install type attribute(:download_url, kind_of: String, default: nil) diff --git a/libraries/resource_plugin.rb b/libraries/resource_plugin.rb index b7cb8f568..0e93366b4 100644 --- a/libraries/resource_plugin.rb +++ b/libraries/resource_plugin.rb @@ -8,10 +8,10 @@ class ElasticsearchCookbook::PluginResource < Chef::Resource::LWRPBase actions(:install, :remove) default_action :install + # if the name or url are different from the resource name + attribute(:plugin_name, kind_of: String, name_attribute: true) + attribute(:url, kind_of: String, name_attribute: true) + # this is what helps the various resources find each other attribute(:instance_name, kind_of: String, default: nil) - - attribute(:plugin_name, kind_of: String, name_attribute: true) - attribute(:version, kind_of: String) - attribute(:url, kind_of: String) end diff --git a/libraries/resource_service.rb b/libraries/resource_service.rb index ca93497d8..c6466ff12 100644 --- a/libraries/resource_service.rb +++ b/libraries/resource_service.rb @@ -3,7 +3,10 @@ class ElasticsearchCookbook::ServiceResource < Chef::Resource::LWRPBase resource_name :elasticsearch_service provides :elasticsearch_service - actions(:configure, :remove) + actions( + :configure, :remove, # our custom actions + :enable, :disable, :start, :stop, :restart, :status # passthrough to service resource + ) default_action :configure # this is what helps the various resources find each other diff --git a/test/fixtures/cookbooks/elasticsearch_test/recipes/default_with_plugins.rb b/test/fixtures/cookbooks/elasticsearch_test/recipes/default_with_plugins.rb index 0ed356acc..d93d953a2 100644 --- a/test/fixtures/cookbooks/elasticsearch_test/recipes/default_with_plugins.rb +++ b/test/fixtures/cookbooks/elasticsearch_test/recipes/default_with_plugins.rb @@ -22,5 +22,8 @@ service_actions [:enable, :start] end -# by default, no plugins -elasticsearch_plugin 'mobz/elasticsearch-head' +# by default, no plugins, but we do one here. +elasticsearch_plugin 'head' do + url 'mobz/elasticsearch-head' + notifies :restart, 'elasticsearch_service[elasticsearch]', :delayed +end diff --git a/test/fixtures/cookbooks/elasticsearch_test/recipes/default.rb b/test/fixtures/cookbooks/elasticsearch_test/recipes/tarball.rb similarity index 100% rename from test/fixtures/cookbooks/elasticsearch_test/recipes/default.rb rename to test/fixtures/cookbooks/elasticsearch_test/recipes/tarball.rb