<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>script on Zwindler's Reflection</title><link>https://blog.zwindler.fr/en/categories/script/</link><description>Recent content in script on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Tue, 14 Aug 2018 11:45:31 +0000</lastBuildDate><atom:link href="https://blog.zwindler.fr/en/categories/script/index.xml" rel="self" type="application/rss+xml"/><item><title>Your very first VM in Azure… deployed with Ansible, of course!</title><link>https://blog.zwindler.fr/en/2018/08/14/your-very-first-vm-in-azure-deployed-with-ansible-of-course/</link><pubDate>Tue, 14 Aug 2018 11:45:31 +0000</pubDate><guid>https://blog.zwindler.fr/en/2018/08/14/your-very-first-vm-in-azure-deployed-with-ansible-of-course/</guid><description>&lt;img src="https://blog.zwindler.fr/2018/06/azure.webp" alt="Featured image of post Your very first VM in Azure… deployed with Ansible, of course!" /&gt;&lt;h2 id="havent-you-already-wrote-an-article-about-ansible-and-vm-provisioning"&gt;Haven’t you already wrote an article about Ansible and VM provisioning?
&lt;/h2&gt;&lt;p&gt;You might have read already a few articles on Ansible on this blog. I &lt;strong&gt;really&lt;/strong&gt; like Ansible. I already wrote a &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=ansible" &gt;few articles on this topic&lt;/a&gt;, even a few in english, and there are a few playbooks on &lt;a class="link" href="https://github.com/zwindler?utf8=%E2%9C%93&amp;amp;tab=repositories&amp;amp;q=ansible&amp;amp;type=&amp;amp;language=/" target="_blank" rel="noopener"
&gt;my Github account&lt;/a&gt; if you want to check it out.&lt;/p&gt;
&lt;p&gt;[French readers]Au cas où vous l’auriez manqué, la version française de cet article &lt;a class="link" href="https://blog.zwindler.fr/2018/08/07/premiere-vm-dans-azure-avec-ansible-bien-sur" &gt;est disponible ici&lt;/a&gt;[/French readers]&lt;/p&gt;
&lt;p&gt;One of the articles that you like the most, especially my english speaking viewers, is the one about deploying virtual machines on VMware vSphere platform. But now that I have moved on past VMware and started working on cloud providers (mostly the big ones, AWS, GCP and Azure), I felt it was time to share my automation playbooks about that also ;)&lt;/p&gt;
&lt;p&gt;As you might have guessed, Ansible and cloud providers teams have been working hard to provide integrations. You can have a look at the BIG list of modules for cloud integrations only!&lt;br&gt;
&lt;a class="link" href="https://docs.ansible.com/ansible/2.9/modules/list_of_cloud_modules.html" target="_blank" rel="noopener"
&gt;https://docs.ansible.com/ansible/latest/modules/list_of_cloud_modules.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That’s especially true for Azure and Microsoft teams, which are relatively available and that provide regular updates (this is going to be the topic of another article, #teasing).&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites
&lt;/h2&gt;&lt;p&gt;Now that I introduced the subject, let’s deploy a VM on Azure. Yay!&lt;/p&gt;
&lt;p&gt;Good news is that’s it’s almost the same thing as deploying a VM in vSphere. We have prerequisites, parameters to fill in and pouf, a VM appears.&lt;/p&gt;
&lt;p&gt;Bad news is that prerequisites are going to be a little bit more tedious to install/configure, but worry not, I’ll give you all the steps ;)&lt;/p&gt;
&lt;p&gt;There are two guides giving us info on how to configure our workstation to start working with Azure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.ansible.com/ansible/2.9/scenario_guides/guide_azure.html" target="_blank" rel="noopener"
&gt;the one form Microsoft&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.microsoft.com/fr-fr/azure/ansible/ansible-overview" target="_blank" rel="noopener"
&gt;the one from Ansible&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="install"&gt;Install
&lt;/h3&gt;&lt;p&gt;On a mint/debian/ubuntu, get the necessary python modules :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;apt install python-pip ansible
pip install setuptools wheel
pip install ansible[azure]
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="configure"&gt;Configure
&lt;/h3&gt;&lt;p&gt;To deploy a VM in Azure, you need&amp;hellip; an Azure account!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thanks, captain obvious.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ok, so assuming you don’t have one, you have to know that you can get a 200$ free credit. To open the account, simply go to &lt;a class="link" href="https://azure.microsoft.com/fr-fr/free/search/?&amp;amp;WT.srch=1&amp;amp;wt.mc_id=AID719808_SEM_Xu5DFmXy&amp;amp;gclid=Cj0KCQjwv-DaBRCcARIsAI9sba9FHepWuC6mzBDlrT2LqPIAQzFYrCdyjTC72M2QqEtYRd6GXXoyooQaAhYsEALw_wcB&amp;amp;dclid=COf_zsaAutwCFY1h0wodDDcOqg" target="_blank" rel="noopener"
&gt;this page&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The only two issues with this is that this credit expires after 30 days (while AWS of GCP gives 365 days!) and that you need a credit card. I know that having to register a credit card can be a little frightening.&lt;/p&gt;
&lt;p&gt;If you read all the informations, they claim that it’s only to avoid bots and that they won’t get money from it. If you consume all you credit or move past the 30 days, the account will be locked. Personnaly it worked great indeed and I didn’t lost a cent, but you shouldn’t believe me and be careful to avoid a bad surprise I case it dooesn’t work as well for you.&lt;/p&gt;
&lt;p&gt;Once we have our account, we have to configure our workstation. The easiest way to do this is to use az cli for linux (but then you need to &lt;a class="link" href="https://docs.microsoft.com/fr-fr/cli/azure/install-azure-cli?view=azure-cli-latest" target="_blank" rel="noopener"
&gt;install it&lt;/a&gt;). You can also configure the files by hand (following the guides I gave previously).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;az login
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code CCHMTROLL to authenticate.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/08/azcli.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;After that, you should have a .azure in your homedir&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ll .azure
total 8
drwxrwxrwx 1 zwindler zwindler 512 Aug 4 17:00 ./
drwxr-xr-x 1 zwindler zwindler 512 Aug 4 16:56 ../
-rw------- 1 zwindler zwindler 7124 Aug 4 17:00 accessTokens.json
-rw-rw-rw- 1 zwindler zwindler 5 Aug 4 16:56 az.json
-rw-rw-rw- 1 zwindler zwindler 5 Aug 4 16:56 az.sess
-rw-rw-rw- 1 zwindler zwindler 333 Aug 4 17:00 azureProfile.json
-rw-rw-rw- 1 zwindler zwindler 66 Aug 4 17:00 clouds.config
-rw------- 1 zwindler zwindler 27 Aug 4 16:56 config
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="soooo-we-deploy-this-vm-or-not"&gt;Soooo&amp;hellip; we deploy this VM or not?
&lt;/h2&gt;&lt;p&gt;Yeah, now that our workstation is configured, this becomes easy again!&lt;/p&gt;
&lt;p&gt;The Azure module to create a VM in a playbook is &lt;strong&gt;azure_rm_virtualmachine&lt;/strong&gt;. Documentation can be found here &lt;a class="link" href="https://docs.ansible.com/ansible/latest/collections/azure/azcollection/azure_rm_virtualmachine_module.html" target="_blank" rel="noopener"
&gt;docs.ansible.com/ansible/latest/collections/azure/azcollection/azure_rm_virtualmachine_module.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here’s one of the examples given in the documentation:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;- name: Create a VM with managed disk
azure_rm_virtualmachine:
resource_group: Testing
name: testvm001
vm_size: Standard_D4
managed_disk_type: Standard_LRS
admin_username: adminUser
ssh_public_keys:
- path: /home/adminUser/.ssh/authorized_keys
key_data: &amp;lt; insert your ssh public key here... &amp;gt;
image:
offer: CoreOS
publisher: CoreOS
sku: Stable
version: latest
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Most of the options given here are a strict minimum. There are many many more. I’ll explain a little what’s what:&lt;/p&gt;
&lt;p&gt;&lt;u&gt;resource_group&lt;/u&gt;&lt;br&gt;
On azure, there are multiple logic entities to segment resources between each other. Subscription is the highest level of segmentation (mostly used for multitenancy, environment segregation or billing) and resources groups. You can have multiple subscription in a same account, and many resource groups in a single subscription.&lt;/p&gt;
&lt;p&gt;&lt;u&gt;name&lt;/u&gt;&lt;br&gt;
The name of the resource we are going to deploy.&lt;/p&gt;
&lt;p&gt;&lt;u&gt;vm_size&lt;/u&gt;&lt;br&gt;
Now we enter inside the topic. This is a size of the VM (in terms of vCPUs and GB of RAM) we are going to give our VM. A guide of the available size can be found here =&amp;gt; &lt;a class="link" href="https://docs.microsoft.com/fr-fr/azure/virtual-machines/windows/sizes-general" target="_blank" rel="noopener"
&gt;docs.microsoft.com/fr-fr/azure/virtual-machines/windows/sizes-general&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;u&gt;managed_disk_type&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;The type of the virtual disk we are going to create at the same time. Basically, will your disk be on full SSD disk array or not. You won’t find much information on exactly how your data is stored aside from SLAs (availability and performance).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.microsoft.com/fr-fr/azure/virtual-machines/windows/premium-storage" target="_blank" rel="noopener"
&gt;docs.microsoft.com/fr-fr/azure/virtual-machines/windows/premium-storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.microsoft.com/fr-fr/azure/virtual-machines/windows/standard-storage" target="_blank" rel="noopener"
&gt;docs.microsoft.com/fr-fr/azure/virtual-machines/windows/standard-storage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, we know that a Premium disk of 128 GB will have a performance threshold of 500 IOPS and 100 MB/s. If you add just one GB (from 129 GB to 256), you’ll get 1100 IOPS and 125 Mo/s. Don’t expect to swindle Azure by have the performance of a 256 GB disk for the price of 128+1 GB, because a the moment you move past 128 GB, you’ll pay for a 256 GB (even if you ask only for 129, and even if you only you 10 GB).&lt;/p&gt;
&lt;p&gt;&lt;u&gt;admin_username &amp;amp; ssh_public_keys&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;Self explainatory.&lt;/p&gt;
&lt;p&gt;&lt;u&gt;image&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;On Azure, you can access preconfigured images:&lt;/p&gt;
&lt;p&gt;If we want a Ubuntu 16.04:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;image:
offer: UbuntuServer
publisher: Canonical
sku: &amp;#39;16.04.0-LTS&amp;#39;
version: latest
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we want a CentOS 7.4 :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;image:
offer: CentOS
publisher: OpenLogic
sku: &amp;#39;7.4&amp;#39;
version: latest
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="mooooar"&gt;Mooooar!
&lt;/h2&gt;&lt;p&gt;Ok, I gave you a little piece of YAML and I explained it to you. That’s nice, but you want more. Can we have more, you ask?&lt;/p&gt;
&lt;p&gt;Of course, you can!&lt;/p&gt;
&lt;p&gt;In fact, you need more to have a working VM. In Azure, as we are not in our own datacenter where everything has been previously set up from network to hypervisors, we need more objects (resources) than just a VM.&lt;/p&gt;
&lt;p&gt;I already told you about it, we first need a resource group, in which we’ll put our VM. But, we also need a virtual network interface that we will attach to the VM. This vNIC will have to have a public IP address if we are going to connect on it. Also, we will need a virtual network for the vNIC, and maybe add some basic firewalling rules.&lt;/p&gt;
&lt;p&gt;We could do all this by hand&amp;hellip; :(&lt;/p&gt;
&lt;p&gt;Or&amp;hellip; we could automated it all with an Ansible playbook !!!&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;---
- name: &amp;#34;Create Azure resources&amp;#34;
connection: local
hosts: all
vars_prompt:
- name: &amp;#34;location&amp;#34;
prompt: &amp;#34;Choose region to deploy VMs&amp;#34;
private: no
default: &amp;#34;westeurope&amp;#34;
- name: &amp;#34;project_prefix&amp;#34;
prompt: &amp;#34;Choose a prefix for all the resources&amp;#34;
private: no
default: &amp;#34;test&amp;#34;
- name: &amp;#34;instances_number&amp;#34;
prompt: &amp;#34;Choose a number of virtual machines to create&amp;#34;
private: no
default: 1
- name: &amp;#34;vm_size&amp;#34;
prompt: &amp;#34;Choose a size for azure virtual machines&amp;#34;
private: no
default: &amp;#34;Standard_B2s&amp;#34;
- name: &amp;#34;managed_disk_type&amp;#34;
prompt: &amp;#34;Choose a type for azure virtual disks&amp;#34;
private: no
default: &amp;#34;Standard_LRS&amp;#34;
- name: &amp;#34;admin_username&amp;#34;
prompt: &amp;#34;Choose an admin username&amp;#34;
private: no
default: &amp;#34;zwindler&amp;#34;
- name: &amp;#34;admin_pub_path&amp;#34;
prompt: &amp;#34;Where can I find the admin public key ?&amp;#34;
private: no
default: &amp;#34;~/.ssh/id_rsa.pub&amp;#34;
- name: &amp;#34;local_ip&amp;#34;
prompt: &amp;#34;your local IP address (skip if you don&amp;#39;t want to add 22 port to NSG)&amp;#34;
private: no
default: &amp;#34;skip&amp;#34;
- name: &amp;#34;virtualnetwork_cidr&amp;#34;
prompt: &amp;#34;Give a network CIDR for virtual network (large)&amp;#34;
private: no
default: &amp;#34;172.16.0.0/18&amp;#34;
- name: &amp;#34;subnet_cidr&amp;#34;
prompt: &amp;#34;Give a subnet of that network&amp;#34;
private: no
default: &amp;#34;172.16.1.0/24&amp;#34;
vars:
- resourcegroup_name: &amp;#34;{{project_prefix}}-rg&amp;#34;
- availabilityset_name: &amp;#34;{{project_prefix}}-avset&amp;#34;
- virtualnetwork_name: &amp;#34;{{project_prefix}}-vnet&amp;#34;
- subnet_name: &amp;#34;{{project_prefix}}-subnet&amp;#34;
- securitygroup_name: &amp;#34;{{project_prefix}}-nsg&amp;#34;
- vm_root_name: &amp;#34;{{project_prefix}}-vm&amp;#34;
- public_ip_name: &amp;#34;{{project_prefix}}-ip&amp;#34;
- nic_root_name: &amp;#34;{{project_prefix}}-nic&amp;#34;
tasks:
- name: &amp;#34;Create {{project_prefix}}-rg Resource Group&amp;#34;
azure_rm_resourcegroup:
name: &amp;#34;{{resourcegroup_name}}&amp;#34;
location: &amp;#34;{{location}}&amp;#34;
- name: &amp;#34;Create {{availabilityset_name}} Availability Set&amp;#34;
azure_rm_availabilityset:
name: &amp;#34;{{availabilityset_name}}&amp;#34;
location: &amp;#34;{{location}}&amp;#34;
resource_group: &amp;#34;{{resourcegroup_name}}&amp;#34;
sku: Aligned
- name: &amp;#34;Create {{virtualnetwork_name}} Virtual Network&amp;#34;
azure_rm_virtualnetwork:
name: &amp;#34;{{virtualnetwork_name}}&amp;#34;
resource_group: &amp;#34;{{resourcegroup_name}}&amp;#34;
address_prefixes_cidr:
- &amp;#34;{{virtualnetwork_cidr}}&amp;#34;
- name: &amp;#34;create {{subnet_name}} Subnet in {{virtualnetwork_name}} for VMs&amp;#34;
azure_rm_subnet:
name: &amp;#34;{{subnet_name}}&amp;#34;
virtual_network_name: &amp;#34;{{virtualnetwork_name}}&amp;#34;
resource_group: &amp;#34;{{resourcegroup_name}}&amp;#34;
address_prefix_cidr: &amp;#34;{{subnet_cidr}}&amp;#34;
register: subnet
- name: &amp;#34;Create {{securitygroup_name}} security rules (if local IP address was given)&amp;#34;
azure_rm_securitygroup:
name: &amp;#34;{{securitygroup_name}}&amp;#34;
resource_group: &amp;#34;{{resourcegroup_name}}&amp;#34;
purge_rules: yes
rules:
- name: &amp;#39;AllowSSHFromYourOwnInternetIP&amp;#39;
protocol: &amp;#39;Tcp&amp;#39;
source_address_prefix: &amp;#34;{{local_ip}}&amp;#34;
destination_port_range: 22
access: Allow
priority: 1000
direction: Inbound
when: local_ip | ipaddr
- name: &amp;#34;Create a {{nic_root_name}}X network interface for each VM&amp;#34;
azure_rm_networkinterface:
name: &amp;#34;{{nic_root_name}}{{item}}&amp;#34;
resource_group: &amp;#34;{{resourcegroup_name}}&amp;#34;
virtual_network: &amp;#34;{{virtualnetwork_name}}&amp;#34;
subnet_name: &amp;#34;{{subnet_name}}&amp;#34;
security_group: &amp;#34;{{securitygroup_name}}&amp;#34;
ip_configurations:
- name: &amp;#34;ipconfig&amp;#34;
public_ip_address_name: &amp;#34;{{public_ip_name}}&amp;#34;
primary: True
with_sequence: count=&amp;#34;{{instances_number}}&amp;#34;
- name: &amp;#34;Create {{vm_root_name}}X VM with existing NIC&amp;#34;
azure_rm_virtualmachine:
resource_group: &amp;#34;{{resourcegroup_name}}&amp;#34;
name: &amp;#34;{{vm_root_name}}{{item}}&amp;#34;
vm_size: &amp;#34;{{vm_size}}&amp;#34;
managed_disk_type: &amp;#34;{{managed_disk_type}}&amp;#34;
admin_username: &amp;#34;{{admin_username}}&amp;#34;
availability_set: &amp;#34;{{availabilityset_name}}&amp;#34;
ssh_password_enabled: false
ssh_public_keys:
- path: &amp;#34;/home/{{admin_username}}/.ssh/authorized_keys&amp;#34;
key_data: &amp;#34;{{lookup(&amp;#39;file&amp;#39;, &amp;#39;{{admin_pub_path}}&amp;#39;) }}&amp;#34;
network_interface_names: &amp;#34;{{nic_root_name}}{{item}}&amp;#34;
image:
offer: UbuntuServer
publisher: Canonical
sku: &amp;#39;16.04.0-LTS&amp;#39;
version: latest
with_sequence: count=&amp;#34;{{instances_number}}&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For those of you that want to be spare the copy paste, this playbook can also be found on this Github repository&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/zwindler/ansible-deploy-azure" target="_blank" rel="noopener"
&gt;github.com/zwindler/ansible-deploy-azure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You only have to run it:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pip install --user netaddr
echo localhost &amp;gt; hosts
ansible-playbook -i hosts azure-deploy.yml
[...]
TASK [Create test-vmX VM with existing NIC] *****************************************
changed: [localhost] =&amp;gt; (item=1)
PLAY RECAP **************************************************************************
localhost : ok=1 changed=7 unreachable=0 failed=0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2018/08/azure_vm.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="final-words"&gt;Final words
&lt;/h2&gt;&lt;p&gt;Where are we now?&lt;/p&gt;
&lt;p&gt;Now, we have a playbook, deploying VMs on Azure, but not only!&lt;/p&gt;
&lt;p&gt;These machines are preinstalled with a Linux OS, preconfigured with your own SSH key and user. Only your local IP address can access it through SSH, all the VMs are in a single private virtual network; All the VMs are spread evenly accross Azure hypervisors to avoid SPOF by adding the VMs in an AVSET (availability set).&lt;/p&gt;
&lt;p&gt;All of this could have been done by someone else by hand, with a little time. But not you. You, you used this playbook to do it all with only one command ;)&lt;/p&gt;
&lt;p&gt;Aren’t you badass?&lt;/p&gt;</description></item><item><title>Deploy VMware virtual machines with Ansible</title><link>https://blog.zwindler.fr/en/2017/09/26/deploy-vmware-virtual-machines-with-ansible/</link><pubDate>Tue, 26 Sep 2017 11:30:00 +0000</pubDate><guid>https://blog.zwindler.fr/en/2017/09/26/deploy-vmware-virtual-machines-with-ansible/</guid><description>&lt;img src="https://blog.zwindler.fr/2017/03/ansible_vpshere.webp" alt="Featured image of post Deploy VMware virtual machines with Ansible" /&gt;&lt;h2 id="why-would-i-deploy-virtual-machines-with-ansible"&gt;Why would I deploy virtual machines with Ansible
&lt;/h2&gt;&lt;p&gt;[Update]I wrote another article about [VM automation, for Azure this time. Check it out!](/2018/08/14/your-first-vm-in-azure-deployed-with-ansible-of-course/[/Update]&lt;/p&gt;
&lt;p&gt;[French readers]La version française de l’article « Déployer des machines virtuelles VMware avec Ansible) est &lt;a class="link" href="https://blog.zwindler.fr/2017/06/20/deployer-machines-virtuelles-ansible-vmware/" &gt;disponible à l’adresse suivante&lt;/a&gt;[/French readers]&lt;/p&gt;
&lt;p&gt;Since a few month, &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=ansible" &gt;I automate all that can be automated with Ansible (FR)&lt;/a&gt;. Still, there was something that I still had to do manually and it bothered me (a lot).&lt;/p&gt;
&lt;p&gt;Until then, I used Ansible both as a deployment tools (to install things on my machines) and also as a « Configuration Management » tool.&lt;/p&gt;
&lt;p&gt;Let me explain :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;From a virtual machine template, I can deploy default configuration (depending of the machine role). I mean by configuration, the first sense of the term like configuration files, but also package installations.&lt;/li&gt;
&lt;li&gt;If I need to modify something on a subset of (or all!) my servers, I can push it on them with one command line.&lt;/li&gt;
&lt;li&gt;Should something/someone modify something on the server managed configuration, I can correct this with my Ansible magic wand by just playing all my playbooks on all the servers once in a while. All « non compliant » servers will be automatically corrected WITHOUT TOUCHING those that ARE compliant.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the last part, it’s not really « magic ». Playbooks have to be written while keeping I mind that they must be « idempotent ». This is really important and that’s why I had to develop &lt;a class="link" href="https://blog.zwindler.fr/2016/12/20/ansible-module-clapi-centreon" &gt;my own Ansible module for Centreon&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2016/11/73068978.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Still, I was frustrated because one last step was still missing: Provisioning VMs directly from Ansible!&lt;/p&gt;
&lt;h2 id="what-is-the-problem"&gt;What is the problem?
&lt;/h2&gt;&lt;p&gt;2 obstacles prevented me from doing it.&lt;/p&gt;
&lt;h3 id="gather-facts"&gt;Gather facts
&lt;/h3&gt;&lt;p&gt;First, Ansible works with an inventory. If you try to tell Ansible that you want to create new machines and you add them to the inventory, the first thing Ansible will try to do is to connect to them&amp;hellip; before they exists!&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ansible-playbook -l 192.168.100.103 zwindler_deploy.yml
PLAY [xxxxxxaaaaaaaaaaa] ********************************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************************************
fatal: [192.168.100.103]: UNREACHABLE! =&amp;gt; {&amp;#34;changed&amp;#34;: false, &amp;#34;msg&amp;#34;: &amp;#34;Failed to connect to the host via ssh: ssh: connect to host 192.168.100.103 port 22: No route to host\r\n&amp;#34;, &amp;#34;unreachable&amp;#34;: true}
PLAY RECAP **********************************************************************************************************************************************************************************
192.168.100.103 : ok=0 changed=0 unreachable=1 failed=0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We need to tell Ansible &lt;strong&gt;not to connect&lt;/strong&gt;, at least at first.&lt;/p&gt;
&lt;p&gt;You can do that by using the option &lt;strong&gt;gather_facts: false&lt;/strong&gt;, which, you guessed, tells Ansible not to gather facts&amp;hellip;&lt;/p&gt;
&lt;p&gt;But that’s still not enough. If you try to run the playbook with just this option, Ansible will still try to connect to the yet to be created server, failing.&lt;/p&gt;
&lt;p&gt;Most of the time, people use the &lt;strong&gt;delegate_to&lt;/strong&gt; option, which tells Ansible to connect to another server for one specific task. I had used it previously &lt;a class="link" href="https://blog.zwindler.fr/2016/12/07/automatisation-de-la-supervision-avec-centreon-et-ansible-3/" &gt;to feed informations in Centreon with CLAPI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here, if you need to run several tasks and none of them have to be executed on the remote machine (that we are trying to deploy), you can just specify at the head of the playbook &lt;em&gt;that all tasks&lt;/em&gt; are to be executed from the local machine, with &lt;strong&gt;connection: local&lt;/strong&gt; :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;gather_facts: false
connection: local
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To sum this up, with these 2 options, you can tell Ansible not to « gather facts » as a preliminary step of every playbook, and to execute everything locally, thus avoiding the failing connection to the yet inexistant servers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Problem solved.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="vsphere_guest-versus-vmware_guest"&gt;vsphere_guest versus vmware_guest
&lt;/h3&gt;&lt;p&gt;My second issue was that 2 groups of modules were available in Ansible core, and one of them was abandoned. &lt;em&gt;Of course&lt;/em&gt;, I was using the oldest abandoned one, because it’s the one that posts up in all the tutorials/examples I could find on Internet ;-) .&lt;/p&gt;
&lt;p&gt;You can find it here &lt;a class="link" href="https://docs.ansible.com/ansible/latest/collections/community/vmware/vmware_guest_module.html" target="_blank" rel="noopener"
&gt;vsphere_guest&lt;/a&gt;. It « works », and it has been integrated to the core way sooner (v 1.6) and needs the python dependancy &lt;a class="link" href="https://github.com/argos83/pysphere" target="_blank" rel="noopener"
&gt;pysphere&lt;/a&gt; (not maintained since 2013)!&lt;/p&gt;
&lt;p&gt;There is no reason « not » to use &lt;strong&gt;vsphere_guest&lt;/strong&gt; to provision your virtual machine. Latest version of this module works for vSphere v5 and should work for 6.X. A good example of what can be done with this module can be found on this nice blog-post from &lt;a class="link" href="http://everythingshouldbevirtual.com/creating-vsphere-vms-using-ansible" target="_blank" rel="noopener"
&gt;EverythingShouldBeVirtual&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yet, you won’t be able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modify the virtual machine (like vCPU, &amp;hellip;) if you generate it from a vm template&lt;/li&gt;
&lt;li&gt;Customize it on the OS level (change hostname, IP, &amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I massively use templates so this was clearly an issue. My typical usecase is this : I deploy a virtual machine from a given template (depending which type of service I want) and then finalize customisation through Ansible playbooks.&lt;/p&gt;
&lt;p&gt;In this case, I would have to deploy my virtual machine, and still have to go into them to modify them (like hostname and IP) before playing my playbooks to customise them.&lt;/p&gt;
&lt;p&gt;Hopefully, people at VMware didn’t stop at VIPerl and PowerCLI. It’s been a few years than there is a Python module, maintained by VMware, and regularly updated to take advantage of the new API functionnalities: &lt;a class="link" href="https://github.com/vmware/pyvmomi" target="_blank" rel="noopener"
&gt;pyvmomi&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;From there, a new Ansible module, taking advantage of this python API, you have much more possibilities.&lt;/p&gt;
&lt;h2 id="let-there-be-light"&gt;Let there be light
&lt;/h2&gt;&lt;p&gt;The list of Ansible modules taking advantage from &lt;strong&gt;pyvmomi&lt;/strong&gt; is quite impressive. You can find them, they all start with &lt;strong&gt;vmware_&lt;/strong&gt; (you can find the list on &lt;a class="link" href="https://docs.ansible.com/ansible/2.9/modules/list_of_cloud_modules.html" target="_blank" rel="noopener"
&gt;the official Ansible documentation&lt;/a&gt;, VMware section).&lt;/p&gt;
&lt;p&gt;Two of them particularly got my attention (but there are a lot more!):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.ansible.com/ansible/latest/collections/community/vmware/vmware_guest_module.html" target="_blank" rel="noopener"
&gt;vmware_guest&lt;/a&gt; can help manage virtual machines&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.ansible.com/ansible/latest/collections/community/vmware/vmware_vm_shell_module.html" target="_blank" rel="noopener"
&gt;vmware_vm_shell&lt;/a&gt; can execute commands directly inside the guest OS, provided it executes VMware Tools&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="prerequisites"&gt;Prerequisites
&lt;/h3&gt;&lt;p&gt;To execute this modules, you need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;pyvmomi&lt;/strong&gt; and its dependancies (python 2.6+ and sphinx)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pip install pyvmomi sphinx
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ansible 2.2&lt;/strong&gt; minimum (but you’d better have 2.3 or even 2.4!)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;del datetime="2017-06-20T14:31:16+00:00"&gt;On paper, the module « works » with 2.2, the actual version on stable depots. But most interesting functions appear in 2.3 so for now you have to compile sources!~~&lt;/p&gt;
&lt;p&gt;The actual version on RHEL/CentOS 7 is 2.3.X. You don’t need to compile sources anymore, UNLESS you need the very latest additions which can be found in 2.4. I give you the necessary steps at the end of the article.&lt;/p&gt;
&lt;h2 id="and-now-the-playbook-"&gt;And now, the playbook !
&lt;/h2&gt;&lt;p&gt;The following playbook will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ask you for a priviledged account for vCenter&lt;/li&gt;
&lt;li&gt;deploy a virtual machine on the vCenter from a template&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This deployment needs some variables that can be given directly from the Ansible host inventory like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;virtual disk size&lt;/li&gt;
&lt;li&gt;vCPU number&lt;/li&gt;
&lt;li&gt;vRAM quantity&lt;/li&gt;
&lt;li&gt;target ESXi and target datasotre&lt;/li&gt;
&lt;li&gt;VM IP address and hostname&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The virtual machine will be deployed as expected, except for hostname and IP. Those 2 parameters will be modified after first boot by VMware Tool.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat zwindler_vmware_add_normal.yml
---
- hosts: all
gather_facts: false
connection: local
vars_prompt:
- name: &amp;#34;vsphere_password&amp;#34;
prompt: &amp;#34;vSphere Password&amp;#34;
- name: &amp;#34;notes&amp;#34;
prompt: &amp;#34;VM notes&amp;#34;
private: no
default: &amp;#34;Deployed with ansible&amp;#34;
tasks:
# get date
- set_fact: creationdate=&amp;#34;{{lookup(&amp;#39;pipe&amp;#39;,&amp;#39;date &amp;#34;+%Y/%m/%d %H:%M&amp;#34;&amp;#39;)}}&amp;#34;
# Create a VM from a template
- name: create the VM
vmware_guest:
hostname: &amp;#39;{{ vsphere_host }}&amp;#39;
username: &amp;#39;{{ vsphere_user }}&amp;#39;
password: &amp;#39;{{ vsphere_password }}&amp;#39;
validate_certs: no
esxi_hostname: esxi_server
datacenter: &amp;#39;ZWINDLER&amp;#39;
folder: A_DEPLOYER
name: &amp;#39;{{ inventory_hostname }}&amp;#39;
state: poweredon
guest_id: rhel7_64Guest
annotation: &amp;#34;{{ notes }} - {{ creationdate }}&amp;#34;
disk:
- size_gb: 150
type: thin
datastore: &amp;#39;{{ vsphere_datastore }}&amp;#39;
networks:
- name: server_network
ip: &amp;#39;{{ custom_ip }}&amp;#39;
netmask: 255.255.252.0
gateway: 192.168.100.1
dns_servers:
- 192.168.100.10
- 192.168.101.10
hardware:
memory_mb: 4096
num_cpus: 2
customization:
dns_servers:
- 192.168.100.10
- 192.168.101.10
domain : zwindler.fr
hostname: &amp;#39;{{ inventory_hostname }}&amp;#39;
template: tmpl-rhel-7-3-app
wait_for_ip_address: yes
- name: add to ansible hosts file
lineinfile:
dest: /etc/ansible/hosts
insertafter: &amp;#39;^\[{{ ansible_host_group }}\]&amp;#39;
line: &amp;#39;{{ item }}&amp;#39;
with_items: &amp;#39;{{play_hosts}}&amp;#39;
run_once: true
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From there&amp;hellip; well, you can do anything that pops in your mind!&lt;/p&gt;
&lt;h2 id="useful-links"&gt;Useful links
&lt;/h2&gt;&lt;p&gt;« pause » module might be useful in some cases when you really have to wait some time. I don’t use it and I wouldn’t even consider it for production.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.ansible.com/ansible/latest/collections/ansible/builtin/pause_module.html" target="_blank" rel="noopener"
&gt;Pause Module&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, I might write the same article with the Proxmox VE module. Stay tuned!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.ansible.com/ansible/latest/collections/community/general/proxmox_kvm_module.html" target="_blank" rel="noopener"
&gt;Proxmox Kvm Module&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="new-functionnalities"&gt;New functionnalities
&lt;/h2&gt;&lt;p&gt;Until &lt;del datetime="2017-06-20T14:31:16+00:00"&gt;2.3~~ 2.4 becomes available in your OS repository, you might encounter this error if you use functions that aren’t included (yet) in your own version of Ansible (&lt;strong&gt;linked_clone&lt;/strong&gt; or &lt;strong&gt;snapshot_src&lt;/strong&gt; released in 2.4 for example) :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ansible-playbook zwindler_vmware_add_micro.yml
vSphere Password:
VM notes [Deployed with ansible]:
PLAY [ansible_node] **********************************************************
TASK [create the VM] ***********************************************************
fatal: [ansible_node]: FAILED! =&amp;gt; {&amp;#34;changed&amp;#34;: false, &amp;#34;failed&amp;#34;: true, &amp;#34;msg&amp;#34;: &amp;#34;unsupported parameter for module: linked_clone&amp;#34;}
PLAY RECAP *********************************************************************
ansible_node : ok=0 changed=0 unreachable=0 failed=1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Should you need a « yet to be released » functionnality, you can compile the latest version of Ansible from the sources (2.4 in my example here):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;git clone https://github.com/ansible/ansible
cd ansible
make
make install
ansible --version
ansible 2.4.0
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Create a plugin for Thruk using Thruk API, and work around permission issues</title><link>https://blog.zwindler.fr/en/2014/08/19/create-a-plugin-for-thruk-using-thruk-api-and-work-around-permission-issues/</link><pubDate>Tue, 19 Aug 2014 09:13:19 +0000</pubDate><guid>https://blog.zwindler.fr/en/2014/08/19/create-a-plugin-for-thruk-using-thruk-api-and-work-around-permission-issues/</guid><description>&lt;img src="https://blog.zwindler.fr/2014/08/perl.gif" alt="Featured image of post Create a plugin for Thruk using Thruk API, and work around permission issues" /&gt;&lt;p&gt;A friend of mine came to me with a problem. During one of his Shinken/Thruk deployment, he came with the idea of writing a plugin that could take advantage of Thruk statistics to graph the load of the monitoring engine.&lt;/p&gt;
&lt;p&gt;Though you can get this information from Nagios itself through nagiostats, it’s a bit more difficult with the couple Thruk/Shinken. You could emulate Nagios by adding the Shinken &lt;em&gt;old-cgi&lt;/em&gt; legacy module, or you could an &lt;em&gt;authenticated wget&lt;/em&gt; the web page of Thruk and parse it, but let’s face it, these « solutions » aren’t pretty. I guess that the prettiest one should be to plug into Shinken, and maybe I’ll cover this later, because I think it’s the best solution, but this may need a little « dev effort ».&lt;/p&gt;
&lt;p&gt;In order to avoid some useless effort, my friend asked Thruk developers how to do it the way Thruk does it. The main dev guided him to the « thruk » command line, which basically just generates the web page, but in a cleaner way as this is done internaly. You can get more information about Thruk command line with a simple « &lt;em&gt;thruk &amp;ndash;help&lt;/em&gt; » in your shell.&lt;/p&gt;
&lt;p&gt;With this information, my friend developped a perl script (because he is a perl addict ;-) ) to parse this page and get the statistics he needed. But when he deployed it *shock*: he couldn’t see a thing INSIDE the Thruk console.&lt;/p&gt;
&lt;p&gt;The main problem here isn’t the fact that the script doesn’t seem to work, but rather the lack of error output.&lt;/p&gt;
&lt;p&gt;When first idea was to add the shinken user in &lt;em&gt;apache&lt;/em&gt; group. This did help to make it work for the shinken user in shell, but for the web page of shinken/thruk it didn’t help.&lt;/p&gt;
&lt;p&gt;To reproduce, I wrote a really simple script&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;#/bin/perl
#Print your page with thruk CLI, and display error output with 2&amp;gt;&amp;amp;1
print `/usr/bin/thruk -A thrukadmin extinfo.cgi?type=4 2&amp;gt;&amp;amp;1 `;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Though now the output was correct (lots of generated HTML jibber jabber) in the shell, the error is still displayed in Thruk&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;open file /etc/thruk/thruk_local.conf failed (id: uid=500(shinken) gid=500(shinken)
groups=500(shinken),0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023,
pwd: /var/run/shinken): at /usr/share/thruk/lib/Thruk/Utils/CLI.pm line 272.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;AH-AH ! So, basically what I did was to add this at the first line of my script, to help me understand those groups/permissions issues.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;#/bin/perl
print `id shinken`;
#Print your page with thruk CLI, and display error output with 2&amp;gt;&amp;amp;1
print `/usr/bin/thruk -A thrukadmin extinfo.cgi?type=4 2&amp;gt;&amp;amp;1 `;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here is the output&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;uid=500(shinken) gid=500(shinken) groups=500(shinken),48(apache)
open file /etc/thruk/thruk_local.conf failed (id: uid=500(shinken) gid=500(shinken)
groups=500(shinken),0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023,
pwd: /var/run/shinken): at /usr/share/thruk/lib/Thruk/Utils/CLI.pm line 272.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is what helped me understand what was really happening here. The groups were &lt;em&gt;shinken&lt;/em&gt; and &lt;em&gt;root&lt;/em&gt;, but there where no mention of &lt;em&gt;apache&lt;/em&gt;, even though I had just added apache to shinken and restarted the whole lot.&lt;/p&gt;
&lt;p&gt;In fact, the groups are set at another level : during the deamonization. By reading the files, I managed to find 3 places where shinken can set it’s own group :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;/etc/default/shinken&lt;/em&gt;, but only used for run and var directories creation (first launch)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;/etc/shinken/shinken.cfg&lt;/em&gt;, only the arbiter&lt;/li&gt;
&lt;li&gt;&lt;em&gt;/etc/daemons/*.ini&lt;/em&gt;, for the daemons&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You need to have read access for these 3 files (for my setup anyway)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ll /etc/thruk/thruk*
-rw-r--r--. 1 apache apache 25933 17 mai 19:13 /etc/thruk/thruk.conf
-rw-rw----. 1 apache apache 671 18 août 15:36 /etc/thruk/thruk_local.conf
ll /var/lib/thruk/secret.key
-rw-r-----. 1 apache apache 32 13 août 13:13 /var/lib/thruk/secret.key
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Opening theses file to « &lt;em&gt;other&lt;/em&gt; » is obviously not an option, and I not a fan of changing the group of these conf files, even though this can/will work.&lt;/p&gt;
&lt;p&gt;So, as of today, my favorite working solution (I’m still searching for a better one, and maybe I’ll switch to Shinken integration instead of Thruk) is to change &lt;em&gt;shinken poller&lt;/em&gt; group in &lt;em&gt;poller.ini&lt;/em&gt; to &lt;em&gt;apache&lt;/em&gt; and restart the daemon. This way, the poller and the associated plugins can access those 3 files and your Thruk API will work in Thruk console as it does in the shell.&lt;/p&gt;</description></item></channel></rss>