using pm2 with ansible - node.js

I am trying to start a node program using pm2 via ansible. The problem is that the pm2 start command is not idempotent under ansible. It gives error when run again.
This is my ansible play
- name: start the application
become_user: ubuntu
command: pm2 start app.js -i max
tags:
- app
Now if i run this the first time then it runs properly but when i run this again then i get the error telling me that the script is already running.
What would be the correct way to get around this error and handle pm2 properly via ansible.

Before starting the script you should delete previous, like this:
- name: delete existing pm2 processes if running
command: "pm2 delete {{ server_id }}"
ignore_errors: True
become: yes
become_user: rw_user
- name: start pm2 process
command: 'pm2 start -x -i 4 --name "{{server_id}}" server.js'
become: yes
become_user: rw_user
environment:
NODE_ENV: "{{server_env}}"

I would use
pm2 reload app.js -i max
It will allow you to reload configuration ;-)

I ended up on this page looking for a solution to start PM2 multiple times when I rerun my playbook. I also wanted PM2 to reload the server when it was already running and pickup the new code I might have deployed. It turns out that PM2 has such an interface:
- name: Start/reload server
command: '{{path_to_deployed_pm2}} startOrReload pm2.ecosystem.config.js'
The startOrReload command requires a so-called "ecosystem" file to be present. See the documentation for more details: Ecosystem File.
This is a minimal pm2.ecosystem.config.js that is working for me:
module.exports = {
apps : [{
script: 'app.js',
name: "My app"
}],
};

Here we can use the "register" module to perform a conditional restart/start.
register the output of following command:
shell: pm2 list | grep <app_name> | awk '{print $2}'
register: APP_STATUS
become: yes
and the use APP_STATUS.stdout to make a conditional start and restart tasks. This way we don't need a pm2 delete step.

Related

'dzdo: service: command not found' when starting a service via SSH

In my gitlab script I'm trying to install and start a java application remotely. The installation part goes fine but when I'm trying to start the service using this command:
ssh $DEPLOY_USER#$DEPLOY_HOST "sudo service my-service start"
I get the next error:
dzdo: service: command not found
All the previous commands with sudo rights are executed successfully. What's wrong with this one?
Adding bash to the command solved the issue:
ssh $DEPLOY_USER#$DEPLOY_HOST "sudo bash service my-service start"

pm2 log-rotate with ansible

I am writing an ansible playbook to perform various pm2 functions.
I have searched a bit and cannot find an example of someone setting up pm2-logrotate.
I believe I am close but I'm not sure my shell commands are working. When I ssh into the child node and run sudo pm2 ls it says In-memory PM2 is out-of-date, do: $ pm2 update even though I am running that command from my playbook. What am I missing here?
---
# RUN playbook
# ansible-playbook -K pm2-setup.yml
- name: Setup pm2 and pm2-logrotate
hosts: devdebugs
remote_user: ansible
become: true
tasks:
- name: Install/Update pm2 globally
community.general.npm:
name: pm2
global: yes
state: latest
- name: Update In-memory pm2
ansible.builtin.shell: pm2 update
- name: Install/Update pm2-logrotate globally
ansible.builtin.shell: pm2 install pm2-logrotate
- name: Copy pm2-logrotate config
ansible.builtin.copy:
src: /home/ubuntu/files/pm2-logrotate-conf.json
dest: /home/ubuntu/.pm2/module_conf.json
owner: root
group: root
mode: '0644'
...
Bonus question: is there a way to skip the shell commands if they aren't needed (i.e. if pm2-logrotate is already installed)?
I was mixing up the users on my server. I fixed this by specifying to run as ubuntu for the update command.

Node.js app can't access any env variables when pm2 is started from a script but can when launched from ssh

