What's the advantage of mere Ansible on mere shell-scripting if one doesn't use communally-maintained...












1














I establish a LAMP with a few extras on a remote Debian machine with a similar shell (Bash) script:



#/bin/bash

apt update -y
apt upgrade ufw sshguard unattended-upgrades wget curl git zip unzip tree -y

ufw --force enable
ufw allow 22,25,80,443

apt upgrade lamp-server^ ssmtp
apt upgrade python-certbot-apache
apt upgrade php-{cli,curl,mbstring,mcrypt,gd} phpmyadmin

curl -sS https://getcomposer.org/installer -o composer-setup.php
php composer-setup.php --install-dir=/usr/local/bin --filename=composer

cat <<-EOF > /etc/php*/conf.d/local.ini
upload_max_filesize = 2000M
post_max_size = 2000M
EOF

a2enmod http2 deflate expires


Some sysadmins who saw a similar script told me sayings like "you better do it with Ansible because otherwise it will be a nightmare to maintain it".



Well, I can achieve basically the same with the following Ansible playbook I wrote (and have yet to test because I don't have a free machine right now but should work when deployed to all machines):



---

- hosts: all
become: yes
become_user: root
tasks:

- name: Update apt package-indexes cache
apt:
update_cache=yes

- name: Install external basics
apt: state=latest
with-items:
- ufw
- sshguard
- unattended-upgrades
- wget
- curl
- git
- zip
- unzip
- tree

- name: Setup firewall with ufw
ufw:
rule: allow
port: 22,25,80,443

- name: Establish a LAPMS (Linux, Apache, PHP, MySQL, SSMTP) server environment
apt: state=latest
with-items:
- apache2 # Web server
- python-certbot-apache
- php
- php-mysql # MySQL server
- php-cli
- php-curl
- php-mbstring
- php-mcrypt
- php-gd
- ssmtp # Email server
- phpmyadmin

- name: Install Composer
get_url:
url: https://getcomposer.org/installer
dest: /tmp/composer-setup.php
command: php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer

- name: Configure PHP variables
shell: |
cat <<-EOF > /etc/php*/conf.d/local.ini
upload_max_filesize = 2000M
post_max_size = 2000M
EOF
args:
executable: /bin/bash

- apache2_module:
state: present
name: http2

- apache2_module:
state: present
name: deflate

- apache2_module:
state: present
name: expires


My contemplation



I don't recognize a significant advantage of using mere Ansible over mere shell-scripting in the above trivial case as Ansible does only what we tell it to and doesn't do release_upgrades (as from Apache 2.4 to 3.4) and will basically give me the same apt upgrade -y automation with scheduling (say with cron) so I can't understand how it will be much of a helper (also the result is basically same but the number of lines is far greater (72 instead 20/21) unless one uses Ansible-Galaxy roles which are well organized programs containing a core of one or more Ansible playbooks.



My question



How does mere Ansible by itself (without using Ansible-Galaxy roles) more efficient than mere shell-scripting in general and Bash in particular in a trivial task such as the above?










share|improve this question















closed as primarily opinion-based by muru, Mr Shunz, Rui F Ribeiro, sourcejedi, Jeff Schaller Dec 19 at 16:20


Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.















  • It is utterly disappointing to me that such an important-understanding question was closed. Please migrate to wherever you see fit: DevOps SE, SuperUser SE, ServerFault, StackOverflow, or whatever. This is the most important Ansible question I ever asked in my life in my opinion. Pleople, please help me to re-open it or flag it with me to migration.
    – JohnDoea
    Dec 20 at 7:29










  • Another reason is that your bash script continues on errors, while Ansible stops on errors and reports them. It also reports which steps changed or didn't change a system.
    – r3m0t
    2 days ago
















1














I establish a LAMP with a few extras on a remote Debian machine with a similar shell (Bash) script:



#/bin/bash

apt update -y
apt upgrade ufw sshguard unattended-upgrades wget curl git zip unzip tree -y

ufw --force enable
ufw allow 22,25,80,443

apt upgrade lamp-server^ ssmtp
apt upgrade python-certbot-apache
apt upgrade php-{cli,curl,mbstring,mcrypt,gd} phpmyadmin

curl -sS https://getcomposer.org/installer -o composer-setup.php
php composer-setup.php --install-dir=/usr/local/bin --filename=composer

cat <<-EOF > /etc/php*/conf.d/local.ini
upload_max_filesize = 2000M
post_max_size = 2000M
EOF

a2enmod http2 deflate expires


Some sysadmins who saw a similar script told me sayings like "you better do it with Ansible because otherwise it will be a nightmare to maintain it".



Well, I can achieve basically the same with the following Ansible playbook I wrote (and have yet to test because I don't have a free machine right now but should work when deployed to all machines):



---

- hosts: all
become: yes
become_user: root
tasks:

- name: Update apt package-indexes cache
apt:
update_cache=yes

- name: Install external basics
apt: state=latest
with-items:
- ufw
- sshguard
- unattended-upgrades
- wget
- curl
- git
- zip
- unzip
- tree

- name: Setup firewall with ufw
ufw:
rule: allow
port: 22,25,80,443

- name: Establish a LAPMS (Linux, Apache, PHP, MySQL, SSMTP) server environment
apt: state=latest
with-items:
- apache2 # Web server
- python-certbot-apache
- php
- php-mysql # MySQL server
- php-cli
- php-curl
- php-mbstring
- php-mcrypt
- php-gd
- ssmtp # Email server
- phpmyadmin

- name: Install Composer
get_url:
url: https://getcomposer.org/installer
dest: /tmp/composer-setup.php
command: php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer

- name: Configure PHP variables
shell: |
cat <<-EOF > /etc/php*/conf.d/local.ini
upload_max_filesize = 2000M
post_max_size = 2000M
EOF
args:
executable: /bin/bash

- apache2_module:
state: present
name: http2

- apache2_module:
state: present
name: deflate

- apache2_module:
state: present
name: expires


My contemplation



I don't recognize a significant advantage of using mere Ansible over mere shell-scripting in the above trivial case as Ansible does only what we tell it to and doesn't do release_upgrades (as from Apache 2.4 to 3.4) and will basically give me the same apt upgrade -y automation with scheduling (say with cron) so I can't understand how it will be much of a helper (also the result is basically same but the number of lines is far greater (72 instead 20/21) unless one uses Ansible-Galaxy roles which are well organized programs containing a core of one or more Ansible playbooks.



My question



How does mere Ansible by itself (without using Ansible-Galaxy roles) more efficient than mere shell-scripting in general and Bash in particular in a trivial task such as the above?










share|improve this question















closed as primarily opinion-based by muru, Mr Shunz, Rui F Ribeiro, sourcejedi, Jeff Schaller Dec 19 at 16:20


Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.















  • It is utterly disappointing to me that such an important-understanding question was closed. Please migrate to wherever you see fit: DevOps SE, SuperUser SE, ServerFault, StackOverflow, or whatever. This is the most important Ansible question I ever asked in my life in my opinion. Pleople, please help me to re-open it or flag it with me to migration.
    – JohnDoea
    Dec 20 at 7:29










  • Another reason is that your bash script continues on errors, while Ansible stops on errors and reports them. It also reports which steps changed or didn't change a system.
    – r3m0t
    2 days ago














1












1








1







I establish a LAMP with a few extras on a remote Debian machine with a similar shell (Bash) script:



#/bin/bash

apt update -y
apt upgrade ufw sshguard unattended-upgrades wget curl git zip unzip tree -y

ufw --force enable
ufw allow 22,25,80,443

apt upgrade lamp-server^ ssmtp
apt upgrade python-certbot-apache
apt upgrade php-{cli,curl,mbstring,mcrypt,gd} phpmyadmin

curl -sS https://getcomposer.org/installer -o composer-setup.php
php composer-setup.php --install-dir=/usr/local/bin --filename=composer

cat <<-EOF > /etc/php*/conf.d/local.ini
upload_max_filesize = 2000M
post_max_size = 2000M
EOF

a2enmod http2 deflate expires


Some sysadmins who saw a similar script told me sayings like "you better do it with Ansible because otherwise it will be a nightmare to maintain it".



Well, I can achieve basically the same with the following Ansible playbook I wrote (and have yet to test because I don't have a free machine right now but should work when deployed to all machines):



---

- hosts: all
become: yes
become_user: root
tasks:

- name: Update apt package-indexes cache
apt:
update_cache=yes

- name: Install external basics
apt: state=latest
with-items:
- ufw
- sshguard
- unattended-upgrades
- wget
- curl
- git
- zip
- unzip
- tree

- name: Setup firewall with ufw
ufw:
rule: allow
port: 22,25,80,443

- name: Establish a LAPMS (Linux, Apache, PHP, MySQL, SSMTP) server environment
apt: state=latest
with-items:
- apache2 # Web server
- python-certbot-apache
- php
- php-mysql # MySQL server
- php-cli
- php-curl
- php-mbstring
- php-mcrypt
- php-gd
- ssmtp # Email server
- phpmyadmin

- name: Install Composer
get_url:
url: https://getcomposer.org/installer
dest: /tmp/composer-setup.php
command: php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer

- name: Configure PHP variables
shell: |
cat <<-EOF > /etc/php*/conf.d/local.ini
upload_max_filesize = 2000M
post_max_size = 2000M
EOF
args:
executable: /bin/bash

- apache2_module:
state: present
name: http2

- apache2_module:
state: present
name: deflate

- apache2_module:
state: present
name: expires


My contemplation



I don't recognize a significant advantage of using mere Ansible over mere shell-scripting in the above trivial case as Ansible does only what we tell it to and doesn't do release_upgrades (as from Apache 2.4 to 3.4) and will basically give me the same apt upgrade -y automation with scheduling (say with cron) so I can't understand how it will be much of a helper (also the result is basically same but the number of lines is far greater (72 instead 20/21) unless one uses Ansible-Galaxy roles which are well organized programs containing a core of one or more Ansible playbooks.



My question



How does mere Ansible by itself (without using Ansible-Galaxy roles) more efficient than mere shell-scripting in general and Bash in particular in a trivial task such as the above?










share|improve this question















I establish a LAMP with a few extras on a remote Debian machine with a similar shell (Bash) script:



#/bin/bash

apt update -y
apt upgrade ufw sshguard unattended-upgrades wget curl git zip unzip tree -y

ufw --force enable
ufw allow 22,25,80,443

apt upgrade lamp-server^ ssmtp
apt upgrade python-certbot-apache
apt upgrade php-{cli,curl,mbstring,mcrypt,gd} phpmyadmin

curl -sS https://getcomposer.org/installer -o composer-setup.php
php composer-setup.php --install-dir=/usr/local/bin --filename=composer

cat <<-EOF > /etc/php*/conf.d/local.ini
upload_max_filesize = 2000M
post_max_size = 2000M
EOF

a2enmod http2 deflate expires


Some sysadmins who saw a similar script told me sayings like "you better do it with Ansible because otherwise it will be a nightmare to maintain it".



Well, I can achieve basically the same with the following Ansible playbook I wrote (and have yet to test because I don't have a free machine right now but should work when deployed to all machines):



---

- hosts: all
become: yes
become_user: root
tasks:

- name: Update apt package-indexes cache
apt:
update_cache=yes

- name: Install external basics
apt: state=latest
with-items:
- ufw
- sshguard
- unattended-upgrades
- wget
- curl
- git
- zip
- unzip
- tree

- name: Setup firewall with ufw
ufw:
rule: allow
port: 22,25,80,443

- name: Establish a LAPMS (Linux, Apache, PHP, MySQL, SSMTP) server environment
apt: state=latest
with-items:
- apache2 # Web server
- python-certbot-apache
- php
- php-mysql # MySQL server
- php-cli
- php-curl
- php-mbstring
- php-mcrypt
- php-gd
- ssmtp # Email server
- phpmyadmin

- name: Install Composer
get_url:
url: https://getcomposer.org/installer
dest: /tmp/composer-setup.php
command: php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer

- name: Configure PHP variables
shell: |
cat <<-EOF > /etc/php*/conf.d/local.ini
upload_max_filesize = 2000M
post_max_size = 2000M
EOF
args:
executable: /bin/bash

- apache2_module:
state: present
name: http2

- apache2_module:
state: present
name: deflate

- apache2_module:
state: present
name: expires


My contemplation



I don't recognize a significant advantage of using mere Ansible over mere shell-scripting in the above trivial case as Ansible does only what we tell it to and doesn't do release_upgrades (as from Apache 2.4 to 3.4) and will basically give me the same apt upgrade -y automation with scheduling (say with cron) so I can't understand how it will be much of a helper (also the result is basically same but the number of lines is far greater (72 instead 20/21) unless one uses Ansible-Galaxy roles which are well organized programs containing a core of one or more Ansible playbooks.



My question



How does mere Ansible by itself (without using Ansible-Galaxy roles) more efficient than mere shell-scripting in general and Bash in particular in a trivial task such as the above?







shell-script software-installation upgrade scheduling ansible






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited yesterday

























asked Dec 19 at 10:39









JohnDoea

1291132




1291132




closed as primarily opinion-based by muru, Mr Shunz, Rui F Ribeiro, sourcejedi, Jeff Schaller Dec 19 at 16:20


Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.






closed as primarily opinion-based by muru, Mr Shunz, Rui F Ribeiro, sourcejedi, Jeff Schaller Dec 19 at 16:20


Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.














  • It is utterly disappointing to me that such an important-understanding question was closed. Please migrate to wherever you see fit: DevOps SE, SuperUser SE, ServerFault, StackOverflow, or whatever. This is the most important Ansible question I ever asked in my life in my opinion. Pleople, please help me to re-open it or flag it with me to migration.
    – JohnDoea
    Dec 20 at 7:29










  • Another reason is that your bash script continues on errors, while Ansible stops on errors and reports them. It also reports which steps changed or didn't change a system.
    – r3m0t
    2 days ago


















  • It is utterly disappointing to me that such an important-understanding question was closed. Please migrate to wherever you see fit: DevOps SE, SuperUser SE, ServerFault, StackOverflow, or whatever. This is the most important Ansible question I ever asked in my life in my opinion. Pleople, please help me to re-open it or flag it with me to migration.
    – JohnDoea
    Dec 20 at 7:29










  • Another reason is that your bash script continues on errors, while Ansible stops on errors and reports them. It also reports which steps changed or didn't change a system.
    – r3m0t
    2 days ago
















It is utterly disappointing to me that such an important-understanding question was closed. Please migrate to wherever you see fit: DevOps SE, SuperUser SE, ServerFault, StackOverflow, or whatever. This is the most important Ansible question I ever asked in my life in my opinion. Pleople, please help me to re-open it or flag it with me to migration.
– JohnDoea
Dec 20 at 7:29




It is utterly disappointing to me that such an important-understanding question was closed. Please migrate to wherever you see fit: DevOps SE, SuperUser SE, ServerFault, StackOverflow, or whatever. This is the most important Ansible question I ever asked in my life in my opinion. Pleople, please help me to re-open it or flag it with me to migration.
– JohnDoea
Dec 20 at 7:29












Another reason is that your bash script continues on errors, while Ansible stops on errors and reports them. It also reports which steps changed or didn't change a system.
– r3m0t
2 days ago




Another reason is that your bash script continues on errors, while Ansible stops on errors and reports them. It also reports which steps changed or didn't change a system.
– r3m0t
2 days ago










3 Answers
3






active

oldest

votes


















4














I do not think there is a big problem with 20 lines, as a shell script for an individual machine or two. That is a good thing to have.



That said, your script is not idempotent. For example it uses apt-get upgrade foo, which can perform changes even if the script has already been run on this system. I do not think it worth using apt-get upgrade foo. That command does not guarantee to apply security or bugfix updates to your dependencies.



A carefully written Ansible playbook can double as a small system check. This relies on the playbook being idempotent (and also that it reports "changed" status accurately). Running ansible-playbook --check will show whether the system still meets all the defined tasks, or whether it has been changed. This can both be useful later on, and also to look for inconsistencies immediately after running a playbook.



And you may set up Ansible so you can run this on several machines at once.



Configuration tools like Ansible are useful at scale. Partly due to these sorts of features. Partly due to these sorts of constraints, which it encourages you to follow.



Encouraging you to write idempotent scripts can also be useful for maintenance. Consider the temptation to write a script that adds lines to an existing file (or adds tokens inside an existing line :-( ). If you ensure idempotence, then you can re-run the modified script without adding duplicate lines.



Another constraint is if you ever want to remove things from an installed system. In many cases this is not a problem, and you could always write an uninstall script/playbook later on. But in some cases you need to be careful about this. E.g. you might want to make sure not to use Ansible lineinfile to replace an individual line, and instead overwrite the entire file with your own version. This can be useful when you no longer want to change line A from the default, but you still want to change line B.



For my usage, I would like to address the removal problem when managing firewalls. If you stop allowing a port in your install script, you might forget to explicitly block the port everywhere. The Ansible ufw module does not help here, because it only allows adding or removing individual rules. I am currently thinking about using an alternative to the ufw firewall, which has proper support for working from configuration files. (E.g. firewalld, shorewall, ferm ...).






share|improve this answer



















  • 1




    The uninstallation angle is particularly hard to get right. Ideally, you want to be able to change your configuration description to omit the part you want to uninstall (since that’s the new target state for your system), and run your configuration management tool again. Thinking in terms of uninstallation playbooks often causes maintenance issues further down the line.
    – Stephen Kitt
    Dec 19 at 13:31










  • I never understood that saying that Ansible is idempotent. It doesn't recursively operate on an operator to recursively bring the same result, it can bring different results (sorry, I didn't lean much math in the past and not sure I understand idempotent well enough to understand the answer, let alone in the Ansible context).
    – JohnDoea
    Dec 19 at 13:31










  • @JohnDoea good Ansible playbooks are idempotent because they describe a desired state, not a desired installation process. If they describe a state, running them through Ansible ensures that the system is in the desired state, not that the desired configuration changes are applied. Applying the same state multiple times results in no change, so it’s idempotent.
    – Stephen Kitt
    Dec 19 at 13:33










  • @JohnDoea HTTP DELETE method, or NFS write operations, are examples of operations which are described as idempotent. They have the same effect if you run them twice, as if you run them once. In NFS3 over UDP, this property allows write requests to be safely re-sent if the client does not receive a success response after a timeout. Even though it might be the response packet that was lost, not the write request packet.
    – sourcejedi
    Dec 19 at 13:38






  • 1




    There are circumstances in which you want a list of all the allowed packages ;-). But yes, I certainly agree this is hard. It also leads to the whole pets-v.-cattle debate: in a cattle situation you’d nuke your VM and create a new one (no uninstallation needed), in the pet situation you need to deal with the ongoing maintenance of your system which always ends up having to deal with clean-up.
    – Stephen Kitt
    Dec 19 at 13:59



















2














The difference between Bash and Ansible is that Ansible, when written properly, is idempotent. There are no changes when a playbook runs repeatedly. In this respect Bash script describes a procedure while Ansible playbook rather describes a state of a system.



To address the comment




"not sure I understand idempotent well enough to understand the answer".




Idempotence means that a playbook "can be applied multiple times without changing the result beyond the initial application". Best practice is to run a playbook twice. During the first run a playbook performs all changes. During the second run no changes should be reported.






share|improve this answer























  • Dear Vladimir, thank you, but if so, anyone who says Ansible uses to automate upgrades is either mistaking or laying, right? I assume yes, but then we can say that Ansible-Galaxy roles are an exception for that idempotence, right?
    – JohnDoea
    yesterday










  • Dear John, to tell you the truth, my experience with "automatic upgrades" is limited to procedures provided by Vendors. Such procedures should be idempotent. But, in most cases I automatically read Release Notes, test and fix potential backward incompatibilities on my own with Ansible.
    – Vladimir Botka
    yesterday










  • Thanks Vladimir, but what are "vendors" in this context, please?
    – JohnDoea
    yesterday



















1














One of the main selling points of Ansible is that playbooks tend to be easier to read than dense BASH one liners due to its use of YAML syntax. You can also use linters and debuggers in a more feature rich way than you can with BASH scripts, and some IDEs even have built in Ansible text completion modules to assist with writing playbooks.






share|improve this answer























  • Hey Timothy, is one such IDE is VSCODE? Because only with it I work and prefer to stick with it. Maybe you have a recommendation for An Ansible plugin for it?
    – JohnDoea
    Dec 20 at 7:26










  • I've never used VSCODE before, but I have used Atom IDE which has several Ansible plugins for auto completion and linting capabilities to assist with writing playbooks.
    – Timothy Pulliam
    yesterday


















3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes









4














I do not think there is a big problem with 20 lines, as a shell script for an individual machine or two. That is a good thing to have.



That said, your script is not idempotent. For example it uses apt-get upgrade foo, which can perform changes even if the script has already been run on this system. I do not think it worth using apt-get upgrade foo. That command does not guarantee to apply security or bugfix updates to your dependencies.



A carefully written Ansible playbook can double as a small system check. This relies on the playbook being idempotent (and also that it reports "changed" status accurately). Running ansible-playbook --check will show whether the system still meets all the defined tasks, or whether it has been changed. This can both be useful later on, and also to look for inconsistencies immediately after running a playbook.



And you may set up Ansible so you can run this on several machines at once.



Configuration tools like Ansible are useful at scale. Partly due to these sorts of features. Partly due to these sorts of constraints, which it encourages you to follow.



Encouraging you to write idempotent scripts can also be useful for maintenance. Consider the temptation to write a script that adds lines to an existing file (or adds tokens inside an existing line :-( ). If you ensure idempotence, then you can re-run the modified script without adding duplicate lines.



Another constraint is if you ever want to remove things from an installed system. In many cases this is not a problem, and you could always write an uninstall script/playbook later on. But in some cases you need to be careful about this. E.g. you might want to make sure not to use Ansible lineinfile to replace an individual line, and instead overwrite the entire file with your own version. This can be useful when you no longer want to change line A from the default, but you still want to change line B.



For my usage, I would like to address the removal problem when managing firewalls. If you stop allowing a port in your install script, you might forget to explicitly block the port everywhere. The Ansible ufw module does not help here, because it only allows adding or removing individual rules. I am currently thinking about using an alternative to the ufw firewall, which has proper support for working from configuration files. (E.g. firewalld, shorewall, ferm ...).






share|improve this answer



















  • 1




    The uninstallation angle is particularly hard to get right. Ideally, you want to be able to change your configuration description to omit the part you want to uninstall (since that’s the new target state for your system), and run your configuration management tool again. Thinking in terms of uninstallation playbooks often causes maintenance issues further down the line.
    – Stephen Kitt
    Dec 19 at 13:31










  • I never understood that saying that Ansible is idempotent. It doesn't recursively operate on an operator to recursively bring the same result, it can bring different results (sorry, I didn't lean much math in the past and not sure I understand idempotent well enough to understand the answer, let alone in the Ansible context).
    – JohnDoea
    Dec 19 at 13:31










  • @JohnDoea good Ansible playbooks are idempotent because they describe a desired state, not a desired installation process. If they describe a state, running them through Ansible ensures that the system is in the desired state, not that the desired configuration changes are applied. Applying the same state multiple times results in no change, so it’s idempotent.
    – Stephen Kitt
    Dec 19 at 13:33










  • @JohnDoea HTTP DELETE method, or NFS write operations, are examples of operations which are described as idempotent. They have the same effect if you run them twice, as if you run them once. In NFS3 over UDP, this property allows write requests to be safely re-sent if the client does not receive a success response after a timeout. Even though it might be the response packet that was lost, not the write request packet.
    – sourcejedi
    Dec 19 at 13:38






  • 1




    There are circumstances in which you want a list of all the allowed packages ;-). But yes, I certainly agree this is hard. It also leads to the whole pets-v.-cattle debate: in a cattle situation you’d nuke your VM and create a new one (no uninstallation needed), in the pet situation you need to deal with the ongoing maintenance of your system which always ends up having to deal with clean-up.
    – Stephen Kitt
    Dec 19 at 13:59
















4














I do not think there is a big problem with 20 lines, as a shell script for an individual machine or two. That is a good thing to have.



That said, your script is not idempotent. For example it uses apt-get upgrade foo, which can perform changes even if the script has already been run on this system. I do not think it worth using apt-get upgrade foo. That command does not guarantee to apply security or bugfix updates to your dependencies.



A carefully written Ansible playbook can double as a small system check. This relies on the playbook being idempotent (and also that it reports "changed" status accurately). Running ansible-playbook --check will show whether the system still meets all the defined tasks, or whether it has been changed. This can both be useful later on, and also to look for inconsistencies immediately after running a playbook.



And you may set up Ansible so you can run this on several machines at once.



Configuration tools like Ansible are useful at scale. Partly due to these sorts of features. Partly due to these sorts of constraints, which it encourages you to follow.



Encouraging you to write idempotent scripts can also be useful for maintenance. Consider the temptation to write a script that adds lines to an existing file (or adds tokens inside an existing line :-( ). If you ensure idempotence, then you can re-run the modified script without adding duplicate lines.



Another constraint is if you ever want to remove things from an installed system. In many cases this is not a problem, and you could always write an uninstall script/playbook later on. But in some cases you need to be careful about this. E.g. you might want to make sure not to use Ansible lineinfile to replace an individual line, and instead overwrite the entire file with your own version. This can be useful when you no longer want to change line A from the default, but you still want to change line B.



For my usage, I would like to address the removal problem when managing firewalls. If you stop allowing a port in your install script, you might forget to explicitly block the port everywhere. The Ansible ufw module does not help here, because it only allows adding or removing individual rules. I am currently thinking about using an alternative to the ufw firewall, which has proper support for working from configuration files. (E.g. firewalld, shorewall, ferm ...).






share|improve this answer



















  • 1




    The uninstallation angle is particularly hard to get right. Ideally, you want to be able to change your configuration description to omit the part you want to uninstall (since that’s the new target state for your system), and run your configuration management tool again. Thinking in terms of uninstallation playbooks often causes maintenance issues further down the line.
    – Stephen Kitt
    Dec 19 at 13:31










  • I never understood that saying that Ansible is idempotent. It doesn't recursively operate on an operator to recursively bring the same result, it can bring different results (sorry, I didn't lean much math in the past and not sure I understand idempotent well enough to understand the answer, let alone in the Ansible context).
    – JohnDoea
    Dec 19 at 13:31










  • @JohnDoea good Ansible playbooks are idempotent because they describe a desired state, not a desired installation process. If they describe a state, running them through Ansible ensures that the system is in the desired state, not that the desired configuration changes are applied. Applying the same state multiple times results in no change, so it’s idempotent.
    – Stephen Kitt
    Dec 19 at 13:33










  • @JohnDoea HTTP DELETE method, or NFS write operations, are examples of operations which are described as idempotent. They have the same effect if you run them twice, as if you run them once. In NFS3 over UDP, this property allows write requests to be safely re-sent if the client does not receive a success response after a timeout. Even though it might be the response packet that was lost, not the write request packet.
    – sourcejedi
    Dec 19 at 13:38






  • 1




    There are circumstances in which you want a list of all the allowed packages ;-). But yes, I certainly agree this is hard. It also leads to the whole pets-v.-cattle debate: in a cattle situation you’d nuke your VM and create a new one (no uninstallation needed), in the pet situation you need to deal with the ongoing maintenance of your system which always ends up having to deal with clean-up.
    – Stephen Kitt
    Dec 19 at 13:59














4












4








4






I do not think there is a big problem with 20 lines, as a shell script for an individual machine or two. That is a good thing to have.



That said, your script is not idempotent. For example it uses apt-get upgrade foo, which can perform changes even if the script has already been run on this system. I do not think it worth using apt-get upgrade foo. That command does not guarantee to apply security or bugfix updates to your dependencies.



A carefully written Ansible playbook can double as a small system check. This relies on the playbook being idempotent (and also that it reports "changed" status accurately). Running ansible-playbook --check will show whether the system still meets all the defined tasks, or whether it has been changed. This can both be useful later on, and also to look for inconsistencies immediately after running a playbook.



And you may set up Ansible so you can run this on several machines at once.



Configuration tools like Ansible are useful at scale. Partly due to these sorts of features. Partly due to these sorts of constraints, which it encourages you to follow.



Encouraging you to write idempotent scripts can also be useful for maintenance. Consider the temptation to write a script that adds lines to an existing file (or adds tokens inside an existing line :-( ). If you ensure idempotence, then you can re-run the modified script without adding duplicate lines.



Another constraint is if you ever want to remove things from an installed system. In many cases this is not a problem, and you could always write an uninstall script/playbook later on. But in some cases you need to be careful about this. E.g. you might want to make sure not to use Ansible lineinfile to replace an individual line, and instead overwrite the entire file with your own version. This can be useful when you no longer want to change line A from the default, but you still want to change line B.



For my usage, I would like to address the removal problem when managing firewalls. If you stop allowing a port in your install script, you might forget to explicitly block the port everywhere. The Ansible ufw module does not help here, because it only allows adding or removing individual rules. I am currently thinking about using an alternative to the ufw firewall, which has proper support for working from configuration files. (E.g. firewalld, shorewall, ferm ...).






share|improve this answer














I do not think there is a big problem with 20 lines, as a shell script for an individual machine or two. That is a good thing to have.



That said, your script is not idempotent. For example it uses apt-get upgrade foo, which can perform changes even if the script has already been run on this system. I do not think it worth using apt-get upgrade foo. That command does not guarantee to apply security or bugfix updates to your dependencies.



A carefully written Ansible playbook can double as a small system check. This relies on the playbook being idempotent (and also that it reports "changed" status accurately). Running ansible-playbook --check will show whether the system still meets all the defined tasks, or whether it has been changed. This can both be useful later on, and also to look for inconsistencies immediately after running a playbook.



And you may set up Ansible so you can run this on several machines at once.



Configuration tools like Ansible are useful at scale. Partly due to these sorts of features. Partly due to these sorts of constraints, which it encourages you to follow.



Encouraging you to write idempotent scripts can also be useful for maintenance. Consider the temptation to write a script that adds lines to an existing file (or adds tokens inside an existing line :-( ). If you ensure idempotence, then you can re-run the modified script without adding duplicate lines.



Another constraint is if you ever want to remove things from an installed system. In many cases this is not a problem, and you could always write an uninstall script/playbook later on. But in some cases you need to be careful about this. E.g. you might want to make sure not to use Ansible lineinfile to replace an individual line, and instead overwrite the entire file with your own version. This can be useful when you no longer want to change line A from the default, but you still want to change line B.



For my usage, I would like to address the removal problem when managing firewalls. If you stop allowing a port in your install script, you might forget to explicitly block the port everywhere. The Ansible ufw module does not help here, because it only allows adding or removing individual rules. I am currently thinking about using an alternative to the ufw firewall, which has proper support for working from configuration files. (E.g. firewalld, shorewall, ferm ...).







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 19 at 14:01

























answered Dec 19 at 12:41









sourcejedi

22.7k435100




22.7k435100








  • 1




    The uninstallation angle is particularly hard to get right. Ideally, you want to be able to change your configuration description to omit the part you want to uninstall (since that’s the new target state for your system), and run your configuration management tool again. Thinking in terms of uninstallation playbooks often causes maintenance issues further down the line.
    – Stephen Kitt
    Dec 19 at 13:31










  • I never understood that saying that Ansible is idempotent. It doesn't recursively operate on an operator to recursively bring the same result, it can bring different results (sorry, I didn't lean much math in the past and not sure I understand idempotent well enough to understand the answer, let alone in the Ansible context).
    – JohnDoea
    Dec 19 at 13:31










  • @JohnDoea good Ansible playbooks are idempotent because they describe a desired state, not a desired installation process. If they describe a state, running them through Ansible ensures that the system is in the desired state, not that the desired configuration changes are applied. Applying the same state multiple times results in no change, so it’s idempotent.
    – Stephen Kitt
    Dec 19 at 13:33










  • @JohnDoea HTTP DELETE method, or NFS write operations, are examples of operations which are described as idempotent. They have the same effect if you run them twice, as if you run them once. In NFS3 over UDP, this property allows write requests to be safely re-sent if the client does not receive a success response after a timeout. Even though it might be the response packet that was lost, not the write request packet.
    – sourcejedi
    Dec 19 at 13:38






  • 1




    There are circumstances in which you want a list of all the allowed packages ;-). But yes, I certainly agree this is hard. It also leads to the whole pets-v.-cattle debate: in a cattle situation you’d nuke your VM and create a new one (no uninstallation needed), in the pet situation you need to deal with the ongoing maintenance of your system which always ends up having to deal with clean-up.
    – Stephen Kitt
    Dec 19 at 13:59














  • 1




    The uninstallation angle is particularly hard to get right. Ideally, you want to be able to change your configuration description to omit the part you want to uninstall (since that’s the new target state for your system), and run your configuration management tool again. Thinking in terms of uninstallation playbooks often causes maintenance issues further down the line.
    – Stephen Kitt
    Dec 19 at 13:31










  • I never understood that saying that Ansible is idempotent. It doesn't recursively operate on an operator to recursively bring the same result, it can bring different results (sorry, I didn't lean much math in the past and not sure I understand idempotent well enough to understand the answer, let alone in the Ansible context).
    – JohnDoea
    Dec 19 at 13:31










  • @JohnDoea good Ansible playbooks are idempotent because they describe a desired state, not a desired installation process. If they describe a state, running them through Ansible ensures that the system is in the desired state, not that the desired configuration changes are applied. Applying the same state multiple times results in no change, so it’s idempotent.
    – Stephen Kitt
    Dec 19 at 13:33










  • @JohnDoea HTTP DELETE method, or NFS write operations, are examples of operations which are described as idempotent. They have the same effect if you run them twice, as if you run them once. In NFS3 over UDP, this property allows write requests to be safely re-sent if the client does not receive a success response after a timeout. Even though it might be the response packet that was lost, not the write request packet.
    – sourcejedi
    Dec 19 at 13:38






  • 1




    There are circumstances in which you want a list of all the allowed packages ;-). But yes, I certainly agree this is hard. It also leads to the whole pets-v.-cattle debate: in a cattle situation you’d nuke your VM and create a new one (no uninstallation needed), in the pet situation you need to deal with the ongoing maintenance of your system which always ends up having to deal with clean-up.
    – Stephen Kitt
    Dec 19 at 13:59








