Unable to find an inventory file

Trellis, bedrock and sage all setup and working great locally but now trying to move the site to production.

Setup a default Ubuntu Digital Ocean droplet. Followed the instructions from https://roots.io/trellis/docs/remote-server-setup/.

In terminal, cd into trellis directory (which contains server.yml.

Entered: ansible-playbook server.yml -e env=production

But it outputs the following error: ERROR: Unable to find an inventory file, specify one with -i ?

The “production” file is in the default hosts directory so not sure why it’s not finding it. Also in that file I added the digital ocean IP address. Any ideas?

Ah looks like it’s just a typo on the roots documentation:

While it says, “ansible-playbook server.yml -e env=production”

On https://github.com/roots/trellis it says: “ansible-playbook -i hosts/production server.yml”

Which does work! So looks like the docs just needs to be updated.

1 Like

Does your ansible.cfg have inventory = hosts? That would be easiest, but you could alternatively add -i to your command:

ansible-playbook server.yml -i hosts/production -e env=production
1 Like

@ChrisC Thanks for catching this. It is the README that needs to be updated and it was my omission in roots/trellis#313. Before #313 (Dec 28, 2015) the command was this:

ansible-playbook -i hosts/production server.yml

After #313 (Dec 28, 2015) the command is this:

ansible-playbook server.yml -e env=production

(and the ansible.cfg sets a default inventory directory)

1 Like

Thanks!

Looks like everything worked with the exception of Failed to Ban which didn’t install and gave the following error:

fatal: [The Server IP] => Failed to template 5XC&7G<{%GJm,|BEqFNWVV170i~7;dX0a+<ZN* U>XS{,a[Puf<VVT(/%F!-qAUX: template error while templating string: Encountered unknown tag 'GJm'.

NOTIFIED: [fail2ban | restart fail2ban] *************************************** 
FATAL: no hosts matched or all hosts have already failed -- aborting


PLAY RECAP ******************************************************************** 
           to retry, use: --limit @/Users/MyAccountName/server.retry

Not sure if that is possibly a DigitalOcean issue I should investigate with them or possibly something on the Roots/MySide.

To note, tried ignoring the error and running, “./deploy.sh production mysitename.com

And provides the following error:

PLAY [Deploy WP site] ********************************************************* 

GATHERING FACTS *************************************************************** 
fatal: [digitalocean-IP-here] => Failed to template {{ wordpress_sites[site] }}: Failed to template 5XC&7G<{%GJm,|BEqFNWVV170i~7;dX0a+<ZN* U>XS{,a[Puf<VVT(/%F!-qAUX: template error while templating string: Encountered unknown tag 'GJm'.

TASK: [deploy | Initialize] *************************************************** 
FATAL: no hosts matched or all hosts have already failed -- aborting


PLAY RECAP ******************************************************************** 
           to retry, use: --limit @/Users/Chris/deploy.retry

digitalocean-IP-here             : ok=0    changed=0    unreachable=1    failed=0

I’m guessing your salts/keys include that problematic string {%
See note. The jinja templating used by Ansible considers this sequence of characters a special templating marker, throwing things off if included in your salts.

  • Regenerate your salts/keys or adjust one of those two characters to something else.
  • rerun server.yml so it can finish the other tasks that were not run due to the failed task.
  • rerun deploy.yml
2 Likes

Would have never considered that. Good catch. Reran server.yml and just see two errors:

One is ssh error on port 22 connection refused and the other is that I must add sudo to admin_user group and a password for it in the suoder file. However, both of those admin_user items are already done so not sure why it’s not working.

MyComputer:trellis MyName$ ansible-playbook server.yml -e env=production

PLAY [Determine Remote User] ************************************************** 

TASK: [remote-user | Determine whether to connect as root or admin_user] ****** 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     35      0 --:--:-- --:--:-- --:--:--    35
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     33      0 --:--:-- --:--:-- --:--:--    33
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
110000        1133        00        1133        00          00          3357            00  ----::----::----  ----::----::----  ----::----::----        3357

ok: [127.0.0.1 -> 127.0.0.1]
ok: [DO-IP-ADDRESS -> 127.0.0.1]

TASK: [remote-user | Set remote user for each host] *************************** 
ok: [127.0.0.1]
ok: [DO-IP-ADDRESS]

TASK: [remote-user | Announce which user was selected] ************************ 
ok: [127.0.0.1] => {
    "msg": "Note: Ansible will attempt connections as user = admin"
}
ok: [DO-IP-ADDRESS] => {
    "msg": "Note: Ansible will attempt connections as user = root"
}

PLAY [WordPress Server - Install LEMP Stack with PHP 5.6 and MariaDB MySQL] *** 

GATHERING FACTS *************************************************************** 
fatal: [127.0.0.1] => SSH Error: ssh: connect to host 127.0.0.1 port 22: Connection refused
    while connecting to 127.0.0.1:22
It is sometimes useful to re-run the command using -vvvv, which prints SSH debug output to help diagnose the issue.
ok: [DO-IP-ADDRESS]

TASK: [common | Validate Ansible version] ************************************* 
ok: [DO-IP-ADDRESS]

TASK: [common | Update Apt] *************************************************** 
ok: [DO-IP-ADDRESS]

TASK: [common | Checking essentials] ****************************************** 
ok: [DO-IP-ADDRESS] => (item=python-software-properties,python-pycurl,build-essential,python-mysqldb,curl,git-core)

TASK: [common | Validate timezone variable] *********************************** 
ok: [DO-IP-ADDRESS]

TASK: [common | Explain timezone error] *************************************** 
skipping: [DO-IP-ADDRESS]

TASK: [common | Get current timezone] ***************************************** 
ok: [DO-IP-ADDRESS]

TASK: [common | Set timezone] ************************************************* 
skipping: [DO-IP-ADDRESS]

TASK: [swapfile | Write swapfile] ********************************************* 
ok: [DO-IP-ADDRESS]

TASK: [swapfile | Set swapfile permissions] *********************************** 
ok: [DO-IP-ADDRESS]

TASK: [swapfile | Create swapfile] ******************************************** 
skipping: [DO-IP-ADDRESS]

TASK: [swapfile | Enable swapfile] ******************************************** 
skipping: [DO-IP-ADDRESS]

TASK: [swapfile | Add swapfile to /etc/fstab] ********************************* 
ok: [DO-IP-ADDRESS]

TASK: [swapfile | Configure vm.swappiness] ************************************ 
skipping: [DO-IP-ADDRESS]

TASK: [swapfile | Configure vm.vfs_cache_pressure] **************************** 
skipping: [DO-IP-ADDRESS]

TASK: [fail2ban | ensure fail2ban is installed] ******************************* 
ok: [DO-IP-ADDRESS]

TASK: [fail2ban | ensure fail2ban is configured] ****************************** 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     36      0 --:--:-- --:--:-- --:--:--    36
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     37      0 --:--:-- --:--:-- --:--:--    36
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     39      0 --:--:-- --:--:-- --:--:--    39
ok: [DO-IP-ADDRESS] => (item=jail.local)
ok: [DO-IP-ADDRESS] => (item=fail2ban.local)

TASK: [fail2ban | ensure fail2ban starts on a fresh reboot] ******************* 
ok: [DO-IP-ADDRESS]

TASK: [ferm | ensure ferm status is in debconf] ******************************* 
ok: [DO-IP-ADDRESS]

TASK: [ferm | ensure ferm is installed] *************************************** 
ok: [DO-IP-ADDRESS]

TASK: [ferm | ensure configuration directories exist] ************************* 
ok: [DO-IP-ADDRESS] => (item=/etc/ferm/ferm.d)
ok: [DO-IP-ADDRESS] => (item=/etc/ferm/filter-input.d)

TASK: [ferm | ensure firewall is configured] ********************************** 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     32      0 --:--:-- --:--:-- --:--:--    32
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     34      0 --:--:-- --:--:-- --:--:--    34
ok: [DO-IP-ADDRESS] => (item=etc/default/ferm)
ok: [DO-IP-ADDRESS] => (item=etc/ferm/ferm.conf)

TASK: [ferm | ensure iptables INPUT rules are removed] ************************ 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     37      0 --:--:-- --:--:-- --:--:--    37
skipping: [159.203.143.30] => (item={'dport': ['http', 'https'], 'type': 'dport_accept', 'filename': 'nginx_accept'})
skipping: [159.203.143.30] => (item={'dport': ['ssh'], 'type': 'dport_accept', 'saddr': [u'50.133.204.54']})
skipping: [159.203.143.30] => (item={'dport': ['ssh'], 'seconds': 300, 'hits': 20, 'type': 'dport_limit'})

TASK: [ferm | ensure iptables INPUT rules are added] ************************** 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     36      0 --:--:-- --:--:-- --:--:--    36
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     36      0 --:--:-- --:--:-- --:--:--    36
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     36      0 --:--:-- --:--:-- --:--:--    36
ok: [DO-IP-ADDRESS] => (item={'dport': ['http', 'https'], 'type': 'dport_accept', 'filename': 'nginx_accept'})
ok: [DO-IP-ADDRESS] => (item={'dport': ['ssh'], 'type': 'dport_accept', 'saddr': [u'50.133.204.54']})
ok: [DO-IP-ADDRESS] => (item={'dport': ['ssh'], 'seconds': 300, 'hits': 20, 'type': 'dport_limit'})

TASK: [ferm | ensure iptables rules are enabled] ****************************** 
skipping: [DO-IP-ADDRESS]

TASK: [ferm | ensure iptables rules are disabled] ***************************** 
ok: [DO-IP-ADDRESS]

TASK: [ntp | Add the OS specific variables] *********************************** 
ok: [DO-IP-ADDRESS]

TASK: [ntp | Install the required packages in Redhat derivatives] ************* 
skipping: [DO-IP-ADDRESS]

TASK: [ntp | Install the required packages in Debian derivatives] ************* 
ok: [DO-IP-ADDRESS]

TASK: [ntp | Copy the ntp.conf template file] ********************************* 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     33      0 --:--:-- --:--:-- --:--:--    33
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    13    0    13    0     0     39      0 --:--:-- --:--:-- --:--:--    39
ok: [DO-IP-ADDRESS]

TASK: [ntp | Start/stop ntp service] ****************************************** 
ok: [DO-IP-ADDRESS]

TASK: [users | Ensure sudo group is present] ********************************** 
ok: [DO-IP-ADDRESS]

TASK: [users | Ensure sudo group has sudo privileges] ************************* 
ok: [DO-IP-ADDRESS]

TASK: [users | Fail if root login will be disabled but admin_user will not be a sudoer] *** 
failed: [DO-IP-ADDRESS] => {"assertion": "False", "evaluated_to": false, "failed": true}
msg: When `sshd_permit_root_login: false`, you must add `sudo` to the `groups` for admin_user (in `users` hash), and set a password for admin_user in `sudoer_passwords`. Otherwise Ansible could lose the ability to run the necessary sudo commands.

PLAY RECAP ******************************************************************** 
           to retry, use: --limit @/Users/MyName/server.retry

127.0.0.1                  : ok=3    changed=0    unreachable=1    failed=0   
DO-IP-ADDRESS             : ok=28   changed=0    unreachable=0    failed=1  

To note in users.yml it has:
# Documentation: https://roots.io/trellis/docs/ssh-keys/
admin_user: admin

users:
  - name: "myusernamehere"
    groups:
      - "myusernamehere"
    keys:
      - "lookup('file', '~/.ssh/id_rsa.pub')"
      # - https://github.com/username.keys
  - name: "admin_user"
    groups:
      - sudo
    keys:
      - "lookup('file', '~/.ssh/id_rsa.pub')"
      - https://github.com/myusername.keys

web_user: web
web_group: www-data
web_sudoers:
  - "/usr/sbin/service hhvm *"
  - "/usr/sbin/service php5-fpm *"

And in sudoer_passwords.yml it has:

    sudoer_passwords:
      admin: passwordhere
      admin_user: passwordhere

I believe you have added inventory = hosts to your ansible.cfg but I should have pointed out that you should only do so if you have updated your Trellis to a version that includes the changes that #313 introduced to the hosts (inventory) files.Trellis shouldn’t be trying attempting the connection to 127.0.0.1 during the gathering facts phase (like in the error above). To fix this, choose one of the following:

  • update your Trellis to a version that includes PR #313 or newer, OR
  • remove the inventory = hosts from your ansible.cfg and specify your inventory via the command line like this: ansible-playbook server.yml -i hosts/production

In your users.yml, change the admin_user name back to the default {{ variable_format_in_brackets }}:

- - name: "admin_user"
+ - name: "{{ admin_user }}"

That will then use the definition of the admin_user variable.

You can also remove the second item from sudoer_passwords. You only need admin (assuming admin_user: admin above), like the default.

See if those changes resolve the issues. :slightly_smiling:

1 Like

Note too that deploy.yml will attempt to connect to your server as web_user , which will only succeed if your users list includes "{{ web_user }}" like the default.

Although you are welcome to include "myusernamehere" in the users list, Trellis does not need it. As indicated the table at the top of the SSH Keys docs, server.yml will connect as root if permitted or as the value of the admin_user variable, and deploy.yml will connect as the value of the web_user variable.

1 Like

Oh wow you rock! Thanks, that was all very helpful.

For now, I’ll remove the inventory = hosts, since while I’m sure updating trellis is easy enough, I’ll probably save that for another day to since I’m so close to getting this first deploy.

I fixed the other issue as well. When I saw “{{ }}” I wasn’t sure if those were place holders or meant to stay, so thank you for the clarification.

Thanks so much again. Working great now. When I deploy I get one error with cloning the project, but I’ll google to see if I can figure that one out and if not will open a separate thread. Thank you!

1 Like