Page MenuHomeSoftware Heritage

No OneTemporary

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 65642a8..f19441d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,764 +1,765 @@
## x.x.x (Month Day, Year)
### Summary
#### Features
* Failures are no longer raised when no instances are defined for a plugin and service restarts are not requested.
* The `datadir` for instances can now be shared among multiple instances by using the `datadir_instance_directories` parameter.
* `repo_baseurl` is now exposed as a top-level parameter for users who wish to control custom repositories.
+* `elasticsearch-keystore` values can now be managed via native Puppet resources.
#### Fixes
## 5.2.0 (May 5, 2017)
### Summary
Release supporting several new features and bugfixes for 5.4.0 users and users who need the ability to update plugins.
#### Features
* Support for Shield/X-Pack logging configuration file added.
* The `elasticsearch::script` type now supports recursively managing directories of scripts.
* All module defined types can now be managed as top-level hash parameters to the `elasticsearch` class (primarily for hiera and PE)
#### Fixes
* Fixed a bug that prevented plugins from being updated properly.
* Fixed deprecated `default.path` options introduced in Elasticsearch 5.4.0.
## 5.1.1 (April 13, 2017)
### Summary
#### Features
* Instance configs now have highest precedence when constructing the final yaml
config file.
#### Fixes
This is a hotfix release to support users affected by [an upstream Elasticsearch issue](https://github.com/elastic/elasticsearch/issues/6887).
See the [associated issue](https://github.com/elastic/puppet-elasticsearch/issues/802#issuecomment-293295930) for details regarding the workaround.
The change implemented in this release is to place the `elasticsearch::instance` `config` parameter at the highest precedence when merging the final config yaml which permits users manually override `path.data` values.
## 5.1.0 (February 28, 2017)
### Summary
Ingest pipeline and index settings support.
Minor bugfixes.
#### Features
* Ingestion pipelines supported via custom resources.
* Index settings support.
#### Fixes
* Custom facts no longer fail when trying to read unreadable elasticsearch config files.
* `Accept` and `Content-Type` headers properly set for providers (to support ES 6.x)
## 5.0.0 (February 9, 2017)
Going forward, This module will follow Elasticsearch's upstream major version to indicate compatability.
That is, version 5.x of this module supports version 5 of Elasticsearch, and version 6.x of this module will be released once Elasticsearch 6 support is added.
### Summary
Note that this is a **major version release**!
Please read the release notes carefully before upgrading to avoid downtime/unexpected behavior.
Remember to restart any puppetmaster servers to clear provider caches and pull in updated code.
### Backwards-Incompatible Changes
* The `elasticsearch::shield::user` and `elasticsearch::shield::role` resources have been renamed to `elasticsearch::user` and `elasticsearch::role` since the resource now handles both Shield and X-Pack.
* Both Shield and X-Pack configuration files are kept in `/etc/elasticsearch/shield` and `/etc/elasticsearch/x-pack`, respectively. If you previously managed Shield resources with version 0.x of this module, you may need to migrate files from `/usr/share/elasticsearch/shield`.
* The default data directory has been changed to `/var/lib/elasticsearch`. If you used the previous default (the Elasticsearch home directory, `/usr/share/elasticsearch/data`), you may need to migrate your data.
* The first changes that may be Elasticsearch 1.x-incompatible have been introduced (see the [elasticsearch support lifecycle](https://www.elastic.co/support/eol)). This only impacts version 1.x running on systemd-based distributions.
* sysctl management has been removed (and the module removed as a dependency for this module), and puppet/yum is used in lieu of ceritsc/yum.
#### Features
* Support management of the global jvm.options configuration file.
* X-Pack support added.
* Restricted permissions to the elasticsearch.yml file.
* Deprecation log configuration support added.
* Synced systemd service file with upstream.
#### Bugfixes
* Fixed case in which index template could prepend an additional 'index.' to index settings.
* Fixed a case in which dependency cycles could arise when pinning packages on CentOS.
* No longer recursively change the Elasticsearch home directory's lib/ to the elasticsearch user.
* Unused defaults values now purged from instance init defaults files.
#### Changes
* Changed default data directory to /var/lib
* sysctl settings are no longer managed by the thias/sysctl module.
* Calls to `elasticsearch -version` in elasticsearch::plugin code replaced with native Puppet code to resolve Elasticsearch package version. Should improve resiliency when managing plugins.
* Shield and X-Pack configuration files are stored in /etc/elasticsearch instead of /usr/share/elasticsearch.
* Removed deprecated ceritsc/yum module in favor of puppet/yum.
#### Testing changes
## 0.15.1 (December 1, 2016)
### Summary
Primarily a bugfix release for Elasticsearch 5.x support-related issues.
Note updated minimum required puppet versions as well.
#### Features
#### Bugfixes
* Removed ES_HEAP_SIZE check in init scripts for Elasticsearch 5.x
* Changed sysctl value to a string to avoid type errors for some versions
* Fixed a $LOAD_PATH error that appeared in some cases for puppet_x/elastic/es_versioning
#### Changes
* Updated minimium required version for Puppet and PE to reflect tested versions and versions supported by Puppet Labs
#### Testing changes
## 0.15.0 (November 17, 2016)
### Summary
* Support for Ubuntu Xenial (16.04) formally declared.
* Initial support for running Elasticsearch 5.x series.
#### Features
* Support management of 5.x-style Elastic yum/apt package repositories.
* Support service scripts for 5.x series of Elasticsearch
#### Bugfixes
* Update the apt::source call to not cause deprecation warnings
* Updated module metadata to correctly require puppet-stdlib with validate_integer()
#### Changes
#### Testing changes
* Ubuntu Xenial (16.04) added to the test matrix.
## 0.14.0 (October 12, 2016)
### Summary
Primarily a bugfix release for issues related to plugin proxy functionality, various system service fixes, and directory permissions.
This release also adds the ability to define logging rolling file settings and a CA file/path for template API access.
#### Features
* Added 'file_rolling_type' parameter to allow selecting file logging rotation type between "dailyRollingFile" or "rollingFile". Also added 'daily_rolling_date_pattern', 'rolling_file_max_backup_index' and 'rolling_file_max_file_size' for file rolling customization.
#### Bugfixes
* Permissions on the Elasticsearch plugin directory have been fixed to permit world read rights.
* The service systemd unit now `Wants=` a network target to fix bootup parallelization problems.
* Recursively create the logdir for elasticsearch when creating multiple instances
* Files and directories with root ownership now specify UID/GID 0 instead to improve compatability with *BSDs.
* Elasticsearch Debian init file changed to avoid throwing errors when DATA_DIR, WORK_DIR and/or LOG_DIR were an empty variable.
* Fixed a broken File dependency when a plugin was set to absent and ::elasticsearch set to present.
* Fixed issue when using the `proxy` parameter on plugins in Elasticsearch 2.x.
#### Changes
* The `api_ca_file` and `api_ca_path` parameters have been added to support custom CA bundles for API access.
* Numerics in elasticsearch.yml will always be properly unquoted.
* puppetlabs/java is now listed as a dependency in metadata.json to avoid unexpected installation problems.
#### Testing changes
## 0.13.2 (August 29, 2016)
### Summary
Primarily a bugfix release to resolve HTTPS use in elasticsearch::template resources, 5.x plugin operations, and plugin file permission enforcement.
#### Features
* Plugin installation for the 5.x series of Elasticsearch is now properly supported.
#### Bugfixes
* Recursively enforce correct plugin directory mode to avoid Elasticsearch startup permissions errors.
* Fixed an edge case where dependency cycles could arise when managing absent resources.
* Elasticsearch templates now properly use HTTPS when instructed to do so.
#### Changes
* Updated the elasticsearch_template type to return more helpful error output.
* Updated the es_instance_conn_validator type to silence deprecation warnings in Puppet >= 4.
#### Testing changes
## 0.13.1 (August 8, 2016)
### Summary
Lingering bugfixes from elasticsearch::template changes.
More robust systemd mask handling.
Updated some upstream module parameters for deprecation warnings.
Support for the Shield `system_key` file.
#### Features
* Added `system_key` parameter to the `elasticsearch` class and `elasticsearch::instance` type for placing Shield system keys.
#### Bugfixes
* Fixed systemd elasticsearch.service unit masking to use systemctl rather than raw symlinking to avoid puppet file backup errors.
* Fixed a couple of cases that broke compatability with older versions of puppet (elasticsearch_template types on puppet versions prior to 3.6 and yumrepo parameters on puppet versions prior to 3.5.1)
* Fixed issues that caused templates to be incorrectly detected as out-of-sync and thus always changed on each puppet run.
* Resources are now explicitly ordered to ensure behavior such as plugins being installed before instance start, users managed before templates changed, etc.
#### Changes
* Updated repository gpg fingerprint key to long form to silence module warnings.
#### Testing changes
## 0.13.0 (August 1, 2016)
### Summary
Rewritten elasticsearch::template using native type and provider.
Fixed and added additional proxy parameters to elasticsearch::plugin instances.
Exposed repo priority parameters for apt and yum repos.
#### Features
* In addition to better consistency, the `elasticsearch::template` type now also accepts various `api_*` parameters to control how access to the Elasticsearch API is configured (there are top-level parameters that are inherited and can be overwritten in `elasticsearch::api_*`).
* The `elasticsearch::config` parameter now supports deep hiera merging.
* Added the `elasticsearch::repo_priority` parameter to support apt and yum repository priority configuration.
* Added `proxy_username` and `proxy_password` parameters to `elasticsearch::plugin`.
#### Bugfixes
* Content of templates should now properly trigger new API PUT requests when the index template stored in Elasticsearch differs from the template defined in puppet.
* Installing plugins with proxy parameters now works correctly due to changed Java property flags.
* The `elasticsearch::plugin::module_dir` parameter has been re-implemented to aid in working around plugins with non-standard plugin directories.
#### Changes
* The `file` parameter on the `elasticsearch::template` defined type has been deprecated to be consistent with usage of the `source` parameter for other types.
#### Testing changes
## 0.12.0 (July 20, 2016)
IMPORTANT! A bug was fixed that mistakenly added /var/lib to the list of DATA_DIR paths on Debian-based systems. This release removes that environment variable, which could potentially change path.data directories for instances of Elasticsearch. Take proper precautions when upgrading to avoid unexpected downtime or data loss (test module upgrades, et cetera).
### Summary
Rewritten yaml generator, code cleanup, and various bugfixes. Configuration file yaml no longer nested. Service no longer restarts by default, and exposes more granular restart options.
#### Features
* The additional parameters restart_config_change, restart_package_change, and restart_plugin_change have been added for more granular control over service restarts.
#### Bugfixes
* Special yaml cases such as arrays of hashes and strings like "::" are properly supported.
* Previous Debian SysV init scripts mistakenly set the `DATA_DIR` environment variable to a non-default value.
* Some plugins failed installation due to capitalization munging, the elasticsearch_plugin provider no longer forces downcasing.
#### Changes
* The `install_options` parameter on the `elasticsearch::plugin` type has been removed. This was an undocumented parameter that often caused problems for users.
* The `elasticsearch.service` systemd unit is no longer removed but masked by default, effectively hiding it from systemd but retaining the upstream vendor unit on disk for package management consistency.
* `restart_on_change` now defaults to false to reduce unexpected cluster downtime (can be set to true if desired).
* Package pinning is now contained within a separate class, so users can opt to manage package repositories manually and still use this module's pinning feature.
* All configuration hashes are now flattened into dot-notated yaml in the elasticsearch configuration file. This should be fairly transparent in terms of behavior, though the config file formatting will change.
#### Testing changes
* The acceptance test suite has been dramatically slimmed to cut down on testing time and reduce false positives.
## 0.11.0 ( May 23, 2016 )
### Summary
Shield support, SLES support, and overhauled testing setup.
#### Features
* Support for shield
* TLS Certificate management
* Users (role and password management for file-based realms)
* Roles (file-based with mapping support)
* Support (repository proxies)[https://github.com/elastic/puppet-elasticsearch/pull/615]
* Support for (SSL auth on API calls)[https://github.com/elastic/puppet-elasticsearch/pull/577]
#### Bugfixes
* (Fix Facter calls)[https://github.com/elastic/puppet-elasticsearch/pull/590] in custom providers
#### Changes
#### Testing changes
* Overhaul testing methodology, see CONTRIBUTING for updates
* Add SLES 12, Oracle 6, and PE 2016.1.1 to testing matrix
* Enforce strict variable checking
#### Known bugs
* This is the first release with Shield support, some untested edge cases may exist
##0.10.3 ( Feb 08, 2016 )
###Summary
Adding support for OpenBSD and minor fixes
####Features
* Add required changes to work with ES 2.2.x plugins
* Support for custom log directory
* Support for OpenBSD
####Bugfixes
* Add correct relation to file resource and plugin installation
* Notify service when upgrading the package
####Changes
* Remove plugin dir when upgrading Elasticsearch
####Testing changes
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.10.2 ( Jan 19, 2016 )
###Summary
Bugfix release and adding Gentoo support
####Features
* Added Gentoo support
####Bugfixes
* Create init script when set to unmanaged
* init_template variable was not passed on correctly to other classes / defines
* Fix issue with plugin type that caused run to stall
* Export ES_GC_LOG_FILE in init scripts
####Changes
* Improve documentation about init_defaults
* Update common files
* Removed recurse option on data directory management
* Add retry functionality to plugin type
####Testing changes
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.10.1 ( Dec 17, 2015 )
###Summary
Bugfix release for proxy functionality in plugin installation
####Features
####Bugfixes
* Proxy settings were not passed on correctly
####Changes
* Cleanup .pmtignore to exclude more files
####Testing changes
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.10.0 ( Dec 14, 2015 )
###Summary
Module now works with ES 2.x completely
####Features
* Work with ES 2.x new plugin system and remain to work with 1.x
* Implemented datacat module from Richard Clamp so other modules can hook into it for adding configuration options
* Fixed init and systemd files to work with 1.x and 2.x
* Made the module work with newer pl-apt module versions
* Export es_include so it is passed on to ES
* Ability to supply long gpg key for apt repo
####Bugfixes
* Documentation and typographical fixes
* Do not force puppet:/// schema resource
* Use package resource defaults rather than setting provider and source
####Changes
####Testing changes
* Improve unit testing and shorten the runtime
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.9.9 ( Sep 01, 2015 )
###Summary
Bugfix release and extra features
####Features
* Work with ES 2.x
* Add Java 8 detection in debian init script
* Improve offline plugin installation
####Bugfixes
* Fix a bug with new ruby versions but older puppet versions causing type error
* Fix config tempate to use correct ruby scoping
* Fix regex retrieving proxy port while downloading plugin
* Fix systemd template for better variable handling
* Template define was using wrong pathing for removal
####Changes
####Testing changes
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.9.8 ( Jul 07, 2015 )
###Summary
####Features
* Work with ES 2.x
####Bugfixes
* Fix plugin to maintain backwards compatibility
####Changes
####Testing changes
* ensure testing works with Puppet 4.x ( Rspec and Acceptance )
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.9.7 ( Jun 24, 2015 )
###Summary
This releases adds several important features and fixes an important plugin installation issue with ES 1.6 and higher.
####Features
* Automate plugin dir extraction
* use init service provider for Amazon Linux
* Add Puppetlabs/apt and ceritsc/yum as required modules
* Added Timeout to fetching facts in case ES does not respond
* Add proxy settings for package download
####Bugfixes
* Fixed systemd template to fix issue with LimitMEMLOCK setting
* Improve package version handling when specifying a version
* Add tmpfiles.d file to manage sub dir in /var/run path
* Fix plugin installations for ES 1.6 and higher
####Changes
* Removed Modulefile, only maintaining metadata.json file
####Testing changes
* Added unit testing for package pinning feature
* Added integration testing with Elasticsearch to find issues earlier
* Fix OpenSuse 13 testing
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.9.6 ( May 28, 2015 )
###Summary
Bugfix release 0.9.6
####Features
* Implemented package version pinning to avoid accidental upgrading
* Added support for Debian 8
* Added support for upgrading plugins
* Managing LimitNOFILE and LimitMEMLOCK settings in systemd
####Bugfixes
####Changes
* Dropped official support for PE 3.1.x and 3.2.x
####Testing changes
* Several testing changes implemented to increase coverage
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.9.5( Apr 16, 2015 )
###Summary
Bugfix release 0.9.5
We reverted the change that implemented the full 40 character for the apt repo key.
This caused issues with some older versions of the puppetlabs-apt module
####Features
####Bugfixes
* Revert using the full 40 character for the apt repo key.
####Changes
####Testing changes
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.9.4( Apr 14, 2015 )
###Summary
Bugfix release 0.9.4
####Features
* Add the ability to create and populate scripts
####Bugfixes
* add support for init_defaults_file to elasticsearch::instance
* Update apt key to full 40characters
####Changes
* Fix readme regarding module_dir with plugins
####Testing changes
* Adding staged removal test
* Convert git urls to https
* Add centos7 node config
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.9.3( Mar 24, 2015 )
###Summary
Bugfix release 0.9.3
####Features
####Bugfixes
* Not setting repo_version did not give the correct error
* Systemd file did not contain User/Group values
####Changes
* Brand rename from Elasticsearch to Elastic
####Testing changes
* Moved from multiple Gemfiles to single Gemfile
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.9.2( Mar 06, 2015 )
###Summary
Bugfix release 0.9.2
####Features
* Introducing es_instance_conn_validator resource to verify instance availability
####Bugfixes
* Fix missing data path when using the path config setting but not setting the data path
####Changes
None
####Testing changes
None
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.9.1 ( Feb 23, 2015 )
###Summary
This is the first bug fix release for 0.9 version.
A bug was reported with the recursive file management.
####Features
None
####Bugfixes
* Fix recursive file management
* Set undefined variables to work with strict_variables
####Changes
None
####Testing changes
None
####Known bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.9.0 ( Feb 02, 2015 )
###Summary
This release is the first one towards 1.0 release.
Our planning is to provide LTS releases with the puppet module
####Features
* Support for using hiera to define instances and plugins.
* Support for OpenSuSE 13.x
* Custom facts about the installed Elasticsearch instance(s)
* Proxy host/port support for the plugin installation
* Ability to supply a custom logging.yml template
####Bugfixes
* Ensure file owners are correct accross all related files
* Fix of possible service name conflict
* Empty main config would fail with instances
* Removal of standard files from packages we dont use
* Ensuring correct sequence of plugin and template defines
* Added ES_CLASSPATH export to init scripts
####Changes
* Java installation to use puppetlabs-java module
* Added Support and testing for Puppet 3.7 and PE 3.7
* Improve metadata.json based on scoring from Forge
####Testing changes
* Added testing against Puppet 3.7 and PE 3.7
* Using rspec3
* Using rspec-puppet-facts gem simplifies rspec testing
####Known Bugs
* Possible package conflicts when using ruby/python defines with main package name
##0.4.0 ( Jun 18, 2014 ) - Backwards compatible breaking release
###Summary
This release introduces instances to facilitate the option to have more then a single instance running on the host system.
####Features
* Rewrite module to incorperate multi instance support
* New readme layout
####Bugfixes
* None
####Changes
* Adding ec2-linux osfamily for repo management
* Retry behaviour for plugin installation
####Testing changes
* Adding Puppet 3.6.x testing
* Ubuntu 14.04 testing
* Using new docker images
* Pin rspec to 2.14.x
####Known Bugs
* No known bugs
##0.3.2 ( May 15, 2014 )
* Add support for SLC/Scientific Linux CERN ( PR #121 )
* Add support for custom package names ( PR #122 )
* Fix python and ruby client defines to avoid name clashes.
* Add ability to use stage instead of anchor for repo class
* Minor fixes to system tests
##0.3.1 ( April 22, 2014 )
* Ensure we create the plugin directory before installing plugins
* Added Puppet 3.5.x to rspec and system tests
##0.3.0 ( April 2, 2014 )
* Fix minor issue with yumrepo in repo class ( PR #92 )
* Implement OpenSuse support
* Implement Junit reporting for tests
* Adding more system tests and convert to Docker images
* Use Augeas for managing the defaults file
* Add retry to package download exec
* Add management to manage the logging.yml file
* Improve inline documentation
* Improve support for Debian 6
* Improve augeas for values with spaces
* Run plugin install as ES user ( PR #108 )
* Fix rights for the plugin directory
* Pin Rake for Ruby 1.8.7
* Adding new metadata for Forge.
* Increase time for retry to insert the template
##0.2.4 ( Feb 21, 2014 )
* Set puppetlabs-stdlib dependency version from 3.0.0 to 3.2.0 to be inline with other modules
* Let puppet run fail when template insert fails
* Documentation improvements ( PR #77, #78, #83 )
* Added beaker system tests
* Fixed template define after failing system tests
* Some fixes so variables are more inline with intended structure
##0.2.3 ( Feb 06, 2014 )
* Add repository management feature
* Improve testing coverage and implement basic resource coverage reporting
* Add puppet 3.4.x testing
* Fix dependency in template define ( PR #72 )
* For apt repo change from key server to key file
##0.2.2 ( Jan 23, 2014 )
* Ensure exec names are unique. This caused issues when using our logstash module
* Add spec tests for plugin define
##0.2.1 ( Jan 22, 2014 )
* Simplify the management of the defaults file ( PR #64 )
* Doc improvements for the plugin define ( PR #66 )
* Allow creation of data directory ( PR #68 )
* Fail early when package version and package_url are defined
##0.2.0 ( Nov 19, 2013 )
* Large rewrite of the entire module described below
* Make the core more dynamic for different service providers and multi instance capable
* Add better testing and devided into different files
* Fix template function. Replace of template is now only done when the file is changed
* Add different ways to install the package except from the repository ( puppet/http/https/ftp/file )
* Update java class to install openjdk 1.7
* Add tests for python function
* Update config file template to fix scoping issue ( from PR #57 )
* Add validation of templates
* Small changes for preperation for system tests
* Update readme for new functionality
* Added more test scenario's
* Added puppet parser validate task for added checking
* Ensure we don't add stuff when removing the module
* Update python client define
* Add ruby client define
* Add tests for ruby clients and update python client tests
##0.1.3 ( Sep 06, 2013 )
* Exec path settings has been updated to fix warnings ( PR #37, #47 )
* Adding define to install python bindings ( PR #43 )
* Scope deprecation fixes ( PR #41 )
* feature to install plugins ( PR #40 )
##0.1.2 ( Jun 21, 2013 )
* Update rake file to ignore the param inherit
* Added missing documentation to the template define
* Fix for template define to allow multiple templates ( PR #36 by Bruce Morrison )
##0.1.1 ( Jun 14, 2013 )
* Add Oracle Linux to the OS list ( PR #25 by Stas Alekseev )
* Respect the restart_on_change on the defaults ( PR #29 by Simon Effenberg )
* Make sure the config can be empty as advertised in the readme
* Remove dependency cycle when the defaults file is updated ( PR #31 by Bruce Morrison )
* Enable retry on the template insert in case ES isn't started yet ( PR #32 by Bruce Morrison )
* Update templates to avoid deprecation notice with Puppet 3.2.x
* Update template define to avoid auto insert issue with ES
* Update spec tests to reflect changes to template define
##0.1.0 ( May 09, 2013 )
* Populate .gitignore ( PR #19 by Igor Galić )
* Add ability to install initfile ( PR #20 by Justin Lambert )
* Add ability to manage default file service parameters ( PR #21 by Mathieu Bornoz )
* Providing complete containment of the module ( PR #24 by Brian Lalor )
* Add ability to specify package version ( PR #25 by Justin Lambert )
* Adding license file
##0.0.7 ( Mar 23, 2013 )
* Ensure config directory is created and managed ( PR #13 by Martin Seener )
* Dont backup package if it changes
* Create explicit dependency on template directory ( PR #16 by Igor Galić )
* Make the config directory variable ( PR #17 by Igor Galić and PR #18 by Vincent Janelle )
* Fixing template define
##0.0.6 ( Mar 05, 2013 )
* Fixing issue with configuration not printing out arrays
* New feature to write the config hash shorter
* Updated readme to reflect the new feature
* Adding spec tests for config file generation
##0.0.5 ( Mar 03, 2013 )
* Option to disable restart on config file change ( PR #10 by Chris Boulton )
##0.0.4 ( Mar 02, 2013 )
* Fixed a major issue with the config template ( Issue #9 )
##0.0.3 ( Mar 02, 2013 )
* Adding spec tests
* Fixed init issue on Ubuntu ( Issue #6 by Marcus Furlong )
* Fixed config template problem ( Issue #8 by surfchris )
* New feature to manage templates
##0.0.2 ( Feb 16, 2013 )
* Feature to supply a package instead of being dependent on the repository
* Feature to install java in case one doesn't manage it externally
* Adding RedHat and Amazon as Operating systems
* fixed a typo - its a shard not a shared :) ( PR #5 by Martin Seener )
##0.0.1 ( Jan 13, 2013 )
* Initial release of the module
diff --git a/README.md b/README.md
index aa1b030..03432fd 100644
--- a/README.md
+++ b/README.md
@@ -1,979 +1,1019 @@
# Elasticsearch Puppet Module
[![Puppet Forge endorsed](https://img.shields.io/puppetforge/e/elasticsearch/elasticsearch.svg)](https://forge.puppetlabs.com/elasticsearch/elasticsearch)
[![Puppet Forge Version](https://img.shields.io/puppetforge/v/elastic/elasticsearch.svg)](https://forge.puppetlabs.com/elastic/elasticsearch)
[![Puppet Forge Downloads](https://img.shields.io/puppetforge/dt/elastic/elasticsearch.svg)](https://forge.puppetlabs.com/elastic/elasticsearch)
#### Table of Contents
1. [Module description - What the module does and why it is useful](#module-description)
2. [Setup - The basics of getting started with Elasticsearch](#setup)
* [The module manages the following](#the-module-manages-the-following)
* [Requirements](#requirements)
3. [Usage - Configuration options and additional functionality](#usage)
4. [Advanced features - Extra information on advanced usage](#advanced-features)
5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
6. [Limitations - OS compatibility, etc.](#limitations)
7. [Development - Guide for contributing to the module](#development)
8. [Support - When you need help with this module](#support)
## Module description
This module sets up [Elasticsearch](https://www.elastic.co/overview/elasticsearch/) instances with additional resource for plugins, templates, and more.
This module is actively tested against Elasticsearch 2.x and 5.x.
## Setup
### The module manages the following
* Elasticsearch repository files.
* Elasticsearch package.
* Elasticsearch configuration file.
* Elasticsearch service.
* Elasticsearch plugins.
* Elasticsearch templates.
* Elasticsearch ingest pipelines.
* Elasticsearch index settings.
* Elasticsearch Shield/X-Pack users, roles, and certificates.
+* Elasticsearch keystores.
### Requirements
* The [stdlib](https://forge.puppetlabs.com/puppetlabs/stdlib) Puppet library.
* [puppet/yum](https://forge.puppetlabs.com/puppet/yum) For yum version lock.
* [richardc/datacat](https://forge.puppetlabs.com/richardc/datacat)
* [Augeas](http://augeas.net/)
* [puppetlabs-java](https://forge.puppetlabs.com/puppetlabs/java) for Java installation (optional).
* [puppetlabs-java_ks](https://forge.puppetlabs.com/puppetlabs/java_ks) for Shield/X-Pack certificate management (optional).
#### Repository management
When using the repository management, the following module dependencies are required:
* Debian/Ubuntu: [Puppetlabs/apt](http://forge.puppetlabs.com/puppetlabs/apt)
* OpenSuSE/SLES: [Darin/zypprepo](https://forge.puppetlabs.com/darin/zypprepo)
### Beginning with Elasticsearch
Declare the top-level `elasticsearch` class (managing repositories) and set up an instance:
```puppet
class { 'elasticsearch':
java_install => true,
manage_repo => true,
repo_version => '5.x',
}
elasticsearch::instance { 'es-01': }
```
**Note**: Elasticsearch 5.x requires a recent version of the JVM.
If you are on a recent version of your distribution of choice (such as Ubuntu 16.04 or CentOS 7), setting `java_install => true` will work out-of-the-box.
If you are on an earlier distribution, you may need to take additional measures to install Java 1.8.
## Usage
### Main class
Most top-level parameters in the `elasticsearch` class are set to reasonable defaults.
The following are some parameters that may be useful to override:
#### Install a specific version
```puppet
class { 'elasticsearch':
version => '1.4.2'
}
```
Note: This will only work when using the repository.
#### Automatically restarting the service (default set to false)
By default, the module will not restart Elasticsearch when the configuration file, package, or plugins change.
This can be overridden globally with the following option:
```puppet
class { 'elasticsearch':
restart_on_change => true
}
```
Or controlled with the more granular options: `restart_config_change`, `restart_package_change`, and `restart_plugin_change.`
#### Automatic upgrades (default set to false)
```puppet
class { 'elasticsearch':
autoupgrade => true
}
```
#### Removal/Decommissioning
```puppet
class { 'elasticsearch':
ensure => 'absent'
}
```
#### Install everything but disable service(s) afterwards
```puppet
class { 'elasticsearch':
status => 'disabled'
}
```
#### API Settings
Some resources, such as `elasticsearch::template`, require communicating with the Elasticsearch REST API.
By default, these API settings are set to:
```puppet
class { 'elasticsearch':
api_protocol => 'http',
api_host => 'localhost',
api_port => 9200,
api_timeout => 10,
api_basic_auth_username => undef,
api_basic_auth_password => undef,
api_ca_file => undef,
api_ca_path => undef,
validate_tls => true,
}
```
Each of these can be set at the top-level `elasticsearch` class and inherited for each resource or overridden on a per-resource basis.
#### Dynamically Created Resources
This module supports managing all of its defined types through top-level parameters to better support Hiera and Puppet Enterprise.
For example, to manage an instance and index template directly from the `elasticsearch` class:
```puppet
class { 'elasticsearch':
instances => {
'es-01' => {
'config' => {
'network.host' => '0.0.0.0'
}
}
},
templates => {
'logstash' => {
'content' => {
'template' => 'logstash-*',
'settings' => {
'number_of_replicas' => 0
}
}
}
}
}
```
### Instances
This module works with the concept of instances. For service to start you need to specify at least one instance.
#### Quick setup
```puppet
elasticsearch::instance { 'es-01': }
```
This will set up its own data directory and set the node name to `$hostname-$instance_name`
#### Advanced options
Instance specific options can be given:
```puppet
elasticsearch::instance { 'es-01':
config => { }, # Configuration hash
init_defaults => { }, # Init defaults hash
datadir => [ ], # Data directory
}
```
See [Advanced features](#advanced-features) for more information.
### Plugins
This module can help manage [a variety of plugins](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/modules-plugins.html#known-plugins).
Note that `module_dir` is where the plugin will install itself to and must match that published by the plugin author; it is not where you would like to install it yourself.
#### From an official repository
```puppet
elasticsearch::plugin { 'lmenezes/elasticsearch-kopf':
instances => 'instance_name'
}
```
#### From a custom url
```puppet
elasticsearch::plugin { 'jetty':
url => 'https://oss-es-plugins.s3.amazonaws.com/elasticsearch-jetty/elasticsearch-jetty-1.2.1.zip',
instances => 'instance_name'
}
```
#### Using a proxy
You can also use a proxy if required by setting the `proxy_host` and `proxy_port` options:
```puppet
elasticsearch::plugin { 'lmenezes/elasticsearch-kopf',
instances => 'instance_name',
proxy_host => 'proxy.host.com',
proxy_port => 3128
}
```
Proxies that require usernames and passwords are similarly supported with the `proxy_username` and `proxy_password` parameters.
Plugin name formats that are supported include:
* `elasticsearch/plugin/version` (for official elasticsearch plugins downloaded from download.elastic.co)
* `groupId/artifactId/version` (for community plugins downloaded from maven central or OSS Sonatype)
* `username/repository` (for site plugins downloaded from github master)
#### Upgrading plugins
When you specify a certain plugin version, you can upgrade that plugin by specifying the new version.
```puppet
elasticsearch::plugin { 'elasticsearch/elasticsearch-cloud-aws/2.1.1': }
```
And to upgrade, you would simply change it to
```puppet
elasticsearch::plugin { 'elasticsearch/elasticsearch-cloud-aws/2.4.1': }
```
Please note that this does not work when you specify 'latest' as a version number.
#### ES 2.x official plugins
For the Elasticsearch commercial plugins you can refer them to the simple name.
See [Plugin installation](https://www.elastic.co/guide/en/elasticsearch/plugins/current/installation.html) for more details.
### Scripts
Installs [scripts](http://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting.html) to be used by Elasticsearch.
These scripts are shared across all defined instances on the same host.
```puppet
elasticsearch::script { 'myscript':
ensure => 'present',
source => 'puppet:///path/to/my/script.groovy'
}
```
Script directories can also be recursively managed for large collections of scripts:
```puppet
elasticsearch::script { 'myscripts_dir':
ensure => 'directory,
source => 'puppet:///path/to/myscripts_dir'
recurse => 'remote',
}
```
### Templates
By default templates use the top-level `elasticsearch::api_*` settings to communicate with Elasticsearch.
The following is an example of how to override these settings:
```puppet
elasticsearch::template { 'templatename':
api_protocol => 'https',
api_host => $::ipaddress,
api_port => 9201,
api_timeout => 60,
api_basic_auth_username => 'admin',
api_basic_auth_password => 'adminpassword',
api_ca_file => '/etc/ssl/certs',
api_ca_path => '/etc/pki/certs',
validate_tls => false,
source => 'puppet:///path/to/template.json',
}
```
#### Add a new template using a file
This will install and/or replace the template in Elasticsearch:
```puppet
elasticsearch::template { 'templatename':
source => 'puppet:///path/to/template.json',
}
```
#### Add a new template using content
This will install and/or replace the template in Elasticsearch:
```puppet
elasticsearch::template { 'templatename':
content => {
'template' => "*",
'settings' => {
'number_of_replicas' => 0
}
}
}
```
Plain JSON strings are also supported.
```puppet
elasticsearch::template { 'templatename':
content => '{"template":"*","settings":{"number_of_replicas":0}}'
}
```
#### Delete a template
```puppet
elasticsearch::template { 'templatename':
ensure => 'absent'
}
```
### Ingestion Pipelines
Pipelines behave similar to templates in that their contents can be controlled
over the Elasticsearch REST API with a custom Puppet resource.
API parameters follow the same rules as templates (those settings can either be
controlled at the top-level in the `elasticsearch` class or set per-resource).
#### Adding a new pipeline
This will install and/or replace an ingestion pipeline in Elasticsearch
(ingestion settings are compared against the present configuration):
```puppet
elasticsearch::pipeline { 'addfoo':
content => {
'description' => 'Add the foo field',
'processors' => [{
'set' => {
'field' => 'foo',
'value' => 'bar'
}
}]
}
}
```
#### Delete a pipeline
```puppet
elasticsearch::pipeline { 'addfoo':
ensure => 'absent'
}
```
### Index Settings
This module includes basic support for ensuring an index is present or absent
with optional index settings.
API access settings follow the pattern previously mentioned for templates.
#### Creating an index
At the time of this writing, only index settings are supported.
Note that some settings (such as `number_of_shards`) can only be set at index
creation time.
```puppet
elasticsearch::index { 'foo':
settings => {
'index' => {
'number_of_replicas' => 0
}
}
}
```
#### Delete an index
```puppet
elasticsearch::index { 'foo':
ensure => 'absent'
}
```
### Bindings/Clients
Install a variety of [clients/bindings](http://www.elasticsearch.org/guide/en/elasticsearch/client/community/current/clients.html):
#### Python
```puppet
elasticsearch::python { 'rawes': }
```
#### Ruby
```puppet
elasticsearch::ruby { 'elasticsearch': }
```
### Connection Validator
This module offers a way to make sure an instance has been started and is up and running before
doing a next action. This is done via the use of the `es_instance_conn_validator` resource.
```puppet
es_instance_conn_validator { 'myinstance' :
server => 'es.example.com',
port => '9200',
}
```
A common use would be for example :
```puppet
class { 'kibana4' :
require => Es_Instance_Conn_Validator['myinstance'],
}
```
### Package installation
There are two different ways of installing Elasticsearch:
#### Repository
This option allows you to use an existing repository for package installation.
The `repo_version` corresponds with the `major.minor` version of Elasticsearch for versions before 2.x.
```puppet
class { 'elasticsearch':
manage_repo => true,
repo_version => '1.4',
}
```
For 2.x versions of Elasticsearch, use `repo_version => '2.x'`.
```puppet
class { 'elasticsearch':
manage_repo => true,
repo_version => '2.x',
}
```
For users who may wish to install via a local repository (for example, through a mirror), the `repo_baseurl` parameter is available:
```puppet
class { 'elasticsearch':
manage_repo => true,
repo_baseurl => 'https://repo.local/yum'
}
```
#### Remote package source
When a repository is not available or preferred you can install the packages from a remote source:
##### http/https/ftp
```puppet
class { 'elasticsearch':
package_url => 'https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.4.2.deb',
proxy_url => 'http://proxy.example.com:8080/',
}
```
Setting `proxy_url` to a location will enable download using the provided proxy
server.
This parameter is also used by `elasticsearch::plugin`.
Setting the port in the `proxy_url` is mandatory.
`proxy_url` defaults to `undef` (proxy disabled).
##### puppet://
```puppet
class { 'elasticsearch':
package_url => 'puppet:///path/to/elasticsearch-1.4.2.deb'
}
```
##### Local file
```puppet
class { 'elasticsearch':
package_url => 'file:/path/to/elasticsearch-1.4.2.deb'
}
```
### Java installation
Most sites will manage Java separately; however, this module can attempt to install Java as well.
This is done by using the [puppetlabs-java](https://forge.puppetlabs.com/puppetlabs/java) module.
```puppet
class { 'elasticsearch':
java_install => true
}
```
Specify a particular Java package/version to be installed:
```puppet
class { 'elasticsearch':
java_install => true,
java_package => 'packagename'
}
```
When configuring Elasticsearch's memory usage, you can do so by either changing init defaults for Elasticsearch 1.x/2.x (see the [following example](#hash-representation)), or modify it globally in 5.x using `jvm.options`:
```puppet
class { 'elasticsearch':
jvm_options => [
'-Xms4g',
'-Xmx4g'
]
}
```
### Service management
Currently only the basic SysV-style [init](https://en.wikipedia.org/wiki/Init) and [Systemd](http://en.wikipedia.org/wiki/Systemd) service providers are supported, but other systems could be implemented as necessary (pull requests welcome).
#### Defaults File
The *defaults* file (`/etc/defaults/elasticsearch` or `/etc/sysconfig/elasticsearch`) for the Elasticsearch service can be populated as necessary.
This can either be a static file resource or a simple key value-style [hash](http://docs.puppetlabs.com/puppet/latest/reference/lang_datatypes.html#hashes) object, the latter being particularly well-suited to pulling out of a data source such as Hiera.
##### File source
```puppet
class { 'elasticsearch':
init_defaults_file => 'puppet:///path/to/defaults'
}
```
##### Hash representation
```puppet
$config_hash = {
'ES_HEAP_SIZE' => '30g',
}
class { 'elasticsearch':
init_defaults => $config_hash
}
```
Note: `init_defaults` hash can be passed to the main class and to the instance.
## Advanced features
### X-Pack/Shield
[X-Pack](https://www.elastic.co/products/x-pack) and [Shield](https://www.elastic.co/products/shield) file-based users, roles, and certificates can be managed by this module.
**Note**: If you are planning to use these features, it is *highly recommended* you read the following documentation to understand the caveats and extent of the resources available to you.
#### Getting Started
Although this module can handle several types of Shield/X-Pack resources, you are expected to manage the plugin installation and versions for your deployment.
For example, the following manifest will install Elasticseach with a single instance running X-Pack:
```puppet
class { 'elasticsearch':
java_install => true,
manage_repo => true,
repo_version => '5.x',
security_plugin => 'x-pack',
}
elasticsearch::instance { 'es-01': }
elasticsearch::plugin { 'x-pack': instances => 'es-01' }
```
The following manifest will do the same, but with Shield:
```puppet
class { 'elasticsearch':
java_install => true,
manage_repo => true,
repo_version => '2.x',
security_plugin => 'shield',
}
elasticsearch::instance { 'es-01': }
Elasticsearch::Plugin { instances => ['es-01'], }
elasticsearch::plugin { 'license': }
elasticsearch::plugin { 'shield': }
```
The following examples will assume the preceding resources are part of your puppet manifest.
#### Roles
Roles in the file realm (the `esusers` realm in Shield) can be managed using the `elasticsearch::role` type.
For example, to create a role called `myrole`, you could use the following resource in X-Pack:
```puppet
elasticsearch::role { 'myrole':
privileges => {
'cluster' => [ 'monitor' ],
'indices' => [{
'names' => [ '*' ],
'privileges' => [ 'read' ],
}]
}
}
```
And in Shield:
```puppet
elasticsearch::role { 'myrole':
privileges => {
'cluster' => 'monitor',
'indices' => {
'*' => 'read'
}
}
}
```
This role would grant users access to cluster monitoring and read access to all indices.
See the [Shield](https://www.elastic.co/guide/en/shield/index.html) or [X-Pack](https://www.elastic.co/guide/en/x-pack/current/xpack-security.html) documentation for your version to determine what `privileges` to use and how to format them (the Puppet hash representation will simply be translated into yaml.)
**Note**: The Puppet provider for `esusers`/`users` has fine-grained control over the `roles.yml` file and thus will leave the default roles Shield installs in-place.
If you would like to explicitly purge the default roles (leaving only roles managed by puppet), you can do so by including the following in your manifest:
```puppet
resources { 'elasticsearch_role':
purge => true,
}
```
##### Mappings
Associating mappings with a role for file-based management is done by passing an array of strings to the `mappings` parameter of the `elasticsearch::role` type.
For example, to define a role with mappings:
```puppet
elasticsearch::role { 'logstash':
mappings => [
'cn=group,ou=devteam',
],
privileges => {
'cluster' => 'manage_index_templates',
'indices' => [{
'names' => ['logstash-*'],
'privileges' => [
'write',
'delete',
'create_index',
],
}],
},
}
```
**Note**: Observe the brackets around `indices` in the preceding role definition; which is an array of hashes per the format in Shield 2.3.x. Follow the documentation to determine the correct formatting for your version of Shield or X-Pack.
If you'd like to keep the mappings file purged of entries not under Puppet's control, you should use the following `resources` declaration because mappings are a separate low-level type:
```puppet
resources { 'elasticsearch_role_mapping':
purge => true,
}
```
#### Users
Users can be managed using the `elasticsearch::user` type.
For example, to create a user `mysuser` with membership in `myrole`:
```puppet
elasticsearch::user { 'myuser':
password => 'mypassword',
roles => ['myrole'],
}
```
The `password` parameter will also accept password hashes generated from the `esusers`/`users` utility and ensure the password is kept in-sync with the Shield `users` file for all Elasticsearch instances.
```puppet
elasticsearch::user { 'myuser':
password => '$2a$10$IZMnq6DF4DtQ9c4sVovgDubCbdeH62XncmcyD1sZ4WClzFuAdqspy',
roles => ['myrole'],
}
```
**Note**: When using the `esusers`/`users` provider (the default for plaintext passwords), Puppet has no way to determine whether the given password is in-sync with the password hashed by Shield/X-Pack.
In order to work around this, the `elasticsearch::user` resource has been designed to accept refresh events in order to update password values.
This is not ideal, but allows you to instruct the resource to change the password when needed.
For example, to update the aforementioned user's password, you could include the following your manifest:
```puppet
notify { 'update password': } ~>
elasticsearch::user { 'myuser':
password => 'mynewpassword',
roles => ['myrole'],
}
```
#### Certificates
SSL/TLS can be enabled by providing an `elasticsearch::instance` type with paths to the certificate and private key files, and a password for the keystore.
```puppet
elasticsearch::instance { 'es-01':
ssl => true,
ca_certificate => '/path/to/ca.pem',
certificate => '/path/to/cert.pem',
private_key => '/path/to/key.pem',
keystore_password => 'keystorepassword',
}
```
**Note**: Setting up a proper CA and certificate infrastructure is outside the scope of this documentation, see the aforementioned Shield or X-Pack guide for more information regarding the generation of these certificate files.
The module will set up a keystore file for the node to use and set the relevant options in `elasticsearch.yml` to enable TLS/SSL using the certificates and key provided.
#### System Keys
Shield/X-Pack system keys can be passed to the module, where they will be placed into individual instance configuration directories.
This can be set at the `elasticsearch` class and inherited across all instances:
```puppet
class { 'elasticsearch':
system_key => 'puppet:///path/to/key',
}
```
Or set on a per-instance basis:
```puppet
elasticsearch::instance { 'es-01':
system_key => '/local/path/to/key',
}
```
### Package version pinning
The module supports pinning the package version to avoid accidental upgrades that are not done by Puppet.
To enable this feature:
```puppet
class { 'elasticsearch':
package_pin => true,
version => '1.5.2',
}
```
In this example we pin the package version to 1.5.2.
### Data directories
There are several different ways of setting data directories for Elasticsearch.
In every case the required configuration options are placed in the `elasticsearch.yml` file.
#### Default
By default we use:
/usr/share/elasticsearch/data/$instance_name
Which provides a data directory per instance.
#### Single global data directory
```puppet
class { 'elasticsearch':
datadir => '/var/lib/elasticsearch-data'
}
```
Creates the following for each instance:
/var/lib/elasticsearch-data/$instance_name
#### Multiple Global data directories
```puppet
class { 'elasticsearch':
datadir => [ '/var/lib/es-data1', '/var/lib/es-data2']
}
```
Creates the following for each instance:
`/var/lib/es-data1/$instance_name`
and
`/var/lib/es-data2/$instance_name`.
#### Single instance data directory
```puppet
class { 'elasticsearch': }
elasticsearch::instance { 'es-01':
datadir => '/var/lib/es-data-es01'
}
```
Creates the following for this instance:
/var/lib/es-data-es01
#### Multiple instance data directories
```puppet
class { 'elasticsearch': }
elasticsearch::instance { 'es-01':
datadir => ['/var/lib/es-data1-es01', '/var/lib/es-data2-es01']
}
```
Creates the following for this instance:
`/var/lib/es-data1-es01`
and
`/var/lib/es-data2-es01`.
#### Shared global data directories
In some cases, you may want to share a top-level data directory among multiple instances.
```puppet
class { 'elasticsearch':
datadir_instance_directories => false,
config => {
'node.max_local_storage_nodes' => 2
}
}
elasticsearch::instance { 'es-01': }
elasticsearch::instance { 'es-02': }
```
Will result in the following directories created by Elasticsearch at runtime:
/var/lib/elasticsearch/nodes/0
/var/lib/elasticsearch/nodes/1
See [the Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#max-local-storage-nodes) for additional information regarding this configuration.
### Main and instance configurations
The `config` option in both the main class and the instances can be configured to work together.
The options in the `instance` config hash will merged with the ones from the main class and override any duplicates.
#### Simple merging
```puppet
class { 'elasticsearch':
config => { 'cluster.name' => 'clustername' }
}
elasticsearch::instance { 'es-01':
config => { 'node.name' => 'nodename' }
}
elasticsearch::instance { 'es-02':
config => { 'node.name' => 'nodename2' }
}
```
This example merges the `cluster.name` together with the `node.name` option.
#### Overriding
When duplicate options are provided, the option in the instance config overrides the ones from the main class.
```puppet
class { 'elasticsearch':
config => { 'cluster.name' => 'clustername' }
}
elasticsearch::instance { 'es-01':
config => { 'node.name' => 'nodename', 'cluster.name' => 'otherclustername' }
}
elasticsearch::instance { 'es-02':
config => { 'node.name' => 'nodename2' }
}
```
This will set the cluster name to `otherclustername` for the instance `es-01` but will keep it to `clustername` for instance `es-02`
#### Configuration writeup
The `config` hash can be written in 2 different ways:
##### Full hash writeup
Instead of writing the full hash representation:
```puppet
class { 'elasticsearch':
config => {
'cluster' => {
'name' => 'ClusterName',
'routing' => {
'allocation' => {
'awareness' => {
'attributes' => 'rack'
}
}
}
}
}
}
```
##### Short hash writeup
```puppet
class { 'elasticsearch':
config => {
'cluster' => {
'name' => 'ClusterName',
'routing.allocation.awareness.attributes' => 'rack'
}
}
}
```
+#### Keystore Settings
+
+Recent versions of Elasticsearch include the [elasticsearch-keystore](https://www.elastic.co/guide/en/elasticsearch/reference/current/secure-settings.html) utility to create and manage the `elasticsearch.keystore` file which can store sensitive values for certain settings.
+The settings and values for this file can be controlled by this module.
+Settings follow the behavior of the `config` parameter for the top-level Elasticsearch class and `elasticsearch::instance` defined types.
+That is, you may define keystore settings globally, and all values will be merged with instance-specific settings for final inclusion in the `elasticsearch.keystore` file.
+Note that each hash key is passed to the `elasticsearch-keystore` utility in a straightforward manner, so you should specify the hash passed to `secrets` in flattened form (that is, without full nested hash representation).
+
+For example, to define cloud plugin credentials for all instances:
+
+```puppet
+class { 'elasticsearch':
+ secrets => {
+ 'cloud.aws.access_key' => 'AKIA....',
+ 'cloud.aws.secret_key' => 'AKIA....',
+ }
+}
+```
+
+Or, to instead control these settings for a single instance:
+
+```puppet
+elasticsearch::instance { 'es-01':
+ secrets => {
+ 'cloud.aws.access_key' => 'AKIA....',
+ 'cloud.aws.secret_key' => 'AKIA....',
+ }
+}
+```
+
+##### Purging Secrets
+
+By default, if a secret setting exists on-disk that is not present in the `secrets` hash, this module will leave it intact.
+If you prefer to keep only secrets in the keystore that are specified in the `secrets` hash, use the `purge_secrets` boolean parameter either on the `elasticsearch` class to set it globally or per-instance.
+
+##### Notifying Services
+
+Any changes to keystore secrets will notify running elasticsearch services by respecting the `restart_on_change` and `restart_config_change` parameters.
+
## Limitations
This module is built upon and tested against the versions of Puppet listed in
the metadata.json file (i.e. the listed compatible versions on the Puppet
Forge).
The module has been tested on:
* Debian 7/8
* CentOS 6/7
* OracleLinux 6/7
* Ubuntu 14.04, 16.04
* OpenSuSE 42.x
* SLES 12
Other distro's that have been reported to work:
* RHEL 6
* Scientific 6
Testing on other platforms has been light and cannot be guaranteed.
## Development
Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for instructions regarding development environments and testing.
## Support
Need help? Join us in [#elasticsearch](https://webchat.freenode.net?channels=%23elasticsearch) on Freenode IRC or on the [discussion forum](https://discuss.elastic.co/).
diff --git a/lib/puppet/provider/elasticsearch_keystore/elasticsearch_keystore.rb b/lib/puppet/provider/elasticsearch_keystore/elasticsearch_keystore.rb
new file mode 100644
index 0000000..f252bbb
--- /dev/null
+++ b/lib/puppet/provider/elasticsearch_keystore/elasticsearch_keystore.rb
@@ -0,0 +1,161 @@
+Puppet::Type.type(:elasticsearch_keystore).provide(
+ :elasticsearch_keystore
+) do
+ desc 'Provider for `elasticsearch-keystore` based secret management.'
+
+ def self.defaults_dir
+ @defaults_dir ||= case Facter.value('osfamily')
+ when 'RedHat'
+ '/etc/sysconfig'
+ else
+ '/etc/default'
+ end
+ end
+
+ def self.home_dir
+ @home_dir ||= case Facter.value('osfamily')
+ when 'OpenBSD'
+ '/usr/local/elasticsearch'
+ else
+ '/usr/share/elasticsearch'
+ end
+ end
+
+ attr_accessor :defaults_dir, :home_dir
+
+ commands :keystore => "#{home_dir}/bin/elasticsearch-keystore"
+
+ def self.run_keystore(args, instance, stdin = nil)
+ options = {
+ :custom_environment => {
+ 'ES_INCLUDE' => File.join(defaults_dir, "elasticsearch-#{instance}")
+ },
+ :uid => 'elasticsearch',
+ :gid => 'elasticsearch'
+ }
+
+ unless stdin.nil?
+ stdinfile = Tempfile.new('elasticsearch-keystore')
+ stdinfile << stdin
+ stdinfile.flush
+ options[:stdinfile] = stdinfile.path
+ end
+
+ begin
+ stdout = execute([command(:keystore)] + args, options)
+ ensure
+ unless stdin.nil?
+ stdinfile.close
+ stdinfile.unlink
+ end
+ end
+
+ stdout.exitstatus.zero? ? stdout : raise(Puppet::Error, stdout)
+ end
+
+ def self.present_keystores
+ Dir[File.join(%w[/ etc elasticsearch *])].select do |directory|
+ File.exist? File.join(directory, 'elasticsearch.keystore')
+ end.map do |instance|
+ settings = run_keystore(['list'], File.basename(instance)).split("\n")
+ {
+ :name => File.basename(instance),
+ :ensure => :present,
+ :provider => name,
+ :settings => settings
+ }
+ end
+ end
+
+ def self.instances
+ present_keystores.map do |keystore|
+ new keystore
+ end
+ end
+
+ def self.prefetch(resources)
+ instances.each do |prov|
+ if (resource = resources[prov.name])
+ resource.provider = prov
+ end
+ end
+ end
+
+ def initialize(value = {})
+ super(value)
+ @property_flush = {}
+ end
+
+ def flush
+ case @property_flush[:ensure]
+ when :present
+ debug(self.class.run_keystore(['create'], resource[:name]))
+ @property_flush[:settings] = resource[:settings]
+ when :absent
+ File.delete(File.join([
+ '/', 'etc', 'elasticsearch', resource[:instance], 'elasticsearch.keystore'
+ ]))
+ end
+
+ # Note that since the property is :array_matching => :all, we have to
+ # expect that the hash is wrapped in an array.
+ if @property_flush[:settings] and not @property_flush[:settings].first.empty?
+ # Flush properties that _should_ be present
+ @property_flush[:settings].first.each_pair do |setting, value|
+ next unless @property_hash[:settings].nil? \
+ or not @property_hash[:settings].include? setting
+ debug(self.class.run_keystore(
+ ['add', '--force', '--stdin', setting], resource[:name], value
+ ))
+ end
+
+ # Remove properties that are no longer present
+ if resource[:purge] and not (@property_hash.nil? or @property_hash[:settings].nil?)
+ (@property_hash[:settings] - @property_flush[:settings].first.keys).each do |setting|
+ debug(self.class.run_keystore(
+ ['remove', setting], resource[:name]
+ ))
+ end
+ end
+ end
+
+ @property_hash = self.class.present_keystores.detect do |u|
+ u[:name] == resource[:name]
+ end
+ end
+
+ # settings property setter
+ #
+ # @return [Hash] settings
+ def settings=(new_settings)
+ @property_flush[:settings] = new_settings
+ end
+
+ # settings property getter
+ #
+ # @return [Hash] settings
+ def settings
+ @property_hash[:settings]
+ end
+
+ # Sets the ensure property in the @property_flush hash.
+ #
+ # @return [Symbol] :present
+ def create
+ @property_flush[:ensure] = :present
+ end
+
+ # Determine whether this resource is present on the system.
+ #
+ # @return [Boolean]
+ def exists?
+ @property_hash[:ensure] == :present
+ end
+
+ # Set flushed ensure property to absent.
+ #
+ # @return [Symbol] :absent
+ def destroy
+ @property_flush[:ensure] = :absent
+ end
+end
diff --git a/lib/puppet/type/elasticsearch_keystore.rb b/lib/puppet/type/elasticsearch_keystore.rb
new file mode 100644
index 0000000..36c333a
--- /dev/null
+++ b/lib/puppet/type/elasticsearch_keystore.rb
@@ -0,0 +1,58 @@
+require 'puppet/parameter/boolean'
+
+Puppet::Type.newtype(:elasticsearch_keystore) do
+ desc 'Manages an Elasticsearch keystore settings file.'
+
+ ensurable do
+ defaultvalues
+ defaultto :present
+ end
+
+ newparam(:instance, :namevar => true) do
+ desc 'Elasticsearch instance this keystore belongs to.'
+ end
+
+ newparam(:purge, :boolean => true, :parent => Puppet::Parameter::Boolean) do
+ desc <<-EOS
+ Whether to proactively remove settings that exist in the keystore but
+ are not present in this resource's settings.
+ EOS
+
+ defaultto false
+ end
+
+ newproperty(:settings, :array_matching => :all) do
+ desc 'A key/value hash of settings names and values.'
+
+ # The keystore utility can only retrieve a list of stored settings,
+ # so here we only compare the existing settings (sorted) with the
+ # desired settings' keys
+ def insync?(is)
+ if resource[:purge]
+ is.sort == @should.first.keys.sort
+ else
+ (@should.first.keys - is).empty?
+ end
+ end
+
+ def change_to_s(currentvalue, newvalue_raw)
+ ret = ''
+
+ newvalue = newvalue_raw.first.keys
+
+ added_settings = newvalue - currentvalue
+ ret << "added: #{added_settings.join(', ')} " unless added_settings.empty?
+
+ removed_settings = currentvalue - newvalue
+ unless removed_settings.empty?
+ if resource[:purge]
+ ret << "removed: #{removed_settings.join(', ')}"
+ else
+ ret << "would have removed: #{removed_settings.join(', ')}, but purging is disabled"
+ end
+ end
+
+ ret
+ end
+ end
+end
diff --git a/manifests/init.pp b/manifests/init.pp
index 649f716..61531d5 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -1,897 +1,915 @@
# == Class: elasticsearch
#
# This class is able to install or remove elasticsearch on a node.
# It manages the status of the related service.
#
# === Parameters
#
# [*ensure*]
# String. Controls if the managed resources shall be <tt>present</tt> or
# <tt>absent</tt>. If set to <tt>absent</tt>:
# * The managed software packages are being uninstalled.
# * Any traces of the packages will be purged as good as possible. This may
# include existing configuration files. The exact behavior is provider
# dependent. Q.v.:
# * Puppet type reference: {package, "purgeable"}[http://j.mp/xbxmNP]
# * {Puppet's package provider source code}[http://j.mp/wtVCaL]
# * System modifications (if any) will be reverted as good as possible
# (e.g. removal of created users, services, changed log settings, ...).
# * This is thus destructive and should be used with care.
# Defaults to <tt>present</tt>.
#
# [*autoupgrade*]
# Boolean. If set to <tt>true</tt>, any managed package gets upgraded
# on each Puppet run when the package provider is able to find a newer
# version than the present one. The exact behavior is provider dependent.
# Q.v.:
# * Puppet type reference: {package, "upgradeable"}[http://j.mp/xbxmNP]
# * {Puppet's package provider source code}[http://j.mp/wtVCaL]
# Defaults to <tt>false</tt>.
#
# [*status*]
# String to define the status of the service. Possible values:
# * <tt>enabled</tt>: Service is running and will be started at boot time.
# * <tt>disabled</tt>: Service is stopped and will not be started at boot
# time.
# * <tt>running</tt>: Service is running but will not be started at boot time.
# You can use this to start a service on the first Puppet run instead of
# the system startup.
# * <tt>unmanaged</tt>: Service will not be started at boot time and Puppet
# does not care whether the service is running or not. For example, this may
# be useful if a cluster management software is used to decide when to start
# the service plus assuring it is running on the desired node.
# Defaults to <tt>enabled</tt>. The singular form ("service") is used for the
# sake of convenience. Of course, the defined status affects all services if
# more than one is managed (see <tt>service.pp</tt> to check if this is the
# case).
#
# [*version*]
# String to set the specific version you want to install.
# Defaults to <tt>false</tt>.
#
# [*restart_on_change*]
# Boolean that determines if the application should be automatically restarted
# whenever the configuration, package, or plugins change. Enabling this
# setting will cause Elasticsearch to restart whenever there is cause to
# re-read configuration files, load new plugins, or start the service using an
# updated/changed executable. This may be undesireable in highly available
# environments.
#
# If all other restart_* parameters are left unset, the value of
# restart_on_change is used for all other restart_*_change defaults.
#
# Defaults to <tt>false</tt>, which disables automatic restarts. Setting to
# <tt>true</tt> will restart the application on any config, plugin, or
# package change.
#
# [*restart_config_change*]
# Boolean that determines if the application should be automatically restarted
# whenever the configuration changes. This includes the Elasticsearch
# configuration file, any service files, and defaults files.
# Disabling automatic restarts on config changes may be desired in an
# environment where you need to ensure restarts occur in a controlled/rolling
# manner rather than during a Puppet run.
#
# Defaults to <tt>undef</tt>, in which case the default value of
# restart_on_change will be used (defaults to false).
#
# [*restart_package_change*]
# Boolean that determines if the application should be automatically restarted
# whenever the package (or package version) for Elasticsearch changes.
# Disabling automatic restarts on package changes may be desired in an
# environment where you need to ensure restarts occur in a controlled/rolling
# manner rather than during a Puppet run.
#
# Defaults to <tt>undef</tt>, in which case the default value of
# restart_on_change will be used (defaults to false).
#
# [*restart_plugin_change*]
# Boolean that determines if the application should be automatically restarted
# whenever plugins are installed or removed.
# Disabling automatic restarts on plugin changes may be desired in an
# environment where you need to ensure restarts occur in a controlled/rolling
# manner rather than during a Puppet run.
#
# Defaults to <tt>undef</tt>, in which case the default value of
# restart_on_change will be used (defaults to false).
#
# [*configdir*]
# Path to directory containing the elasticsearch configuration.
# Use this setting if your packages deviate from the norm (/etc/elasticsearch)
#
# [*plugindir*]
# Path to directory containing the elasticsearch plugins
# Use this setting if your packages deviate from the norm (/usr/share/elasticsearch/plugins)
#
# [*package_url*]
# Url to the package to download.
# This can be a http,https or ftp resource for remote packages
# puppet:// resource or file:/ for local packages
#
# [*package_provider*]
# Way to install the packages, currently only packages are supported.
#
# [*package_dir*]
# Directory where the packages are downloaded to
#
# [*package_name*]
# Name of the package to install
#
# [*purge_package_dir*]
# Purge package directory on removal
#
# [*package_dl_timeout*]
# For http,https and ftp downloads you can set howlong the exec resource may take.
# Defaults to: 600 seconds
#
# [*proxy_url*]
# For http and https downloads you can set a proxy server to use
# Format: proto://[user:pass@]server[:port]/
# Defaults to: undef (proxy disabled)
#
# [*elasticsearch_user*]
# The user Elasticsearch should run as. This also sets the file rights.
#
# [*elasticsearch_group*]
# The group Elasticsearch should run as. This also sets the file rights
#
# [*purge_configdir*]
# Purge the config directory for any unmanaged files
#
# [*service_provider*]
# Service provider to use. By Default when a single service provider is possibe that one is selected.
#
# [*init_defaults*]
# Defaults file content in hash representation
#
# [*init_defaults_file*]
# Defaults file as puppet resource
#
# [*init_template*]
# Service file as a template
#
# [*config*]
# Elasticsearch configuration hash
#
# [*config_hiera_merge*]
# Enable Hiera merging for the config hash
# Defaults to: false
#
# [*datadir*]
# Allows you to set the data directory of Elasticsearch
#
# [*datadir_instance_directories*]
# Control whether individual directories for instances will be created within
# each instance's data directorry.
# Value type is Boolean
# Defaults to: true
#
# [*logdir*]
# Use different directory for logging
#
# [*java_install*]
# Install java which is required for Elasticsearch.
# Defaults to: false
#
# [*java_package*]
# If you like to install a custom java package, put the name here.
#
# [*jvm_options*]
# Array of options to set in jvm_options.
# Value type is Array
# Default value: []
#
# [*manage_repo*]
# Enable repo management by enabling our official repositories
#
# [*repo_baseurl*]
# If a custom repository URL is needed (such as for installations behind
# restrictive firewalls), this parameter overrides the upstream repository
# URL. Note that any additional changes to the repository metdata (such as
# signing keys and so on) will need to be handled appropriately.
# Value type is String
# Default value: undef
#
# [*repo_version*]
# Our repositories are versioned per major version (0.90, 1.0) select here which version you want
#
# [*repo_priority*]
# Repository priority. yum and apt supported.
# Default: undef
#
# [*repo_key_id*]
# String. The apt GPG key id
# Default: 46095ACC8548582C1A2699A9D27D666CD88E42B4
#
# [*repo_key_source*]
# String. URL of the apt GPG key
# Default: http://packages.elastic.co/GPG-KEY-elasticsearch
#
# [*repo_proxy*]
# String. URL for repository proxy
# Default: undef
#
# [*logging_config*]
# Hash representation of information you want in the logging.yml file
#
# [*logging_file*]
# Instead of a hash you can supply a puppet:// file source for the logging.yml file
#
# [*logging_template*]
# Use a custom logging template - just supply the relative path ie ${module}/elasticsearch/logging.yml.erb
#
# [*default_logging_level*]
# Default logging level for Elasticsearch.
# Defaults to: INFO
#
# [*repo_stage*]
# Use stdlib stage setup for managing the repo, instead of anchoring
#
# [*indices*]
# Define indices via a hash. This is mainly used with Hiera's auto binding
# Defaults to: undef
#
# [*indices_hiera_merge*]
# Enable Hiera's merging function for indices
# Defaults to: false
#
# [*instances*]
# Define instances via a hash. This is mainly used with Hiera's auto binding
# Defaults to: undef
#
# [*instances_hiera_merge*]
# Enable Hiera's merging function for the instances
# Defaults to: false
#
# [*pipelines*]
# Define pipelines via a hash. This is mainly used with Hiera's auto binding
# Defaults to: undef
#
# [*pipelines_hiera_merge*]
# Enable Hiera's merging function for pipelines
# Defaults to: false
#
# [*plugins*]
# Define plugins via a hash. This is mainly used with Hiera's auto binding
# Defaults to: undef
#
# [*plugins_hiera_merge*]
# Enable Hiera's merging function for the plugins
# Defaults to: false
#
# [*roles*]
# Define roles via a hash. This is mainly used with Hiera's auto binding
# Defaults to: undef
#
# [*roles_hiera_merge*]
# Enable Hiera's merging function for roles
# Defaults to: false
#
# [*scripts*]
# Define scripts via a hash. This is mainly used with Hiera's auto binding
# Defaults to: undef
#
# [*scripts_hiera_merge*]
# Enable Hiera's merging function for scripts
# Defaults to: false
#
# [*templates*]
# Define templates via a hash. This is mainly used with Hiera's auto binding
# Defaults to: undef
#
# [*templates_hiera_merge*]
# Enable Hiera's merging function for templates
# Defaults to: false
#
# [*users*]
# Define templates via a hash. This is mainly used with Hiera's auto binding
# Defaults to: undef
#
# [*users_hiera_merge*]
# Enable Hiera's merging function for users
# Defaults to: false
#
# [*package_pin*]
# Enables package version pinning.
# This pins the package version to the set version number and avoids
# package upgrades.
# Defaults to: true
#
# [*api_protocol*]
# Default protocol to use when accessing Elasticsearch APIs.
# Defaults to: http
#
# [*api_host*]
# Default host to use when accessing Elasticsearch APIs.
# Defaults to: localhost
#
# [*api_port*]
# Default port to use when accessing Elasticsearch APIs.
# Defaults to: 9200
#
# [*api_timeout*]
# Default timeout (in seconds) to use when accessing Elasticsearch APIs.
# Defaults to: 10
#
# [*validate_tls*]
# Enable TLS/SSL validation on API calls.
# Defaults to: true
#
# [*api_basic_auth_username*]
# Defines the default REST basic auth username for API authentication.
# Defaults to: undef
#
# [*api_basic_auth_password*]
# Defines the default REST basic auth password for API authentication.
# Defaults to: undef
#
# [*api_ca_file*]
# Path to a CA file which will be used to validate server certs when
# communicating with the Elasticsearch API over HTTPS.
# Defaults to: undef
#
# [*api_ca_path*]
# Path to a directory with CA files which will be used to validate server
# certs when communicating with the Elasticsearch API over HTTPS.
# Defaults to: undef
#
# [*system_key*]
# Source for the Shield/x-pack system key. Valid values are any that are
# supported for the file resource `source` parameter.
# Value type is string
# Default value: undef
#
# [*file_rolling_type*]
# Configuration for the file appender rotation. It can be 'dailyRollingFile'
# or 'rollingFile'. The first rotates by name, and the second one by size.
# Value type is string
# Default value: dailyRollingFile
#
# [*daily_rolling_date_pattern*]
# File pattern for the file appender log when file_rolling_type is 'dailyRollingFile'
# Value type is string
# Default value: "'.'yyyy-MM-dd"
#
# [*rolling_file_max_backup_index*]
# Max number of logs to store whern file_rolling_type is 'rollingFile'
# Value type is integer
# Default value: 1
#
# [*rolling_file_max_file_size*]
# Max log file size when file_rolling_type is 'rollingFile'
# Value type is string
# Default value: 10MB
#
# [*security_plugin*]
# Which security plugin will be used to manage users, roles, and
# certificates. Valid values are 'shield' and 'x-pack'
# Value type is string
# Default value: undef
#
# [*security_logging_content*]
# File content for shield/x-pack logging configuration file (will be placed
# into logging.yml or log4j2.properties file as appropriate).
# Default value: undef
#
# [*security_logging_source*]
# File source for shield/x-pack logging configuration file (will be placed
# into logging.yml or log4j2.properties file as appropriate).
# Default value: undef
#
+# [*secrets*]
+# Optional default configuration hash of key/value pairs to store in the
+# Elasticsearch keystore file. If unset, the keystore is left unmanaged.
+# Value type is hash
+# Default value: undef
+#
+# [*purge_secrets*]
+# Whether or not keys present in the keystore will be removed if they are not
+# present in the specified secrets hash.
+# Value type is Boolean
+# Default value: false
+#
# The default values for the parameters are set in elasticsearch::params. Have
# a look at the corresponding <tt>params.pp</tt> manifest file if you need more
# technical information about them.
#
# === Examples
#
# * Installation, make sure service is running and will be started at boot time:
# class { 'elasticsearch': }
#
# * Removal/decommissioning:
# class { 'elasticsearch':
# ensure => 'absent',
# }
#
# * Install everything but disable service(s) afterwards
# class { 'elasticsearch':
# status => 'disabled',
# }
#
#
# === Authors
#
# * Richard Pijnenburg <mailto:richard.pijnenburg@elasticsearch.com>
#
class elasticsearch(
$ensure = $elasticsearch::params::ensure,
$status = $elasticsearch::params::status,
$restart_on_change = $elasticsearch::params::restart_on_change,
$restart_config_change = $elasticsearch::restart_on_change,
$restart_package_change = $elasticsearch::restart_on_change,
$restart_plugin_change = $elasticsearch::restart_on_change,
$autoupgrade = $elasticsearch::params::autoupgrade,
$version = false,
$package_provider = 'package',
$package_url = undef,
$package_dir = $elasticsearch::params::package_dir,
$package_name = $elasticsearch::params::package,
$package_pin = true,
$purge_package_dir = $elasticsearch::params::purge_package_dir,
$package_dl_timeout = $elasticsearch::params::package_dl_timeout,
$proxy_url = undef,
$elasticsearch_user = $elasticsearch::params::elasticsearch_user,
$elasticsearch_group = $elasticsearch::params::elasticsearch_group,
$configdir = $elasticsearch::params::configdir,
$purge_configdir = $elasticsearch::params::purge_configdir,
$service_provider = 'init',
$init_defaults = undef,
$init_defaults_file = undef,
$init_template = "${module_name}/etc/init.d/${elasticsearch::params::init_template}",
$config = undef,
$config_hiera_merge = false,
$datadir = $elasticsearch::params::datadir,
$datadir_instance_directories = true,
$logdir = $elasticsearch::params::logdir,
$plugindir = $elasticsearch::params::plugindir,
$java_install = false,
$java_package = undef,
$jvm_options = [],
$manage_repo = false,
$repo_baseurl = undef,
$repo_version = undef,
$repo_priority = undef,
$repo_key_id = '46095ACC8548582C1A2699A9D27D666CD88E42B4',
$repo_key_source = 'https://artifacts.elastic.co/GPG-KEY-elasticsearch',
$repo_proxy = undef,
$logging_file = undef,
$logging_config = undef,
$logging_template = undef,
$default_logging_level = $elasticsearch::params::default_logging_level,
$repo_stage = false,
$indices = undef,
$indices_hiera_merge = false,
$instances = undef,
$instances_hiera_merge = false,
$pipelines = undef,
$pipelines_hiera_merge = false,
$plugins = undef,
$plugins_hiera_merge = false,
$roles = undef,
$roles_hiera_merge = false,
$scripts = undef,
$scripts_hiera_merge = false,
$templates = undef,
$templates_hiera_merge = false,
$users = undef,
$users_hiera_merge = false,
$api_protocol = 'http',
$api_host = 'localhost',
$api_port = 9200,
$api_timeout = 10,
$api_basic_auth_username = undef,
$api_basic_auth_password = undef,
$api_ca_file = undef,
$api_ca_path = undef,
$validate_tls = true,
$system_key = undef,
$file_rolling_type = $elasticsearch::params::file_rolling_type,
$daily_rolling_date_pattern = $elasticsearch::params::daily_rolling_date_pattern,
$rolling_file_max_backup_index = $elasticsearch::params::rolling_file_max_backup_index,
$rolling_file_max_file_size = $elasticsearch::params::rolling_file_max_file_size,
$security_plugin = undef,
$security_logging_content = undef,
$security_logging_source = undef,
+ $secrets = undef,
+ $purge_secrets = false,
) inherits elasticsearch::params {
anchor {'elasticsearch::begin': }
#### Validate parameters
# ensure
if ! ($ensure in [ 'present', 'absent' ]) {
fail("\"${ensure}\" is not a valid ensure parameter value")
}
# autoupgrade
validate_bool($autoupgrade)
# service status
if ! ($status in [ 'enabled', 'disabled', 'running', 'unmanaged' ]) {
fail("\"${status}\" is not a valid status parameter value")
}
if ! ($file_rolling_type in [ 'dailyRollingFile', 'rollingFile']) {
fail("\"${file_rolling_type}\" is not a valid type")
}
validate_array($jvm_options)
validate_integer($rolling_file_max_backup_index)
validate_string($daily_rolling_date_pattern)
validate_string($rolling_file_max_file_size)
# restart on change
validate_bool(
$restart_on_change,
$restart_config_change,
$restart_package_change,
$restart_plugin_change
)
# purge conf dir
validate_bool($purge_configdir)
if is_array($elasticsearch::params::service_providers) {
# Verify the service provider given is in the array
if ! ($service_provider in $elasticsearch::params::service_providers) {
fail("\"${service_provider}\" is not a valid provider for \"${::operatingsystem}\"")
}
$real_service_provider = $service_provider
} else {
# There is only one option so simply set it
$real_service_provider = $elasticsearch::params::service_providers
}
if ($package_url != undef and $version != false) {
fail('Unable to set the version number when using package_url option.')
}
if $ensure == 'present' {
# validate config hash
if ($config != undef) {
validate_hash($config)
}
if ($logging_config != undef) {
validate_hash($logging_config)
}
+
+ if ($secrets != undef) {
+ validate_hash($secrets)
+ }
}
# java install validation
validate_bool($java_install)
validate_bool(
$datadir_instance_directories,
$manage_repo,
$package_pin
)
if ($manage_repo == true and $ensure == 'present') {
if $repo_baseurl != undef {
validate_string($repo_baseurl)
} elsif $repo_version == undef {
fail('Please fill in a repository version at $repo_version')
} else {
validate_string($repo_version)
}
}
if ($version != false) {
case $::osfamily {
'RedHat', 'Linux', 'Suse': {
if ($version =~ /.+-\d/) {
$pkg_version = $version
} else {
$pkg_version = "${version}-1"
}
}
default: {
$pkg_version = $version
}
}
}
# Various parameters governing API access to Elasticsearch
validate_string($api_protocol, $api_host)
validate_bool($validate_tls)
if $api_basic_auth_username { validate_string($api_basic_auth_username) }
if $api_basic_auth_password { validate_string($api_basic_auth_password) }
if ! is_integer($api_timeout) {
fail("'${api_timeout}' is not an integer")
}
if ! is_integer($api_port) {
fail("'${api_port}' is not an integer")
}
if $system_key != undef { validate_string($system_key) }
#### Manage actions
# package(s)
class { 'elasticsearch::package': }
# configuration
class { 'elasticsearch::config': }
# Hiera support for configuration hash
validate_bool($config_hiera_merge)
if $config_hiera_merge == true {
$x_config = hiera_hash('elasticsearch::config', $config)
} else {
$x_config = $config
}
# Hiera support for indices
validate_bool($indices_hiera_merge)
if $indices_hiera_merge == true {
$x_indices = hiera_hash('elasticsearch::indices', $::elasticsearch::indices)
} else {
$x_indices = $indices
}
if $x_indices {
validate_hash($x_indices)
create_resources('elasticsearch::index', $x_indices)
}
# Hiera support for instances
validate_bool($instances_hiera_merge)
if $instances_hiera_merge == true {
$x_instances = hiera_hash('elasticsearch::instances', $::elasticsearch::instances)
} else {
$x_instances = $instances
}
if $x_instances {
validate_hash($x_instances)
create_resources('elasticsearch::instance', $x_instances)
}
# Hiera support for pipelines
validate_bool($pipelines_hiera_merge)
if $pipelines_hiera_merge == true {
$x_pipelines = hiera_hash('elasticsearch::pipelines', $::elasticsearch::pipelines)
} else {
$x_pipelines = $pipelines
}
if $x_pipelines {
validate_hash($x_pipelines)
create_resources('elasticsearch::pipeline', $x_pipelines)
}
# Hiera support for plugins
validate_bool($plugins_hiera_merge)
if $plugins_hiera_merge == true {
$x_plugins = hiera_hash('elasticsearch::plugins', $::elasticsearch::plugins)
} else {
$x_plugins = $plugins
}
if $x_plugins {
validate_hash($x_plugins)
create_resources('elasticsearch::plugin', $x_plugins)
}
# Hiera support for roles
validate_bool($roles_hiera_merge)
if $roles_hiera_merge == true {
$x_roles = hiera_hash('elasticsearch::roles', $::elasticsearch::roles)
} else {
$x_roles = $roles
}
if $x_roles {
validate_hash($x_roles)
create_resources('elasticsearch::role', $x_roles)
}
# Hiera support for scripts
validate_bool($scripts_hiera_merge)
if $scripts_hiera_merge == true {
$x_scripts = hiera_hash('elasticsearch::scripts', $::elasticsearch::scripts)
} else {
$x_scripts = $scripts
}
if $x_scripts {
validate_hash($x_scripts)
create_resources('elasticsearch::script', $x_scripts)
}
# Hiera support for templates
validate_bool($templates_hiera_merge)
if $templates_hiera_merge == true {
$x_templates = hiera_hash('elasticsearch::templates', $::elasticsearch::templates)
} else {
$x_templates = $templates
}
if $x_templates {
validate_hash($x_templates)
create_resources('elasticsearch::template', $x_templates)
}
# Hiera support for users
validate_bool($users_hiera_merge)
if $users_hiera_merge == true {
$x_users = hiera_hash('elasticsearch::users', $::elasticsearch::users)
} else {
$x_users = $users
}
if $x_users {
validate_hash($x_users)
create_resources('elasticsearch::user', $x_users)
}
if $java_install == true {
# Install java
class { '::java':
package => $java_package,
distribution => 'jre',
}
# ensure we first install java, the package and then the rest
Anchor['elasticsearch::begin']
-> Class['::java']
-> Class['elasticsearch::package']
}
if $package_pin {
class { 'elasticsearch::package::pin':
before => Class['elasticsearch::package'],
}
}
if ($manage_repo == true) {
if ($repo_stage == false) {
# use anchor for ordering
# Set up repositories
class { 'elasticsearch::repo': }
# Ensure that we set up the repositories before trying to install
# the packages
Anchor['elasticsearch::begin']
-> Class['elasticsearch::repo']
-> Class['elasticsearch::package']
} else {
# use staging for ordering
if !(defined(Stage[$repo_stage])) {
stage { $repo_stage: before => Stage['main'] }
}
class { 'elasticsearch::repo':
stage => $repo_stage,
}
}
}
#### Manage relationships
#
# Note that many of these overly verbose declarations work around
# https://tickets.puppetlabs.com/browse/PUP-1410
# which means clean arrow order chaining won't work if someone, say,
# doesn't declare any plugins.
#
# forgive me for what you're about to see
if $ensure == 'present' {
# Anchor, installation, and configuration
Anchor['elasticsearch::begin']
-> Class['elasticsearch::package']
-> Class['elasticsearch::config']
# Top-level ordering bindings for resources.
Class['elasticsearch::config']
-> Elasticsearch::Plugin <| ensure == 'present' or ensure == 'installed' |>
Elasticsearch::Plugin <| ensure == 'absent' |>
-> Class['elasticsearch::config']
Class['elasticsearch::config']
-> Elasticsearch::Instance <| |>
Class['elasticsearch::config']
-> Elasticsearch::User <| |>
Class['elasticsearch::config']
-> Elasticsearch::Role <| |>
Class['elasticsearch::config']
-> Elasticsearch::Template <| |>
Class['elasticsearch::config']
-> Elasticsearch::Pipeline <| |>
Class['elasticsearch::config']
-> Elasticsearch::Index <| |>
} else {
# Main anchor and included classes
Anchor['elasticsearch::begin']
-> Class['elasticsearch::config']
-> Class['elasticsearch::package']
# Top-level ordering bindings for resources.
Anchor['elasticsearch::begin']
-> Elasticsearch::Plugin <| |>
-> Class['elasticsearch::config']
Anchor['elasticsearch::begin']
-> Elasticsearch::Instance <| |>
-> Class['elasticsearch::config']
Anchor['elasticsearch::begin']
-> Elasticsearch::User <| |>
-> Class['elasticsearch::config']
Anchor['elasticsearch::begin']
-> Elasticsearch::Role <| |>
-> Class['elasticsearch::config']
Anchor['elasticsearch::begin']
-> Elasticsearch::Template <| |>
-> Class['elasticsearch::config']
Anchor['elasticsearch::begin']
-> Elasticsearch::Pipeline <| |>
-> Class['elasticsearch::config']
Anchor['elasticsearch::begin']
-> Elasticsearch::Index <| |>
-> Class['elasticsearch::config']
}
# Install plugins before managing instances or users/roles
Elasticsearch::Plugin <| ensure == 'present' or ensure == 'installed' |>
-> Elasticsearch::Instance <| |>
Elasticsearch::Plugin <| ensure == 'present' or ensure == 'installed' |>
-> Elasticsearch::User <| |>
Elasticsearch::Plugin <| ensure == 'present' or ensure == 'installed' |>
-> Elasticsearch::Role <| |>
# Remove plugins after managing users/roles
Elasticsearch::User <| |>
-> Elasticsearch::Plugin <| ensure == 'absent' |>
Elasticsearch::Role <| |>
-> Elasticsearch::Plugin <| ensure == 'absent' |>
# Ensure roles are defined before managing users that reference roles
Elasticsearch::Role <| |>
-> Elasticsearch::User <| ensure == 'present' |>
# Ensure users are removed before referenced roles are managed
Elasticsearch::User <| ensure == 'absent' |>
-> Elasticsearch::Role <| |>
# Ensure users and roles are managed before calling out to REST resources
Elasticsearch::Role <| |>
-> Elasticsearch::Template <| |>
Elasticsearch::User <| |>
-> Elasticsearch::Template <| |>
Elasticsearch::Role <| |>
-> Elasticsearch::Pipeline <| |>
Elasticsearch::User <| |>
-> Elasticsearch::Pipeline <| |>
Elasticsearch::Role <| |>
-> Elasticsearch::Index <| |>
Elasticsearch::User <| |>
-> Elasticsearch::Index <| |>
# Manage users/roles before instances (req'd to keep dir in sync)
Elasticsearch::Role <| |>
-> Elasticsearch::Instance <| |>
Elasticsearch::User <| |>
-> Elasticsearch::Instance <| |>
# Ensure instances are started before managing REST resources
Elasticsearch::Instance <| ensure == 'present' |>
-> Elasticsearch::Template <| |>
Elasticsearch::Instance <| ensure == 'present' |>
-> Elasticsearch::Pipeline <| |>
Elasticsearch::Instance <| ensure == 'present' |>
-> Elasticsearch::Index <| |>
# Ensure instances are stopped after managing REST resources
Elasticsearch::Template <| |>
-> Elasticsearch::Instance <| ensure == 'absent' |>
Elasticsearch::Pipeline <| |>
-> Elasticsearch::Instance <| ensure == 'absent' |>
Elasticsearch::Index <| |>
-> Elasticsearch::Instance <| ensure == 'absent' |>
}
diff --git a/manifests/instance.pp b/manifests/instance.pp
index 1c1c648..e96bbd9 100644
--- a/manifests/instance.pp
+++ b/manifests/instance.pp
@@ -1,553 +1,589 @@
# == Define: elasticsearch::instance
#
# This define allows you to create or remove an elasticsearch instance
#
# === Parameters
#
# [*ensure*]
# String. Controls if the managed resources shall be <tt>present</tt> or
# <tt>absent</tt>. If set to <tt>absent</tt>:
# * The managed software packages are being uninstalled.
# * Any traces of the packages will be purged as good as possible. This may
# include existing configuration files. The exact behavior is provider
# dependent. Q.v.:
# * Puppet type reference: {package, "purgeable"}[http://j.mp/xbxmNP]
# * {Puppet's package provider source code}[http://j.mp/wtVCaL]
# * System modifications (if any) will be reverted as good as possible
# (e.g. removal of created users, services, changed log settings, ...).
# * This is thus destructive and should be used with care.
# Defaults to <tt>present</tt>.
#
# [*status*]
# String to define the status of the service. Possible values:
# * <tt>enabled</tt>: Service is running and will be started at boot time.
# * <tt>disabled</tt>: Service is stopped and will not be started at boot
# time.
# * <tt>running</tt>: Service is running but will not be started at boot time.
# You can use this to start a service on the first Puppet run instead of
# the system startup.
# * <tt>unmanaged</tt>: Service will not be started at boot time and Puppet
# does not care whether the service is running or not. For example, this may
# be useful if a cluster management software is used to decide when to start
# the service plus assuring it is running on the desired node.
# Defaults to <tt>enabled</tt>. The singular form ("service") is used for the
# sake of convenience. Of course, the defined status affects all services if
# more than one is managed (see <tt>service.pp</tt> to check if this is the
# case).
#
# [*config*]
# Elasticsearch configuration hash
#
# [*configdir*]
# Path to directory containing the elasticsearch configuration.
# Use this setting if your packages deviate from the norm (/etc/elasticsearch)
#
# [*datadir*]
# Allows you to set the data directory of Elasticsearch
#
# [*datadir_instance_directories*]
# Control whether individual directories for instances will be created within
# each instance's data directorry.
# Value type is Boolean
# Defaults to: true
#
# [*logging_file*]
# Instead of a hash you can supply a puppet:// file source for the logging.yml file
#
# [*logging_config*]
# Hash representation of information you want in the logging.yml file
#
# [*logging_template*]
# Use a custom logging template - just supply the reative path ie ${module}/elasticsearch/logging.yml.erb
#
# [*logging_level*]
# Default logging level for Elasticsearch.
# Defaults to: INFO
#
# [*deprecation_logging*]
# Wheter to enable deprecation logging. If enabled, deprecation logs will be
# saved to ${cluster.name}_deprecation.log in the elastic search log folder.
# Default value: false
#
# [*deprecation_logging_level*]
# Default deprecation logging level for Elasticsearch.
# Defaults to: DEBUG
#
# [*init_defaults*]
# Defaults file content in hash representation
#
# [*init_defaults_file*]
# Defaults file as puppet resource
#
# [*service_flags*]
# Service flags used for the OpenBSD service configuration, defaults to undef.
#
# [*init_template*]
# Service file as a template
#
# [*logdir*]
# Log directory for this instance.
#
# [*ssl*]
# Whether to manage TLS certificates for Shield. Requires the ca_certificate,
# certificate, private_key and keystore_password parameters to be set.
# Value type is boolean
# Default value: false
#
# [*ca_certificate*]
# Path to the trusted CA certificate to add to this node's java keystore.
# Value type is string
# Default value: undef
#
# [*certificate*]
# Path to the certificate for this node signed by the CA listed in
# ca_certificate.
# Value type is string
# Default value: undef
#
# [*private_key*]
# Path to the key associated with this node's certificate.
# Value type is string
# Default value: undef
#
# [*keystore_password*]
# Password to encrypt this node's Java keystore.
# Value type is string
# Default value: undef
#
# [*keystore_path*]
# Custom path to the java keystore file. This parameter is optional.
# Value type is string
# Default value: undef
#
# [*system_key*]
# Source for the Shield system key. Valid values are any that are
# supported for the file resource `source` parameter.
# Value type is string
# Default value: undef
#
# [*file_rolling_type*]
# Configuration for the file appender rotation. It can be 'dailyRollingFile'
# or 'rollingFile'. The first rotates by name, and the second one by size.
# Value type is string
# Default value: dailyRollingFile
#
# [*daily_rolling_date_pattern*]
# File pattern for the file appender log when file_rolling_type is 'dailyRollingFile'
# Value type is string
# Default value: "'.'yyyy-MM-dd"
#
# [*rolling_file_max_backup_index*]
# Max number of logs to store whern file_rolling_type is 'rollingFile'
# Value type is integer
# Default value: 1
#
# [*rolling_file_max_file_size*]
# Max log file size when file_rolling_type is 'rollingFile'
# Value type is string
# Default value: 10MB
#
# [*security_plugin*]
# Which security plugin will be used to manage users, roles, and
# certificates. Inherited from top-level Elasticsearch class.
#
+# [*secrets*]
+# Optional configuration hash of key/value pairs to store in the instance's
+# Elasticsearch keystore file. If unset, the keystore is left unmanaged.
+# Value type is hash
+# Default value: undef
+#
+# [*purge_secrets*]
+# Whether or not keys present in the keystore will be removed if they are not
+# present in the specified secrets hash.
+# Value type is Boolean
+# Default value: false
+#
# === Authors
#
# * Tyler Langlois <mailto:tyler@elastic.co>
# * Richard Pijnenburg <mailto:richard.pijnenburg@elasticsearch.com>
#
define elasticsearch::instance(
$ensure = $elasticsearch::ensure,
$status = $elasticsearch::status,
$config = undef,
$configdir = undef,
$datadir = undef,
$datadir_instance_directories = $elasticsearch::datadir_instance_directories,
$logdir = undef,
$logging_file = undef,
$logging_config = undef,
$logging_template = undef,
$logging_level = $elasticsearch::default_logging_level,
$deprecation_logging = false,
$deprecation_logging_level = 'DEBUG',
$service_flags = undef,
$init_defaults = undef,
$init_defaults_file = undef,
$init_template = $elasticsearch::init_template,
$ssl = false,
$ca_certificate = undef,
$certificate = undef,
$private_key = undef,
$keystore_password = undef,
$keystore_path = undef,
$system_key = $elasticsearch::system_key,
$file_rolling_type = $elasticsearch::file_rolling_type,
$daily_rolling_date_pattern = $elasticsearch::daily_rolling_date_pattern,
$rolling_file_max_backup_index = $elasticsearch::rolling_file_max_backup_index,
$rolling_file_max_file_size = $elasticsearch::rolling_file_max_file_size,
$security_plugin = $elasticsearch::security_plugin,
+ $secrets = undef,
+ $purge_secrets = $elasticsearch::purge_secrets,
) {
require elasticsearch::params
File {
owner => $elasticsearch::elasticsearch_user,
group => $elasticsearch::elasticsearch_group,
}
Exec {
path => [ '/bin', '/usr/bin', '/usr/local/bin' ],
cwd => '/',
}
# ensure
if ! ($ensure in [ 'present', 'absent' ]) {
fail("\"${ensure}\" is not a valid ensure parameter value")
}
if $ssl or ($system_key != undef) {
if $security_plugin == undef or ! ($security_plugin in ['shield', 'x-pack']) {
fail("\"${security_plugin}\" is not a valid security_plugin parameter value")
}
}
$notify_service = $elasticsearch::restart_config_change ? {
true => Elasticsearch::Service[$name],
false => undef,
}
# Instance config directory
if ($configdir == undef) {
$instance_configdir = "${elasticsearch::configdir}/${name}"
} else {
$instance_configdir = $configdir
}
if ($ensure == 'present') {
# Configuration hash
if ($config == undef) {
$instance_config = {}
} else {
validate_hash($config)
$instance_config = deep_implode($config)
}
if(has_key($instance_config, 'node.name')) {
$instance_node_name = {}
} else {
$instance_node_name = { 'node.name' => "${::hostname}-${name}" }
}
# String or array for data dir(s)
if ($datadir == undef) {
validate_bool($datadir_instance_directories)
if ($datadir_instance_directories) {
if (is_array($elasticsearch::datadir)) {
$instance_datadir = array_suffix($elasticsearch::datadir, "/${name}")
} else {
$instance_datadir = "${elasticsearch::datadir}/${name}"
}
} else {
$instance_datadir = $elasticsearch::datadir
}
} else {
$instance_datadir = $datadir
}
# Logging file or hash
if ($logging_file != undef) {
$logging_source = $logging_file
$logging_content = undef
$_log4j_content = undef
} elsif ($elasticsearch::logging_file != undef) {
$logging_source = $elasticsearch::logging_file
$logging_content = undef
$_log4j_content = undef
} else {
if(is_hash($elasticsearch::logging_config)) {
$main_logging_config = deep_implode($elasticsearch::logging_config)
} else {
$main_logging_config = { }
}
if(is_hash($logging_config)) {
$instance_logging_config = deep_implode($logging_config)
} else {
$instance_logging_config = { }
}
$logging_hash = merge(
$elasticsearch::params::logging_defaults,
$main_logging_config,
$instance_logging_config
)
if ($logging_template != undef ) {
$logging_content = template($logging_template)
$_log4j_content = template($logging_template)
} elsif ($elasticsearch::logging_template != undef) {
$logging_content = template($elasticsearch::logging_template)
$_log4j_content = template($elasticsearch::logging_template)
} else {
$logging_content = template("${module_name}/etc/elasticsearch/logging.yml.erb")
$_log4j_content = template("${module_name}/etc/elasticsearch/log4j2.properties.erb")
}
$logging_source = undef
}
if ($elasticsearch::x_config != undef) {
$main_config = deep_implode($elasticsearch::x_config)
} else {
$main_config = { }
}
$instance_datadir_config = { 'path.data' => $instance_datadir }
if(is_array($instance_datadir)) {
$dirs = join($instance_datadir, ' ')
} else {
$dirs = $instance_datadir
}
# Manage instance log directory
if ($logdir == undef) {
$instance_logdir = "${elasticsearch::logdir}/${name}"
} else {
$instance_logdir = $logdir
}
$instance_logdir_config = { 'path.logs' => $instance_logdir }
validate_bool($ssl)
if $ssl {
validate_absolute_path($ca_certificate, $certificate, $private_key)
validate_string($keystore_password)
if ($keystore_path == undef) {
$_keystore_path = "${instance_configdir}/${security_plugin}/${name}.ks"
} else {
validate_absolute_path($keystore_path)
$_keystore_path = $keystore_path
}
if $security_plugin == 'shield' {
$tls_config = {
'shield.transport.ssl' => true,
'shield.http.ssl' => true,
'shield.ssl.keystore.path' => $_keystore_path,
'shield.ssl.keystore.password' => $keystore_password,
}
} elsif $security_plugin == 'x-pack' {
$tls_config = {
'xpack.security.transport.ssl.enabled' => true,
'xpack.security.http.ssl.enabled' => true,
'xpack.ssl.keystore.path' => $_keystore_path,
'xpack.ssl.keystore.password' => $keystore_password,
}
}
# Trust CA Certificate
java_ks { "elasticsearch_instance_${name}_keystore_ca":
ensure => 'latest',
certificate => $ca_certificate,
target => $_keystore_path,
password => $keystore_password,
trustcacerts => true,
}
# Load node certificate and private key
java_ks { "elasticsearch_instance_${name}_keystore_node":
ensure => 'latest',
certificate => $certificate,
private_key => $private_key,
target => $_keystore_path,
password => $keystore_password,
}
} else { $tls_config = {} }
if $system_key != undef {
validate_string($system_key)
}
exec { "mkdir_logdir_elasticsearch_${name}":
command => "mkdir -p ${instance_logdir}",
creates => $instance_logdir,
require => Class['elasticsearch::package'],
before => File[$instance_logdir],
}
file { $instance_logdir:
ensure => 'directory',
owner => $elasticsearch::elasticsearch_user,
group => undef,
mode => '0644',
require => Class['elasticsearch::package'],
before => Elasticsearch::Service[$name],
}
if ($datadir_instance_directories) {
exec { "mkdir_datadir_elasticsearch_${name}":
command => "mkdir -p ${dirs}",
creates => $instance_datadir,
require => Class['elasticsearch::package'],
before => Elasticsearch::Service[$name],
}
-> file { $instance_datadir:
ensure => 'directory',
owner => $elasticsearch::elasticsearch_user,
group => undef,
mode => '0644',
require => Class['elasticsearch::package'],
before => Elasticsearch::Service[$name],
}
}
exec { "mkdir_configdir_elasticsearch_${name}":
command => "mkdir -p ${instance_configdir}",
creates => $elasticsearch::configdir,
require => Class['elasticsearch::package'],
before => Elasticsearch::Service[$name],
}
file { $instance_configdir:
ensure => 'directory',
mode => '0644',
purge => $elasticsearch::purge_configdir,
force => $elasticsearch::purge_configdir,
require => [ Exec["mkdir_configdir_elasticsearch_${name}"], Class['elasticsearch::package'] ],
before => Elasticsearch::Service[$name],
}
file {
"${instance_configdir}/logging.yml":
ensure => file,
content => $logging_content,
source => $logging_source,
mode => '0644',
notify => $notify_service,
require => Class['elasticsearch::package'],
before => Elasticsearch::Service[$name];
"${instance_configdir}/log4j2.properties":
ensure => file,
content => $_log4j_content,
source => $logging_source,
mode => '0644',
notify => $notify_service,
require => Class['elasticsearch::package'],
before => Elasticsearch::Service[$name];
}
file { "${instance_configdir}/scripts":
ensure => 'link',
target => "${elasticsearch::params::homedir}/scripts",
}
if $security_plugin != undef {
file { "${instance_configdir}/${security_plugin}":
ensure => 'directory',
mode => '0644',
source => "${elasticsearch::configdir}/${security_plugin}",
recurse => 'remote',
owner => 'root',
group => '0',
before => Elasticsearch::Service[$name],
notify => $notify_service,
}
}
if $system_key != undef {
file { "${instance_configdir}/${security_plugin}/system_key":
ensure => 'file',
source => $system_key,
mode => '0400',
before => Elasticsearch::Service[$name],
require => File["${instance_configdir}/${security_plugin}"],
}
}
# build up new config
$instance_conf = merge(
$main_config,
$instance_node_name,
$instance_datadir_config,
$instance_logdir_config,
$tls_config,
$instance_config
)
# defaults file content
# ensure user did not provide both init_defaults and init_defaults_file
if (($init_defaults != undef) and ($init_defaults_file != undef)) {
fail ('Only one of $init_defaults and $init_defaults_file should be defined')
}
if (is_hash($elasticsearch::init_defaults)) {
$global_init_defaults = $elasticsearch::init_defaults
} else {
$global_init_defaults = { }
}
$instance_init_defaults_main = {
'CONF_DIR' => $instance_configdir,
'ES_HOME' => $elasticsearch::params::homedir,
'LOG_DIR' => $instance_logdir,
}
if (is_hash($init_defaults)) {
$instance_init_defaults = $init_defaults
} else {
$instance_init_defaults = { }
}
$init_defaults_new = merge(
{ 'DATA_DIR' => $elasticsearch::params::datadir },
$global_init_defaults,
$instance_init_defaults_main,
$instance_init_defaults
)
$user = $elasticsearch::elasticsearch_user
$group = $elasticsearch::elasticsearch_group
datacat_fragment { "main_config_${name}":
target => "${instance_configdir}/elasticsearch.yml",
data => $instance_conf,
}
datacat { "${instance_configdir}/elasticsearch.yml":
template => "${module_name}/etc/elasticsearch/elasticsearch.yml.erb",
notify => $notify_service,
require => Class['elasticsearch::package'],
owner => $elasticsearch::elasticsearch_user,
group => $elasticsearch::elasticsearch_group,
mode => '0440',
}
+ if ($elasticsearch::secrets != undef or $secrets != undef) {
+ if ($elasticsearch::secrets != undef) {
+ $main_secrets = $elasticsearch::secrets
+ } else {
+ $main_secrets = {}
+ }
+
+ if ($secrets != undef) {
+ $instance_secrets = $secrets
+ } else {
+ $instance_secrets = {}
+ }
+
+ validate_bool($purge_secrets)
+
+ elasticsearch_keystore { $name :
+ purge => $purge_secrets,
+ settings => merge($main_secrets, $instance_secrets),
+ notify => $notify_service,
+ }
+ }
+
$require_service = Class['elasticsearch::package']
$before_service = undef
} else {
file { $instance_configdir:
ensure => 'absent',
recurse => true,
force => true,
}
$require_service = undef
$before_service = File[$instance_configdir]
$init_defaults_new = {}
}
elasticsearch::service { $name:
ensure => $ensure,
status => $status,
service_flags => $service_flags,
init_defaults => $init_defaults_new,
init_defaults_file => $init_defaults_file,
init_template => $init_template,
require => $require_service,
before => $before_service,
}
}
diff --git a/spec/defines/005_elasticsearch_instance_spec.rb b/spec/defines/005_elasticsearch_instance_spec.rb
index 4e02a77..aefe6c8 100644
--- a/spec/defines/005_elasticsearch_instance_spec.rb
+++ b/spec/defines/005_elasticsearch_instance_spec.rb
@@ -1,627 +1,704 @@
require 'spec_helper'
describe 'elasticsearch::instance', :type => 'define' do
let(:title) { 'es-01' }
let(:pre_condition) { %q{
class { "elasticsearch": }
} }
on_supported_os.each do |os, facts|
context "on #{os}" do
case facts[:osfamily]
when 'Debian'
let(:defaults_path) { '/etc/default' }
let(:pkg_ext) { 'deb' }
let(:pkg_prov) { 'dpkg' }
case facts[:operatingsystem]
when 'Debian'
if facts[:operatingsystemmajrelease].to_i >= 8
let(:initscript) { 'systemd' }
else
let(:initscript) { 'Debian' }
end
when 'Ubuntu'
if facts[:operatingsystemmajrelease].to_i >= 15
let(:initscript) { 'systemd' }
else
let(:initscript) { 'Debian' }
end
end
when 'RedHat'
let(:defaults_path) { '/etc/sysconfig' }
let(:pkg_ext) { 'rpm' }
let(:pkg_prov) { 'rpm' }
if facts[:operatingsystemmajrelease].to_i >= 7
let(:initscript) { 'systemd' }
else
let(:initscript) { 'RedHat' }
end
when 'Suse'
let(:defaults_path) { '/etc/sysconfig' }
let(:pkg_ext) { 'rpm' }
let(:pkg_prov) { 'rpm' }
let(:initscript) { 'systemd' }
end
let(:facts) do
facts.merge('scenario' => '', 'common' => '')
end
it { should contain_elasticsearch__service(
'es-01'
).with(
:init_template =>
"elasticsearch/etc/init.d/elasticsearch.#{initscript}.erb",
:init_defaults => {
'CONF_DIR' => '/etc/elasticsearch/es-01',
'DATA_DIR' => '/var/lib/elasticsearch',
'LOG_DIR' => '/var/log/elasticsearch/es-01',
'ES_HOME' => '/usr/share/elasticsearch'
}
)}
end # of on os context
end # of on supported OSes loop
# Test all non OS-specific functionality with just a single distro
let :facts do {
:operatingsystem => 'CentOS',
:kernel => 'Linux',
:osfamily => 'RedHat',
:operatingsystemmajrelease => '6',
:scenario => '',
:common => '',
:hostname => 'foo'
} end
let(:params) do
{ :config => { 'node' => { 'name' => 'test' } } }
end
describe 'config file' do
it { should contain_datacat_fragment('main_config_es-01') }
it { should contain_datacat('/etc/elasticsearch/es-01/elasticsearch.yml') }
it { should contain_datacat_collector(
'/etc/elasticsearch/es-01/elasticsearch.yml'
) }
it { should contain_file('/etc/elasticsearch/es-01/elasticsearch.yml') }
end
describe 'service restarts' do
context 'do not happen when restart_on_change is false (default)' do
it { should_not contain_datacat(
'/etc/elasticsearch/es-01/elasticsearch.yml'
).that_notifies('Elasticsearch::Service[es-01]') }
it { should_not contain_package(
'elasticsearch'
).that_notifies('Elasticsearch::Service[es-01]') }
end
context 'happen when restart_on_change is true' do
let(:pre_condition) { 'class { "elasticsearch": restart_on_change => true }' }
it { should contain_datacat(
'/etc/elasticsearch/es-01/elasticsearch.yml'
).that_notifies('Elasticsearch::Service[es-01]') }
it { should contain_package(
'elasticsearch'
).that_notifies('Elasticsearch::Service[es-01]') }
end
context 'on package change' do
let(:pre_condition) { %q{
class { "elasticsearch": restart_package_change => true }
}}
it { should_not contain_datacat(
'/etc/elasticsearch/es-01/elasticsearch.yml'
).that_notifies('Elasticsearch::Service[es-01]') }
it { should contain_package(
'elasticsearch'
).that_notifies('Elasticsearch::Service[es-01]') }
end
context 'on config change' do
let(:pre_condition) { %q{
class { "elasticsearch": restart_config_change => true }
}}
it { should contain_datacat(
'/etc/elasticsearch/es-01/elasticsearch.yml'
).that_notifies('Elasticsearch::Service[es-01]') }
it { should_not contain_package(
'elasticsearch'
).that_notifies('Elasticsearch::Service[es-01]') }
end
end
context 'config dir' do
context 'default' do
it { should contain_exec('mkdir_configdir_elasticsearch_es-01') }
it { should contain_file('/etc/elasticsearch/es-01').with(:ensure => 'directory') }
it { should contain_datacat_fragment('main_config_es-01') }
it { should contain_datacat('/etc/elasticsearch/es-01/elasticsearch.yml') }
it { should contain_file('/etc/elasticsearch/es-01/logging.yml') }
it { should contain_file('/etc/elasticsearch/es-01/log4j2.properties') }
it { should contain_file('/usr/share/elasticsearch/scripts') }
it { should contain_file('/etc/elasticsearch/es-01/scripts').with(:target => '/usr/share/elasticsearch/scripts') }
end
context 'set in main class' do
let(:pre_condition) { <<-EOS
class { "elasticsearch":
configdir => "/etc/elasticsearch-config"
}
EOS
}
it { should contain_exec('mkdir_configdir_elasticsearch_es-01') }
it { should contain_file('/etc/elasticsearch-config').with(:ensure => 'directory') }
it { should contain_file('/usr/share/elasticsearch/templates_import').with(:ensure => 'directory') }
it { should contain_file('/etc/elasticsearch-config/es-01').with(:ensure => 'directory') }
it { should contain_datacat_fragment('main_config_es-01') }
it { should contain_datacat('/etc/elasticsearch-config/es-01/elasticsearch.yml') }
it { should contain_file('/etc/elasticsearch-config/es-01/logging.yml') }
it { should contain_file('/etc/elasticsearch-config/es-01/log4j2.properties') }
it { should contain_file('/etc/elasticsearch-config/jvm.options') }
it { should contain_file('/usr/share/elasticsearch/scripts') }
it { should contain_file('/etc/elasticsearch-config/es-01/scripts').with(:target => '/usr/share/elasticsearch/scripts') }
end
context 'set in instance' do
let :params do {
:configdir => '/etc/elasticsearch-config/es-01'
} end
it { should contain_exec('mkdir_configdir_elasticsearch_es-01') }
it { should contain_file('/etc/elasticsearch').with(:ensure => 'directory') }
it { should contain_file('/etc/elasticsearch-config/es-01').with(:ensure => 'directory') }
it { should contain_datacat_fragment('main_config_es-01') }
it { should contain_datacat('/etc/elasticsearch-config/es-01/elasticsearch.yml') }
it { should contain_file('/etc/elasticsearch-config/es-01/logging.yml') }
it { should contain_file('/etc/elasticsearch-config/es-01/log4j2.properties') }
it { should contain_file('/usr/share/elasticsearch/scripts') }
it { should contain_file('/etc/elasticsearch-config/es-01/scripts').with(:target => '/usr/share/elasticsearch/scripts') }
end
end
context 'data directory' do
context 'default' do
it { should contain_exec('mkdir_logdir_elasticsearch_es-01') }
it { should contain_exec('mkdir_datadir_elasticsearch_es-01') }
it { should contain_file('/var/lib/elasticsearch/es-01').with(:ensure => 'directory') }
it { should contain_file('/var/lib/elasticsearch').with(:ensure => 'directory') }
end
context 'datadir_instance_directories' do
let(:pre_condition) do
<<-EOS
class { "elasticsearch":
datadir_instance_directories => false
}
EOS
end
it { should contain_exec('mkdir_logdir_elasticsearch_es-01') }
it { should_not contain_exec('mkdir_datadir_elasticsearch_es-01') }
it { should_not contain_file('/var/lib/elasticsearch/es-01').with(:ensure => 'directory') }
it { should contain_file('/var/lib/elasticsearch').with(:ensure => 'directory') }
end
context 'single from main config ' do
let(:pre_condition) { <<-EOS
class { "elasticsearch":
datadir => "/var/lib/elasticsearch-data"
}
EOS
}
it { should contain_exec('mkdir_logdir_elasticsearch_es-01') }
it { should contain_exec('mkdir_datadir_elasticsearch_es-01') }
it { should contain_file('/var/lib/elasticsearch-data').with(:ensure => 'directory') }
it { should contain_file('/var/lib/elasticsearch-data/es-01').with(:ensure => 'directory') }
end
context 'single from instance config' do
let :params do {
:datadir => '/var/lib/elasticsearch/data'
} end
it { should contain_exec('mkdir_logdir_elasticsearch_es-01') }
it { should contain_exec('mkdir_datadir_elasticsearch_es-01') }
it { should contain_file('/var/lib/elasticsearch/data').with(:ensure => 'directory') }
end
context 'multiple from main config' do
let(:pre_condition) { <<-EOS
class { "elasticsearch":
datadir => [
"/var/lib/elasticsearch-data01",
"/var/lib/elasticsearch-data02"
]
}
EOS
}
it { should contain_exec('mkdir_logdir_elasticsearch_es-01') }
it { should contain_exec('mkdir_datadir_elasticsearch_es-01') }
it { should contain_file('/var/lib/elasticsearch-data01').with(:ensure => 'directory') }
it { should contain_file('/var/lib/elasticsearch-data01/es-01').with(:ensure => 'directory') }
it { should contain_file('/var/lib/elasticsearch-data02').with(:ensure => 'directory') }
it { should contain_file('/var/lib/elasticsearch-data02/es-01').with(:ensure => 'directory') }
end
context 'multiple from instance config' do
let :params do {
:datadir => [
'/var/lib/elasticsearch-data/01',
'/var/lib/elasticsearch-data/02'
]
} end
it { should contain_exec('mkdir_logdir_elasticsearch_es-01') }
it { should contain_exec('mkdir_datadir_elasticsearch_es-01') }
it { should contain_file('/var/lib/elasticsearch-data/01').with(:ensure => 'directory') }
it { should contain_file('/var/lib/elasticsearch-data/02').with(:ensure => 'directory') }
end
context 'conflicting setting path.data' do
let :params do {
:datadir => '/var/lib/elasticsearch/data',
:config => { 'path.data' => '/var/lib/elasticsearch/otherdata' }
} end
it { should contain_exec('mkdir_logdir_elasticsearch_es-01') }
it { should contain_exec('mkdir_datadir_elasticsearch_es-01') }
it { should contain_file('/var/lib/elasticsearch/data').with(:ensure => 'directory') }
it { should_not contain_file('/var/lib/elasticsearch/otherdata').with(:ensure => 'directory') }
end
context 'conflicting setting path => data' do
let :params do {
:datadir => '/var/lib/elasticsearch/data',
:config => {
'path' => { 'data' => '/var/lib/elasticsearch/otherdata' }
}
} end
it { should contain_exec('mkdir_logdir_elasticsearch_es-01') }
it { should contain_exec('mkdir_datadir_elasticsearch_es-01') }
it { should contain_file('/var/lib/elasticsearch/data').with(:ensure => 'directory') }
it { should_not contain_file('/var/lib/elasticsearch/otherdata').with(:ensure => 'directory') }
end
context 'with other path options defined' do
let :params do {
:datadir => '/var/lib/elasticsearch/data',
:config => { 'path' => { 'home' => '/var/lib/elasticsearch' } }
} end
it { should contain_exec('mkdir_logdir_elasticsearch_es-01') }
it { should contain_exec('mkdir_datadir_elasticsearch_es-01') }
it { should contain_file('/var/lib/elasticsearch/data').with(:ensure => 'directory') }
end
end
context 'logs directory' do
context 'default' do
it { should contain_file('/var/log/elasticsearch/es-01')
.with(:ensure => 'directory') }
it { should contain_file('/var/log/elasticsearch')
.with(:ensure => 'directory') }
end
context 'single from main config ' do
let(:pre_condition) { <<-EOS
class { "elasticsearch":
logdir => "/var/log/elasticsearch-logs"
}
EOS
}
it { should contain_file('/var/log/elasticsearch-logs')
.with(:ensure => 'directory') }
it { should contain_file('/var/log/elasticsearch-logs/es-01')
.with(:ensure => 'directory') }
end
context 'single from instance config' do
let :params do {
:logdir => '/var/log/elasticsearch/logs-a'
} end
it { should contain_file('/var/log/elasticsearch/logs-a').with(:ensure => 'directory') }
end
context 'Conflicting setting path.logs' do
let :params do {
:logdir => '/var/log/elasticsearch/logs-a',
:config => { 'path.logs' => '/var/log/elasticsearch/otherlogs' }
} end
it { should contain_file('/var/log/elasticsearch/logs-a')
.with(:ensure => 'directory') }
it { should_not contain_file('/var/log/elasticsearch/otherlogs')
.with(:ensure => 'directory') }
end
context 'Conflicting setting path => logs' do
let :params do {
:logdir => '/var/log/elasticsearch/logs-a',
:config => { 'path' => { 'logs' => '/var/log/elasticsearch/otherlogs' } }
} end
it { should contain_file('/var/log/elasticsearch/logs-a')
.with(:ensure => 'directory') }
it { should_not contain_file('/var/log/elasticsearch/otherlogs')
.with(:ensure => 'directory') }
end
context 'With other path options defined' do
let :params do {
:logdir => '/var/log/elasticsearch/logs-a',
:config => { 'path' => { 'home' => '/var/log/elasticsearch' } }
} end
it { should contain_file('/var/log/elasticsearch/logs-a').with( :ensure => 'directory') }
end
end
context 'logging' do
context 'default' do
it { should contain_file('/etc/elasticsearch/es-01/logging.yml')
.with_content(
/^logger.index.search.slowlog: TRACE, index_search_slow_log_file$/,
/type: dailyRollingFile/,
/datePattern: "'.'yyyy-MM-dd"/
).with(:source => nil)
}
end
context 'from main class' do
context 'config' do
let(:pre_condition) { <<-EOS
class { "elasticsearch":
logging_config => {
"index.search.slowlog" => "DEBUG, index_search_slow_log_file"
}
}
EOS
}
it { should contain_file('/etc/elasticsearch/es-01/logging.yml').with_content(/^logger.index.search.slowlog: DEBUG, index_search_slow_log_file$/).with(:source => nil) }
end
context 'logging file ' do
let(:pre_condition) { <<-EOS
class { "elasticsearch":
logging_file => "puppet:///path/to/logging.yml"
}
EOS
}
it { should contain_file('/etc/elasticsearch/es-01/logging.yml').with(:source => 'puppet:///path/to/logging.yml', :content => nil) }
end
end
context 'from instance' do
context 'config' do
let :params do {
:logging_config => {
'index.search.slowlog' => 'INFO, index_search_slow_log_file'
}
} end
it { should contain_file('/etc/elasticsearch/es-01/logging.yml').with_content(/^logger.index.search.slowlog: INFO, index_search_slow_log_file$/).with(:source => nil) }
end
context 'logging file' do
let :params do {
:logging_file => 'puppet:///path/to/logging.yml'
} end
it { should contain_file('/etc/elasticsearch/es-01/logging.yml').with(:source => 'puppet:///path/to/logging.yml', :content => nil) }
end
context 'deprecation logging' do
let :params do {
:deprecation_logging => true
} end
it { should contain_file('/etc/elasticsearch/es-01/logging.yml').with_content(/^logger.deprecation: DEBUG, deprecation_log_file$/).with(:source=> nil) }
it { should contain_file('/etc/elasticsearch/es-01/logging.yml')
.with_content(
/deprecation_log_file:$/,
/type: dailyRollingFile$/,
/file: ${path.logs}\/\${cluster.name}_deprecation.log$/,
/datePattern: "'.'yyyy-MM-dd"$/,
/layout:$/,
/type: pattern$/,
/conversionPattern: "[%d{ISO8601}][%-5p][%-25c] %m%n"$/
).with(:source=>nil)
}
end
context 'deprecation logging level' do
let :params do {
:deprecation_logging => true,
:deprecation_logging_level => 'INFO'
} end
it { should contain_file('/etc/elasticsearch/es-01/logging.yml').with_content(/^logger.deprecation: INFO, deprecation_log_file$/).with(:source=> nil) }
end
end
describe 'rollingFile apender' do
let(:pre_condition) {%q{
class { 'elasticsearch':
file_rolling_type => 'rollingFile',
rolling_file_max_backup_index => 10,
rolling_file_max_file_size => '100MB',
}
}}
it { should contain_file('/etc/elasticsearch/es-01/logging.yml')
.with_content(
/type: rollingFile/,
/maxBackupIndex: 10/,
/maxBackupIndex: 10/,
/maxFileSize: 100MB/)
}
end
end
context 'running as an other user' do
let(:pre_condition) { <<-EOS
class { "elasticsearch":
elasticsearch_user => "myesuser",
elasticsearch_group => "myesgroup"
}
EOS
}
it { should contain_file('/var/lib/elasticsearch/es-01').with(:owner => 'myesuser') }
it { should contain_file('/etc/elasticsearch/es-01').with(:owner => 'myesuser', :group => 'myesgroup') }
it { should contain_datacat('/etc/elasticsearch/es-01/elasticsearch.yml').with(:owner => 'myesuser', :group => 'myesgroup') }
it { should contain_file('/etc/elasticsearch/es-01/elasticsearch.yml').with(:owner => 'myesuser', :group => 'myesgroup') }
it { should contain_file('/etc/elasticsearch/es-01/logging.yml').with(:owner => 'myesuser', :group => 'myesgroup') }
it { should contain_file('/etc/elasticsearch/es-01/log4j2.properties').with(:owner => 'myesuser', :group => 'myesgroup') }
end
context 'setting different service status then main class' do
let(:pre_condition) { 'class {"elasticsearch": status => "enabled" }' }
context 'status option' do
let :params do {
:status => 'running'
} end
it { should contain_service('elasticsearch-instance-es-01').with(:ensure => 'running', :enable => false) }
end
end
context 'init_template' do
context 'default' do
it { should contain_elasticsearch__service('es-01').with(:init_template => 'elasticsearch/etc/init.d/elasticsearch.RedHat.erb') }
end
context 'override in main class' do
let(:pre_condition) { <<-EOS
class { "elasticsearch":
init_template => "elasticsearch/etc/init.d/elasticsearch.systemd.erb"
}
EOS
}
it { should contain_elasticsearch__service('es-01')
.with(:init_template => 'elasticsearch/etc/init.d/elasticsearch.systemd.erb') }
end
end
describe 'security plugins' do
describe 'system_key' do
context 'inherited' do
let(:pre_condition) {%q{
class { 'elasticsearch':
security_plugin => 'shield',
system_key => '/tmp/key'
}
}}
it { should contain_file('/etc/elasticsearch/es-01/shield') }
it { should contain_file(
'/etc/elasticsearch/es-01/shield/system_key'
).with_source(
'/tmp/key'
) }
end
context 'from instance' do
let(:pre_condition) {%q{
class { 'elasticsearch':
security_plugin => 'x-pack',
}
}}
let :params do {
:system_key => 'puppet:///test/key'
} end
it { should contain_file('/etc/elasticsearch/es-01/x-pack') }
it { should contain_file(
'/etc/elasticsearch/es-01/x-pack/system_key'
).with_source(
'puppet:///test/key'
) }
end
end
end
describe 'recursive configuration directory management' do
['shield', 'x-pack'].each do |plugin|
context 'shield' do
context 'without resource notifications' do
let(:pre_condition) do
%(
class { 'elasticsearch':
security_plugin => '#{plugin}',
}
)
end
it "copies the #{plugin} directory from the source" do
should(
contain_file(
"/etc/elasticsearch/es-01/#{plugin}"
).with(
:ensure => 'directory',
:mode => '0644',
:source => "/etc/elasticsearch/#{plugin}",
:recurse => 'remote',
:owner => 'root',
:group => '0',
:before => 'Elasticsearch::Service[es-01]'
)
)
end
end
context 'with resource notifications' do
let(:pre_condition) do
%(
class { 'elasticsearch':
security_plugin => '#{plugin}',
restart_on_change => true,
}
)
end
it "copies the #{plugin} directory from the source" do
should(
contain_file(
"/etc/elasticsearch/es-01/#{plugin}"
).with(
:ensure => 'directory',
:mode => '0644',
:source => "/etc/elasticsearch/#{plugin}",
:recurse => 'remote',
:owner => 'root',
:group => '0',
:before => 'Elasticsearch::Service[es-01]',
:notify => 'Elasticsearch::Service[es-01]'
)
)
end
end
end
end
end
+
+ describe 'keystore' do
+ let(:settings) do {
+ 'cloud.aws.access_key' => 'AKIA...',
+ 'cloud.aws.secret_key' => 'AKIA...'
+ } end
+
+ describe 'secrets' do
+ context 'inherited' do
+ let(:pre_condition) do
+ <<-EOS
+ class { 'elasticsearch':
+ secrets => #{settings}
+ }
+ EOS
+ end
+
+ it { should contain_elasticsearch_keystore('es-01').with_settings(settings) }
+ end
+
+ context 'from instance' do
+ let :params do {
+ :secrets => settings
+ } end
+
+ it { should contain_elasticsearch_keystore('es-01').with_settings(settings) }
+ end
+
+ context 'notify events' do
+ let(:pre_condition) do
+ <<-EOS
+ class { 'elasticsearch':
+ restart_on_change => true
+ }
+ EOS
+ end
+
+ let :params do {
+ :secrets => {}
+ } end
+
+ it { should contain_elasticsearch_keystore('es-01').that_notifies('Elasticsearch::Service[es-01]') }
+ end
+ end
+
+ describe 'purge_secrets' do
+ context 'default' do
+ let :params do {
+ :secrets => settings
+ } end
+
+ it { should contain_elasticsearch_keystore('es-01').with_purge(false) }
+ end
+
+ context 'inherited' do
+ let(:pre_condition) do
+ <<-EOS
+ class { 'elasticsearch':
+ purge_secrets => true,
+ secrets => #{settings}
+ }
+ EOS
+ end
+
+ it { should contain_elasticsearch_keystore('es-01').with_purge(true) }
+ end
+
+ context 'from instance' do
+ let :params do {
+ :purge_secrets => true,
+ :secrets => settings
+ } end
+
+ it { should contain_elasticsearch_keystore('es-01').with_purge(true) }
+ end
+ end
+ end
end
diff --git a/spec/unit/provider/elasticsearch_keystore/elasticsearch_keystore_spec.rb b/spec/unit/provider/elasticsearch_keystore/elasticsearch_keystore_spec.rb
new file mode 100644
index 0000000..fc1f93b
--- /dev/null
+++ b/spec/unit/provider/elasticsearch_keystore/elasticsearch_keystore_spec.rb
@@ -0,0 +1,150 @@
+require 'spec_helper'
+
+shared_examples 'keystore instance' do |instance|
+ describe "instance #{instance}" do
+ subject { described_class.instances.find { |x| x.name == instance } }
+
+ it { expect(subject.exists?).to be_truthy }
+ it { expect(subject.name).to eq(instance) }
+ it { expect(subject.settings)
+ .to eq(['node.name', 'cloud.aws.access_key']) }
+ end
+end
+
+describe Puppet::Type.type(:elasticsearch_keystore).provider(:elasticsearch_keystore) do
+ let(:executable) { '/usr/share/elasticsearch/bin/elasticsearch-keystore' }
+ let(:instances) { [] }
+
+ before do
+ allow(described_class)
+ .to receive(:command)
+ .with(:keystore)
+ .and_return(executable)
+
+ allow(File).to receive(:exist?)
+ .with('/etc/elasticsearch/scripts/elasticsearch.keystore')
+ .and_return(false)
+ end
+
+ describe 'instances' do
+ before do
+ allow(Dir).to receive(:[])
+ .with('/etc/elasticsearch/*')
+ .and_return((['scripts'] + instances).map do |directory|
+ "/etc/elasticsearch/#{directory}"
+ end)
+
+ instances.each do |instance|
+ instance_dir = "/etc/elasticsearch/#{instance}"
+ defaults_file = "/etc/default/elasticsearch-#{instance}"
+
+ allow(File).to receive(:exist?)
+ .with("#{instance_dir}/elasticsearch.keystore")
+ .and_return(true)
+
+ described_class
+ .expects(:execute)
+ .with(
+ [executable, 'list'],
+ :custom_environment => { 'ES_INCLUDE' => defaults_file },
+ :uid => 'elasticsearch', :gid => 'elasticsearch'
+ )
+ .returns(
+ Puppet::Util::Execution::ProcessOutput.new(
+ "node.name\ncloud.aws.access_key\n", 0
+ )
+ )
+ end
+ end
+
+ it 'should have an instance method' do
+ expect(described_class).to respond_to(:instances)
+ end
+
+ context 'without any keystores' do
+ it 'should return no resources' do
+ expect(described_class.instances.size).to eq(0)
+ end
+ end
+
+ context 'with one instance' do
+ let(:instances) { ['es-01'] }
+
+ it { expect(described_class.instances.length).to eq(instances.length) }
+ include_examples 'keystore instance', 'es-01'
+ end
+
+ context 'with multiple instances' do
+ let(:instances) { ['es-01', 'es-02'] }
+
+ it { expect(described_class.instances.length).to eq(instances.length) }
+ include_examples 'keystore instance', 'es-01'
+ include_examples 'keystore instance', 'es-02'
+ end
+ end # of describe instances
+
+ describe 'prefetch' do
+ it 'should have a prefetch method' do
+ expect(described_class).to respond_to :prefetch
+ end
+ end
+
+ describe 'flush' do
+ let(:provider) { described_class.new(:name => 'es-03') }
+ let(:resource) do
+ Puppet::Type.type(:elasticsearch_keystore).new(
+ :name => 'es-03',
+ :provider => provider
+ )
+ end
+
+ it 'creates the keystore' do
+ expect(described_class).to(
+ receive(:execute)
+ .with(
+ [executable, 'create'],
+ :custom_environment => {
+ 'ES_INCLUDE' => '/etc/default/elasticsearch-es-03'
+ },
+ :uid => 'elasticsearch', :gid => 'elasticsearch'
+ )
+ .and_return(Puppet::Util::Execution::ProcessOutput.new('', 0))
+ )
+ resource[:ensure] = :present
+ provider.create
+ provider.flush
+ end
+
+ it 'deletes the keystore' do
+ expect(File).to(
+ receive(:delete)
+ .with(File.join(%w[/ etc elasticsearch es-03 elasticsearch.keystore]))
+ )
+ resource[:ensure] = :absent
+ provider.destroy
+ provider.flush
+ end
+
+ it 'updates settings' do
+ settings = {
+ 'cloud.aws.access_key' => 'AKIAFOOBARFOOBAR',
+ 'cloud.aws.secret_key' => 'AKIAFOOBARFOOBAR'
+ }
+
+ settings.each do |setting, value|
+ expect(provider.class).to(
+ receive(:run_keystore)
+ .with(['add', '--force', '--stdin', setting], 'es-03', value)
+ .and_return(Puppet::Util::Execution::ProcessOutput.new('', 0))
+ )
+ end
+
+ # Note that the settings hash is passed in wrapped in an array to mimic
+ # the behavior in real-world puppet runs.
+ resource[:ensure] = :present
+ resource[:settings] = [settings]
+ provider.settings = [settings]
+ provider.flush
+ end
+ end # of describe flush
+end # of describe Puppet::Type elasticsearch_keystore
diff --git a/spec/unit/type/elasticsearch_keystore_spec.rb b/spec/unit/type/elasticsearch_keystore_spec.rb
new file mode 100644
index 0000000..a203bf8
--- /dev/null
+++ b/spec/unit/type/elasticsearch_keystore_spec.rb
@@ -0,0 +1,93 @@
+require 'spec_helper'
+
+describe Puppet::Type.type(:elasticsearch_keystore) do
+ let(:resource_name) { 'es-01' }
+
+ describe 'validating attributes' do
+ %i[instance purge].each do |param|
+ it "should have a `#{param}` parameter" do
+ expect(described_class.attrtype(param)).to eq(:param)
+ end
+ end
+
+ %i[ensure settings].each do |prop|
+ it "should have a #{prop} property" do
+ expect(described_class.attrtype(prop)).to eq(:property)
+ end
+ end
+
+ describe 'namevar validation' do
+ it 'should have :instance as its namevar' do
+ expect(described_class.key_attributes).to eq([:instance])
+ end
+ end
+ end # of describe validating attributes
+
+ describe 'when validating values' do
+ describe 'ensure' do
+ it 'should support present as a value for ensure' do
+ expect { described_class.new(
+ :name => resource_name,
+ :ensure => :present
+ ) }.to_not raise_error
+ end
+
+ it 'should support absent as a value for ensure' do
+ expect { described_class.new(
+ :name => resource_name,
+ :ensure => :absent
+ ) }.to_not raise_error
+ end
+
+ it 'should not support other values' do
+ expect { described_class.new(
+ :name => resource_name,
+ :ensure => :foo
+ ) }.to raise_error(Puppet::Error, /Invalid value/)
+ end
+ end
+
+ describe 'settings' do
+ [{ 'node.name' => 'foo' }, ['node.name', 'node.data']].each do |setting|
+ it "accepts #{setting.class}s" do
+ expect { described_class.new(
+ :name => resource_name,
+ :settings => setting
+ ) }.to_not raise_error
+ end
+ end
+
+ describe 'insync' do
+ it 'only checks lists or hash key membership' do
+ expect(described_class.new(
+ :name => resource_name,
+ :settings => { 'node.name' => 'foo', 'node.data' => true }
+ ).property(:settings).insync?(
+ %w[node.name node.data]
+ )).to be true
+ end
+
+ context 'purge' do
+ it 'defaults to not purge values' do
+ expect(described_class.new(
+ :name => resource_name,
+ :settings => { 'node.name' => 'foo', 'node.data' => true }
+ ).property(:settings).insync?(
+ %w[node.name node.data node.attr.rack]
+ )).to be true
+ end
+
+ it 'respects the purge parameter' do
+ expect(described_class.new(
+ :name => resource_name,
+ :settings => { 'node.name' => 'foo', 'node.data' => true },
+ :purge => true
+ ).property(:settings).insync?(
+ %w[node.name node.data node.attr.rack]
+ )).to be false
+ end
+ end
+ end
+ end
+ end # of describing when validating values
+end # of describe Puppet::Type

File Metadata

Mime Type
text/x-diff
Expires
Jul 4 2025, 7:28 PM (7 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3346696

Event Timeline