1




1




The uninstallation angle is particularly hard to get right. Ideally, you want to be able to change your configuration description to omit the part you want to uninstall (since that’s the new target state for your system), and run your configuration management tool again. Thinking in terms of uninstallation playbooks often causes maintenance issues further down the line.
– Stephen Kitt
Dec 19 at 13:31




The uninstallation angle is particularly hard to get right. Ideally, you want to be able to change your configuration description to omit the part you want to uninstall (since that’s the new target state for your system), and run your configuration management tool again. Thinking in terms of uninstallation playbooks often causes maintenance issues further down the line.
– Stephen Kitt
Dec 19 at 13:31












I never understood that saying that Ansible is idempotent. It doesn't recursively operate on an operator to recursively bring the same result, it can bring different results (sorry, I didn't lean much math in the past and not sure I understand idempotent well enough to understand the answer, let alone in the Ansible context).
– JohnDoea
Dec 19 at 13:31




I never understood that saying that Ansible is idempotent. It doesn't recursively operate on an operator to recursively bring the same result, it can bring different results (sorry, I didn't lean much math in the past and not sure I understand idempotent well enough to understand the answer, let alone in the Ansible context).
– JohnDoea
Dec 19 at 13:31












@JohnDoea good Ansible playbooks are idempotent because they describe a desired state, not a desired installation process. If they describe a state, running them through Ansible ensures that the system is in the desired state, not that the desired configuration changes are applied. Applying the same state multiple times results in no change, so it’s idempotent.
– Stephen Kitt
Dec 19 at 13:33




