0

I've just started to learn Ansible. I have the following tasks defined in a role for installing elasticsearch.

---
- name: install elasticsearch
  homebrew: name=elasticsearch state=present
- command: brew --prefix elasticsearch
  register: elasticsearch_home
- name: install elasticsearch-head
  command: "{{ elasticsearch_home.stdout }}/bin/plugin --install mobz/elasticsearch-head"
- name: install elasticsearch-analysis-icu
  command: "{{ elasticsearch_home.stdout }}/bin/plugin --install elasticsearch/elasticsearch-analysis-icu/2.2.0"
- name: install elasticsearch-inquisitor
  command: "{{ elasticsearch_home.stdout }}/bin/plugin --install polyfractal/elasticsearch-inquisitor"

And I get the following error when running my playbook.

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [localhost]

TASK: [java | install latest java] ********************************************
ok: [localhost]

TASK: [elasticsearch | install elasticsearch] *********************************
ok: [localhost]

TASK: [elasticsearch | command brew --prefix elasticsearch] *******************
changed: [localhost]

TASK: [elasticsearch | install elasticsearch-head] ****************************
failed: [localhost] => {"changed": true, "cmd": "/usr/local/opt/elasticsearch/bin/plugin --install mobz/elasticsearch-head", "delta": "0:00:00.264923", "end": "2015-03-21 21:18:36.863296", "rc": 1, "start": "2015-03-21 21:18:36.598373", "warnings": []}
stderr: Exception in thread "main" org.elasticsearch.common.settings.SettingsException: Failed to load settings from [file:/Users/<username>/elasticsearch.yml]
at org.elasticsearch.common.settings.ImmutableSettings$Builder.loadFromStream(ImmutableSettings.java:947)
at org.elasticsearch.common.settings.ImmutableSettings$Builder.loadFromUrl(ImmutableSettings.java:931)
at org.elasticsearch.node.internal.InternalSettingsPreparer.prepareSettings(InternalSettingsPreparer.java:77)
at org.elasticsearch.plugins.PluginManager.main(PluginManager.java:389)
Caused by: org.elasticsearch.ElasticsearchParseException: malformed, expected settings to start with 'object', instead was [START_ARRAY]
at org.elasticsearch.common.settings.loader.XContentSettingsLoader.load(XContentSettingsLoader.java:65)
at org.elasticsearch.common.settings.loader.XContentSettingsLoader.load(XContentSettingsLoader.java:45)
at org.elasticsearch.common.settings.loader.YamlSettingsLoader.load(YamlSettingsLoader.java:46)
at org.elasticsearch.common.settings.ImmutableSettings$Builder.loadFromStream(ImmutableSettings.java:944)
... 3 more

FATAL: all hosts have already failed -- aborting

PLAY RECAP ********************************************************************
       to retry, use: --limit @/Users/<username>/elasticsearch.retry

localhost                  : ok=4    changed=1    unreachable=0    failed=1

At first I thought it might be a bug in the plugin installer that was incorrectly handling the case where the plugin was already installed. I uninstalled the plugin and then ran the plays again, but I received the exact same error. I also tried using shell instead of command, but there was no difference in result.

stderr: Exception in thread "main" org.elasticsearch.common.settings.SettingsException: Failed to load settings from [file:/Users/<username>/elasticsearch.yml]

This line makes me think that elasticsearch is not receiving some configurations correctly. But I don't understand why it would expect to get information from the yml file. Even if there was some feature that allowed for piping settings into the elasticsearch plugin installer, I would expect that using Ansible's shell module would execute the command in a separate shell and therefore elasticsearch would have no clue about the yml file or Ansible. Any ideas?

glevine
  • 697
  • 1
  • 7
  • 19
  • I forgot to mention that the plugin installs without error when I run the command in my terminal instead of using Ansible. – glevine Mar 22 '15 at 12:41
  • Maybe Elastic Search legitimately expects to get some settings from a file named `elasticsearch.yml` and I guess it conflicts with your playbook file? If you rename your playbook, does that filename changes too? – Mxx Mar 22 '15 at 17:03
  • Can you post the playbook where you include the tasks as well as the command line invocation? Also did you replace actual username with `` in output or that's how ansible printed it? – Kashyap Mar 22 '15 at 21:46
  • @Mxx - Great call. I hadn't considered that possibility, but that's exactly it. For the time being, I'll just rename my task, but I'm definitely curious as to why this comes up or if there is a way to avoid it. I want to know if Ansible is sending this file to elasticsearch or if elasticsearch is looking for it in the cwd. So I'll have to dig into that. Thanks! – glevine Mar 23 '15 at 01:07
  • @thekashyap - `` was just me redacting my actual user name for obscurity. No real good reason behind it. The rest of the output was legitimate. – glevine Mar 23 '15 at 01:08

2 Answers2

2

According to http://www.elastic.co/guide/en/elasticsearch/reference/master/setup-configuration.html

Elasticsearch Settings

elasticsearch configuration files can be found under ES_HOME/config folder. The folder comes with two files, the elasticsearch.yml for configuring Elasticsearch different modules, and logging.yml for configuring the Elasticsearch logging.

So most likely what was happening is elasticsearch got confused and thought that your playbook file was elasticsearch's own config file.

The simplest way to solve this problem is to rename your playbook file to a different filename.

However, a more proper way is to modify your task to use chdir parameter of command module.

- name: install elasticsearch-head
  command: "bin/plugin --install mobz/elasticsearch-head chdir={{ elasticsearch_home.stdout }}"

That way this command is run from within ES's bin/ directory.

Mxx
  • 8,979
  • 4
  • 27
  • 37
  • It has more to do with how elasticsearch loads its settings file. It will search a few locations, but the issue in my case is that it is found in the cwd. Ansible cd's into the dir with the playbooks before executing them. So Ansible's behavior leads to an unintended consequence that just so happens to occur with elasticsearch. But I'm sure this is the minority. Changing the playbook filename works as a workaround. – glevine Mar 23 '15 at 13:31
  • Here is a thread on the Ansible Google Group page describing the issue in more detail. https://groups.google.com/d/topic/ansible-project/Fv32e6pdx3Q/discussion – glevine Mar 23 '15 at 13:32
  • I never down voted it. I'm not sure what is responsible for that. – glevine Mar 23 '15 at 13:37
  • @glevine I updated this answer to have your comment. This way this is the canonical answer. – Mxx Mar 23 '15 at 15:17
2

An alternative to changing the playbook filename is to use Ansible's chdir feature for the command action.

Changing...

- name: install elasticsearch-head
  command: "{{ elasticsearch_home.stdout }}/bin/plugin --install mobz/elasticsearch-head"

... to...

- name: install elasticsearch-head
  command: "bin/plugin --install mobz/elasticsearch-head chdir={{ elasticsearch_home.stdout }}"

... solves the problem. I prefer this solution because it means I'm not restricted in choice of filename. However, the selected answer (and comments) is chosen because it describes the root cause and this solution is only necessary if you care about the filename.

glevine
  • 697
  • 1
  • 7
  • 19