I am trying to launch a node.js app on a production EC2 server with pm2 process manager.
When I ssh into the instance and run pm2 start app.js, PM2 starts just fine and has access to all environment variables. Everything good.
However, I want to run pm2 start app.js from a Codedeploy hook script called applicationstart.sh, the app fails with an errored status becasue it is missing all environment variables.
Here is where the script is added so it is launched with each deployment and calls pm2 start: appspec.yml
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/teller-install
hooks:
AfterInstall:
- location: scripts/afterinstall.sh
timeout: 1000
runas: root
ApplicationStart:
- location: scripts/applicationstart.sh
timeout: 300
runas: ubuntu
Here is the applicationstart script:
#!/bin/bash
echo "Running Hook: applicationstart.sh"
cd /home/ubuntu/teller-install/Server/
pm2 start app.js
exit 0
I am logged in as ubuntu when I run the script from ssh and I set the script in the appconfig.yml to run as ubuntu as well.
Why would there be any difference between starting pm2 from terminal and starting it from a launch hook script?
Here is running directly from ssh:
I can provide any information necessary in dire need of solution. Thanks!
I had to add source /etc/profile before I call pm2 start app.js to load in environment variables.
The script now looks like
#!/bin/bash
echo "Running Hook: applicationstart.sh"
cd /home/ubuntu/teller-install/Server/
source /etc/profile
pm2 start app.js
exit 0

Ansible. How to run node.js application through pm2

What is the proper way to setup node.js app on Ubuntu server with Ansible?
Now I'm trying to register pm2 as a service like code below:
- name: install pm2
npm:
name: pm2
global: yes
state: present
- name: create pm2 init.d script
template:
src: pm2_init_config.j2
dest: "/etc/init.d/pm2"
backup: yes
- name: ensure pm2 service is started
service:ยท
name: pm2
state: started
enabled: yes
but meet strange error:
pm2 unrecognized service in Ansible console
The pm2_init_config is similar to this one
if I ssh to the box and run sudo service pm2 start everything works as expected
The change below fixed the problem:
- name: create pm2 init.d script
template:
src: pm2_init_config.j2
dest: "/etc/init.d/pm2"
backup: yes
mode: 0751
I don't know why it works. Can somebody explain this trick with mode?

Running Forever in Ansible Provision Never Fires or Always Hangs

I've come across a problem with Anisble hanging when trying to start a forever process on an Ansible node. I have a very simple API server I'm creating in vagrant and provisioning with Ansible like so:
---
- hosts: all
sudo: yes
roles:
- Stouts.nodejs
- Stouts.mongodb
tasks:
- name: Install Make Dependencies
apt: name={{ item }} state=present
with_items:
- gcc
- make
- build-essential
- name: Run NPM Update
shell: /usr/bin/npm update
- name: Create MongoDB Database Folder
shell: /bin/mkdir -p /data/db
notify:
- mongodb restart
- name: Generate Dummy Data
command: /usr/bin/node /vagrant/dataGen.js
- name: "Install forever (to run Node.js app)."
npm: name=forever global=yes state=latest
- name: "Check list of Node.js apps running."
command: /usr/bin/forever list
register: forever_list
changed_when: false
- name: "Start example Node.js app."
command: /usr/bin/forever start /vagrant/server.js
when: "forever_list.stdout.find('/vagrant/server.js') == -1"
But even though Ansible acts like everything is fine, no forever process is started. When I change a few lines to remove the when: statement and force it to run, Ansible just hands, possibly running the forever process (forever, I presume) but not launching the VM to where I can interact with it.
I've referenced essentially two points online; the only sources I can find.
as stated in the comments the variable content needs to be included in your question for anyone to provide a correct answer but to overcome this I suggest you can do it like so:
- name: "Check list of Node.js apps running."
command: /usr/bin/forever list|grep '/vagrant/server.js'|wc -l
register: forever_list
changed_when: false
- name: "Start example Node.js app."
command: /usr/bin/forever start /vagrant/server.js
when: forever_list.stdout == "0"
which should prevent ansible from starting the JS app if it's already running.

Resources