@JohnDoea good Ansible playbooks are idempotent because they describe a desired state, not a desired installation process. If they describe a state, running them through Ansible ensures that the system is in the desired state, not that the desired configuration changes are applied. Applying the same state multiple times results in no change, so it’s idempotent.
– Stephen Kitt
Dec 19 at 13:33












@JohnDoea HTTP DELETE method, or NFS write operations, are examples of operations which are described as idempotent. They have the same effect if you run them twice, as if you run them once. In NFS3 over UDP, this property allows write requests to be safely re-sent if the client does not receive a success response after a timeout. Even though it might be the response packet that was lost, not the write request packet.
– sourcejedi
Dec 19 at 13:38




@JohnDoea HTTP DELETE method, or NFS write operations, are examples of operations which are described as idempotent. They have the same effect if you run them twice, as if you run them once. In NFS3 over UDP, this property allows write requests to be safely re-sent if the client does not receive a success response after a timeout. Even though it might be the response packet that was lost, not the write request packet.
– sourcejedi
Dec 19 at 13:38




1




1




There are circumstances in which you want a list of all the allowed packages ;-). But yes, I certainly agree this is hard. It also leads to the whole pets-v.-cattle debate: in a cattle situation you’d nuke your VM and create a new one (no uninstallation needed), in the pet situation you need to deal with the ongoing maintenance of your system which always ends up having to deal with clean-up.
– Stephen Kitt
Dec 19 at 13:59




