Similar to that, in IT automation there are procedural languages like ruby, python where you need to specify steps and the programming language executes the steps as it is. And then there are programming languages like puppet where you dont need to specify all steps but have to express your desire. Such as “I wish to have apache software installed on all my 1000 servers” or “I wish to ensure that all my 1000 servers will have ntp service enabled”. A tool like puppet can read such desired state instructions and ensure that all of your 1000 servers follow the same. In servers where ntp is already running, it will skip them. And on the ones, ntp is not running, it will start them. Had it been ruby/python, you had to specify all steps for all servers, and then these programs would have forced start of ntp even on servers where ntp would have been running already as the ruby/python coding languages do not have the inbuilt infrastructure management intelligence that can be seen in tools like puppet.
For example: Puppet follows desired state definition. If any target environment is already compliant to the desired state, it does not force run the commands anymore on the same, and rather skips that environment. This behavior is known as idempotency. Example: If the instruction to puppet is to ensure that ntp service is running across all servers, then it will skip the servers where ntp is already running.
Think about difference between these two commands on linux shell:
echo “hello” > test.txt
echo “hello” >> test2.txt
If you run both commands 10 times, you will end up with a test2.txt that has the word “hello” written 10 times in it. Whereas test.txt will have “hello” written only once. So across the 10 executions, every time test2.txt got different values – 1 line of hello, 2 lines of hello, 3 lines of hello …. 10 lines of hello. But test.txt outcome always remained same – 1 line of hello – no matter how many times you run the first command. Hence, first command is idempotent, and second command is non idempotent.
So lets say, in your datacenter you have implemented VMWare Virtualization. And then you have written a code that once launched can create all the VMs and network routes on VMWare. So now you have a code that defines your entire infrastructure on VMWare. Think of a scenario, when for some reason you need to rebuild that same set of VMs and Networks on another VMWare setup in another datacenter. So all you need is another VMWare installation in another datacenter as your only pre-requisite. Once you get that, you can run your existing code on the new VMWare setup and voila! your entire infrastructure setup on VMWare is recreated through execution of your code ‘automatically’. This is what is called as managing infrastructure as code.
Another use of infrastructure as code is infrastructure versioning. Lets say you run an application on 10 servers using an infrastructure code which we will call as v1. Then you decided to reduce the number of VMs to 3. So you modified the infrastructure code to delete 7 vms and keep only 3 – we will call this version of code as v2. Then you launched v2 and it reduced number of servers. After a while you realized that it has been a bad decision as the application is not able to perform properly on 3 servers. So you want to go back to situation where you had 10 servers. In the infrastructure as code management practice, this would just mean rolling back to previous version of code and launching the same to regain the same previous setup of 10 servers. Hence the infrastructure designs and architectures become version controlled.
Which brings us to creating a new test server whenever such testing is required. Hence for continuous testing, we will have continuous provisioning of servers.
Now provisioning a server is not enough for running an application. For example, if you try to run a java application directly on just a fresh installation of ubuntu server, it wont work. Because a java application needs something more than the operating system to run. This middle level of software layer required by application software layer on top of the operating system layer is said to be the middleware. Different applications require different middlewares. For example java applications require JRE but .NET applications require .NET runtime environment.
Setting up of all these runtime environments, middleware, databases – are called as configuration of the operating system. When you automate that with tools and programming languages like puppet, we call that as configuration automation. When such configuration automation happens as part of continuous provisioning process as part of a CI/CD pipeline, it is referred to as Continuous Configuration Automation.