There are circumstances in which you want a list of all the allowed packages ;-). But yes, I certainly agree this is hard. It also leads to the whole pets-v.-cattle debate: in a cattle situation you’d nuke your VM and create a new one (no uninstallation needed), in the pet situation you need to deal with the ongoing maintenance of your system which always ends up having to deal with clean-up.
– Stephen Kitt
Dec 19 at 13:59













2














The difference between Bash and Ansible is that Ansible, when written properly, is idempotent. There are no changes when a playbook runs repeatedly. In this respect Bash script describes a procedure while Ansible playbook rather describes a state of a system.



To address the comment




"not sure I understand idempotent well enough to understand the answer".




Idempotence means that a playbook "can be applied multiple times without changing the result beyond the initial application". Best practice is to run a playbook twice. During the first run a playbook performs all changes. During the second run no changes should be reported.






share|improve this answer























  • Dear Vladimir, thank you, but if so, anyone who says Ansible uses to automate upgrades is either mistaking or laying, right? I assume yes, but then we can say that Ansible-Galaxy roles are an exception for that idempotence, right?
    – JohnDoea
    yesterday










  • Dear John, to tell you the truth, my experience with "automatic upgrades" is limited to procedures provided by Vendors. Such procedures should be idempotent. But, in most cases I automatically read Release Notes, test and fix potential backward incompatibilities on my own with Ansible.
    – Vladimir Botka
    yesterday










  • Thanks Vladimir, but what are "vendors" in this context, please?
    – JohnDoea
    yesterday
















2














The difference between Bash and Ansible is that Ansible, when written properly, is idempotent. There are no changes when a playbook runs repeatedly. In this respect Bash script describes a procedure while Ansible playbook rather describes a state of a system.



To address the comment




"not sure I understand idempotent well enough to understand the answer".




Idempotence means that a playbook "can be applied multiple times without changing the result beyond the initial application". Best practice is to run a playbook twice. During the first run a playbook performs all changes. During the second run no changes should be reported.






share|improve this answer























  • Dear Vladimir, thank you, but if so, anyone who says Ansible uses to automate upgrades is either mistaking or laying, right? I assume yes, but then we can say that Ansible-Galaxy roles are an exception for that idempotence, right?
    – JohnDoea
    yesterday










  • Dear John, to tell you the truth, my experience with "automatic upgrades" is limited to procedures provided by Vendors. Such procedures should be idempotent. But, in most cases I automatically read Release Notes, test and fix potential backward incompatibilities on my own with Ansible.
    – Vladimir Botka
    yesterday










  • Thanks Vladimir, but what are "vendors" in this context, please?
    – JohnDoea
    yesterday














2












2








2






The difference between Bash and Ansible is that Ansible, when written properly, is idempotent. There are no changes when a playbook runs repeatedly. In this respect Bash script describes a procedure while Ansible playbook rather describes a state of a system.



To address the comment




"not sure I understand idempotent well enough to understand the answer".




Idempotence means that a playbook "can be applied multiple times without changing the result beyond the initial application". Best practice is to run a playbook twice. During the first run a playbook performs all changes. During the second run no changes should be reported.






share|improve this answer














The difference between Bash and Ansible is that Ansible, when written properly, is idempotent. There are no changes when a playbook runs repeatedly. In this respect Bash script describes a procedure while Ansible playbook rather describes a state of a system.



To address the comment




"not sure I understand idempotent well enough to understand the answer".




Idempotence means that a playbook "can be applied multiple times without changing the result beyond the initial application". Best practice is to run a playbook twice. During the first run a playbook performs all changes. During the second run no changes should be reported.







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 19 at 14:21

























answered Dec 19 at 10:54









Vladimir Botka

1815




1815












  • Dear Vladimir, thank you, but if so, anyone who says Ansible uses to automate upgrades is either mistaking or laying, right? I assume yes, but then we can say that Ansible-Galaxy roles are an exception for that idempotence, right?
    – JohnDoea
    yesterday










  • Dear John, to tell you the truth, my experience with "automatic upgrades" is limited to procedures provided by Vendors. Such procedures should be idempotent. But, in most cases I automatically read Release Notes, test and fix potential backward incompatibilities on my own with Ansible.
    – Vladimir Botka
    yesterday










  • Thanks Vladimir, but what are "vendors" in this context, please?
    – JohnDoea
    yesterday


















  • Dear Vladimir, thank you, but if so, anyone who says Ansible uses to automate upgrades is either mistaking or laying, right? I assume yes, but then we can say that Ansible-Galaxy roles are an exception for that idempotence, right?
    – JohnDoea
    yesterday










  • Dear John, to tell you the truth, my experience with "automatic upgrades" is limited to procedures provided by Vendors. Such procedures should be idempotent. But, in most cases I automatically read Release Notes, test and fix potential backward incompatibilities on my own with Ansible.
    – Vladimir Botka
    yesterday










  • Thanks Vladimir, but what are "vendors" in this context, please?
    – JohnDoea
    yesterday
















Dear Vladimir, thank you, but if so, anyone who says Ansible uses to automate upgrades is either mistaking or laying, right? I assume yes, but then we can say that Ansible-Galaxy roles are an exception for that idempotence, right?
– JohnDoea
yesterday




Dear Vladimir, thank you, but if so, anyone who says Ansible uses to automate upgrades is either mistaking or laying, right? I assume yes, but then we can say that Ansible-Galaxy roles are an exception for that idempotence, right?
– JohnDoea
yesterday












Dear John, to tell you the truth, my experience with "automatic upgrades" is limited to procedures provided by Vendors. Such procedures should be idempotent. But, in most cases I automatically read Release Notes, test and fix potential backward incompatibilities on my own with Ansible.
– Vladimir Botka
yesterday




Dear John, to tell you the truth, my experience with "automatic upgrades" is limited to procedures provided by Vendors. Such procedures should be idempotent. But, in most cases I automatically read Release Notes, test and fix potential backward incompatibilities on my own with Ansible.
– Vladimir Botka
yesterday












Thanks Vladimir, but what are "vendors" in this context, please?
– JohnDoea
yesterday




Thanks Vladimir, but what are "vendors" in this context, please?
– JohnDoea
yesterday











1














One of the main selling points of Ansible is that playbooks tend to be easier to read than dense BASH one liners due to its use of YAML syntax. You can also use linters and debuggers in a more feature rich way than you can with BASH scripts, and some IDEs even have built in Ansible text completion modules to assist with writing playbooks.






share|improve this answer























  • Hey Timothy, is one such IDE is VSCODE? Because only with it I work and prefer to stick with it. Maybe you have a recommendation for An Ansible plugin for it?
    – JohnDoea
    Dec 20 at 7:26










  • I've never used VSCODE before, but I have used Atom IDE which has several Ansible plugins for auto completion and linting capabilities to assist with writing playbooks.
    – Timothy Pulliam
    yesterday
















1














One of the main selling points of Ansible is that playbooks tend to be easier to read than dense BASH one liners due to its use of YAML syntax. You can also use linters and debuggers in a more feature rich way than you can with BASH scripts, and some IDEs even have built in Ansible text completion modules to assist with writing playbooks.






share|improve this answer























  • Hey Timothy, is one such IDE is VSCODE? Because only with it I work and prefer to stick with it. Maybe you have a recommendation for An Ansible plugin for it?
    – JohnDoea
    Dec 20 at 7:26










  • I've never used VSCODE before, but I have used Atom IDE which has several Ansible plugins for auto completion and linting capabilities to assist with writing playbooks.
    – Timothy Pulliam
    yesterday














1












1








1






One of the main selling points of Ansible is that playbooks tend to be easier to read than dense BASH one liners due to its use of YAML syntax. You can also use linters and debuggers in a more feature rich way than you can with BASH scripts, and some IDEs even have built in Ansible text completion modules to assist with writing playbooks.






share|improve this answer














One of the main selling points of Ansible is that playbooks tend to be easier to read than dense BASH one liners due to its use of YAML syntax. You can also use linters and debuggers in a more feature rich way than you can with BASH scripts, and some IDEs even have built in Ansible text completion modules to assist with writing playbooks.







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 19 at 20:56









Rui F Ribeiro

38.8k1479129




38.8k1479129










answered Dec 19 at 13:44









Timothy Pulliam

1,130821




1,130821












  • Hey Timothy, is one such IDE is VSCODE? Because only with it I work and prefer to stick with it. Maybe you have a recommendation for An Ansible plugin for it?
    – JohnDoea
    Dec 20 at 7:26










  • I've never used VSCODE before, but I have used Atom IDE which has several Ansible plugins for auto completion and linting capabilities to assist with writing playbooks.
    – Timothy Pulliam
    yesterday


















  • Hey Timothy, is one such IDE is VSCODE? Because only with it I work and prefer to stick with it. Maybe you have a recommendation for An Ansible plugin for it?
    – JohnDoea
    Dec 20 at 7:26










  • I've never used VSCODE before, but I have used Atom IDE which has several Ansible plugins for auto completion and linting capabilities to assist with writing playbooks.
    – Timothy Pulliam
    yesterday
















Hey Timothy, is one such IDE is VSCODE? Because only with it I work and prefer to stick with it. Maybe you have a recommendation for An Ansible plugin for it?
– JohnDoea
Dec 20 at 7:26




Hey Timothy, is one such IDE is VSCODE? Because only with it I work and prefer to stick with it. Maybe you have a recommendation for An Ansible plugin for it?
– JohnDoea
Dec 20 at 7:26












I've never used VSCODE before, but I have used Atom IDE which has several Ansible plugins for auto completion and linting capabilities to assist with writing playbooks.
– Timothy Pulliam
yesterday




I've never used VSCODE before, but I have used Atom IDE which has several Ansible plugins for auto completion and linting capabilities to assist with writing playbooks.
– Timothy Pulliam
yesterday



Popular posts from this blog

Список кардиналов, возведённых папой римским Каликстом III

Deduzione

Mysql.sock missing - “Can't connect to local MySQL server through socket”